“Clean code” isn't actually clean
sdegutis.comMost guru's take an 'all or nothing' approach, this goes beyond programming, look at food-guru's "eat only carbs, never eat refined sugar" etc. This is for me the same as "always do TDD, never use static methods".
People without experience often look at guru's because they can not yet think for themselves.
I'm a developer in my 40s, have done a lot of projects in a lot of different companies. Having this experience gives me intuition about what to do in what situation. I just (think I) know when I should write a unit test and when not.
The 'all or nothing' attitude is created by people who want to be guru's and is followed by people who want to have some guidance.
This is not a bad thing, it takes time to shape yourself as a programmer. This takes years: http://www.norvig.com/21-days.html
Learn from the guru's, and be consious, people preaching an 'all or nothing' view of the world are NEVER right :)
Fully agree. But to gain experience and intuition, sometimes you have to work close to one extreme, and the other extreme, to know in what situation the middle ground is. And to get a real feel what the benefits and drawbacks are.
Everything is always a trade-off. And it's the situation that can tell you which trade-offs you are prepared to make.
I like the phrase that your code, tests, etc, need to be "good enough". Because "good enough" is, you know, good enough. That way you can spend time on what matters the most.
Please, it's just "gurus", no apostrophe needed.
its not plural, its possessive so apostrophe needed.
IME the 'best' code solves an existing problem with the least amount of code, is human-readable, and easy to throw away (instead of being 'future proof').
Of course this 'easy to throw away' will also lead to a slow replacement process of 'good code' (that's easy to replace) with new 'bad code' (that's incrementally harder to replace) and eventually each software project will end up in the same broken mess, no matter how well it started ;)
Replace `least amount of code` with `least amount of complexity` and I completely agree!
This has been my "go-to" definition for a while, though I'd add a caveat: complexity can be subjective, based on the reader's particular experience or background.
Whenever I use FRP, I'm worried that the code is super maintainable and readable for me, but a hell for a less experienced coder.
Yes, else it ends up as some form of Perl Golf
Yes that's better. The intent was to not have unnecessary code (often happens when when 'cargo-culting' some design pattern).
Make it easy to throw away; you will, anyway (to mix-gurus).
The problem with modules that are easy to throw away is that the hole they leave is not so easily discarded. This negative space traces the module boundary; the interfaces between modules.
The only way to throw away interfaces is to throw away...? Everything. You will, anyway.
"Easy to throw away" sounds to me like high cohesion, low coupling.
This just seems like poor justification for laziness.
You need to keep a project clean. This means profound refactors when concepts for the product change. Some rules are:
- Keep it readable
- Don't over engineering
- Easy to remove
- Good tests (complete, min stubbing, interface oriented. Never refactor and change tests at the same time.
A lot of "veterans" are just resented with new paradigms and too egotistical to stay relevant. It takes effort to maintain a clean project, many will try to say "it's not worth it". That's just out of the question, it's your job, it doesn't have to be always pleasant or easy. If you don't suffer for it a bit now, someone else will in the future (maybe clients or users).
This is what I like about open source projects, it teaches maintaince discipline. In the end, you can sum up all rules into one:
- Make it easy to maintain
> A lot of "veterans" are just resented with new paradigms and too egotistical to stay relevant.
Sometimes, your new paradigm is actually something that they tried 10 years ago.
> In the end, you can sum up all rules into one: Make it easy to maintain
That is only one of the many facets of programming that you have to balance: performance, memory consumption, ... .
If you want to push your system performance to the extreme, believe me, "easy to maintain" is not going to happen. But that is the trade-off that you will have to make at that point.
Veterans know that everything is a trade-off.
Let me give you one extreme: you are writing a throw away prototype. How much time and effort are you going to spend (=waste) on making your code easy to maintain?
I'll give you my veteran answer:
- If you are in 100% control of the project, you know you will throw away the prototype, and you can throw things quickly together.
- If you have a manager, he will take 1 look at the prototype and say "Wow, it's almost complete! Don't start a new project, just add these features to your prototype and it's done.". So in that case, make the "throw away prototype" easy to maintain.
That is what veterans bring to the table: making trade-offs in specific situations. And they've been through a lot of situations.
Good points. For the record: I'm not saying all veterans are egotistical.
I think code based performance is something that is just not as big as an issue as before. In web world it's common to solve extreme performance via cache, replication, etc.
In any case, I think that in very few cases you get to a performance requirement so intense that you can't write maintainable code. We can't argue on extremes :)
I experienced while writing a lot of tests, the code suddenly became - more readable - less over-engineered - replaceable - easier to maintain since it's easier to write tests for "clean code".
Exactly, even if you don't write tests for a component, it pays off to think about how it could be made testable. You can still choose to add tests later on.
I'm 33, and while I don't think I'm "at the top of my field", I have experienced quite a bit and am confident that I can both produce and identify high-quality code.
In my mind, the biggest change as I've grown in my career is that I've gone from judging code quality to judging code suitability.
For example - the application I'm working on right now, there is is a javascript file that initializes complex data tables using the jQuery DataTables plugin. It's several hundred lines of redundant code, with several functions that actually do the initialization differently depending on the classes that are applied to the table element. It is unquestionably "low quality" code, but I have no intention of attempting to refactor it. Why? Because there are customers whose UIs are dependent upon the bugs and undocumented assumptions that are baked into that code, and refactoring it would break things from their perspective. If I did that, by the time I dealt with all the bug reports and feature requests from customers, the nice clean code that I'd written would look like the code I have now. Instead, I've written a new JavaScript file to initialize data tables going forward, and all new instances use that. They are slightly visually distinct from the "old-style" versions so users know to expect the slightly different (but now consistent) behavior. I'm very resistant to adding features to the legacy code, and instead, offer to "convert" the legacy tables to the new layout one-by-one when a new feature is requested. Eventually, we may reach a point where we can retire the legacy code - but in all likelihood, that code will be there longer than I will work here. This approach of "walling off" code that has become unwieldy and difficult to modify is one of the things that I look for when determining where a developer is in their career.
> You need to keep a project clean. This means profound refactors when concepts for the product change.
If the purpose of a company were to produce the most excellent software possible, I'd agree with you, but the purpose of a company is to make a profit. If you do a "profound refactor" every time requirements significantly change you're likely to never launch a product at all, much less iterate quickly enough to build a profitable product. You have to learn to deal with cruft and manage its lifecycle, not try futilely to prevent it from ever occurring. Part of that is learning to break things down into discrete components and limit interdependencies so you can refactor each component in isolation, but another part is learning to segregate cruft that has accumulated and keep shipping without creating a mess that slows down how quickly you can iterate in the future.
> It takes effort to maintain a clean project, many will try to say "it's not worth it".
"Worth it" doesn't necessarily mean "worth it from the perspective of the developer". It can also mean "doing this right is going to take longer, and in order to meet our business goals we can't take the time". As long as the long-term impact of these decisions are passed on to the decision-makers on the business side, there are absolutely times when "it's not worth it" to write clean code.
> That's just out of the question, it's your job, it doesn't have to be always pleasant or easy.
Nope. Your job as a developer is to provide more business value than you consume. If you're getting paid $100k you must provide more than $100k of value or you will eventually be out a job, regardless of how clean your code is.
So no data, no examples, no anything. Full of such wisdom as "Testing isn't as important as it might seem but it's still important"
The only thing actually articulated was "you don't need 100% test coverage", which is not contrary to existing practice (afaik). I'm not sure the singular point nested in platitudes can be useful to me.
A lot of software engineering practices lean towards tribal wisdom instead of being evidence-based.
The only resource I know of that provides citations to studies is Code Complete by McConnell. But having data is no guarantee of correctness. Bossavit debunks some SWE common sense in "The leprechauns of software engineering", including the cone of uncertainty which is referenced by McConnell.
I'm also planning on reading SW engineering best practices by Capers Jones, which is likewise based on data, not anecdotes.
Shouldn't everyone demand more before promoting ideas without any basis? (https://vimeo.com/9270320)
Even if it is just "tribal wisdom", is HN where you recruit a tribe from a vapor posting? I would hope you at least have a tribe before upvoting it up the pile. It feels like it's being promoted for no reason or through a backchannel.
It didn't even give a wiki link to the Chesterton's fence analogy. Sigh.
If we went for the evidence we’d all be pair programmingband doing some form of agile development.
It would be nice, and it’s backed by various studies, but we’re not.
On my side projects at home, I can't even remember the last time I had to slow down or got stuck on maintenance/integration type stuff (as opposed to new functionality or algorithms, which don't rely on existing code). And I have a couple of fairly big ones, it's not all "Todo list" stuff.
It's happened constantly at work though, throughout multiple jobs. Sometimes I've been so stuck I've got basically nothing done for days or weeks at a time. Sometimes that happens a few times in a row and I feel like I'm an inch away from being fired for incompetence. This even happens on relatively small projects. It's not confined to big 10 year old monstrosities.
The sad thing is, I work for startups, which should be all about lean, clean code and making big changes rapidly to respond to business needs.
I think a lot of it comes down to how hard it is to work on other's code. I don't think any of the conventional wisdom is a solution to this problem either. I haven't noticed any discernable difference between projects with big fuck off linters, or 50 page style guides. It's not a mish mash of semi-colons that's causing trouble (although consistency is nice).
"Dirty code" is really the crux of the problem. But like the author of this article, I don't always agree with what the conventional wisdom says about writing clean code.
To me, the most important part of keeping your code clean is always having the minimal solution to the problem. Your code shouldn't do one thing extra it doesn't need to. Half of this is YAGNI, half of it is being a good enough developer to come up with simple solutions that aren't too fancy.
On that note, don't get too fancy, and don't take DRY too seriously. Whatever complicated mess of higher order functions you're writing probably isn't going to phase other experienced devs in a vacuum, but combined with all the other icky parts of the code base and it might just be the straw that breaks the camel's back. If you need to write twice as many lines to make it more grokable, that's fine.
Speaking of YAGNI, people should be applying it somewhat to dependencies as well as functionality. It's just far too easy for a simple React project to blow out in complexity because of an over-reliance on other's code. Sometimes it's easier to build something out of code than NPM Lego.
I like NPM Lego a lot, especially if the legos are tiny and (battle-)tested.
At the same time if I can replicate the gist of lodash.omit in 5 lines I will.
I'm going to start using NPM Lego, thank you.
Criticizing code for not being "clean code" is 70% of the time "I don't like this code for various reasons"
Not to mention of the pedantism of one of the biggest proponents of clean code.
So, in essence, worry that your code has a certain quality but in the end all projects will end up in the trash can. It's software, not the Mona Lisa.
I think the problem here is that 'clean' is an umbrella term for a bunch of different things. To sum them it is: 'how does this code make me feel inside'. But what goes into that are: readability, extensibility, maintainability, testability, clarity, correctness, simplicity, and yes, aesthetics. Some of these are objectively always good, and some of them are contingently good.
For instance, a simple algorithm for distributed consensus is probably not correct, and you should rightly not view it as 'clean'. Some things simply aren't simple. The goodness of simplicity is contingent on the complexity of the problem.
But aesthetics is at the final end of the spectrum: it's purely subjective. And yet we wrap all these things up under the term 'clean', and so it is confusing. People will defend their notion of cleanliness using the objective standards, and then apply it to the subjective cases.
Given how young the practice of programming is, I doubt anyone alive today knows how to write truly good code. Just look at the kind of code people used to write 30 or so years ago. It's interesting to think about: what will "clean code" look like in 2047?
This seems to couch the idea that older professions finally "understand it." Look at the houses people made 40 or so years ago. We now have to have disclaimers indicating that the materials they used were... not so wise to be used.
Go back further, suddenly you will be left with basically nothing but survivor bias. It will seem like they had it together, but it is just as likely they did not. Pull it in some and you get the hastily built houses that seemed to fall apart way too easily.
I feel like this can go with software. It is actually trivial to find software that is still is use from the 80s. Older fortran code still exists. It is far harder to find any lessons in those software packages. Even when I desperately want to.
Sure, but we've been building houses for a long time. We know a lot more about building houses today (or even 40 years ago) than they did when the practice of house-building was still relatively new. And most of this knowledge didn't come from building houses over and over, but from developing better theories of how buildings stay up, using better materials, etc....
I think we'd both be surprised on how much actually does come from "building houses over and over." My assertion being that much of material science advancement came from required advancements from previous failed houses.
That's my same experience with programming. That's kind of what I was getting at in this article actually: that you get better by doing your best and making mistakes. Nothing beats hard-earned experience.
Completely agreed. It is good to learn from the mistakes of others, though.
To that end, it is good to have exposure to a lot of things that have failed. Seeing how they succeeded isn't as instructive, interestingly.
RE: Automated testing.
Modulo certain forms of static analysis, your code is ultimately only as good as it is well tested[1]. Non-automated tests do count here, but for long-maintained codebases the cost of automating pays for itself very quickly.
1: Note that pretty much all code has been informally integration tested (A "can I run it" type of smoke-test is a very simple integration test). Similarly all compiled languages (and any interpreted languages that parse an entire file before running code) has some static analysis, as syntax errors will be caught. Unless you check in code without compiling or running it, you are already doing some testing.
I don't understand the negativity in the top voted comments here! It's almost as though I read a completely different article than the one being commented on.
The comments here are being dismissive and then reiterating what the post said! Here's the summary from the post :
> So I stopped worrying about whether my code is perfect. And I just accepted that if I can't see any immediate flaws with the code, and if all the tests pass (whether automated or manual), then it's fine. And I trusted that if I ever come across a bug, I can fix it.
Why, specifically, is that a bad thing?
I love the story about a group of American car manufacturer executives visiting factories of Japanese car manufacturers in the 80's. After returning to the US they were asked about their visit and they remarked that the Japanese did not show them their real factories, as the Japanese factories were too clean according to the American executives. As it turns out, a clean work environment (and that includes source code) has benefits if you are doing logical work.
Sometimes the warts are just warts and mistakes, sometimes there is a deep undocumented reason for it. Which indicates a problem as reasons like that should be explicitly documented.
And yes, often clean code actually is finished. Mess is often produced by wrong architecture or rushed development which means not finished if maintainability is in your definition of code being done. What the author probably meant is concise code instead.
There is something really cool about looking at a large enough codebase, and just reading it. Then when you absorb it, then you might see a way to refactor it. I did this with the error handling code in the VCL module of LibreOffice. Frankly, I just did some renaming and a small bit of logic changes, but it just made the code far easier to understand and work with.
Promising title, but not enough content.
Shitty documented code beats clean undocumented code for maintenance. Maybe we need more "how to document my codebase" tutorials than "how to reinvent the wheel in this shinny new language" ones.
Attended a couple of clean code trainings, always wrote the shittiest code for a week or two afterwards. ¯\_(ツ)_/¯
Do you have examples of things you learned on the courses that you thought made your code more difficult to understand and modify?
After that, did you completely switch back to the code style you were using before the courses? Did you cherry pick some things and not others?
Just to make my view plain, for me 'clean code' was the most important book I've read in my career, and what I learned from it has (in my view) massively positively influenced the quality of my code over the years. I'm really interested in getting an opposing viewpoint. At the end of the day I'm aiming for my code to be understandable and maintainable by other people as much as myself.
The single most dangerous thing I learned was that "cleaning" as you go and the "intrinsic quality of the code" were somehow paramount.
I'm not against the ideas, per se. But they have a cost. And at the end of the day the quality of the product you are building is far more important than any intrinsic quality of the product. Worse, it would be nice if they correlated, at the least. They don't seem to, IME. I'd be welcome to data showing otherwise. Make sure you understand your budget. And for the love of god, realize that idioms in the codebase and in the general programmer pool are more important than purity of some style.
I agree, Clean Code was the most important book for me too. But I wouldn't follow it blindly. Also, it's less useful for non-Java and much less useful for non-OOP languages (it's ok to have a focus, but one has to keep in mind that sometimes, certain idioms, best practices or design patterns are actually workarounds around the limitations of Java).
My favorite example: Overdoing the short functions thing. I've seen this a lot. Unsurprisingly, considering that for most devs, when you ask them what makes good code, "short functions" seems to be the first thing that comes to mind.
Splitting code into extremely short functions has a few disadvantages too: a) in what order they're called is not immediately clear, b) where they can be called from is not immediately clear, c) going up/down the stack can make it harder to follow when debugging interactively. d) It increases the LOC and noise. And e) especially in OOP languages, short methods make it more tempting to turn variables into attributes to avoid passing them around explicitly (bad due to longer lifetime).
Splitting functions should only be done if it makes sense semantically. Each function should make sense on its own. If some logic is highly cohesive (e.g. because it implements a specific algorithm), not independently reusable, and it's subblocks only make sense in one order, and it all fits on a few screenfuls, it might make sense to keep it in one longer function instead of dividing it into fairly arbitrary chunks.
I think the short functions thing is a funny one. The benefits of short functions are definitely praised in the book, but they are really more of a side effect of the real goal: to have pieces of logic that do one single thing that can be summed up in a function name and understood as a clear input -> output 'step' at the level of abstraction above, without having to dig in to find out 'how it works' or understand any weird quirks / unexpected side effects etc.
Usually, by their nature, such functions don't end up being very long. This is great, but it remains just a nice side effect of the real goal, and one that is not more important than the real goal. To artificially break up a slightly longer function which is very focused in its behaviour, just for the sake of line count, is probably a mistake.
To be honest, I can't remember how clearly the book makes this distinction, or if it does at all, but I feel like it probably could be made clearer given how common this misinterpretation is.
Essentially you are recommending that people slack off as soon as they face trouble instead of spending time making sure they don't break stuff. Had you mentioned Continuous Integration and many commits per hour I would agree that tests and nurture is less important but you seem to base your thoughts on the laziness of old people.
What's the fence story?
Chesterton's Fence: https://en.wikipedia.org/wiki/Wikipedia%3AChesterton%27s_fen...
That's why you document why you do things some way and not how. So when the why changes or disappear you can change things.
Same problem with rules. Document why they exist.
Simple coding example: the one exit rule. It exists to make easier the resource management in a function. So it is useful in languages for which the coder has to manage resources. For a scripting language or one where resources are managed by the language? No. So there you can enjoy early returns.
Thanks!
YAGNI?
You Ain't Gonna Need It. (I think)
This guy mix and match totally unrelated things.
- clean != finished
- clean != perfect
- ugly is not clean
- you can understand a code and find it still ugly
What is he actually talking about?
> Automated tests are not that important
I agree with the content of this section, but the title is bad.