35 ms·
Clean Code vs. A Philosophy Of Software Design
- htk 2y agoWhat a great discussion between two prominent figures in the field of software design. Thank you for posting this!
- htk 2y agoYou guys really hated that I found the discussion interesting?
- throw16180339 2y agoFWIW, me too comments are usually downvoted.
- htk 2y agoMakes sense now, they don't add much, or anything. We already have the upvote button for this.
- kragen 2y agoIt seemed like a content-free comment. I was no better informed after reading it than before, and it was of no artistic or cultural value. It did not induce me to question any of my assumptions or investigate anything. It expressed your experience, but your experience was not unusual or surprising in any way, except perhaps that you did not know that "Uncle" Bob Martin was an incompetent charlatan. Possibly those were among the reasons people downvoted it.
- htk 2y agoFair points! Thank you.
- wglb 2y agoDownvotes are a legitimate expression of disagreement, not hate.
- htk 2y ago"Hate" was too strong of a word to use.
- ilrwbwrkhv 2y agojohn ousterhout's book is the only book on how to write software that has any actual evidence behind it. i highly recommend it as the only book to read on how to write code. and uncle bob, well, best to avoid his stuff as much as possible. clean code takes away about 5 years from every dev's life as they think they need to read it to become an intermediate developer and one they realize that is not the way, can they finally grow.
- owl_vision 2y ago5 years is about right. when i found a copy of clean code in a bookstore, it only took me a few minutes to put it back. I had read John Ousterhout's book prior.
- pinoy420 2y agoIn typical HN commenter smugness. It took me less than that to realise it was bullshit. It didn’t make things clear, it made them more abstract and more resistive to change. Similarly with DDD. Just build what you need and deal with the consequences of inevitable change later. No one cares if you miraculously perfectly modelled your “definitely the final form” of your domain from day 0. Oh and TDD?! Ah yes those perfectly defined unit cases you write for implementation details. The best comment I read recently (sorry I can’t find it) something akin to “The first unit I write is to validate the intended side effects through properly exercising associated mocks” As with everything there is no “best way” to do something, but in software engineering… there are far more bad “best ways” than best “best ways”
- rswail 2y agoDDD is a good way to extract the business logic from the implementation. By modelling the business you raise the business logic up to a 1st class element. By implementing the business objects you encapsulate their functionality in the business. The words "Account" or "Outstanding Balance" have business meanings. Modelling them allows you to express the business logic explicitly. It also allows you to create tests that are related to that business logic, not the implementation. You can still "build what you need and deal with the consequences of inevitable change later". Model what you need to build, the business is going to have to make changes to that model to implement their changes, IT systems are a detail. Change by extending and changing the DDD models. To reverse the question, how do you write code that "does what you need" without understanding the domain?
- zbentley 2y agoIt's striking to me how out of touch Martin seems to be with the realities of software engineering in this transcript. Stylistic refactors that induce performance regressions, extremely long and tortured method names for three-line methods, near-total animus towards comments ... regardless of who is right/wrong about what, those takes seem like sophomoric extremism at its worst, not reasoned pragmatism that can be applied to software development in the large. When I encounter an Uncle Bob devotee, I'm nearly always disappointed with the sheer rigidity of their approach: everything must be reduced thus, into these kind of pieces, because it is Objectively Better software design, period. Sure, standard default approaches and best practices are important things to keep in mind, but the amount of dogma displayed by folks who like Martin is really shocking and concerning. I worry that his approach allows a certain kind of programmer to focus on like ... aesthetic, dogmatic uniformity (and the associated unproductivity of making primarily aesthetically-motivated, dogmatic changes rather than enhancements, bugfixes, or things that other coders on a project agree improves maintainability) instead of increasing their skills and familiarity with their craft. Maintainability/appropriate factoring are subjective qualities that depend a lot on the project, the other programmers on it, and the expectations around how software engineering is done in that environment. Pretending that's not true--that a uniform "one clean code style to rule them all" is a viable approach--does everyone involved a disservice. Seasoned engineers trying to corral complexity, new engineers in search of direction and rigor, customers waiting for engineering to ship a feature, business stakeholders confused as to why three sprints have gone by with "refactor into smaller methods" being the only deliverable--everyone.
- pinoy420 2y ago[dead]
- frozenlettuce 2y agoI don't know why people take UB seriously. He never provided proof of any work experience - he claims to have worked for just a single company that... never shipped any code into production. Even his code examples on GitHub are just snippets, not even a to-do app (well, I think that his style of "just one thing per function" works as a self-fulfilling prophecy). Maybe people like him are the reason why we have to do leet code tests (I don't believe he would be capable of solving even an easy problem).
- mkoubaa 2y agoI can just tell that John Ousterhout works with much better developers on average than UB and that probably informs their biases.
- Jach 2y agoHe also works with a lot more students, with student-sized projects and problems and code lifetimes. He's used his book for classes, I think it's on a level appropriate for a freshman. Both books are bad, but APOSD is my most disliked technical book ever. CC is at least interesting as an exercise to see that critics are way too uncharitable. Kernighan and Pike's The Practice of Programming is far better than either. And https://antirez.com/news/124 https://antirez.com/news/124 is one of the few good discourses on comments out there, something as a profession we care way too much about when the cost of doing it "wrong" is typically so low.
- tikhonj 2y agoWhat's there to dislike so much in APOSD? The book struck me as giving mostly reasonable advice, none is which was overly prescriptive. None of the things I disagreed with struck me as egregious.
- Jach 2y agoHere's mostly from what I wrote down after reading it. Indeed, the "reasonableness" is part of the problem. What's agreeable is mostly only so because it's such a straightforward platitude. "Things that are not important should be hidden, and the more of them the better. But when something is important, it must be exposed." Ok? Anyone want to argue to the contrary? This is not teaching or learning anything new or of value, it's not even inviting argument like CC makes it easy to do. I was also hoping that with the book being so short it would be concise, but alas, it's full of this sort of stuff. The single page summary of design principles at the end is similar. A few of them you could quibble about, but arguments would likely just be in fully understanding the meaning of the terminology and what background contexts are assumed. Much advice is dependent on context! Context is something not really called out much in this book. As one example there was only a very slight hint that the author is aware that writing for the code reader means a reader from a particular audience, often your co-workers, and that gives you certain affordances you wouldn't have for say random blogger. Elsewhere, not in the book, the author once wrote "The strong typing of object-oriented languages encourages narrowly defined packages that are hard to reuse. Each package requires objects of a specific type; if two packages are to work together, conversion code must be written to translate between the types required by the packages." This is actually a nuanced point and is good to discuss. The context of whether you have static types or dynamic types or a half-baked OOP system or a full-baked OOP system is very important context. But it seems a completely absent point of consideration from his "philosophy", even when you'd think it'd be appropriate to go over in the final chapter where he highlights OOP as a "trend". A lot of the author's rants seem to be snipes at Java. Fine, whatever, though Java has answers to the complaints. (Especially modern Java.) Lastly, and originally my first complaint because it's about the very beginning of the book (including the cover art), he's on shaky foundations with its definition of simplicity/complexity by conflating it with the subjective easy/hard. I was hoping for a post-Hickey (of Clojure/"Simple Made Easy" talk fame for anyone unaware) understanding that complexity is objective, but alas. It's not like Hickey invented that understanding, but in current year, I think it's quite questionable to disagree. So, the book: "For the purposes of this book ... complexity is anything related to the structure of a software system that makes it hard to understand and modify the system." Sorry, that's not a useful definition of complexity, and now the whole book is harder to read/easier to misinterpret because of the custom definition. Well, at least it's explicit that it's custom.
- sudobash1 2y agoThere is an important case for comments that neither of them touched on. Sometimes you are dealing with bugs or counterintuitive processes beyond your control. For example, I am writing some driver software for a USB device right now. It is so easy to get the device into a bad state, even when staying within the documented protocol. Every time I implement a workaround, or figure out exactly how the device expects a message to appear, I put in a comment to document it. Otherwise, when (inevitably) the code needs to have features added, or refactoring, I will completely forget why I wrote it that way. The prime number example is a self-contained, deterministic algorithm. While I did find it far easier to parse with comments, I could still spend the time to understand it without them. In my USB device driver, no amount of review without comments would tell another person why I wrote the sequence of commands a certain way, or what timings are important. The only way around that would be with stupid method names like `requestSerialNumberButDontCallThisAfterSettingDisplayData` or `sendDisplayDataButDontCallTwiceWithin100Ms`.
- mbo 2y agoWhile I am not a Uncle Bob-style "no comments"er I do love a ridiculous method name. I pay very close attention to that method and the context in which it is called because, well, it must be doing something very weird to deserve a name length like that.
- tikhonj 2y agoThere are a few Haskell functions with names like reallyUnsafePtrEquality# or accursedUnutterablePerformIO, and you know something interesting is going on :P
- hakunin 2y agoThat’s exactly why you should save that length only for a method that’s indeed doing something weird. If every method is long, the codebase turns into noise. (IOW I agree)
- ninetyninenine 2y agoThis doesn’t happen in reality. Your program does so many things that practically speaking short names work for a lot of functions in the program. It’s like English. There are big words and there are small words and usually to communicate a combination of big and small words are used. Nobody practically communicates with big words. A long function name only pops up when needed.
- marcusbuffett 2y agoI strongly recommend "A Philosophy of Software Design". It basically boils down to measuring the quality of an abstraction by the ratio of the complexity it contains vs the complexity of the interface. Or at least, that's the rule of thumb I came away with, and it's incredible how far that heuristic takes you. I'm constantly thinking about my software design in these terms now, and it's hugely helpful. I didn't feel like my code became better or easier to maintain, after reading other programming advice books, including "Clean Code". A distant second recommendation is Programming Pearls, which had some gems in it.
- narnarpapadaddy 2y agoImplicitly, IIRC, the optimal ratio is 5-20:1. Your interface must cover 5-20 cases for it have value. Any fewer, the additional abstraction is unneeded complexity. Any more, and your abstraction is likely too broad to be useful/understandable. The example he gives specifically was considering the number of subclasses in a hierarchy. It’s like a secret unlock code for domain modeling. Or deciding how long functions should be (5-20 lines, with exceptions). I agree, hugely usual principle.
- abhis3798 2y agoThis is a good rule of thumb, but what would be a good response to have interfaces because, "what if a new scenario comes up in the future"?
- lmm 2y ago"We'll extract interfaces as and when we need them - and when we know what the requirements are we'll be more able to design interfaces that fit them. Extracting them now is premature, unless we really don't have any other feature work to be doing?"
- Copenjin 2y agoThe scenario NEVER comes up in the future as it was originally expected. You'll end up having to remove and refactor a lot of code. Abstractions are useful only used sparingly and when they don't account for handling something that doesn't even exist yet.
- getnormality 2y agoUncle Bob's insistence that functions should be 2-4 lines long is baffling to me. I don't understand how he can be taken seriously. Is there a single application in the entire world with substantial functionality that conforms to this rule?
- Scubabear68 2y agoThere are. A lot of Java code bases look like this. It is all as bad as you imagine. Functionality is spread out all of the place so it is very difficult to reason about how it all hangs together.
- nyarlathotep_ 2y agoIt's always fun stepping through 412 stack frames that are all 2-line long methods to figure out where the thing you're interested in actually happened.
- MobiusHorizons 2y agoI once fully spelunked such a Java call stack to convert some code to golang. It was amazing, there were like 5 layers of indirection over some code that actually did what I want, but I had to fully trace it keeping arguments from the full call stack in mind to figure this out, because several of the layers of indirection had the potential of doing substantially more work with much more complex dependency graphs. I ended up with a single go file with two functions (one that reproduced the actually interesting Java code and one that called it the way it would have been called across all the layers of indirection. It was less than 100 lines and _much_ easier to understand.
- monksy 2y agoAdd in Go and C++ code bases to that as well.
- PlunderBunny 2y agoI've seen this in what I call 'lasagna code' - multiple thin layers that seem to do nothing (or almost nothing) but each one is an implementation of some abstruse interface that exists in the mind of the original developer. Eventually, your code has to do something. Get that thing in one place where you can look at it in its whole.
- emtel 2y agoRelated: https://news.ycombinator.com/item?id=27276706 https://news.ycombinator.com/item?id=27276706
- namuol 2y agoI’ve come full-circle back to my junior engineer attitude with respect to coding “best practices”: Avoid anything resembling dogma.
- ctrlp 2y agoI've enjoyed both books but Uncle Bob is something you grow out of. He was a bit of a cult figure at the time. Trying to actually follow the guidelines in Clean Code taught me a lot about "over-decomposition" and, ultimately, how not to write code. It reminds me it's possible to take aesthetics so far the results become ugly. Fussing over a proliferation of small functions that do only one thing is a kind of madness. Each individual function eventually does zero things. You are left sifting through the ashes of your program wondering "Where did I go wrong?" On the meta level, these exchanges, while mildly interesting, have the vibe of debating how many angels can dance on the head of a pin. I'm reminded of the old saying: "Writing about music is like dancing about architecture." If you want to write good code, read good code. Develop a taste that makes sense to you. I don't think I'll ever read a book about code composition again.
- Willingham 2y ago> If you want to write good code, read good code. As a junior in the field working at a small company, I often rely on this community for guidance, and this seems the most sound advice on this thread.
- acmj 2y agoYou need to know what is good code. Opinions may vary a lot between programmers, even senior ones. The Clean Code cult would tell you to find good code there but that is the most poisonous programming book I have read.
- ctrlp 2y agothere are lots of very robust programs in various languages to learn from. It would be hard to know in isolation but by contrast it is easier to learn what good code looks like. Some code will flow and be easy to read. Other code will be obtuse. Start with simpler projects that don't involve a lot of low-level calls. Work up to more complex implementations. There was never a better time to read code than now with an LLM as a tutor. If you use one of the AI-integrated editors or a code packer you can provide a lot of context to the LLM. Ask the LLM for important modules and work your way through them. Ask it for alternative implementations of a function or translated into a different language. Set up an program in a running environment and walk through using a debugger. Look at the way the code is organized in files and modules. You will inevitably encounter cruft and "bad code". Sometimes there are good reasons for that too. If you prefer books, the Architectures of Open Source Applications (AOSA) books are interesting, but there really isn't a way to avoid pulling down a repo and reading the code. Soon, you'll develop your own taste for what makes sense to you and be able to think independently about the choices the developer made. It is a bit sad but I think with the advent of LLMs some of the stylistic quirks of programmers past will become a bit anachronistic. Still, they will present opportunities for code archeology.
- WalterBright 2y agoOne method of commenting that has paid off for me the most was inserting links to: 1. the online documentation of the function being called 2. the instruction documentation for an instruction being generated, inserting 3. the issue that the code fixes 4. the specification of what the function is trying to implement Then I fixed my text editor to enable click on those links.
- WalterBright 2y agoI also fixed the disassembler to also add a clickable link to the instruction spec page for each instruction.
- wglb 2y agoI did that back in the day (before we could click on anything) about what the compiler was thinking as it generated the code. That was fun.
- vishnugupta 2y agoWhile on this topic, one book I really enjoyed is "Beautiful Code"[1]. It is not preachy or prescriptive but a diverse set of programmers showing the code they enjoyed writing. [1] https://www.goodreads.com/book/show/405790.Beautiful_Code https://www.goodreads.com/book/show/405790.Beautiful_Code
- hakunin 2y agoFor anyone like me who at first skipped over this article because it seems from the title that someone just compared two approaches: No, it’s an actual debate between the actual John and Bob. Them debating each other. It’s an amazing read.
- seanwilson 2y agoI find the lack of discussion of type systems really surprising in these sorts of discussions and books. Effective use of type systems is a killer factor for me for creating clean, safe, readable and maintainable software designs. When used correctly, strong static type checking make certain kinds of bugs impossible, spare you from writing many kinds of tedious tests that often get in the way of refactoring, serve as documentation, and make refactoring/maintenance an order of magnitude faster and safer. Even when a type checker isn't available, avoiding dynamic behaviour is very often the safer way to go so learning how to think in that way is still beneficial. Most of these minor topics like how big a function should be, what to name your variables, or even if you write tests before/after coding... it's like trying to come up with general rules on how to write essays, creating graphic designs, or how to cook. "It depends" on the context and juggling different priorities each time. It's the kind of thing you only learn properly through practice (https://en.wikipedia.org/wiki/Tacit_knowledge https://en.wikipedia.org/wiki/Tacit_knowledge), so there's only so much to gain in reading about it or discussing it after you've defined the no-brainer things to always do and always avoid.
- WillAdams 2y agoThat was exactly the approach taken by Prof. Ousterhout in setting up the class which lead to this book --- rather than just having students turn in working code for a grade, the code is reviewed with the student and the student then works to make it better --- in turn, the 2nd edition of the book was informed by the experience of teaching the class and the author actually changed his position based on the experience gained.
- deleted 2y ago[deleted]
- seanwilson 2y agoWhy is that convincing though? Students aren't experienced coders, aren't working in large teams, and student assignments aren't like long-term large commercial projects. If you mean the additions here https://web.stanford.edu/~ouster/cgi-bin/book.php https://web.stanford.edu/~ouster/cgi-bin/book.php, I read these and it still sounds like general rules of thumb you'll only really learn and understand by practicing a lot e.g. "In my experience, the sweet spot is to implement new modules in a somewhat general-purpose fashion" "Having good taste is an important part of being a good software designer".
- dionian 2y ago"That's a valid concern. However, it is tempered by the fact that the functions are presented in the order they are called. Thus we can expect that the reader has already seen the main loop and understands that candidate increases by two each iteration." I think this missed the point entirely. If i had to read the entire code to understand the behavior of that method, then is it really cleaner? Side-effects are evil
- khana 2y ago[dead]
- overgard 2y agoBob's comments on... commenting.. are so bizarre that I can't help but think that he just refuses to concede the point rather than admit he might have been wrong about it. Like, the paranoia around incorrect/stale comments is fairly absurd, I've been coding for 20 years across many code bases, and I can't even recall a time when I've been significantly mislead by a comment which caused a significant waste of time. However, the amount of time I've wasted on unclear code that has zero comments is absolutely staggering. However, what really sealed the weirdness to me was his argument that this was somehow a good comment: X 1111111111111111111111111 1111122222333334444455555666667777788888999990000011111222223333344444 35791357913579135791357913579135791357913579135791357913579135791357913579 !!! !! !! ! !! ! !! ! ! !! ! !! ! ! ! ! !! !! ! 3 |||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||-||- 5 |||||||||||-||||-||||-||||-||||-||||-||||-||||-||||-||||-||||- 7 |||||||||||||||||||||||-||||||-||||||-||||||-||||||-||||||-||||||- 11 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||-||||||||||- 13 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ... 113|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| That's verbatim, I'm not unfairly clipping context away from it. Like, what the hell is that supposed to tell someone?! Wouldn't it just be easier to drop a link to the algorithm, or briefly explain the algorithm, or just give a name of the algorithm so someone can look it up? Instead he just talks about taking a bike ride to understand it and making a weird picture. He also has bizarre arguments that if something can't be expressed in a programming language, it's the fault of the programming language (what?!) and that code is more understandable than English. I really find it hard to believe that he thinks these are actually good arguments, I just get the impression he does not want to concede that he was wrong about this.
- seabombs 2y agoLol, this reminded me of those engravings we put on spacecraft. Like, if we had to communicate the algorithm to an alien civilization then sure, this might be the best way to do it! https://en.wikipedia.org/wiki/Pioneer_plaque https://en.wikipedia.org/wiki/Pioneer_plaque
- jillesvangurp 2y agoThey are both mostly right but the devil is in the details and to try to not get too dogmatic about things. For example function length is one of those things that you can obsess about and debate endlessly. What's the value of extracting a function that is used only once or twice. It's probably very limited. It's debatable whether that even should be a public function and whether you should encourage more use. And then we can look at the function declaration as well. Does it have a lot of parameters? Is there any complexity to its implementation? Does it have tests? Are there going to be lot of uses of the function? If the answer to all those questions is no, you could probably inline it without losing much. But the flip side is that you wouldn't gain much by doing so. A small function that is used a lot is probably somewhat valuable. And there's a third thing that needs to be considered: does a function increase the API surface of your module. Having lots of private functions makes your module hard to understand. Having lots of public functions, makes the API less cohesive. So, there's a grey area here. Languages like Kotlin give you a additional options: make it a nested function, make it an extension function, put it in a Companion object, etc. You can put functions in functions and those can help readability. The whole point of doing that is preventing usage outside the context of the outer function. Nested functions should probably be very short. And their only goal should be to make the outer function logic more readable/understandable. It's not something I use a lot but I've found a few uses for this. There's no point to using nested functions other than for readability. And speaking of Kotlin, it's standard library is full of very small extension functions. Most of them are one or two lines. They are clearly valuable because people use them all the time. You get such gems as fun List.isNullOrEmpty(): Boolean which helps make your if statements a lot more readable and less flaky. Also works on Java lists. Stuff like that is a big part of why I like Kotlin. I tend to dumb down a lot of advice like both are debating here to cohesiveness and coupling. In the context of functions, you get coupling via parameters and side effects (e.g. modifying state via parameters) instead of return values. And you lose cohesiveness if a single function starts doing too many not so related things. High coupling and low cohesiveness usually means poor testability. You'll find yourself mocking parameters just to be able to test a function. Improving testability is a valid reason for extracting smaller, easier to test functions.
- imjonse 2y agoI am biased ( a former coworker was an Uncle Bob fan, and was bent on doing everything by the book, with layers of abstraction, patterns, hexagonal architecture, lots of unit tests, no cutting corners, even as we did not know what exactly we want to build and needed an MVP ASAP) but I'll just say this: Ousterhout wrote TCL - widely considered one of the best C codebases - besides being a professor at Standford and having other software achievements under their belt, while Robert Martin is more like a software technology evangelist. The former good at actual deliverables the latter good at selling. Also Ousterhout's book on design is very easy to read and I guess I liked it because I mostly just nodded in approval while reading and there were very few things that made me stop.
- begueradj 2y agoLet's not forget that Uncle Bob, by the time of writing "Clean Code" had 4 decades coding experience.
- kragen 2y agoMy middle school English teacher had 4 decades of experience writing. What she wrote was lesson plans. That doesn't make her Stephen King.
- WillAdams 2y agoDo not make the mistake of the craftsman who claims to have 20 years of experience, but in truth only has 1 year of experience repeated 20 times.
- wglb 2y agoAre there large code bases that he has written that we know anything about?
- intelVISA 2y agoSoftware is results driven, there's no value in simply warming a seat for X YOE, talking about code instead of actually executing.
- throw16180339 2y ago
- LunicLynx 2y agoThe example they use is irrelevant. A solved problem can be written how ever one likes. Code that will change or can’t ever be considered final, is the real challenge. Overly cutting code into methods makes code just rigid. This could be the point, I guess, but if you need to change the methods name in order to reflect the methods intent, than you just wrote the classic unhelpful comment of: // check a is not null if (a != 0) { … } Overuse of comments has the same issue as overuse of methods. Without rigor, comments and methods names will start to lie. Because their content / name weren’t necessary to understand the code. And should just not exist in the first place.
- pjmlp 2y agoAll great, but generaly useless in most big corp project with offshoring, where we are already happy that we actually delivered something that works in first place.
- nickm12 2y agoThis was a fun read. I read APoSD for the first time a couple of months ago and found myself nodding enthusiastically as I read. I have a few quibbles, of course, but overall it matches my experience in how to write software that is correct, maintainable, extensible, and understandable. I've never read CC, but I've read some of the take downs[1]. I was worried that the take downs were attacking a strawman, but no, Uncle Bob believes this stuff, including that comments are evil and you just need to read all the code and keep it in your head. Even if that were true, the code I write is better for having written the comments, especially interface comments, because the writing helps my thinking. Moreover, it helps my code reviewers—without written interfaces. If all you have is the code and not a description of what the code is supposed to do, how can you know if it is correct? I think most code reviewers are verifying the code against what they infer the interface to be. It helps us both to just be explicit. [1]: https://qntm.org/clean https://qntm.org/clean
- nickm12 2y agoburied at the end: there's a planned second edition of Clean Code! Given Bob's intransigence in this conversation, I wonder what he'll change.
- ninetyninenine 2y agoCleanliness AND Design is Highly correlated with IO, side effects and state. Most programmers know about this in 2025 but they didn't back then. Looks like the authors don't even mention it.
- dgunay 2y agoI find it funny how much people obsess over Clean Code. In my opinion Robert Martin's Clean Architecture is a much more valuable and realistic idea than all this madness about 3 line functions, no comments, do one thing, etc. I would take the ugliest code that followed Clean Architecture over any "Clean Code" that didn't bother sensibly separating business logic and I/O. I don't like the guy very much, but for web development even just mostly following Clean Architecture does so much to keep things from devolving into chaos long term.
- blt 2y agoThe prime number code hurts to read. I feel like Bob is living in a different reality than most of us.
- jonashus 2y agoYes, no, I think he has different mental capabilities than most (most of the commenters here at least) and by that actually are living in a different reality. Human brains function vastly different. Two examples stood out to me. 1) UB said he reads the code in its full from left to right with the if(isTooHot) example. I only resort to reading code in that way as a last resort if I really can't figure out what the code is doing. I mean I look at a block or row and take it in more as a whole. 2) UB said comments are annoying because he has to read them and keep the whole of the comment text in his mind. This again says he reads everything left to right, and he can likely store everything that he has read up to a certain amount. My mind works nothing like that. I can hold very few words in my working memory but can instead hold concepts/ideas. For that to work good I need to see as much of the involved code as possible and my mental image evaporates if I have to navigate too far where I started.
- myst 2y agoWhere can I find Martin’s code? I would like to see and compile it.
- brodo 2y agohttps://github.com/unclebob/fitnesse https://github.com/unclebob/fitnesse
- sharas- 2y agoWhoes uncle is he anyways?
- jacobsenscott 2y agoI was around before the clean code movement, and like all software movements, it was a reaction to real problems in the software industry. Massive procedural functions with deeply nested conditionals, no structure, global variables, no testing at all. That was all the norm. Clean Code pushed things in a better direction, but it over-corrected. In many ways APOSD (published in 2018) is a correction against the excesses of Clean Code (published in 2008). Will people swing too far back, to giant methods, deeply nested conditionals, etc? I don't know. But probably.
- matsemann 2y agoI think learning extremes can be useful, just don't take any one paradigm as gospel. Practicing Clean Code forces you to think in a special way, and when you've tried it, you start to get a feeling for where you should draw the line. Doing CC makes you a better programmer, but you have to figure out yourself where the tradeoffs are. Other examples are TDD. Forcing myself to write tests for everything for a period has made all my code since better, even though I don't practice TDD now.
- lyu07282 2y agoI feel the same way, the benefit of testing is that it forces you to write code that can be tested, which tends to make code better just in general.
- k__ 2y agoIf you don't nest that much, big functions aren't so bad. You can just scroll down and see what happens in a linear fashion.
- pclmulqdq 2y agoThis is the Linux kernel approach, and is a big part of why the kernel uses 8-space tabs. It's generally very effective for understanding what is happening. I'm happy with a 200-line straight-line-with-error-handling function, while a monstrosity of 10 20-line functions that all do if-else is quite a bit harder to read. The latter is "clean code."
- coopykins 2y agoAs someone who's recently started to read a philosophy of software design, I have to say that a lot of the points the author makes are things that I've come to learn with experience, which feels pretty good. As opposed to clean code, which I read when I was starting, and although at that time it felt good to have some guidelines—I still think having some guidelines is better than having nothing at all. I think you grow out of that advice very soon, because it's not very practical, it feels out of touch. The result is not code that is easier to read, quite the contrary. I think the Java world has been influenced for worse by him. But I don't have anything against him, as other comments say, the problem is dogmatism and trying to follow these authors blindly instead of thinking about it.
- wg0 2y agoThe arguments from staunch clean code zealots have wasted so much time on PRs that I have lost count. Hours and hours and sometimes weeks - PRs having ideological discussions on something that neither the underlying machine cares nor the end user. Multiply that across the industry and that probably easily reaches in hundreds of millions of dollars productivity wasted. Ps: Not advocating cowboy coding or spaghetti code either.
- Copenjin 2y agoYou just need to work on one project built by someone that implemented Uncle Bob recommendations blindly when the books came out to know how much they are worth. There were some low hanging fruits to pick at the time regarding trying to be better at software engineering and he generated some text about them. Full of terrible advices, he never wrote anything significant (in scope and notoriety) during his time as a software engineer like many other prominent authors at the beginning of the agile era. The success is only the result of a wave of junior devs searching for some sort of guidance, something that there is a never-ending need for. Horrible recommendations that produced a lot of code that is a pain to work on with the abundant amount of indirection it has. Really painful guys.
- __loam 2y agoA Philosophy of Software Design on the other hand is concise, excellent, and based on decades of teaching experience.
- lynguist 2y agoThis was such a riveting and literary read, I enjoyed it and couldn’t put it away, like a novel where I was invested in the characters! Are there any other such reads in the software engineering field?
- WillAdams 2y agoKnuth? He has argued in the past that the concept of Literate Programming http://literateprogramming.com/ http://literateprogramming.com/ is the most important work he has done, and I highly recommend his various collections of lecture notes/papers including: https://www.goodreads.com/book/show/112245.Literate_Programming_Lecture_Notes_ https://www.goodreads.com/book/show/112245.Literate_Programm...
- wglb 2y agoA Discipline of Programming, Dijkstra The architecture of Concurrent Programs, Per Brinch Hansen Literate programming--see http://www.literateprogramming.com/ http://www.literateprogramming.com/ I don't recommend Design Patterns, as these are elements needed if your programming language is inadequate. There are many more.
- ilitirit 2y agoIt still blows my mind how dogmatic some people can be about things like this. I don't understand why anyone takes these things as gospel. Who else has had to deal with idiots who froth at the mouth when you exceed an 80 line character margin? And it's not just programming styles, patterns and idioms. It's arguably even worse when it comes to tech stacks and solution architecture. It's super-frustrating when I'm dealing with people in a professional setting and they're quick to point out something they read in a book, or even worse - a blog - with very little else to add. This was especially bad during the NoSQL and Microservice hype. Still somewhat feeling it with PAAS/SAAS and containerization. We have so many really really basic things running as Function Apps or lambdas, or simple transformations running in ADF or Talend that add zero value and only add to the support and maintenance overhead. Always keep in mind that sometimes the only difference between yourself and the person writing the book/blog/article is that they actually wrote it. And that their opinions were written down don't make them fact. Apply your own mind and experience.
- hdkrgr 2y ago>> Always keep in mind that sometimes the only difference between yourself and the person writing the book/blog/article is that they actually wrote it. Well said!
- abirch 2y agoRemember when most people give presentations about a technology, they’re in the honeymoon stage
- catlover76 2y ago[dead]
- raverbashing 2y ago> Who else has had to deal with idiots who froth at the mouth when you exceed an 80 line character margin? Honestly, no better indication of a very mediocre developer
- 2y ago
- kragen 2y agoCrucial context here: Ousterhout is one of the great programmers who built the free software world we live in today, and Uncle Bob is a faker. Ousterhout is not without his problems (Stallman famously called him a "parasite" on the free software community, as well as fervently disagreeing with his technical taste) but he's written truly world-changing software. By contrast, Uncle Bob is a windbag book author who has never managed to write any software worth using, to my knowledge. Ousterhout to Uncle Bob: > maybe you were surprised that it is hard to understand, but I am not. Said another way, if you are unable to predict whether your code will be easy to understand, there are problems with your design methodology. This debate is full of treasures like this. What a brilliantly clear and understated way to expose charlatanism! What is this “world-changing software” I'm saying Ousterhout has shipped? Tcl. (Hold on, now, don't downvote just yet.) Tcl has been a crucial enabling technology for EDA and automated regression testing since literally the 01980s. Probably every VLSI chip in the computer you're reading this on was designed, verified, and tested with workflows involving unholy amounts of Tcl. GCC's test suite is also Tcl. Still. Automated testing in the 01980s? Yes. It's true that automated testing wasn't very prevalent in the software world until the Agile guys (Uncle Bob and his less incompetent compatriots) popularized it around the turn of the century, but EEs and compiler engineers have been pervasively automating testing a lot longer than that, and Tcl was for a long time the least awful option, believe it or not. And that was John Ousterhout's doing. Do you know what the SPICE developers did to make SPICE scriptable, before there was Tcl? They linked csh into it. Motherfucking csh. If you've never tried to maintain a large script in csh, you do not know the meaning of suffering. Good programmers write good software; bad programmers write bad software, or no software. Ousterhout has written one of the few pieces of software that can be called great. (In its historical context. In 01978 csh was great software too.) What software has Uncle Bob written? Listening to Uncle Bob's programming advice over Ousterhout's would be like listening to your middle-school English teacher's writing advice instead of Stephen King's. It's not that King could never give you worse advice, but if you need your English teacher's advice, generally your judgment will not be good enough to distinguish the rare occasions King gets it wrong.
- WillAdams 2y agoCurious what Stallman has to say about Robert C. Martin --- looked, but couldn't find anything....
- okaleniuk 2y agoIt's sad that we demoted the field from engineering to philosophy. But it is what it is. Next step - fashion and belief.
- WillAdams 2y agoIt's an improvement over demagoguery and blind rule-following. Moreover, the book argues for engineering principles (in pretty much all possible senses of that phrase).
- okaleniuk 2y agoSure! I'm not saying that philosophy is bad. Maybe making software just never meant to become an engineering discipline. I mean making clothes, laws, and music isn't. And it's fine. But engineering does imply some rule-following.
- floydnoel 2y agophilosophy is the basis of reason, math, and science. it's sad that "engineers" don’t understand it or it's import.
- okaleniuk 2y agoEngineers believe in definitions. By definition, philosophy is not a scientific discipline, because as soon as a discipline becomes scientific it... stops being philosophy. As Alexander Pyatigorsky famously wrote, "the value of philosophy is in that nobody needs it".
- floydnoel 2y agowhat i meant was- it is a poor engineer indeed who doesn't understand the concepts of philosophy such as ethics, logic, and how that led to the scientific method. science without philosophy is just scientism. it leads to engineers creating previously unimaginable horrors!
- cjfd 2y agoPDSD is correct on length of methods. The methods given in an example in CC are ridiculously short. CC is more correct on comments than PDSD. Especially mandating comments in certain places leads to very low quality and, frankly, utterly disgusting comments point out, helpfully that the 'get_height' method 'gets the height'. CC is more correct on TDD than PDSD. The noticed danger of just focussing on implementation details over the structure of the API is always there but TDD has a refactor step to fix that. The general idea of working in small steps with there being a safe state between every small step is worth its weight in gold.
- samiv 2y agoInstead of "Clean Code" I'd really suggest people read either - Code Complete - The Pragmatic Programmer https://en.wikipedia.org/wiki/Code_Complete https://en.wikipedia.org/wiki/Code_Complete https://en.wikipedia.org/wiki/The_Pragmatic_Programmer https://en.wikipedia.org/wiki/The_Pragmatic_Programmer
- mrkeen 2y agoI read Clean Code and don't remember a single thing from it. To be fair it was a while ago. But the SOLID and Clean Architecture principles inform me almost daily.
- kragen 2y agoI wouldn't recommend Code Complete today; I think The Practice of Programming covers most of the same material, is much shorter, is much better written, and isn't tainted by McConnell's later embrace of snake-oil methodologies, some of which made it into the second edition of CC. TPOP didn't exist when CC changed my world.
- bena 2y agoIt's been a hot minute since I've read Code Complete. I don't have it on hand, but I'm pretty sure it was the second edition as it has the gray cover. And I'm pretty sure I got the second edition closer to when it was published than today. I remember it being pretty decent back in the day. I can't remember any takes that were too hot in it. Honestly, I can only remember a general sense of satisfaction(?) with the book. If you were to ask me what exactly I took from Code Complete and applied in my job today, I couldn't tell you. What would you classify as "snake oil" in it? Do they recommend Hungarian notation or something weird?
- kragen 2y agoI read some of the more questionable parts of the second edition just now, and while I think there are a lot of things to criticize in it, I suspect that it's just rose-tinted hindsight, or ignorance, that made me not object to them in the first edition; I'm pretty sure most of these problems were already there: - All the time wasted on the dumb "construction" analogy. - The total lack of attention to open-source software, possibly because he was misled by his own "construction" analogy. There's no such thing as a freely redistributable cabinet that's extra reliable because your house shares it with the local nuclear reactor, or a rotten floor joist you can't fix without negotiating a source license. (He does discuss buying libraries, just as you can buy cabinets instead of building them.) Though this was surely also lacking in the first edition, it was a more forgivable oversight in 01994. - Very little attention given to automated testing; we don't get to "developer testing" until chapter 22, and even that's mostly about manual testing, though there are a few offhand remarks in §4.4 and §9.4 about unit testing and test-first programming, with no explanation of what that means. Even when he tries to explain "test-first programming" in §22.2, there's no hint that we're talking about automated testing. And we finally see mentions of "test code" and "JUnit" in §22.4, and then §22.5 and §22.6 have information about actual automated testing, though without any actual test code. The advice on test-case design is still excellent. - Also, very little about source control. I know this was a deficiency in the first edition because I remember the revelation of learning about RCS a couple of years after I read it. I think it actually got better in the second edition; there's a little "Version Control" section in §30.2 which refers you to §28.2, "Configuration Management", which talks a little bit about the problem but doesn't mention Subversion (first released October 02000), CVS (01990), RCS (01982), SCCS (01973), or even Visual SourceSafe (01994). Instead, it mostly describes implementing similar processes manually, through bureaucracy, because this is the "Managing Construction" chapter. But there is technically half a page on p. 668 singing the praises of version-control software, calling it "indispensable on team projects", which manages to not mention a single program you could use for it. An understandable oversight in 01994, unforgivable in 02004, but again, incompetence rather than snake oil. - Although he pays lip service at the beginning of the book to the independence of project phases and project activities, he often conflates them later, often presuming a quasi-waterfall model (when he isn't outright advocating it), where a requirements-analysis phase is followed by an architecture phase, then a detailed design phase, then a "construction" phase, then a testing phase, and then finally a maintenance phase. This is obviously completely unlike the reality of projects like Microsoft Windows, Emacs, Linux, GCC, and Facebook. When did Facebook mostly move from detailed design to construction? Would it have been a better social-networking website if it had spent a year or two on architecture before beginning "construction"? He does kind of go back and forth on this a lot, though, sometimes advocating more incremental approaches and then contradicting himself a page later. - Relatedly, he advocates a division of labor where "the architect consumes the requirements; the designer consumes the architecture; and the coder consumes the design." (Traditionally, though he doesn't say this, the QA tester then consumes the code.) This division of labor has been tried many times, and the companies that have tried it have been mostly outcompeted by companies with less dysfunctional divisions of labor; they mostly survive only in niches where they have legally enforceable monopolies, such as DoD cost-plus prime contractors. None of them have been able to produce products of quality comparable to things like Linux, GCC, and Facebook. I think this is the snake-oiliest part of the book. - Code Complete's table of "Average Cost of Fixing Defects Based on When They're Introduced and Detected", table 3-1, is convincing, compelling, thoroughly footnoted with decades of literature, and completely made up. See https://softwareengineering.stackexchange.com/questions/163701/does-software-testing-methodology-rely-on-flawed-data https://softwareengineering.stackexchange.com/questions/1637... https://web.archive.org/web/20121101231451/http://blog.securemacprogramming.com/2012/09/an-apology-to-readers-of-test-driven-ios-development/ https://web.archive.org/web/20121101231451/http://blog.secur... https://www.lesswrong.com/posts/4ACmfJkXQxkYacdLt/diseased-disciplines-the-strange-case-of-the-inverted-chart https://www.lesswrong.com/posts/4ACmfJkXQxkYacdLt/diseased-d... https://gist.github.com/Morendil/258a523726f187334168f11fc8331569 https://gist.github.com/Morendil/258a523726f187334168f11fc83.... This made-up data is McConnell's major justification for advocating waterfall-like models. More recent research that investigates the question empirically instead of relying on made-up hearsay finds, by contrast, "We found no evidence for the delayed issue effect; i.e., the effort to resolve issues in a later phase was not consistently or substantially greater than when issues were resolved soon after their introduction." https://arxiv.org/pdf/1609.04886 https://arxiv.org/pdf/1609.04886 https://agilemodeling.com/essays/costofchange.htm https://agilemodeling.com/essays/costofchange.htm https://buttondown.com/hillelwayne/archive/i-ing-hate-science/ https://buttondown.com/hillelwayne/archive/i-ing-hate-scienc.... - The section about "user interface design" is cringe-inducingly bad. He thinks you can design a good user interface up front without having working software ("The user interface is often specified at requirements time. If it isn't, it should be specified in the software architecture,") rather than incrementally responding to usability feedback from people using a working system. It's a very short section, and that in itself is eyebrow-raising; usability is a central concern of most kinds of software, and one of the most challenging aspects of software. Really, almost everything in most software should be driven ultimately by user experience and grounded out in usability testing. Games, websites, browsers, and even compilers live and die on usability. But McConnell treats it as one minor detail among many. - The section about the "architecture prerequisite" sounds like it was written by IBM mainframe programmers in 01978, then decorated with some OO and WWW jargon. Yes, clearly the architecture should "describe the major files and table designs to be used". That makes sense. Yes, "Input/output (...) is another area that deserves attention in the architecture. The architecture should specify a read-ahead, read-behind, or just-in-time reading scheme." I mean, seriously? Note that words like "client", "server", "tier", "cache", "protocol", "network", "message", "queue", and even "process" (as in a running instance of a program) are completely missing here. It's not that he uses different terms for them; he just doesn't talk about them at all, using any words. - He tries to discuss "fault tolerance" with a totally nonsensical example "the square root of a number", necessarily making complete hash of the topic as a result. He doesn't mention any of the techniques that actually work for achieving fault-tolerance, such as statelessness, idempotence, the end-to-end principle, transactions, journaling, fail-stopness, checksums, disk mirroring, hardware trimodular redundancy, watchdog timers, ECC, anomaly detection, network timeouts, monitoring, alarms, etc. The only exception is that he sort of mentions granular restarts. I'm restricting myself to techniques that were well-known when he wrote the first edition of the book here, excluding things like Paxos, eventual consistency, and Merkle graphs. - There are a lot of cases where he repeats something he's heard that he evidently doesn't understand. The muddled attempt to explain fault tolerance above is one example, but we could also mention, for example, his attempt in §4.1 to describe Fortran programmers writing Fortran in C++, which completely misses the actual major difficulty (it's mostly about structuring the data as arrays, not the control flow), or his remark, "Assembler is regarded as the second-generation language," devoid of the historical context to provide any meaning to it. - One problem that I think is actually new in the second edition is its presumption that all software is object-oriented (despite paying lip service to the fact that Visual Basic [6] was the most popular language among professional programmers, many people were still programming in Ada and assembly and Cobol and C and Fortran, etc.) and that looks a bit snake-oilier from our perspective now than it did at the time. I think OO is a useful approach to software design, but if I'm writing a generic tutorial on how to design a program, I wouldn't have a step in it called "Level 3: Division into Classes" as McConnell does in §5.2, because that makes my book completely inapplicable to programming in C, Go, Fortran, Rust, Racket, VB6, or Clojure, and inapplicable to much of what people do in Python, PHP, JS, Octave, and R. The snake oil here is not object-orientation but a totalizing ideology that everything must be OO; the Chapter 6 introduction says, "In the twenty-first century, programmers think about programming in terms of classes.". The way I remember it, the first edition didn't have this problem. - This totalizing OO outlook is somewhat exacerbated by the fact that he doesn't really understand object orientation at all, so he gives a lot of bad advice, like, "A large percentage of routines in object-oriented programs will be accessor routines, which will be very short," §7.4. His whole chapter 6 is about designing classes, but he never mentions the actual core concept of object-orientation, which is polymorphic message sends, presumably because although he knows they exist, he isn't really comfortable with them and doesn't understand how central they are to the OO worldview. Instead he treats classes as a newfangled synonym for CLU's "clusters" or Ada "packages". Much of the chapter is devoted to workarounds for shortcomings of C++. This isn't really "snake oil," just incompetence. - Another problem that I'm pretty sure wasn't present in the first edition is the counterproductive recommendations of worthless IEEE management process standards in virtually every chapter. This is kind of snake-oily; these standards are of abominable literary quality and contain no useful information that could conceivably help anyone to improve the software they write. As a representative emetic example, check out IEEE 1028, recommended in Chapter 20 and again in Chapter 21. http://profs.etsmtl.ca/claporte/english/enseignement/cmu_sqa/travaux/TP_Reviews/IEEE%201028-2002%20-%20Software%20Reviews.pdf http://profs.etsmtl.ca/claporte/english/enseignement/cmu_sqa.... Unlike some other IEEE management process standards I've had the misfortune of reading, it at least doesn't seem to contain any misinformation, but that's because it manages to spend 47 pages saying nothing at all about software. There's still much material in the book that's solid, and lots of references to good information, but it's mixed with a lot of serious misinformation, misleading analogies, and embarrassing incompetence. And it's a slog to get through so much verbiage. But it's certainly better than Clean Code. Still, now that The Practice of Programming, The Pragmatic Programmer, and A Philosophy of Software Design are out, I think there's no longer any reason to recommend Code Complete.
- donatj 2y agoI have worked with a couple of people over the years who instead of breaking functions out when something would say make sense to be reused or made some sort of logical sense as a unit, instead seemingly just bundle lines whose only real relationship was that they happened to be near each other when they decided to "refactor". Having read Clean Code back in college as it was assigned reading, it was absolutely the vibe I got from Uncle Bob generally. See any number of lines at the same indentation level, select them, extract method, name it vaguely for some part of what it does, repeat. I honestly think that it comes from this type of school of thought that a function should be X lines rather than a function achieving a function. Thinking about this now, it's sort of the difference between "subroutines" and "functions". Working on their code, I thank god for modern IDEs ability to inline. I often go through and restructure the code just to understand the full scope of what it's doing, before restoring what I can of the original to make my changes as minimal as possible.
- zelos 2y agoThe warning sign I see when methods are split too much is that the method boundaries start to get messy: methods take too many arguments, or state is saved into confusingly named class members, or you end up returning some struct containing a grab bag of unrelated values.
- donatj 2y agoAll of this all the time
- kraftman 2y agoIt's been a long time since I've read the book but I took it to be less 'cut the function at X lines' and more 'long functions tend to be doing too many things at a time'. I think if you're able to give a good name to some sub section of a function, it's a good sign that it can be extracted out. At that point, you shouldnt need to look at the functions implementation unless its the specific function that you want to modify, because its name and arguments should be enough to know what it does and that you don't need to touch it. Are we talking about the same thing and you'd still find that hard to understand?
- ArchieMaclean 2y agoMy take on the prime example: import itertools def generate_n_primes(n): """ Generate n prime numbers using a modified Sieve of Eratosthenes. The algorithm keeps track of a list of primes found so far, and a corresponding list of 'multiples', where multiples[i] is a multiple of primes[i], (multiples[i] is initially set to be primes[i]**2, see the optimisations section below). The main loop iterates over every integer k until enough primes have been found, with the following steps: - For each prime found so far - While the corresponding multiple is smaller than k, increase it by steps of the prime - If the multiple is now the same as k, then k is divisible by the prime - hence k is composite, ignore it. - If, for EVERY prime, the multiple is greater than k, then k isn't divisible by any of the primes found so far. Hence we can add it to the prime list and multiple list! There are a few optimisations that can be done: - We can insert 2 into primes at the start, and only iterate over every odd k from there on - When we're increasing the multiple, we can now increase by 2*prime instead of 1*prime, so that we skip over even numbers, since we are now only considering odd k - When we find a prime p, we add it to the prime and multiple list. However, we can instead add its square to the multiple list, since for any number between p and p**2, if it's divisible by p then it must be divisible by another prime k < p (i.e. it will be caught by an earlier prime in the list) """ # Insert 2 into primes/multiples primes = [2] multiples = [4] # Iterate over odd numbers starting at 3 for k in itertools.count(3, 2): # If we've found enough primes, return! if len(primes) >= n: return primes # For each prime found so far for i in range(len(primes)): # Increase its corresponding multiple in steps of 2*prime until it's >= k while multiples[i] < k: multiples[i] += 2 * primes[i] # If its corresponding multiple == k then k is divisible by the prime if multiples[i] == k: break else: # If k wasn't divisible by any prime, add it to the primes/multiples list primes.append(k) multiples.append(k ** 2) return primes Some might find the docstring as well as comments too much - I find the comments help relate the code to the docstring. Open to suggestions!
- aswerty 2y agoWhile I enjoyed the discussion as an exercise in stripping back positions to underlying principles. I find it a great irony that the overarching reason why they diverge on what is "good practice" is not discussed. John sounds like he is about to start building a new type of database, and Bob sounds like he's knee deep in a 20 year old code base for a logistics company. Both of their positions are reasonable, and both optimized for specific contexts. I found Bob's responses more measured (which I value a lot), with John's at times being more compelling. I do agree that over-composition is a real problem that Bob is on the wrong side of the line on. But to be fair, Bob and Clean Code comes from a time where it was the opposite and his position on this feels like a philosophy that has an over-correction (albeit - not necessarily a flaw) at it's core.
- ptx 2y agoUB says at one point: > Would that we had such a crystal ball And then it seems like he actually found his crystal ball, because in the very next question he refers to things that have not yet occurred in the conversation: > interpreting your rewrite (below) And later: > In your solution, which we are soon to see below This makes it somewhat confusing to read, with answers being based on counterpoints that will only have been made in the future. (Which, I suppose, is similar to the problem Ousterhout has with UB's PrimeGenerator example.)
- bonsaiKiller 2y agoThere’s obviously a balance. Having worked in both environments, I tend to appreciate the code of someone who at least read the books, but treats it as suggestion rather than gospel. Contrast to someone who never read the books, has no clue what’s “good” and hacks everything. On the one hand, the books are popular because a lot of people reading them think it makes a good point, and share that view. On the other hand, just because something is popular doesn’t make it right! I think this is where AI gets so much wrong. GIGO! If you base all your code on whatever is most common, are you really really sure that common pattern is really the best? AI, and these book evangelist, often have no clue. Just parroting others. I’d rather deal with “principles” as opposed to “rules” every time. Glean the principles from the books, and at least try to write clean code!
- bob1029 2y agoI'm currently dealing with one of those codebases representative of the consequences of blindly following "Clean Code", et. al. My experience has taught me that you never want to be the first person to recommend a rewrite. Since I am a mere contractor on this one, I am strongly inclined to let it unwind on its own. There seems to be a lot of ego embedded in those pointless data access layer wrappers. I'd hate to get on someone's bad side right now. The market is quite rarified.
- bluGill 2y agoRewrite is only useful it you get something else that you can't get otherwise. Mixing Rust and C++ in a project is hard but doable - odds are if you try it you will find enough "friction" that eventually it will be worth rewriting to get rid of one.
- sam_bishop 2y agoOne of my beefs with Clean Code is its name. There is no objective measure of code cleanliness. So if "clean code" is your goal, then you have no meaningful criteria to evaluate alternatives. (Including those pitched by Bob Martin.) It gets worse, though. There's a subconscious element that causes even more trouble. It's obviously a good thing to write "clean code", right? (Who's going to argue otherwise?) And to do otherwise would be a moral failing. The foundation on which "Uncle Bob" tries to build is rotten from the get-go. But it's a perfect recipe for dogmatism.
- bpicolo 2y agoHonestly that kind of makes the word "clean" seem like a good fit to me. I can't say that measuring the cleanliness of my house is objective.
- jjice 2y agoLots of negative comments about Uncle Bob in this thread. I personally didn't like Clean Code and really enjoyed A Philosophy of Software Design, but I do think that some of his other books are really solid. I accept that non-fiction books on anything will oversell the value of their way, and try to take what I can at a more moderate level. Through that lens, Clean Code didn't give me much, but Clean Architecture did. The Clean Coder is also an interesting read on professionalism in software, and Clean Agile is an interesting read on Agile roots. I don't know anyone that practices "true" agile (nor do I care to do so myself), but there are some really solid ideas in there. I get that Clean Code kind of had a cult-like following in that people followed it blindly, but damn some of these comments are just rude about Uncle Bob. I still think he's a pretty good author and has given me some advice through his other books that helped me a lot as a fresh faced dev.
- mangodrunk 2y agoUncle Bob has been a horrible influence on our industry, and we’re expressing that. He has not actually worked on anything but yet he’s been able to make some money selling his inexperienced opinions.
- Hasu 2y ago> I bemoan the fact that we must sometimes use a human language instead of a programming language. Human languages are imprecise and full of ambiguities. Using a human language to describe something as precise as a program is very hard, and fraught with many opportunities for error and inadvertent misinformation. This quote from Uncle Bob is shameful, considering that he has made 100% of his career on writing English, not code.
- WillAdams 2y agoAn interesting contrast to it is Ousterhout's observation: >If you can visualize a system, you can probably implement it in a >computer program.... This means that the greatest limitation in writing >software is our ability to understand the systems we are creating. Though interestingly it is in marked contrast to a different statement in the "Software Design Book" Google mailing list: >John Ousterhout, Aug 21, 2018, 12:30:15 PM >I've never felt that graphs are a particularly useful way of describing software structure. >The interactions between classes end up so complicated that the graph becomes an unreadable mess. >Also, I'm not sure that the complexity of a graph representation of software correlates with its >practical complexity (the graph representation might look very complicated, but the software might >still be pretty easy to maintain). and I'd be interested if someone knows of a text/video/interview which resolves that twain, or what sort of visualization is advocated for/recommended.
- Izkata 2y agoStructure graphs are rarely useful for me, but visualizing the data flow is how I think about code in general. Sometimes it's graph-like, but more wishy-washy and I'm only holding the relevant parts for the task at hand in my head rather than everything.
- loganmhb 2y agoPlenty of people are ragging (justifiably) on Clean Code, but I really admire by contrast Ousterhout's commitment to balanced principles and in particular learning from non-trivial examples. Philosophy of Software Design is a great and thought-provoking read.
- cowboylowrez 2y agoPhilosophy of Software Design seemed more pragmatic to me.
- 0xbadcafebee 2y ago> For me, the fundamental goal of software design is to make it easy to understand and modify the system. I use the term "complexity" to refer to things that make it hard to understand and modify a system. This explains everything that's wrong with modern software. When you design a Formula 1 race car engine, the purpose of engine design is not to "make the engine easier to modify". It's to win races. And that depends on the race - a funny car engine, a formula 1 engine, a LeMans engine, Nascar engine, etc, are all different because the races are different. Another example: when you design a building, the goal isn't to make it easier to understand the building. The goal is to meet the requirements of the building, its uses, requirements, environment, etc. Sometimes a better building is just more complicated, and making the architect or builders' jobs easier, while nice, isn't the goal. Some things aren't supposed to be easy to understand, because ease of understanding is not the goal of the thing. Focus on the real goal of the thing, and achieving that; don't get distracted by ancillary goals.
- kraftman 2y agoMost people aren't building Formula 1 cars. Buildings are a better analogy: they are designed to be maintained. You can replace a door handle without replacing the door or the wall, you can turn off the power to different sections to do repairs. Dangerous or complex parts are labelled, moved into their own rooms or cupboards, and locked.
- allemagne 2y agoA genius architect/Formula 1 engineer can design a building/engine that fits all the requirements astonishingly perfectly, but if the builders have difficulties understanding it, or later contractors can't figure out how to maintain or fix anything, then it's only a perfect design in theory and an awful design in reality. It's not a nice-to-have to make people's lives a little easier, it defines the success of the project. The genius architect/engineer can insist that the complex design reflects the underlying domain as much as they want but at some point they will have to back that up to someone else who isn't a genius. Obviously, writing code such that a first year comp sci student can understand what's happening and can start contributing immediately is absurd, but at the same time nobody builds anything in a vacuum. There's a certain legibility required within any context you're designing something for.
- jpitz 2y ago"Do One Thing" is to me maybe best understood in the context of the Single Layer Of Abstraction Principal - it has helped me numerous times to be very intentional about following SLAP in complex code, and Do One Thing seems to fall very naturally out of it.
- nadam 2y agoI was just thinking about what AI assisted coding brings to the design discussion, especially as AI become more and more powerful and we rely on it more and more. You still want to make things modular and easy to understand so that AI understands it easily and the needed info to modify a module can fit in a relatively small context window, but the difference is that it is very easy to make large scale measurement about which code style is understood better by an LLM, so maybe some of these debates will be decided relatively objectively! For the topic: the discussed topics are relatively trivial surface level stuff, mostly I agree with POSD, but these will be handled by AI anyway. I guess humans will use the spare brain capacity to deal with the real deep design questions (for a while).
- zzzeek 2y agoI've been programming since the early 80s and have never seen real world, production code that was done in so-called "clean code" style
- spacechild1 2y agoIMO the "PrimeGenerator" example from Clean Code is horrendous and completely unreadable! This would be so much better as a single method/function with a few interspersed comments that explain the algorithm. I mean, just look at this abomination: private static boolean isMultipleOfNthPrimeFactor(int candidate, int n) { return candidate == smallestOddNthMultipleNotLessThanCandidate(candidate, n); } Not only is the method itself completely pointless, it also happens to have side effects! Who would expect this from the method name? So much for self-documenting code... Ousterhout rightfully calls him out on this bullshit. In fact, Ousterhout makes such great points that I really want to read his book. Conversely, I'm now even less inclined to read Clean Code.
- spacechild1 2y ago> This would be so much better as a single method/function with a few interspersed comments that explain the algorithm. I haven't read the whole article when I wrote that comment. Turns out that Ousterhout provides a rewritten version of "PrimeGenerator" that does exactly this. At least UB concedes that this version is indeed much better.
- pcblues 2y agoOn reflection, my attitude to books like these indicated where I was in my understanding of programming. They used to be useful life-buoys that one clung to for dear life early in one's career in a fast-moving and often-changing industry. Then they become an interesting side-note reminding one of what they clung to as the good precepts that served them well stand out from the rest of the books. And finally they become unnecessary and seemingly dogmatic when one has become adept at swimming. In other words, essential reading depending on where you find yourself :) Disclaimer: out of these two, I only read Clean Code.
- __mharrison__ 2y agoThis is actually a great read. I'm in the middle of designing a course for a client on teaching software engineering best practices for data scientists (and folks who live in Jupyter all day). There seems to be a huge lack of material for these types that aren't "programmers", don't live in an "IDE", and are essentially writing code all day.
- MetaWhirledPeas 2y agoI think the reason most people have a problem with Uncle Bob is because they know their own practices are a far cry from his recommendations, and they take his prescriptive and uncompromising advice as a personal attack. I also wonder how many people interpret his advice as that of a mindless, pedantic dictator. My own introduction to UB was from some random YouTube video he made about programming languages, so my first impression of him included his humor and his ability to see both sides of an issue while being unafraid of having a strong opinion. I really enjoy speaking with and listening to people with strong, long-marinated opinions, regardless of whether I agree or not. At the very least it means they've put a lot of thought into it, which makes for better discussion and learning. I also lack a long history of code commits, being more of a dabbler here and there, so perhaps I have a smaller surface area for UB's jabs to land upon. Still, I acknowledge that a Clean Code Nazi would probably rip me to shreds for some of the practices I've followed and some that I continue to follow. But improvement is a much more achievable goal than perfection, and gleaning valuable information is better than being dogmatic. In the end I love listening to UB talk. I don't follow all his practices but I do keep them in the back of my mind. If not worth following strictly they are always worth considering, especially the intent behind them. So when I see his opinions on comments or his opinions on abstraction and variable naming my first instinct is not to lament about how he is poisoning our youth or insulting my code, but rather to ask myself how I can make use of his perspective. I'd encourage others to do the same; it's much more fun that way, not just for programming but for everything. As for those of you stuck in "Clean Code" hell with oppressive supervisors demanding strict adherence... that sounds like a personal failure, or a personal incompatibility, or both. I would blame the messenger there, not the message.
- overgard 2y agoMy problem with UB is that by promoting his brand and his style so much to junior developers (in both subtle and fairly overt ways), he's warped the mind of a lot of people in a way that effects them for a long time and the people around them. I don't really have anything personally against UB, but dealing with the code that one of his acolytes creates is deeply frustrating and often they claim it's "best practice" even though there's basically no validation around most of his claims and if you read the criticism, they're fairly common sense.
- jdmoreira 2y agoUncle Bob probably the biggest scammer in Software. What a complete pile of garbage. So much energy wasted in all these design patterns, SOLID and other OOP bullshit. Turns out you can just pass immutable data in and get immutable data out. Who would have guessed? The whole 90s - 00s Java OOP garbage still gives me nightmares
- mrkeen 2y agoFWIW Uncle Bob has been preaching functional for more than 10 years now. https://youtu.be/7Zlp9rKHGD4 https://youtu.be/7Zlp9rKHGD4
- ad_hockey 2y agoSomething I find odd about Uncle Bob's style is the preference for reading and modifying shared state over pure functions that take args. It makes me do a double take when I read a method registerTheCandidateAsPrime() (taken from UB's rewrite) that doesn't take a candidate arg. How would you unit test those methods? You'd have to directly set the field values, then call the method, then assert on the fields. If the answer is "you don't unit test private methods" then that's completely fine, because I agree with that (perhaps this is implicit from the private keyword, I don't know Java). But I'm struggling to imagine how you would get to those private methods with such a strict adherence to TDD as Bob recommends. Methods like increaseEachPrimeMultipleToOrBeyondCandidate() are quite complex, and would be tricky to build up using TDD if you couldn't exercise them directly. If nothing else, surely Bob's approach is not thread safe. Call PrimeGenerator3.generateFirstNPrimes() concurrently and they'll trample all over each other. John Ousterhout's stateless version doesn't have that problem.
- ben30 2y agoThe primary goal of software design should be to facilitate understanding and modification for future developers, emphasizing the importance of code readability.
- beryilma 2y ago"Uncle Bob" is not a software engineer (as he calls himself) and anything he says on the subject is theoretical at best, and snake oil at worst. Can anyone point to any substantial piece of code that he wrote before he can be taken seriously. The code pieces at his GitHub repos, other than style, etc., are just simplistic stuff. It is probably OK to be thinking on issues related to a field (i.e., software engineering) without being a practitioner in the field, but producing fads-du-jour and selling them as solid (pun intended) theories and expecting to be taken seriously is just ludicrous to me.
- pnt12 2y agoSome software gurus really grind my gears, and Robert Martin is one of them. When confronted with bad advice he gave, he's quick to say it's not meant to be taken literally. Then, gurus like Kent Beck, say that you cannot criticize their approaches if you don't implement exactly as they say. So, while this is not exactly a paradox (different people with different opinions), I feel like gurus make their livings on unfalsiable claims while shaping the world of software engineering. So, some kudos to Robert for accepting criticism and discussing it, but no cigar for downplaying his own advice when confronted - I also recall a different discussion, where someone confronts his statement "you don't practice tdd you're not a professional", and his answer "it was not meant to be taken seriously". These people had great ideas but they should be more critical of themselves, eg "here's when not to apply this", "here's where to bend this", not "you're doing it wrong" or "don't take it literally".
- dqft 2y agoI don't understand how that works on people. Dog whistling, "Hey, hey, leave me to my grift."
- xiphias2 2y agoThe more I tried to implement Clean Code, the more it helped me appreciate Worse is Better approach, which comes from an observation, not a dogma: while all programmers strive for simplicity both in implementation and interface, when they come into conflict, simple implementation usually wins over simple interfaces, as they are easier to modify. https://dreamsongs.com/RiseOfWorseIsBetter.html https://dreamsongs.com/RiseOfWorseIsBetter.html
- Applejinx 2y agoIt's always fascinating to me to see this subject talked about, because I've been programming for years in a niche field (audio plugin DSP development) and have interacted with Clean Code programmers, but I seemingly cannot grasp what they do at all. This is to the point that, in order to program and do the things I want to do, I have to essentially write nearly everything out longhand, to the point of unrolling things in repetitive fashion, and organizing things in blocks of code separated by comments about what's being done in each block. I can do this so predictably and regularly that my code gets parsed by other people's more Clean Code and ingested as sort of blocks of program behavior to be used in other software, to the point where it's an 886-star repo with 79 forks: not Bob-scale, but then I haven't written books or revolutionized corporate coding. I've had to learn useful things about where my approach doesn't take advantage of its hypothetical strengths: heedlessly unrolling everything doesn't give you speed boosts, and I've had to learn to declare variables nearer to where they're used. But I've also had to learn that I could do the opposite of Clean Code for performance gains. Back in the day, you could assign variables for calculations to avoid Repeating Yourself, but on modern processors it turns out… in addition to techniques like running calculations in parallel on wide data words that contain different data processed together… you can even take advantage of how eager CPUs are to do math, to avoid creating extra variables. It can be more efficient to just do the math a couple times rather than create a whole new variable just to skip the math. This world makes sense to me. It acts like assembly language, except it's C (not even C++). I don't know to what extent there are other people who think this way, or struggle to keep track of even simple abstractions. It's just the context with which I see Bob acolytes, rather than just declaring a variable to not do the math twice, breaking it off into about twelve different methods for seemingly purely semantic reasons, and insisting anything else is stupid. And there I am, producing and re-using reams of shockingly primitive code that seems to work and where I can return to it, even a couple decades later, and have no trouble figuring out what I did. There's something to be said for being SO stupid that your work just works.
- tdiff 2y agoIs there still any apologet of Bob Martin nowadays?
- ptx 2y agoI'm surprised that Ousterhout doesn't point out the huge problem introduced with the PrimeGenerator3 refactor: It stores state in static (!) fields, so it's completely unusable in the presence of threads, unless you add a global lock. Even if Uncle Bob thinks tiny methods are great, why would he introduce the pseudo-constructor "initializeTheGenerator" and make everything static if he needs state? If the helper methods were instance methods instead, the static "generateFirstNPrimes" method could simply construct a new instance to store the state.
- de6u99er 2y agoClran code is just one of the tools in a good software engineer's toolbox.
- lincpa 2y ago[dead]
- mschoenert 2y agoThis prime generating code has fascinated me for a while. It was first described by E.W. Dijkstra "Notes on Structured Programming (EWD249), 2nd; 1970; TH Eindhoven". https://www.cs.utexas.edu/~EWD/ewd02xx/EWD249.PDF https://www.cs.utexas.edu/~EWD/ewd02xx/EWD249.PDF And then reformulated by D.E. Knuth "Literate Programming; 1984" http://www.literateprogramming.com/knuthweb.pdf http://www.literateprogramming.com/knuthweb.pdf Both use it to demonstrate their way of deriving and documenting an algorithm. And then R. Martin used it again in his book "Clean Code; 2008". (Though I'm not 100% certain what he wants to demonstrate with his rather difficult formulation.) For the sake of this email I am going to call it "Dijkstra's algorithm". If we look at it from an engineering perspective, then Dijkstra's algorithm is never the best choice (at least not in 2025). If performance is not the most important aspect, e.g. if we need less than 100000 primes, then the straightforward trial division is just as fast - and soooo much simpler (basically impossible to get wrong). Note that this is different in 2025 than it was in 1970, back then multiplications and divisions were much more expensive so it made sense to minimize them. If performance is the most important aspect, then the sieve of Eratosthenes is much faster. And you can implement the sieve with a sliding window, which is just as fast (or even a bit faster because of caching) and uses a bounded amount of memory. Concretely - my implementation of the sliding window sieve of Eratosthenes is about 50 times faster than Dijkstra's algorithm (on the same machine) when generating the first 200 million primes (7.5 sec vs 6 min). The reformulation - both by Ousterhout and Martin - computes multiples for every new prime found. This will quickly lead to overflow, e.g. the 6543-th prime is 65537, so its square will overflow 32 bit unsigned integers. Dijkstra's formulation on the other hand only computes multiples that are actually used to filter, the multiples are never (much) larger than the candidate. Note that computing the multiples so eagerly will also make the multiples vector unnecessarily large (wasting memory). Knuth and Dijkstra both remark that there is a subtle problem with the correctness of the algorithm. When incrementing lastMultiple and then later accessing primes[lastMultiple] und multiples[lastMultiple] it is not obvious that those will already be assigned. In fact they will be, but it is very difficult to prove that. It is a consequence of the fact that for every integer n there is always a prime between n and n*n, which follows from Betrand's theorem, a difficult number-theoretical result. So if you look at Ousterhout's and Martin's reformulation and think "a yes - now I get the algorithm", then beware: You've missed at least two aspects that are relevant for the algorithm's correctness. ;-)