5 ms·
There is a call-stack depth problem here that is specific to codebases though. For one familiar with the the conventions, key data abstractions (not just data m
by jacobr1 2y ago
There is a call-stack depth problem here that is specific to codebases though. For one familiar with the the conventions, key data abstractions (not just data model but convention of how models are structured and relate) and key code abstractions, a well formed function is easy to understand. But someone relatively new to the codebase will need to take a bunch of time switching between levels to know what can be assumed about the state or control flow of the system in the context of when that function/subroutine is running. Better codebases avoid side-effects, but even with good separation there, non-trivial changes require strong reasoning about where to make changes in the system to avoid introducing side-effects and not just passing extra state or around all over the place.
So, I'd take "good architecture" with ok and above readability, over excellent readability but "poor architecture" any day. Where architecture in this context means the broader code structure of the whole project.
- zwnow 2y agoBut who talked about bad architecture? Good readable code doesn't rule out good architecture. Surely some things are complicated but even then, a dev should be able to quickly see whats going on with minimal expertise in a codebase.
- swatcoder 2y agoThey're suggesting that readability and "5-second accessibility" are essentially contextual and build on a conceptual language that might be specific to a tool, team, or project. The novel function that might take "5 seconds to read" for the 20 people contributing to a mature project with a good architecture might nonetheless take 10 minutes for a new hire to decipher because they don't know the local vocabulary (architecture, idioms) and need to trace and interpret things elsewhere in the project and its libraries. Meanwhile, writing implementations in a way that tried to avoid a local vocabulary altogether might make naive reads easier, but less readable to experienced team member because they're not as concise as they could be. Your general advice to "make things easily readable" is good advice, but like with writing compelling prose or making accessible graphic design, you need to consider your audience and your choices might look different than the ones somebody else might make.
- hinkley 2y agoGo is a board game with simple rules but combinatorial consequences to those rules. Minutes to learn and a lifetime to master. This is where “simple recursive data structures” can be simple to read but difficult to track and comprehend. An architecture that descends through distinct layers at least has landmarks that the recursive one does not have. If you are not at the root or the leaf you don’t really know where you are, lost in the middle.
- jacobr1 2y agoThe broader problem is "cognitive load to understand the code I'm looking at." There are a variety of factors that lead enabling that. This is a very limited example. function isReadyToDoThing(Foo foo) { return foo.ready } function processStuff((Foo foo) { if isReadyToDoThing(foo) { res = workflowA(foo) res2 = workflowB(foo) return res && res2 } } This might be dumb, if isReadyToDoThing is trivial, and it could be easily inlined. Or alternatively it could be a good way to self-document, or annotate a preferred approach (imagine several similar named methods). Regardless if you don't know the code, you'll want to go look at the method, especially if it is in a different file. But also consider: function isReadyToDoThing(Foo foo) { return foo.attribute1 && foo.attribute2 && ! otherThing(foo) } This or more complex logic might be encapsulated, in which case this is probably good to separate. Making these kind of tradeoffs involve thinking about the overall system design, not just the way you structure the code within a given function.
- maleldil 2y agoIf `isReadyToDoThing` is only used in one place, I'd argue that it's better to inline it with an appropriately-named variable so I don't have to "go to definition" to understand what it's doing. I think people get too caught up in "small functions" and lose the readability of code locality.
- ikrenji 2y agothe purpose of the function should be clear from its name. if its too complex to convey this information it should have a docstring that clearly explains what it does. it's not rocket science
- horsawlarway 2y agoNames are jargon. They are themselves their own form of complexity, and they require a similar timeline to become acquainted with. Further - the more of them you need (call depth) the worse this problem becomes.
- apelapan 2y agoIn the general case I fully agree. It is ideal that the name of anything clearly indicates whatever is important about that thing. But who is the viewer of that name? How much context can they be assumed to have? The name of the class? The name of of the module? The nature and terminology of the business that the function serves? The nature and terminology of the related subsystems, infrastructure and libraries? There is a context dependent local optimum for how to name something. There are conflicts of interest and trade-offs have to made.
- skydhash 2y ago> How much context can they be assumed to have? The name of the class? The name of of the module? The nature and terminology of the business that the function serves? The nature and terminology of the related subsystems, infrastructure and libraries? All of this.
- jajko 2y agoYeah, not disagreeing with what you write but parent is talking about different type of complexity which your description/approach doesn't magically fix, I'd call it spread of complexity