Ch3. Functions

Every system is built from a domain-specific language designed by the programmers to describe the system. Functions are the verbs of that language, and classes are the nouns.

Ch4. Comments

Ch5. Formatting

Small files are easier to understand than large files are

The newspaper metaphor

Source file should be like a newspaper article

Vertical formatting

Horizontal formatting

Ch6. Objects and Data Structures

Data/Object anti-symmetry

Objects hide their data behind abstractions and expose functions that operate on that data. Data structure expose their data and have no meaningful functions

Mature programmers know that the idea that everything is an object is a myth. Sometimes you really do want simple data structures with procedures operating on them

Data transfer objects (DTO)

DTO: quintessential form of a data structure -> a class with public variables and no functions

Active records

Objects

Data Structures

Ch7. Error Handling

Things can go wrong, and when they do, we as programmers are responsible for making sure that our code what it needs to do

Write your Try-Catch-Finally statement first

Provide context with exceptions

Wrapping third-party APIs is a best practice -> minimize your dependencies upon it: you can choose to move to a different library in the future without much penalty; makes it easier to mock out third-party calls when you are testing your own code

Define the normal flow

Special case pattern: you create a class or configure an object so that it handles a special case for you -> the client code doesn’t have to deal with exceptional behavior

Ch8. Boundaries

Avoid letting too much of our code know about the third-party particulars. It’s betters to depend on something you control than on something you don’t control, lest it end up controlling you

Ch9. Unit Tests

The three laws of TDD

Keeping tests clean

Test code is just as important as production code. It requires thought, design, and care. It must be kept as clean as production code

Clean tests

Readability is perhaps even more important in unit tests than it is in production code

BUILD-OPERATE-CHECK pattern:

Domain-Specific Testing Language: testing language (specialized API used by the tests) -> make tests expressive and succint -> make the tests more convenient to write and easier to read

given-when-then convention: makes the tests even easier to read

TEMPLATE METHOD pattern -> putting the given/when parts in the base classs, and the then parts in different derivatives

F.I.R.S.T.

Ch10. Classes

The Single Responsibility Principle

Trying to identify responsibilities (reasons to change) often helps us recognize and create better abstractions in our code

Cohesion

Organizing for change

Open-Closed Principle (OCP): another key OO class design principle -> Classes should be open for extension but closed for modification

Dependency Inversion Principle (DIP) -> classes should depend upon abstractions, not on concrete details

Ch11. Systems

Separate constructing a system from using it

Software systems should separate the startup process, when the application objects are constructed and the dependencies are “wired” together, from the runtime logic that takes over after startup

Separation of main

Factories

Dependency injection (DI)

An object should not take responsibility for instantiating dependencies itself. Instead, it should pass this responsibility to another “authoritative” mechanism (inverting control). Setup is a global concern, this authoritative mechanism will be either the “main” routine or a special-purpose container

Scaling up

Test drive the system architecture

Optimize decision making

Whether you are designing systems or individual modules, never forget to use the simplest thing that can possibly work

Ch12. Emergence

A design is “simple”, if it follows these rules:

Simple design rule 1: runs all the tests

Simple design rule 2-4: refactoring

For each few lines of code we add, we pause and reflect on the new design

No duplication

Expressive

It’s easy to write code that we understand, because at the time we write it we’re deep in an understanding of the problem we’re trying to solve. Other maintainers of the code aren’t going to have so deep an understanding

Minimal classes and methods

Although it’s important to keep class and function count low, it’s more important to have tests, eliminate duplication, and express yourself

Ch13. Concurrency

Objects are abstractions of processing. Threads are abstractions of schedule - James O. Coplien

Why concurrency?

Myths and misconceptions

Concurrency defense principles

Know your execution models

Others

Code that is simple to follow can become nightmarish when multiple threads and shared data get into the mix -> you need to write clean code with rigor or else face subtle and infrequent failures

Updated: July 26, 2020