1. 30
  1. 7

    The more I see this sort of thing in code bases, the more I learn that for some people this thing doesn’t matter at all, and for others it matters significantly. (I’m one of the latter, but have worked with the former a bunch). Neither way is right per se.

    The arguments against this are:

    1. filenames and class names are generally unique enough that the folder structure is irrelevant once the file is open
    2. component types have many similarities, which makes conventions easier to see.
    3. the person responsible for models / controllers may be different than for the view.

    There are probably others, and each of those has counterpoints:

    1. filenames are often a thing that makes it easier to make decisions and changes on (e.g. looking at a feature’s git history, checking whether the feature is complete, working out whether we can we move the feature into another system, …). Grouping by
    2. often the same person is responsible for M/V/C
    1. 7

      I’m usually of the same opinion and don’t really care what the code looks like - sometimes it matters slightly more for opinionated languages or frameworks (especially when your IDE is suggesting things that may not be relevant)

      But one aspect I think is overlooked a lot is onboarding new developers: juniors or contractors being the most important. A junior wants to be able to navigate easily and not be dropped into a huge mess that’s only well understood in some team veteran’s head and contractors you don’t want them spending days getting up to speed with a codebase.

      1. 6

        Yep. I think the most succinct way of stating this view is:

        To reduce the cognitive burden inherent software development, things which are closely related should be located close to each other. This concept applies to every level of a software stack - statements, functions, classes, files, folders, modules, services, and systems.

        1. 2

          One thing we’ve been striving for is consistency. We have a decently large code base, maybe 600 files, 20-30 engineers at a time (50+ engineers over time), but the whole code base looks exactly the same. Doesn’t matter what area of the code you’re in, you can hop to a different team in an entirely different area of the code and it’s still familiar. That’s been very empowering.

          It’s kind of like the idea of not wanting to introduce additional languages at your org taken to the extreme.

      2. 6

        This is called “package by component” and it was how I was taught to write code and have done ever since. Generally I avoid packaging by syntax (all your types go here, all your classes go there, etc) However I do follow a vague DDD-like separation of transports, business logic and data store. These three feel like the simplest abstractions, no more and no less.

        1. 3

          Probably because even though they can look like they’re very related and do often change together, files in different domains often don’t interact one to one. And if they do change together, it’s usually because a change in a whole other component required it.

        2. 6

          I’m having just this frustration in a web project where the HTML templates, CSS files and TypeScript files are in separate directories … but I’m commonly working on feature.tmpl, feature.ts and feature.css at the same time.

          The problem is, I can’t easily rearrange the files because the application needs them segregated this way. The CSS files are static, the template directory is read by the templating engine, and the script directory gets compiled by tsc.

          I guess (doing some rubber-ducky brainstorming here) I could have a build script or makefile that copies them out of a single directory into the separate ones the app needs…

          1. 2

            HTML templates, CSS files and TypeScript files are in separate directories

            …and stuff being last modified on mondays in separate directories from tuesdays etc. That would make great fun!

            But seriously, soft-links during transition for a rescue.

            1. 2

              or, heck, set up a whole parallel tree of just the stuff you’re interested in, with symlinks into the main tree.

            2. 1

              it’d be nice if the source of truth accurately reflected your semantic structure and then it gets rearranged into the structure that is compatible with the thing you are using… it is possible to do this with literate programming stuff like tangling org-mode things but that solution is not tool-agnostic enough (or people would probably use it more), I’d like it if we solved these kinds of templating problems once and for all … but maybe it’s not possible … eventually I’ll know how good my attempt works (but I don’t make very fast progress, I have too little confidence and would rather do other things usually), I don’t see anything glaringly wrong with my approach but no one seems very interested so I suppose it can’t be very clever. Still the way we do things now is too much work (it’s partly the reason I am so bored with trying to get my stuff to the point that it is useful).

            3. 4

              Organizing with Single-File Components (SFCs) is one of the reasons I like Vue so much.

              That said: Does nobody use fuzzy file find any more?

              1. 3

                I’ve heard somewhere that the folder structure philosophy at Facebook/Meta is to just put everything in the same folder and to have long and descriptive filenames, and I tend to agree.

                Having lots of nesting means you’ll be searching for files most of the time because remembering the taxonomy of the file you need is often much harder than just calling it by name, and having everything in the same folder avoids duplicate names that would mess up the search.

                1. 5

                  I don’t see how task_for_deleting_stuff.lang and task_for_creating_stuff.lang is better than tasks/delete_stuff.lang and tasks/create_stuff.lang. I understand that duplicate names might be slightly annoying, but if you’re doing a Sublime-style project-wide search when opening a file, it doesn’t really matter if you end up with foo/bar.lang and qux/bar.lang or foo_bar.lang and qux_bar.lang. If you have too long names, they’ll get abbreviated on your editor’s tabs as well, so you’d end up seeing only ...bar.lang anyway. With a project-wide search you’d type almost the same anyway: foo bar would open the file in either structure.

                  However, sticking things in directories makes it much easier for newcomers to discover what’s there, how it relates to eachother and arguably makes it easier to spot dead code and delete it.

                  1. 1

                    Long names are great if you can afford a big screen! Not everyone can.

                    I do prefer folders but keep them quite minimal in terms of depth.

                    1. 2

                      My point was that even on a big screen, with many editor tabs open or a complex modeline (vim/emacs) the names would get abbreviated anyway, both with long names and with a directory structure.

                      If the project is large enough, a deeper directory structure with more nesting may be warranted. I feel that in a lot of smaller projects (especially Java), directory nesting can be overly deep.

                      1. 1

                        Oh yeah I’ve seen both ends too! My first job at a large company involved a codebase with about a hundred Go files in one folder, I spend weeks untangling it and trying to understand it! The other end of the extreme (huge Java projects) is just as bad though.

                    2. 1

                      I actually like both? I would tend to do tasks/task_for_deleting_stuff.lang (or more likely deleting_stuff/deleting_stuff_task.lang). Very few downsides to this I’ve found. With fuzzy searching or just listing that directory you get all the deleting_stuff files. If you fuzzy search task .lang you can get most of the tasks if you’re updating a common pattern or such across them.

                      1. 1

                        Sure, but you’re not dumping everything into a single directory like Facebook seems to be doing.

                    3. 2

                      That sounds like the ObjectiveC model for namespacing.

                      1. 1

                        Objective-C/Cocoa encouraged a degree of files being named MyClass.m MyClass+Thing.m etc as Objective-C allows multiple distinct implementation regions for a class.

                      2. 2

                        This also opens up opportunities for logical grouping of files in ways that enable other features later on – for example, Django’s “app” concept comes out of having files organized like this, and I’ve long argued that’s one of its most powerful but least appreciated design features.

                        1. 2

                          At my previous job we successfully used Django apps to logically group related functionality in a large system, and it made things a lot easier to navigate. Also, in the ERD diagram we could group and color-code the entities by app which was helpful in making sense of it all. For instance, you’d have the “invoice” app which dealt with invoices, payments and so on, the “user” app would deal with authentication and rights management, the “asset” app dealt with all the uniquely identifiable hardware the company owned (which was an important part for this project).

                          The one thing that bugged me a bit is that it wasn’t really possible to avoid circular dependencies between the apps, which required some extra thinking here and there to avoid loading/importing problems. I think Django’s app concept was more intended to have separate, independent apps (or perhaps apps with only one-directional dependencies). Nevertheless, we made it work quite effectively and this was only a minor stumbling block.

                          1. 1

                            having come to django after experimenting with a bunch of other frameworks, it’s definitely the most appreciated design feature for me!

                          2. 2

                            The solution is obviously to have everything in a single file :D

                            More seriously, I think that the Jade language (https://en.wikipedia.org/wiki/JADE_(programming_language)) in the early-mid 2000s was essentially that: You had an IDE that you had to use, with a list of “files” that I think were not actually exposed to you directly, and the object database from when you were running your program (IIRC all objects were by default persistent).

                            At the time I had to use it, it was fairly terrible but as it was from an NZ company founded by people from my university’s business school, they were hired for a huge amount of money to replace the old management systems the university used. As you might expect from this path to selection, this caused problems - they had made it have a fixed cap on the length of building names, and rather than requiring them to fix it the university literally renamed every building. It then took something like a year to get useful performance as Jade was a terrible and slow database system, in addition to being a terrible and slow programming language.

                            1. 1

                              IMO similar access permissions also be taken into account. And nesting matters a lot.

                              Especially for assets.

                              1. 1

                                Just stop storing and editing code as a fixed hierarchy of files and folders.

                                1. 2

                                  This isn’t necessarily a new viewpoint, and so it has many pros and cons. The chief among the cons is that all (most?) existing tooling assumes that files and folders is the primary mechanism for organization.

                                  Do you have any concrete suggestions on this that take this from the concept to implementation?

                                  1. 2

                                    It is indeed a very big zero-to-one problem :-/

                                    1. 1

                                      Ya, http://datalisp.is, you still treat files and folders as the API of the compiler (or whatever) that you are targeting, but you are free to rearrange the access to sections of text (like materialized views or whatever). There’s lots you can do but the key for these tools to exist is some standard way for them to work together.. which is datalisp.

                                      1. 1

                                        In my casual perusal of datalisp, I wasn’t able to really get a sense of what it is. It seems rather opaque right now. It seems like it’s very much a research project. Is there something more concrete that I’m missing on this?

                                        1. 1

                                          It’s stupid simple really, it’s an attempt at a decentralized name system, but before that it is just a data interchange format and some associated tools (templating, version control, etc). The problem of co-locating stuff will be tackled with logic programming over the template data that you use to export a codebase, which is painfully manual, but you can share stuff and work with others.

                                          The frontier is what I’ve been staring at but really all I’m trying to do is find solid assumptions to build on.

                                    2. 1

                                      I don’t think that’s necessarily a solution - the way your tools would display the “units of code” still has to be organised somehow. This would probably still require the programmer to make a taxonomy of code units, since automated relations are typically not that great and may miss more “implicit” relationships between code. Perhaps that can be done by tagging them? This reminds me of Doxygen which can IIRC have clickable “see also” links in descriptions so you can help the reader find related functionality.

                                      I mean, trivially you could do away with a fixed hierarchy of files and folders by simply storing all of your code in a single file. Most languages would allow you to do that already, today. The reason we don’t typically do that is because it’s such a mess to find things (although there are some notable single-file projects and people typically praise them for their ease of drop-in into an existing codebase).

                                      Besides, an IDE should technically be able to show existing code from multiple viewpoints, already, even if the actual storage is in files and directories. For example, showing class by hierarchy with “jump to definition” is something that existing IDEs can already do, I think.