3 ms·
> any piece of core logic is scattered over 102 code points in 34 modules — instead of just residing in a single, well readable and commented main function that
by Swizec 3y ago
> any piece of core logic is scattered over 102 code points in 34 modules — instead of just residing in a single, well readable and commented main function that would neatly self-explain
The tragedy of McCabe metrics is that this is a tooling failure. You can and should apply McCabe to whole software and then all these smol-functions approaches start falling apart. McCabe goes through the roof because the metric doesn’t depend on length.
McCabe measures decision points. A 5000 line linear function has a McCabe complexity of 1. It’s fine.
An even better measure is architectural complexity. I’ve written about this a lot after reading some papers and a PhD thesis about it [1]. Tried turning it into a book but that didn’t quite happen. It will be a subpoint in a new project :)
Architectural Complexity uses visibility metrics to say how intertwined your software has become. A good rule of thumb is that the more imports/exports you have in a file, the more architecturally complex it is. Best seen with a dependency graph visualizer, but you can also feel it viscerally when you have to bounce around a bazillion files to understand what happens with any code flow.
[1] https://swizec.com/blog/why-taming-architectural-complexity-is-paramount https://swizec.com/blog/why-taming-architectural-complexity-...
- throwanem 3y agoI think it's a shame you didn't write the book. I know some people who desperately need to read it.
- chrisweekly 3y agoSame! Also, Swizec's an awesome writer. (Long-time email subscriber, and fan of his posts and Serverless Handbook book, etc).
- epage 3y agoLike cpus with icache and dcache which leverage memory locality, we overlook the effect of locality on understanding code.
- tetha 3y agoI mean I'm not working on big code bases anymore, more tooling, analytics and managment. But both the open/closed principle and some advice from Sandy Metz and others really stuck with me: Don't bother abstracting. Just write straight line code. And then introduce indirections and abstractions if good reasons demand it. In fact, if changes to the code demand it. For example, introducing an abstraction for an external database can improve testing prospects. If you need to fix the same bug in several places, it's usually time to extract a common abstraction. If you need to touch some established piece of code to introduce a choice what kinda algorithm/strategy/formatting/.... you need to use here, that's a decent point to introduce some abstraction and to inject some function/object here. If you would have to replicate the exact complex logic from somewhere else, and those places need to move in sync for reasons, moving that to a common place is probably a good idea. Just following what the code needs and the changes and requirements around the code need has resulted in much simpler code and way more effective abstractions for myself.