11 ms·
Qualities of clean code
- JustSomeNobody 10y agoA "Top X" post on HN. And can there really be anything new said about qualities of clean code now that hasn't already been said many ... many times before? Given that it is a "Top X" post, I don't feel confident there will be. I'm passing on this article.
- noxToken 10y agoMods, can you change the title of the article to Stuff About Clean Code We Already Know? This way, we can let the new users and new programmers know that everyone in the world has already seen this content? Thanks! Just because you know it doesn't mean everyone else does.
- JustSomeNobody 10y agoThere a thousands(!) of articles on clean code. And at least one _really_ good book on it. I would bet dollars to doughnuts that this articles has NOTHING more to add on the subject based solely on the title.
- noxToken 10y agoI know that. You that. I'm sure 99% of the commenters of the article[citation needed] know that. But there are people who haven't read Clean Code or the bevy of of other articles on this topic. The point of a forum (usually) is to promote discussion. I click on article written about stuff I know all the time. Reading the article might not tell me anything new, but the comment discussion can bring up new points or challenge existing norms that make me reconsider why I do the things I do.
- cLeEOGPw 10y agoThere are tons of people who haven't read the articles that were before.
- deleted 10y ago[deleted]
- pif 10y agoIf written by someone else, clean code is: all and only the code that I personally won't have to maintain :-)
- ewjordan 10y agoOver the years I've seen many more unmaintainable atrocities caused by diligent adherence to these principles than I ever have because of ignorance of them. All the horrid Java libraries that we hated working with 10 years ago were created because of slavish devotion to the single responsibility principle, short methods, DRY, and testability. The absolute worst codebases I've ever seen sprung from an overaggressive concern for extensibility. I do agree with the guiding principle, that when you're writing code, it should be written for other people to read and work with. But sometimes that actually does mean that a class should represent an object that does more than one thing, and you shouldn't fight it. Sometimes a gritty algorithm really does make the most sense if it's laid out as a 40 line function in one place rather than spread across 5 different classes so each part is independently swappable and testable. Sometimes you really don't need extensibility, you know that up-front, and building it in just pisses off everyone that ever has to touch your code because now they have to go through five or six "Find implementing classes" dances to find the actual code that runs when your interface methods (of which, of course, there's only a single implementation) are called. Don't even get me started on abuses of dependency injection when it's not necessary... Part of me is glad that these concepts are so commonly discussed, because they really are good things to consider, and can make code much tidier and easier to work with in the best case. But it takes a lot of experience to know when and where you should and shouldn't follow these "rules", and it tends to be much easier to unwind a novice's spaghetti code and tidy it up than it is to pick apart a poorly conceived tangle of abstraction and put it back together in a way that makes sense.
- k2xl 10y agoCouldn't agree more. One of the reasons I enjoyed learning and writing Go was that it sort of encouraged keeping things "tight" Often times programmers look at lines of code or number of classes written as a source of pride, when we really should be looking at these things as expenditures.
- blakecaldwell 10y agoAgree. I like Go for the same reason. With Java, there's a weird pressure to spend a week designing class hierarchies and to set up all the factories and abstract factories. In Go - uh, you can do it, but you're going against the grain.
- k2xl 10y agoClean code isn't always the most efficient code, but I think that's fine. Many times in my career I've found that you don't always need the most optimal, efficient, and performant solution to get the job done, and that sometimes you need to sacrifice those attributes for clear, readable, understandable code. Good architecture usually supercedes speed of individual algorithms. Hence why you see almost every major language under the sun has been used at scale. I remember when looking into neural nets, the basic python code to get one running was super easy for me to understand. However, I also realize that the optimal, most efficient methods of neural network libraries are way more complicated (and for good reason).
- pyrale 10y ago> 3. It should not be redundant Not sure I agree with this one. While abstractions are a great way to reduce the length of code, sometimes they break readability. When you read code, sometimes, you feel like you don't read a solution to your problem, but a way to solve your problem masked behind abstractions far removed from the domain concepts. That's why, sometimes, redundancy is better than the wrong abstraction.
- taneq 10y agoI've seen some very good arguments about 'redundancy' that's actually the same lines of code performing a different function in different places. In this case, naive de-duplication just adds unnecessary interdependencies between otherwise unrelated parts of the codebase.
- baron816 10y agoMost of all, clean code should be easy to reason about.
- moreoutput 10y agoThis is my first requirement in deciding if a program itself is well written. One of the best ways to achieve this, if your design isn't evident, is solid documentation that covers not only API issues but reasoning for context and perhaps a little history.
- todd8 10y ago> Most of all, clean code should be easy to reason about. This one sentence should be guiding principle for any set of recommendations. Programmers should tape it to the top of their monitor. Programs difficult to reason about are hard to get working and hard to debug and hard to maintain. In my opinion, this is the key requirement of "good" or clean code. Likewise, programming languages that facilitate this are "better" programming languages. Depending upon the goals of a program there can be other important requirements (for example, efficiency), but however the program is constructed it should be as easy to reason about as possible given the constraints imposed by these other requirements. Recognizing this, I tend to pick programming languages that make my programs easier to reason about and tend to program in a style that makes informal reasoning easier. For kernel development, programming in C was appropriate (back when I was doing it) because I needed to know exactly what was going on in the machine in response to the code. At the other end of the scale, straightforward Python code often results in such short programs that they fit entirely on one screen and are consequently easy to understand and reason about. This style of programming has led me to be very impatient with the "keep debugging" until you think it works style of development. I tend to think that each bug found is evidence of the presence of more bugs.
- moreoutput 10y ago"This style of programming has led me to be very impatient with the "keep debugging" until you think it works style of development. I tend to think that each bug found is evidence of the presence of more bugs." Well said (currently programming by dead reckoning).
- mosselman 10y agoWhile some of these points have something to do with 'clean' code or maintainable code or whatever, this copy-pasted list of very very shallow statements about code isn't really useful. I expected there would at least be a few examples on how to implement these principles, perhaps in a 'before and after'. Maybe there should be a 'click-bait' button on HN with which we can report things as such, along with posts such as 'Why I won't be using popular-technology-x ever again' and '10 things I hate about SQL'
- Can_Not 10y agoI was definitely looking for something more insightful and/or deeper to share with my colleagues. Any recommendations would be appreciated.
- deleted 10y ago[deleted]
- gravypod 10y agoI've often wanted to talk to people about things like these and I'm often pushed back by people saying "This is simple, we all know this" but I don' think that's the case. If anything I think we know very little about how to keep software clean and simple. I've been trying to change that in my works by having people comment on my code that I've recently written for homework but people aren't really up for the idea. I've had one discussion that stood out. We were talking about functional programming and I said that the idea of functional programming was the segregate state to the smallest unit of computation that must operate on it. I was met with my "friend" just blindly telling me to "stop saying that". I asked for a counter argument to that statement but they just said that I should stop saying that. We as a community are horrible at speaking about code quality , evaluating each others work, and even just sifting out opinions from facts. It's crazy and it's something that needs to change if we want to take our field to a future where we can all be happy with the code we are writing. I've got some suggestions I'm happy to talk to others about. My email is in my about page on this website. Please comment here or email me and I'd like to talk about this!
- pikzel 10y agoIt's -presented- in a very simple way. The list doesn't give any real insight or even a single code example. That's why they say it's too simple, and you say we know very little about it, and you're both right.
- gravypod 10y agoThe problem is we don't have much in the ways of examples. I'd say one of the few people in the world who has given grade-a examples is Rob Pike. That said I don't agree with him on much but I do very much respect his talent for simplicity. I'm directly referring to his Regex parser. It's amazing work although I'd much rather see him implement it live from scratch. Something like the SICP lectures on youtube. It's amazing what they go over and do in that class and how they teach you about abstracting your problem domain.
- hyperdeficit 10y agoThis is a real problem in our industry. We all like to think that we 'know' how to write good code, after all we read 'Clean Code' once. That, combined with either overconfidence in our abilities or the negative perception that comes with not knowing the answer to every problem leads to a lot of software that has applied 'good' coding practices and architecture to produce a mess of awful code. In reality it is probably a lot more like learning how to apply any other concept, it takes practice, yet we don't spend enough time practicing our craft. This is particularly a problem because in the course of developing a product you will only get to implement a new solution to a problem a few times at best, or once more likely. This means we don't get enough experience with the different possible approaches to really internalize what a 'good' solution looks like. We spend much more time learning the software development approach du jour, XP, Scrum, Kanban, Lean, etc. It doesn't matter what software development approach you use if the output is an unmaintainable mess of code.
- deleted 10y ago[deleted]
- taneq 10y agoSomething that lists like this always seem to miss is locality of reference. You shouldn't have to jump around all over a file (much less through several files) to follow the code that does a single thing. The single responsibility principle should really be "exactly one" rather than "not more than one". If a function is responsible for less than a whole thing, it shouldn't be a function on its own.
- morbidhawk 10y ago> locality of reference. You shouldn't have to jump around all over a file (much less through several files) to follow the code that does a single thing This is something I was learning when I was working in Swift, in a WWDC video they called it local reasoning; being able to reason about the code in one particular function without having to worry about state changes elsewhere. Now working in C# it seems to be a common thing to pass an object by reference to a bunch of different functions to fill in it's values and map properties. If you do too much of that it can become a maintenance and debugging nightmare when a property didn't map up the way you wanted it to. I also agree with what was said in a different comment about not breaking functions up too much if it's not necessary and that would help eliminate this need to modify state in so many places.
- caub 10y agoin the background image, the code would be better with arrow functions, or object shorthand methods
- kevindqc 10y agoI don't think it's an example of clean code (all the arguments are a and b for example). Also the article is from 2013, did these exist then?
- keithb- 10y ago>> Can be easily extended by any other developer This is a tenet that will lead inexperienced developers astray. This "rule" is just too ambiguous. Extensibility is a fascination for object-oriented programmers but in my experience doesn't have a lot of successful examples. Typically I have seen this manifest itself in either a Command+Composite style where every meaningful class is a composite of other SRP classes, or in a proliferation of interfaces that seldom have method definitions and are instead used to enforce coding standards or dependencies. KISS is incompatible with this rule and you should kill this rule with fire because simple is not extensible. Perhaps when the goal is extensibility then should you consider other developers, but if you are developing a "beige" application then you should not consider extensibility. Instead, just assume that release management will handle changes, i.e. another developer will update rather than extend your class and that will be released in version 1.1. Of course, to do this also means admitting that version 1.0 of your class was pretty much garbage and that it needed to be "extended". Tough pill to swallow for some.
- js8 10y agoI somewhat disagree. Interestingly, one of the most extensible SW systems ever is Unix shell, which is completely opposite to the OOP idea. The idea in Unix is that data are the interface, in case of Unix the data are unstructured text, but I think it can be generalized to systems with structured data. So contrary to OOP, most extensible systems seem to be the ones that (self)document their data structures as interface and leave it at that.
- hxegon 10y agoClojure agrees with this philosophy IMO. Paraphrasing, but "100 functions on 1 data structure is better than 10 functions on 10 structures"
- js8 10y agoTrue. I think in general it's a philosophy of functional programming, where data structures are types, and type signature of functions are their APIs.
- pif 10y agoI recommend "What Could Possibly Be Worse Than Failure?" by Alex Papadimoulis (http://thedailywtf.com/articles/What_Could_Possibly_Be_Worse_Than_Failure_0x3f_ http://thedailywtf.com/articles/What_Could_Possibly_Be_Worse...). An excerpt: We are practically the only industry where completion and success are synonymous. If the foundation of a one-year-old home is crumbling and its roof is plagued with leaks, would anybody actually call that a success? Despite being filmed and produced on budget, is there anyone who would not be ashamed to have Gigli on their filmography? Of course not! So why are the products we create – complex information systems that should last at least fifteen years – be held to a different standard? Now think back those projects of yours. How many would you say are maintainable by someone with less business knowledge and a weaker grasp of the system’s design? How many will not snowball into an unmaintainable mess? How many do you truly believe could last fifteen years? I’ll bet that number is quite a bit lower than all of them.
- _pmf_ 10y ago> How many would you say are maintainable by someone with less business knowledge and a weaker grasp of the system’s design? How many will not snowball into an unmaintainable mess? How many do you truly believe could last fifteen years? I’ll bet that number is quite a bit lower than all of them. Coincidentally, the number of projects where the client offers to pay for tens of man years is also quite low. This is something I'd recommend to be taken into consideration by armchair philosophers portraying the state of the software industry.
- deleted 10y ago[deleted]
- pif 10y agoI've seen this worshipping of "ship soon" many times. It always ended with a buggy and messy software, an unhappy customer and a stressed development team.
- nickpsecurity 10y agoIt also turns people into millionaires and billionaires. It's how the top hardware and software companies got their market share. So, one should always assess on given project or company the First Mover & time-to-market for feature sets advantages vs quality or user perception.
- kasey_junk 10y agoExtensibility is important in some cases and a detriment in others. Most of the rules about extensibility came from environments where the code was running in many places at the same time (ie delivered to customers). In a SaaS environment the code needn't be extensible as there is only 1 copy of it. It is much more important for the code to be changeable, rather than extensible and in many cases the things you do to make code extensible make it harder to alter fundamentally. Its important to understand that how you deliver your software is one of the biggest guiding factors in how you design your software and take that into account.
- drakonka 10y agoIf I'm remembering correctly this article seems to mostly paraphrase what the various developers Robert C. Martin interviewed for this book ("Clean Code: A Handbook of Agile Software Craftsmanship") said...in mostly the same order.
- erlich 10y agoBeing able to simulate amnesia is my goal. I write code that I come back to and don't understand, and realise its terribly complex because I understood everything at the time, but could not imagine what it would be like coming back after a month to make a change, or for someone new to try to understand it. Code is for people to understand. Some people think its for being able to write good tests, eliminating all side-effects and shared state, for the computer to be able to run quickly and optimise, to be easy to read. But its really just about being able to be understood. Most time will be spent in maintenance. When you modify and debug, you are diving into the middle. You are not walking through the code base from the beginning and reading all the comments. It needs to be understandable from all locations. I'm a strong believer in micro-modules. Left pad et. al. I try to create small modules which do one thing well that I can trust and not have to think about.
- swalsh 10y agoSomething I've noticed, in bad code if you need to learn something, or change something... Simply "searching" the code isn't enough. Maybe there are multiple places that do a similar thing, maybe the names are weird, maybe it's so condensed as to be unreadable. Whatever the cause... The only way to find the piece doing the thing is to step though it. Good code, you can search it... even if the majority of it is unfamiliar. Find a piece, and say "oh this is probably the spot" with out ever executing it.
- z5h 10y agoI believe an important quality is that code should TELL A STORY. Consider a biography: you could simply collect facts about a person and write them in an arbitrary order and call it a biography. It could be a complete and accurate account, and still be impossible to read or follow. Well written code is not only complete, but it also guides the reader through the logic. Consider the difference between: statuses = [] reporter = Reporter.new jobs.each do |job| statuses << job.complete && !job.error end and job_statuses = jobs.map do |job| job.complete && !job.error end job_status_reporter = Reporter.new In the first case, we see statuses declared. Statuses of what? Not yet clear. And the code that updates it is separated by unrelated code. Also, what will reporter be reporting? In the second case, map and better naming are used making it clear that we are getting a status for every job. Aha! I don't even need to look at the implementation of the do block to understand what's happening.
- bruxis 10y agoPersonally, I would rather see the first version with better variable names. I always find that map() methods tend to obscure the purpose of the values whereas a simple appears more explicit.
- z5h 10y ago"map", "select", "reduce", "flat_map" and the like make your intention visible upfront. "each" just tells me you're doing "something" with each item. Not sure how giving less information is preferred over being explicit, but hey, whatever works for you.
- textmode 10y agoWith the exception of shell scripting which I'm writing every day, I remove "code" more than I write it. C is the language I deal with. The easier it is to remove code from someone else's program, the "cleaner" the code. That's my definition of "clean code". For example, I just had to edit the code for a text-only browser to remove a few "features". For example, the author recently decided it would be a good idea to non-interactively access no-content refs in a page such as "prefetch" and other garbage.
- mmarx 10y ago> The easier it is to remove code from someone else's program, the "cleaner" the code. But then, contrary to intuition, a program becomes less clean by actually removing code (since now there is less code to remove, hence it is more difficult to remove code). A minimal (in the sense that no more code can be removed) program would be maximally unclean, whereas, intuitively, should it not be considered clean? Also, adding code always makes a program cleaner, since the newly added code can always be removed easily.
- textmode 10y ago"... in the sense that mo more code can be removed" Or else what happens? "... should it not be considered clean?" It should be considered finished. "... since the newly added code can always be removed easily." Not true in my experience. Unfortunately. Sometimes it's necessary to add some code, e.g., a new driver for a new item of hardware. I have nothing against adding, per se.
- mmarx 10y ago> Or else what happens? In the extreme case (the empty program), there is no more code left to remove. It suffices that any proper subset of the code is insufficient to provide the needed functionality, though. > It should be considered finished. And yet you obtain a cleaner version of the finished program by adding superfluous code to it. In fact, every unfinished version (a version where you can still remove code) of the program is cleaner than a finished version (where there is no code left to remove) of it. > Not true in my experience. Unfortunately. Removing the code is reverting back to the previous version. How is that not easy to do? > Sometimes it's necessary to add some code, e.g., a new driver for a new item of hardware. I have nothing against adding, per se. But that changes the requirements, and thus changes which code can be removed. However, the point was that you could obtain an arbitrarily clean version of a program by adding redundant code to it—since it's easy to remove that code, it is cleaner than the irredundant version of the program.
- partycoder 10y agoA piece of code should not know a lot about the system and should work under a restricted set of assumptions and preconditions. When this rule is not respected: 1) You end up with lot of coupling 2) Unit tests end up with a lot of overhead
- abhas9 10y agoSomeone very experienced once told me: "For one change in requirement there should me one change in your code. That's a clean code. If you can achieve it without any change in code, it's even better." This quote always sticks in my mind :)
- k__ 10y agoThe thing I learned from working with absolute beginners to mediocre developers is: good modularization/isolation is the key to success. Yes, most things in the article are nice to have, but you can't teach everything in a month and people need to be prodcutive to be worth their money.
- antoaravinth 10y ago>> 5. Can be easily extended by any other developer I can remember a instance, when I started my carrier. I was a JS developer. I wrote a module with Functors, Compose, Partial etc. In code review my team told they didn't understand anything and reading such a code is not pleasant for them. I was upset, I was thinking why my team is not happy with it. Today I can make lot of sense; stick to the pattern/design of your team. If your team follows / loves functional programming in your project, stick to it. If not try to advice them why functional programming would be better than normal approach. End of the day, all it matters is writing simple, elegant code which others can understand.