Skip to content

Instantly share code, notes, and snippets.

@vcarl
Last active January 10, 2018 01:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vcarl/058c8456b19021318cfdd19f006ab7a6 to your computer and use it in GitHub Desktop.
Save vcarl/058c8456b19021318cfdd19f006ab7a6 to your computer and use it in GitHub Desktop.

“Honesty in small things is not a small thing.”

This is a book about humble concerns whose value is nonetheless far from small.

We can accept for granted that responsible professionals give some time to thinking and planning at the outset of a project.

I think this is one of the base assumptions the book makes about its readers. If your routine is to hop directly into code without a thought for the overall design, you may try to change that habit.

Total Productive Maintenance

A focus on maintenance rather than on production.

  • Seiri, or organization (think “sort” in English). Knowing where things are—using approaches such as suitable naming—
  • Seiton, or tidiness (think “systematize” in English). There is an old American saying: A place for everything, and everything in its place. A piece of code should be where you expect to find it—and, if not, you should re-factor to get it there.
  • Seiso, or cleaning (think “shine” in English): Keep the workplace free of hanging wires, grease, scraps, and waste.
  • Seiketsu, or standardization: The group agrees about how to keep the workplace clean.
  • Shutsuke, or discipline (self-discipline). This means having the discipline to follow the practices and to frequently reflect on one’s work and be willing to change.

If you take up the challenge of reading and applying this book, you’ll come to understand and appreciate Shutsuke (self-discipline).

Breakdown maintenance—waiting for bugs to surface—is the exception. Instead, we go up a level: inspect the machines every day and fix wearing parts before they break.

This is how it works in other high-value engineering roles. Aircraft, ships, large buildings, are all routinely inspected with the expectation that any code violations are promptly fixed.

We should probably re-do major software chunks from scratch every seven years or so to sweep away creeping cruft. Perhaps we should update Brooks’ time constant to an order of weeks, days or hours instead of years. That’s where detail lies.

Not just to keep away cruft, but also to keep it updated with changing best practices. We've been writing code for 50 years: compared to the time we've been building bridges, cars, even airplanes, the field is in its adolescence.

We abandon our code early, not because it is done, but because our value system focuses more on outward appearance than on the substance of what we deliver.

Bell Labs Software Production Research organization.

Bell Labs was an incredible center for innovation. For further reading, look at [The Idea Factory](https://smile.amazon.com/dp/B005GSZIWG/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)

Quality is the result of a million selfless acts of care—not just of any great method that descends from the heavens.

While rework in the manufacturing metaphor leads to cost, rework in design leads to value.

It is a recommended practice in Scrum that re-factoring be part of the concept of “Done.”

Which door represents your code? Which door represents your team or your company?

Learning to write clean code is hard work. It requires more than just the knowledge of principles and patterns. You must sweat over it. You must practice it yourself, and watch yourself fail.

You must see them agonize over decisions and see the price they pay for making those decisions the wrong way.

The detail in section 2 is intense. You will have to flip back and forth between the narrative and the code listings. You will have to analyze and understand the code we are working with and walk through our reasoning for making each change we make. Set aside some time because this should take you days.

This knowledge base is of limited value if you don’t do the work of carefully reading through the case studies in the second part of this book.

We will never be rid of code, because code represents the details of the requirements. At some level those details cannot be ignored or abstracted; they have to be specified. And specifying requirements in such detail that a machine can execute them is programming. Such a specification is code. Well-specified requirements are as formal as code and can act as executable tests of that code!

Cycle of debt

[The company] had rushed the product to market and had made a huge mess in the code. As they added more and more features, the code got worse and worse until they simply could not manage it any longer. It was the bad code that brought the company down.

We’ve all felt the relief of seeing our messy program work and deciding that a working mess is better than nothing. We’ve all said we’d go back and clean it up later. Of course, in those days we didn’t know LeBlanc’s law: Later equals never.

Teams that were moving very fast at the beginning of a project can find themselves moving at a snail’s pace. Every change they make to the code breaks two or three other parts of the code. No change is trivial. Every addition or modification to the system requires that the tangles, twists, and knots be “understood” so that more tangles, twists, and knots can be added.

The team rebels. They inform management that they cannot continue to develop in this odious code base. They demand a redesign. Management does not want to expend the resources on a whole new redesign of the project, but they cannot deny that productivity is terrible. Eventually they bend to the demands of the developers and authorize the grand redesign in the sky.

Spending time keeping your code clean is not just cost effective; it’s a matter of professional survival.

The fault, dear Dilbert, is not in our stars, but in ourselves. We are unprofessional. What if you were a doctor and had a patient who demanded that you stop all the silly hand-washing in preparation for surgery because it was taking too much time?

Being able to recognize clean code from dirty code does not mean that we know how to write clean code!

A programmer without “code-sense” can look at a messy module and recognize the mess but will have no idea what to do about it. A programmer with “code-sense” will look at a messy module and see options and variations.

Bjarne Stroustrup, inventor of C++ and author of The C++ Programming Language I like my code to be elegant and efficient. The logic should be straightforward to make it hard for bugs to hide, the dependencies minimal to ease maintenance, error handling complete according to an articulated strategy, and performance close to optimal so as not to tempt people to make the code messy with unprincipled optimizations. Clean code does one thing well.

Bad code tempts the mess to grow!

Like a good novel, clean code should clearly expose the tensions in the problem to be solved. It should build those tensions to a climax and then give the reader that “Aha! Of course!” as the issues and tensions are resolved in the revelation of an obvious solution.

Clean code can be read, and enhanced by a developer other than its original author. Clean code always looks like it was written by someone who cares. There is nothing obvious that you can do to make it better. You know you are working on clean code when each routine you read turns out to be pretty much what you expected.

When the same thing is done over and over, it’s a sign that there is an idea in our mind that is not well represented in the code.

Martial artists do not all agree about the best martial art, or the best technique within a martial art. Often master martial artists will form their own schools of thought and gather students to learn from them.

The next time you write a line of code, remember you are an author, writing for readers who will judge your effort. If you want to go fast, if you want to get done quickly, if you want your code to be easy to write, make it easy to read.

Books on art don’t promise to make you an artist. All they can do is give you some of the tools, techniques, and thought processes that other artists have used. So too this book cannot promise to make you a good programmer.

Programmers create problems for themselves when they write code solely to satisfy a compiler or interpreter.

Number-series naming (a1, a2, .. aN) is the opposite of intentional naming. Such names are not disinformative—they are noninformative; they provide no clue to the author’s intention.

In the absence of specific conventions, the variable moneyAmount is indistinguishable from money, customerInfo is indistinguishable from customer, accountData is indistinguishable from account, and theMessage is indistinguishable from message.

Make your names pronounceable. If you can’t pronounce it, you can’t discuss it without sounding like an idiot.

Encoding type or scope information into names simply adds an extra burden of deciphering. People quickly learn to ignore the prefix (or suffix) to see the meaningful part of the name. The more we read the code, the less we see the prefixes.

Our goal, as authors, is to make our code as easy as possible to understand.

We want to use the popular paperback model whereby the author is responsible for making himself clear and not the academic model where it is the scholar’s job to dig the meaning out of the paper.

You need to place names in context for your reader by enclosing them in well-named classes, functions, or namespaces. When all else fails, then prefixing the name may be necessary as a last resort.

Shorter names are generally better than longer ones, so long as they are clear.

The hardest thing about choosing good names is that it requires good descriptive skills and a shared cultural background.

People are also afraid of renaming things for fear that some other developers will object. We do not share that fear and find that we are actually grateful when names change (for the better).

The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that.

the three steps of the function are one level of abstraction below the stated name of the function.

If a function does only those steps that are one level below the stated name of the function, then the function is doing one thing. After all, the reason we write functions is to decompose a larger concept (in other words, the name of the function) into a set of steps at the next level of abstraction.

another way to know that a function is doing more than “one thing” is if you can extract another function from it with a name that is not merely a restatement of its implementation [G34].

In order to make sure our functions are doing “one thing,” we need to make sure that the statements within our function are all at the same level of abstraction.

once details are mixed with essential concepts, more and more details tend to accrete within the function.

It turns out to be very difficult for programmers to learn to follow this rule and write functions that stay at a single level of abstraction.

Don’t be afraid to make a name long. A long descriptive name is better than a short enigmatic name. A long descriptive name is better than a long descriptive comment.

Choosing descriptive names will clarify the design of the module in your mind and help you to improve it. It is not at all uncommon that hunting for a good name results in a favorable restructuring of the code.

Be consistent in your names. Use the same phrases, nouns, and verbs in the function names you choose for your modules.

The ideal number of arguments for a function is zero (niladic). Next comes one (monadic), followed closely by two (dyadic). Three arguments (triadic) should be avoided where possible.

When you are reading the story told by the module, includeSetupPage() is easier to understand than includeSetupPageInto(newPage-Content).

Note: i would argue that the object that a method is being called on is effectively the same as an argument. x.render() and render(x) have the same information in them

Output arguments are harder to understand than input arguments. When we read a function, we are used to the idea of information going in to the function through arguments and out through the return value.

Passing a boolean into a function is a truly terrible practice. It immediately complicates the signature of the method, loudly proclaiming that this function does more than one thing.

Reducing the number of arguments by creating objects out of them may seem like cheating, but it’s not. When groups of variables are passed together, the way x and y are in the example above, they are likely part of a concept that deserves a name of its own.

Side effects are lies. Your function promises to do one thing, but it also does other hidden things.

Temporal couplings are confusing, especially when hidden as a side effect. If you must have a temporal coupling, you should make it clear in the name of the function.

Anything that forces you to check the function signature is equivalent to a double-take.

much of the need for output arguments disappears in OO languages because this is intended to act as an output argument.

If your function must change the state of something, have it change the state of its owning object.

Functions should either do something or answer something, but not both. Either your function should change the state of an object, or it should return some information about that object. Doing both often leads to confusion.

When you return an error code, you create the problem that the caller must deal with the error immediately.

Functions should do one thing. Error handing is one thing. Thus, a function that handles errors should do nothing else.

when the Error enum changes, all those other classes need to be recompiled and redeployed.11 This puts a negative pressure on the Error class. Programmers don’t want to add new errors because then they have to rebuild and redeploy everything. So they reuse old error codes instead of adding new ones.

When you use exceptions rather than error codes, then new exceptions are derivatives of the exception class. They can be added without forcing any recompilation or redeployment.

Look back at Listing 3-1 carefully and you will notice that there is an algorithm that gets repeated four times, once for each of the SetUp, SuiteSetUp, TearDown, and SuiteTearDown cases.

Duplication may be the root of all evil in software.

Writing software is like any other kind of writing. When you write a paper or an article, you get your thoughts down first, then you massage it until it reads well. The first draft might be clumsy and disorganized, so you wordsmith it and restructure it and refine it until it reads the way you want it to read.

Comments are, at best, a necessary evil. If our programming languages were expressive enough, or if we had the talent to subtly wield those languages to express our intent, we would not need comments very much—perhaps not at all. When you find yourself in a position where you need to write a comment, think it through and see whether there isn’t some way to turn the tables and express yourself in code.

One of the more common motivations for writing comments is bad code. We write a module and we know it is confusing and disorganized. We know it’s a mess. So we say to ourselves, “Ooh, I’d better comment that!” No! You’d better clean it!

Sometimes it is just helpful to translate the meaning of some obscure argument or return value into something that’s readable. In general it is better to find a way to make that argument or return value clear in its own right; but when its part of the standard library, or in code that you cannot alter, then a helpful clarifying comment can be useful.

Sometimes it is useful to warn other programmers about certain consequences.

Plopping in a comment just because you feel you should or because the process requires it, is a hack. If you decide to write a comment, then spend the time necessary to make sure it is the best comment you can write.

It is just plain silly to have a rule that says that every function must have a javadoc, or every variable must have a comment. Comments like this just clutter up the code, propagate lies, and lend to general confusion and disorganization.

The connection between a comment and the code it describes should be obvious. The purpose of a comment is to explain code that does not explain itself. It is a pity when a comment needs its own explanation.

As useful as javadocs are for public APIs, they are anathema to code that is not intended for public consumption. Generating javadoc pages for the classes and functions inside a system is not generally useful, and the extra formality of the javadoc comments amounts to little more than cruft and distraction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment