The source code for this blog is available on GitHub.

Blog.

Clean Code

Cover Image for Clean Code
Jason Varbedian

Written by Robert C. Martin Chapters Covered All chapters

TOC

Synopsis

Book Notes

Chapter 1

Sort - naming identifiers are important tidiness/systematize - a piece of code should be where you expect to find it cleaning - don’t leave comments or wishes for the future standardization - consistent coding style and set of practices discipline - reflect on practices and be willing to change

It's your job to defend the code, manager's /pm's to defend the schedule

Meaningful Names

  • Name should tell you why it exists, what it does and how it is used.
  • avoid misinformation, accountsList should just be accounts or group of accounts. Don't encode the type unless it's actually and list and even then avoid it.
  • Length of a name should correspond to the size of its scope. Longer names are easier to search
  • Don't want users to know I'm handing them an interface, don’t include the I. Call the implementation ShapeFactoryImp
  • class names should have noun or noun phrase names Account, AddressParser. A class name should not be a verb
  • method names should have verb or verb phrase
  • one word per concept get/retrieve
  • careful to not make a pun. If add means to combine two things and you add a new method that puts a single parameter in a collection use insert or append
  • don't add gratuitous context accountaddress is fine for the instance but call the class address

Functions

  • Smaller: only those steps that are one level below the stated name. Can you extract another function from it with a name that is not merely a restatement of its implementation.
  • top to bottom:the stepdown rule- read the program as though it were a set of TO paragraphs. The TO references a lower level of abstraction
  • one switch statement, for polymorphism in a factory. Think employees with salaried, hourly, commissioned pay, is payday, deliver pay would all have switches which is bad.
  • open/closed principle: extension shouldn't require modification. If you add a new kind of employee, you shouldn't have to change old code
  • single responsibility principle: there should only be one reason to modify a class. If you have a class that compiles and prints a report, if the format or printer changes you have to change the class.
  • monadic forms: asking a question, transforming, telling event
  • avoid flag arguments: make two different functions
  • dyadic functions: can often be made into classes where you make the output/out param a member
  • have no side effects
  • separate actions and queries
  • error handling is one thing
  • write the code first and then refine. Making sure it passes the unit tests as you go

Comments

  • comments are always failures
  • informative, explanation of intent or clarification
  • bad comments are the worst

Formatting

  • minimize vertical distance. How far a variable or method is used
  • caller above callee
  • horizontal alignment isn't important
  • a source file is a hierarchy similar to an outline. Info important to the file, class, method and blocks in the method. Indentation shows this
  • team rules trump individual so a reader can trust one source file to another

Objects and Data Structures

  • allow users to manipulate the essence of the data -objects hide their data behind abstractions and expose functions
  • data structures expose their data and have no meaningful functions
  • if you are adding data types use oo, functions use data structures
  • law of Demeter: The method should not invoke methods on objects that are returned by any of the allowed functions. This helps keep date structures and objects separate.
  • data transfer objects are classes with members and no functions. Bean are private but with setters/getters
  • if you will add new behaviors use structures, new types use objects

Error Handling

  • if error handling obscures logic, then it's wrong
  • write tests to force errors/exceptions and then fix your code
  • checked exceptions violate open/closed principle
  • define exception for caller/catch
  • wrap third party APIs is a best practice
  • return empty instead of null

Boundaries

  • It is maps or a third party interface. avoid returning it from, or accepting it as an argument to, public APIs.
  • write learning/unittests for third party APIs
  • code at boundaries needs clear separations and tests that define expectations
  • can use adapter pattern

Unit Tests

  • first law: You may not write production code until you have written a failing unit test.
  • second law: You may not write more of a unit test than is sufficient to fail, and not compiling is failing
  • third law: You may not write more production code than is sufficient to pass the currently failing test
  • tests enable change
  • keep tests readable and clean, don't care about efficiency
  • domain specific testing API First:
  • Fast: Tests should be fast
  • independent: Tests should not depend on each other
  • repeatable: Tests should be repeatable in any environment
  • self-validating: Pass or fail
  • timely: Write tests just before product code

Classes

  • single responsibility. If you need something protected for a test then that rules.
  • describe without using if, and, or, but
  • many small drawers well defined or large drawers you toss everything into?
  • it's ok to make it work and then finish
  • cohesion:method should manipulate at least one variable. If all manipulate all that's perfect cohesion. If you have a subset using a subset then that's another class trying to get out.
  • SQL used interfaces for the operations