I’ve been brainstorming about ways to solve the N-dimensional code organization problem, and am thinking about developing a Smalltalk-like code-browsing experience. Even after I left my Smalltalk job and moved to Java, I configured Eclipse to give me the same IDE experience: an object browser that let me focus on Classes and Methods, which was the level of abstraction I was working at. (And not files.)
How I see the problem:
When developers ask “Where does this file go? What do I call it?”, they’re really asking:
“How do I map this multi-dimensional concept onto a single hierarchical path?”
Example: A customer email notification worker
Domain: Customers
Technology: Worker
Integration: Email
Access: Internal
I think that the unit of thought should be:
Modules (not files)
Functions (not line numbers)
Concepts (not directories)
Relationships (not imports)
This is probably the most promising direction for truly solving the n-dimensional organization problem.
Some editors, e.g. VSCode paired with ElixirLS, let’s you view and navigate your project by symbol.
That can be both symbols in the current file or global across your project.
Nice thing is it also works for multiple languages, so that you can also navigate to say JS symbols and even Markdown headers (e.g. to jump to READMEs or documentation).
Maybe a setup like that would provide a similar experience to what you described?
After playing with Pharo and Glamorous Toolkit a few years ago, I totally understand what you mean by this!
I’m hoping the end-game of the upcoming official Expert LSP implementation gives us a similar experience with Elixir. I’ve not had many issues with ElixirLS and friends, but a unified/official LSP will make our lives so much easier!
The real problem isn’t “how do we organize files better?” but rather “why are we organizing files at all?"
This dovetails with what college professors are observing with students that did not grow up with the traditional desktop metaphor with its hierarchal file based directory structure as their dominant GUI paradigm.
Not only did they not know where their files were saved — they didn’t understand the question… Gradually, Garland came to the same realization that many of her fellow educators have reached in the past four years: the concept of file folders and directories, essential to previous generations’ understanding of computers, is gibberish to many modern students.
…
More broadly, directory structure connotes physical placement — the idea that a file stored on a computer is located somewhere on that computer, in a specific and discrete location. That’s a concept that’s always felt obvious to Garland but seems completely alien to her students. “I tend to think an item lives in a particular folder. It lives in one place, and I have to go to that folder to find it,” Garland says. “They see it like one bucket, and everything’s in the bucket.”
It seems like that mindset shift is happening in software development, especially with LSPs and LLMs offering developers new ways of writing and searching through code. In Elixir land, there are projects like LiveBook and Phoenix Playground - The easiest way to run single-file Phoenix apps that have been chipping away at the traditional one module per file convention.
I wholeheartedly agree. As a matter of fact, that was the topic of my talk at this year’s GigCity Elixir.
It wouldn’t be popular with the VI EMACs crew but for those that are willing to use VSCode, might find an IDE that is more like the Smalltalk IDE very useful.
Features like
Show me the call tree for this function
Show me the headers for functions of this type in this module. Types defined by an @tag.
Just show me the function I am working on and just the headers in a list window for all the others. So I don’t have to constantly scroll through a wall of code.
If the module file name is by convention, then just use that convention and let me say “new Module X” and create the file but just show me the module definition. I should never need to look for the file. Just apps, modules and functions.
Show me the function @doc as it would look rendered in a separate pane from the function definition.
Let me easily see all callers as a list based on the AST. Then let me select each caller to drill down. Or let me trace a series of calls using AST and again make each reference a link to the definition. Without losing my place in the tree.
Let me select code to be executed right now using local constants and ask me for sample argument values. Or run the @doc iex test by selecting it and run with output in a separate pane/space.
It’s kind of crazy that we somehow haven’t moved past files when it comes to storing our code.
As Kent Beck said: Source code in files? How quaint. How seventies.
I think that at the very least it should be possible to add tags to modules/classes/whatever a language uses so that we can always view the codebase the way we need to. This would remove the endless war between structuring directories by layer vs by domain. We could easily get a by-domain view when working on business logic and a by-layer view when dealing with project-wide infrastructure code, for example.
Of course, the potential is much higher than that and I would love to work with a richer representation of my code.
Yeah but then nobody would agree on domains, or whatever other axis people try to organize their code around.
Personally I’d go with tags, and not only that but I want my editor to suggest tags and gradually learn from me as well. Tags don’t impose any hierarchical structure. Organize things as you like and as it makes sense to you.
I don’t think we have to do away with the filesystem hierarchy, but making the paths an implementation detail could get us something similar to what you are suggesting.
And we’re are already manually following a convention. If a module is named MyApp.Models.Organization it would be under lib/my_app/models/organization.ex. If the editor enforces this convention automatically, then we don’t have to think about the tedious implementation detail of where to place files based on the mdoule name.