I'm probably late to the party, but I was hoping to see a larger discussion on "Too many small methods, classes or modules" aka Deep Module vs Shallow Modules. I think we can probably debate just that last sentence alone for a while. I would imagine "module" here simply means a group of classes that are collectively related. Having "too many modules" is likely just the implicit complexity of the problem you're trying to solve. You either have all those modules or you have no product. If all products were trivial to code, no one would be employing you to create the product.
So the main thing we typically come across is "too many classes" and that's the example the author gave in the article. Nearly all the developers at my company go with the "throw everything into one class" approach regardless whether they're junior, senior, etc. I tend to go the extreme opposite route and usually create small classes for things that seem critical to test in isolation. While I'm coding that small class and writing unit tests, it feels perfect. When I revisit the code, it is a bit overwhelming to understand the relationships between the classes. So I understand the article's criticisms of too many small classes.
However, I have my doubts that moving this class into the main class as a simple method would reduce cognitive load. For one, due to the nature of our tools, e.g. JUnit, I would be forced to make that method public in order to test it (and now it's part of the large class's API contract). So I can either make it public, remove my unit tests, or attempt to make my unit tests part of the greater component's test which really overcomplicates the parent's unit tests. Ignoring the testing issue, is the cognitive load complexity just a file structure issue? Instead of turning those small classes into methods in a large class, I could just use nested classes in a single file. Or, there can be some package naming convention so readers know "these helper classes are only used by this parent class". I would be interested to hear others thoughts, but due to the nature of HN's algorithm, it's likely too late too see many replies :)
I mean it sounds to me like testing is your only problem so it’s kind of hard to ignore.
Personally I prefer fewer larger modules over more smaller modules. Deeply nested code is harder for me to reason about, I need to push stuff on my stack more often as I go down a debugging rabbit hole.
You can never reason locally about a bug. All code looks good locally. Bugs always manifest in the totality of your code and that is where you have to look at it. Your unit tests for the release running on production are all green, someone reviews all those lines that are in there. Locally it all made sense, local reasoning is how you ended up with that bug in production.
If you write a small little class with one method to help implement some bigger interaction, if your change does not touch the unit tests of the ”wrapper” class actually implementing the bigger interaction, what the users use, you are likely writing meaningless code or your test coverage for the actual use cases is not good enough.
> if your change does not touch the unit tests of the ”wrapper” class
I don't think this is a good example. In fact, this is more supportive of having the small little class. The "wrapper" class only needs to have 1-2 unit tests to test the scenarios in which the small little class is invoked without needing to be concerned with the complexity of everything that small little class is actually doing. I've never written a small helper class without writing corresponding tests in the wrapper so I've never had that problem - it's usually the first thing I write after adding the helper class. For that specific problem there's automated and manual processes anyway. Code coverage tools can easily tell you if you missed writing tests for the invocation and reviewers should spot that in PR reviews.
So the main thing we typically come across is "too many classes" and that's the example the author gave in the article. Nearly all the developers at my company go with the "throw everything into one class" approach regardless whether they're junior, senior, etc. I tend to go the extreme opposite route and usually create small classes for things that seem critical to test in isolation. While I'm coding that small class and writing unit tests, it feels perfect. When I revisit the code, it is a bit overwhelming to understand the relationships between the classes. So I understand the article's criticisms of too many small classes.
However, I have my doubts that moving this class into the main class as a simple method would reduce cognitive load. For one, due to the nature of our tools, e.g. JUnit, I would be forced to make that method public in order to test it (and now it's part of the large class's API contract). So I can either make it public, remove my unit tests, or attempt to make my unit tests part of the greater component's test which really overcomplicates the parent's unit tests. Ignoring the testing issue, is the cognitive load complexity just a file structure issue? Instead of turning those small classes into methods in a large class, I could just use nested classes in a single file. Or, there can be some package naming convention so readers know "these helper classes are only used by this parent class". I would be interested to hear others thoughts, but due to the nature of HN's algorithm, it's likely too late too see many replies :)