8 ms·
The concept of clarity is why I don’t like the consequence of SOLID, where you have lots of tiny classes. It’s easier to understand complex functions and a sim
by kosievdmerwe 7y ago
The concept of clarity is why I don’t like the consequence of SOLID, where you have lots of tiny classes.
It’s easier to understand complex functions and a simple class structure than the other way around. Because jumping between multiple files/classes incurs a high understandability cost, whereas complex functions fit on your screen typically.
And reading some more about it, I found this good article: http://qualityisspeed.blogspot.com/2014/08/why-i-dont-teach-solid.html?m=1 http://qualityisspeed.blogspot.com/2014/08/why-i-dont-teach-...
- azeirah 7y agoI typically find it very difficult to understand complex functions, (100+ lines of code, ~3 or more nesting levels deep) and even simpler complex functions (mixing 2-3 concepts into a 15 line function). I've only just started doing TDD the "Growing Object Oriented Software guided by tests" way, and I find it incredibly helpful that each and every class does just _one_ thing, even splitting up those 15 line functions into two or three separate classes implementing an interface -- single responsibility -- helps me a lot in reasoning about the code. I _have_ experienced the dependencies issue myself already though, it's very annoying to click on a method in my IDE, and then get shown the interface definition of that particular method. I'll then have to trace my way through a couple of files to find the dependency, very annoying.
- kosievdmerwe 7y agoYeah, but I would say it depends on context, clarity is very context dependent. Do what makes the code easiest to read taking into account that human limitations. Sometimes splitting out code makes sense by making the underlying structure clearer, sometimes it makes it bothersome to find the actual important details. For instance, logic that filters what jobs to run based on conditions, it might make sense to abstract the logic for the conditions into one class per condition, to make the filtering logic clearer.
- azeirah 7y ago> Sometimes splitting out code makes sense by making the underlying structure clearer, sometimes it makes it bothersome to find the actual important details. Yeah, that seems to be something I'll have to spend some time learning about. Right now I'm just mindlessly splitting off everything, and it kind of works, but it's annoying to navigate all over the place just to find some detail somewhere
- jpittis 7y ago> I typically find it very difficult to understand complex functions It seems to me like "complex" and "ability to understand" mean the same thing, so this phrase doesn't have much meaning. It's difficult to define "ability to understand" / "complex" without using either of those words in the definition. For example, you mention lines of code, nesting and multiple concepts. I tend to agree with your examples, however not necessarily the lines of code. I've seen single large functions that represent an algorithm in a way that's easier to understand than the implementation that breaks it up into tens of little functions. It made liberal use of comments to explain each section of code in the function. I believe its advantage was that when reading, you could simply scroll down the function line by line rather than having to jump all over the file.
- azeirah 7y agoSure, all I mean is that I get frustrated and lose unnecessarily much time being distracted by keeping a model of how the function works and how variables interact in my head. I have ADHD so my working memory isn't fantastic for these kinds of functions. I suppose you could take my definition of complexity to be approximate to cyclomatic complexity
- JamesBarney 7y agoLocal functions are also really handy when you want to break up a large function into smaller pieces but keep them localized.
- dang 7y agoThis is widely believed and repeated, but empirical evidence actually runs the other way: according to studies cited in the book Code Complete, functions in the range of 100 to 150 LOC are more maintainable than shorter ones. https://news.ycombinator.com/item?id=6229801 https://news.ycombinator.com/item?id=6229801 https://news.ycombinator.com/item?id=3876434 https://news.ycombinator.com/item?id=3876434 https://hn.algolia.com/?query=by:cpeterso%20%22code%20complete%22%20function&sort=byDate&dateRange=all&type=comment&storyText=false&prefix=false&page=0 https://hn.algolia.com/?query=by:cpeterso%20%22code%20comple...
- BurningFrog 7y agoAt the end of the day, a simple measure like LOC can never capture readability, good or bad, and you get eaten by Goodhart's Law if you focus too much on it. https://en.wikipedia.org/wiki/Goodhart%27s_law https://en.wikipedia.org/wiki/Goodhart%27s_law
- smitty1e 7y agoOh, save us from the scenes, Where the end becomes the means, And the forest gets so lost among the trees; When polishing the source, Blunts all our creative force, And procedure kills the genius it claims it frees.
- dang 7y agoNo one would argue otherwise. Indeed, you can trivially take any readable function and transform it into an unreadable one of exactly the same length. But this doesn't seem like a valid reason to dismiss specific findings of specific studies. Don't you think it's interesting that such research as we have contradicts the most often-repeated claim about this aspect of programming?
- BurningFrog 7y agoI don't know. I've learned over the years that there is always a study confirming or contradicting whatever point you want to make. "Beware The Man Of One Study". I say that without even looking at those studies, which is perhaps unfair. But there are So Many Studies... My personal experience is that when I was exposed to shorter simple and (so important!) well named functions, my work became so much better. And that is now the school I subscribe to. That's not - at all - to say you can't also find very good practices doing different things. But that's not where I found it.
- blub 7y agoI have a theory about why this functional atomization has become so popular: small design topics (functions, classes) are easy to talk about so the various wannabe OOP gurus like Robert Martin keep talking about them the most, becoming more and more extreme to the point that we end up with hundreds of one line functions which can only really be put together in one way so that they fulfill the arbitrary criteria of reading like prose. This is an excellent example of local optimizations - i.e. local design optimizations - which end up harming the overall design and maintainability. You've discovered this yourself, but still cling to this dogma of tiny functions.
- azeirah 7y agoI made it clear that there are upsides. It's a tradeoff, not "gurus bad".
- PhilippGille 7y ago> it's very annoying to click on a method in my IDE, and then get shown the interface definition of that particular method. I'll then have to trace my way through a couple of files to find the dependency, very annoying. The IDE should be able to show you the implementations. When using Java and Eclipse for example, you just hold Ctrl and hover with the mouse over a method call. In the appearing dialogue you can then select "Go to implementation" instead of "Go to definition" (or similar) and Eclipse searches for and then shows you all classes that contain an override for that method and then you can click on one of them to view that specific overriding method.
- dave_sid 7y agoWhat you should really aim for is a simple class structure and simple functions within. Complexity at either level is not your friend and certainly not something the next developer to maintain the code will thank you for. That’s the person you should be designing for.
- TravHatesMe 7y ago> whereas complex functions fit on your screen typically Are the complex functions unit-testable? Do they depend on other units of work or other libraries? Does it have multiple responsibilities? You are probably following most of what SOLID entails. I find it funny that HN consistently bashes SOLID, I feel like SOLID has been misrepresented. They are _guidelines_ for development, they do not dictate everything. They might influence or support a decision. Those who bash SOLID: have you worked on gigantic projects that are in active development for decades? I advocate for SOLID is because I have witnessed first-hand its great benefits. I have built and worked on plenty of projects that apply these principles, I have seen wonderful open-source projects that embrace them. And of course I have seen adverse effects from it (eg. your linked article complains of innumerable, non-sensical interfaces) but that is mostly due to inexperienced developers that don't get it. And of course there are some devs/architects that go overboard, introducing premature abstractions, etc.. To those people I say YAGNI. The point being: following SOLID doesn't guarantee nice design. It is easy to produce shit code following SOLID, but it is even easier without it. At the end of the day, there are trade-offs. I think using SOLID as development guidelines produces a scalable codebase divided cohesively into units of work.
- stcredzero 7y agoI find it funny that HN consistently bashes SOLID, I feel like SOLID has been misrepresented. They are _guidelines_ for development, they do not dictate everything. They might influence or support a decision. And of course I have seen adverse effects from it...but that is mostly due to inexperienced developers that don't get it. Whether SOLID is seen to pay off in the medium term, or the long term, or the very long term, is dependent on environment. In some environments, the payoff is apparent sooner. In others, it's only longer term. This is why inexperienced developers may not get it. Of course, that beings up the question, "How can we better communicate the benefits?" Can we document and present those, from the actual history of the project? EDIT: To better relate this to my other comment in this thread, a problem with SOLID in environments where there's a lot of bookkeeping for the compiler's sake and compile times slow down the edit-test cycle, less experienced developers are going to first notice, "Hey, this stuff makes me flip back and forth between files!" If they never see the benefits, they're naturally going to conclude it's a bad thing.
- stcredzero 7y agoThe concept of clarity is why I don’t like the consequence of SOLID, where you have lots of tiny classes. tl;dr - Context! The problem with a lot of the principles developed from the Smalltalk days, is that different environments have differing cost/benefit results for different tasks. This means that many practices which are awesome in a dynamic, programmer-is-god-of-runtime environment like Smalltalk are doing to bog down in other environments. (see below) It’s easier to understand complex functions and a simple class structure than the other way around. Because jumping between multiple files/classes incurs a high understandability cost, whereas complex functions fit on your screen typically. What this reveals about the above observation, is that reading and conceptualizing large chunks of operation of the code has a higher cost/benefit in the accustomed environment. My day job is in C++, and because of the compile times, that's certainly the case in that environment. However, in an environment like VisualWorks Smalltalk, where the debugger is 10X nimbler and has literally made students in my Smalltalk classes cry out, "This debugger is GOD!" the cost/benefit trade-offs are very different. Most of the time, code is read and edited in the debugger, and flipping between multiple classes in that context happens automatically by navigating. Also, the work for navigating relationships in the object model in a clean code base is an entirely different order of magnitude. Instead of O(2^n) on n == distance by references, it's O(n), because there's no fan-out for different kinds of references. It's all done by "message sends" or calls of a method. A lot of damage over the past 3 decades has been done by very smart OO people who tried to transplant methodologies from Smalltalk to C++ and Java. If one wants to be a step above, then look at the largest 7 or so cost/benefit trade-offs that affect the methodology. Then adjust accordingly. Context!
- tracker1 7y agoSimilarly, probably the main reason I really like JS... I can apply different paradigms to different areas of code where a given approach makes more sense in terms of understanding or cognitive overhead. JS debugging is relatively nice as well, though in some cases the tooling leaves a bit to be desired. When I'm in C# by contrast, I often get irritated that I can't just have a couple functions that I can reuse, no, I have to create as static class, ideally in a namespace and do a bit more. I do try to minimize the complexity of my classes and separate operational classes that work on data, and data classes that hold values.
- hyperpallium 7y ago> lots of tiny classes Is a source of complexity, yes. But it really depends on what you're doing. Any orthodoxy is a poor substitute for actual thought.
- mrkeen 7y agoI've never really understood why those particular 5 design principles became a sort of "top 5". Then I grokked dependency inversion and it really changed how I write code. > And reading some more about it, I found this good article: http://qualityisspeed.blogspot.com/2014/08/why-i-dont-teach-solid.html?m=1 http://qualityisspeed.blogspot.com/2014/08/why-i-dont-teach-... That article bashes (among other things) IOC containers and mocking frameworks. I absolutely hate Spring IOC and mockito. But dependency inversion is not dependency injection. It wasn't until I got sufficiently fed up with Spring being everywhere in my Java code that I figured out how to hide Spring as an implementation detail. This is where I ended up: https://sites.google.com/site/unclebobconsultingllc/home/articles/dependency-injection-inversion https://sites.google.com/site/unclebobconsultingllc/home/art...
- blub 7y agoThese are just a bunch of ideas that have been cobbled-together by Robert Martin and accidentally ended up as folklore in a world without rigor and order. Kevlin Henney basically refuted the idea that SOLID has any meaning or use in software development.
- jghn 7y agoThis is a subjective opinion. I’ve had this debate with countless coworkers as I take the exact opposite stance as you. Neither of us is correct, neither of us is wrong. The problem with declaring simplicity and clarity to be the final goal is that’s not an objective truth
- Frost1x 7y agoThis is the very issue I have with a lot of SE dogmas and those that subscribe to one particular set, not just the one described here. Objective truth is an afterthought in most cases. Most these dogmas are anecdotal at best with very little to no empirical backing within surrounding context, but people will stand by certain approaches as if they were well tested theories like general relativity, newtonian mechanics, or QED.
- abraae 7y agoNo silver bullet
- afarrell 7y agoYou would probably like the book A Philosophy of Software Design by Dr. John Osterhout.
- gilbetron 7y agoSOLID is rather old, and never really grabbed me that much. Well, rather, I kinda agreed with it (but I had been in OOP for about a decade before it came along) for a bit, but no longer. Most of it is rather obvious, and I find the terms just buzzwords. "Dependency Injection" particularly drives me crazy, as we've been passing in references to objects forever, and suddenly we need a Special Term for it. What next, instead of pointers we call them Dependency Actors? I also agree that I'm tired of tiny classes and tiny functions. I went on a rant to my coworkers the other day about them, after spending an afternoon figuring out how some code works that fully believed in small functions. Nothing makes 100 lines of code more readable than splitting them across 100 functions in 10 classes in 10 files! /s I agree with another poster, though, that VisualWorks Smalltalk made it a lot more palatable. I'd honestly really like to try a system that treats a program as a database of functions rather than a directory structure of files. I don't think the directory structure adds anything that a tagging system couldn't do.
- Matthias247 7y ago> "Dependency Injection" particularly drives me crazy, as we've been passing in references to objects forever Might have been old to you, but not to everyone. I have seen plenty of codebases which inject nothing and where all objects create their dependencies themself. Lower level code is especially susceptibly to this - the amount if C code that I've seen that made use of some kind of DI tends to go towards zero. And with that often also the amount of tests that are available for the codebase (with claims like: This is not testable). I find the term "Dependency Injection" also still unnatural and academic, but I really like the core idea, which isn't that hard to teach (pass dependencies instead of creating them yourself). Whether one also needs DI frameworks is another topic, on which I have no strong opinion.
- blub 7y agoThe whole thing is just a pretentious sounding term for the extremely basic idea of passing parameters. No dependencies are being inverted. The name is just complete crap.
- hinkley 7y agoThe complexity of tests tends to go up faster than the complexity of the functions under test. One of the thought experiments I use for teaching testing is to remind them that nobody wants to read your code. The next person to read your test is probably going to be reading it because it’s failing. They are in effect already having a bad day. Don’t make it worse. They will assign that negative emotion to you. This has started to affect all of my design thinking. I’m probably only reading your code because I’m trying to hunt down a bug (or my attempt to add new functionality has failed spectacularly). Every time I run into a function that contains code smells, I have to stop long enough to figure out if those smells are the bug I’m looking for or something else. In a particularly bad codebase, like the one I inhabit now, by the time I finally find what I’m looking for, I no longer recall why I was looking for it in the first place. This is not good code. It’s shitty code written by people who aren’t emotionally secure enough to write straightforward code. Or are running from one emergency to the next, all day every day. Or both. Or are young developers just copying what they see around them.
- kosievdmerwe 7y agoAll interesting points, the reason I hate class clutter is especially because of debugging/understanding. I don't want to have to spend a long time building a mental hierarchy of classes and what they do just to figure why a link doesn't have the right URI. Essentially, people use classes to achieve magic code. Code that's very, very convenient when it works, but is monstrous to debug when it doesn't. Especially if the code isn't something you're familiar with.
- therealdrag0 7y agoClasses and methods are abstractions. They hide code. It's like putting your dishes in the cupboard instead of leaving on them a mess on the counter. There is a small initial payment to know where they are located, but then for the rest of time you benefit from the mental space by having them out of mind until you need them. With modern IDEs, going to class/method definitions is a breeze. In my experience people who write big walls of code are often those who don't know how to leverage modern IDEs.