Skip to content

Instantly share code, notes, and snippets.

@qnm
Created May 20, 2014 06:31
Show Gist options
  • Save qnm/b36467f872581a521074 to your computer and use it in GitHub Desktop.
Save qnm/b36467f872581a521074 to your computer and use it in GitHub Desktop.
Notes from POODR, compiled by @qnm
* Part of the difficulty of design is that every problem has two components. You must not only write code for the feature you plan to deliver today, you must also create code that is amenable to being changed later. For any period of time that extends past initial delivery of the beta, the cost of change will eventually eclipse the original cost of the application.
* Your job is one of synthesis; you must combine an overall understanding of your application’s requirements with knowledge of the costs and benefits of design alternatives and then devise an arrangement of code that is cost effective in the present and will continue to be so in the future.
* Designs that anticipate specific future requirements almost always end badly. Practical design does not anticipate what will happen to your application, it merely accepts that something will and that, in the present, you cannot know what.
* The break-even point for design depends on the programmer. Inexperienced programmers who do a lot of anticipatory design may never reach a point where their earlier design efforts pay off. Skilled designers who write carefully crafted code this morning may save money this afternoon.
* interesting design decisions occur at the place where likelihood of change intersects with number of dependents. Some of the possible combinations are healthy for your application; others are deadly.
* Delegation is tempting as a solution to the Demeter problem because it removes the visible evidence of violations. This technique is sometimes useful, but beware, it can result in code that obeys the letter of the law while ignoring its spirit. Using delegation to hide tight coupling is not the same as decoupling the code.
* Abstract superclasses use the template method pattern to invite inheritors to supply specializations, and use hook methods to allow these inheritors to contribute these specializations without being forced to send super.
* Inheritance, by its very nature, adds powerful dependencies on the structure and arrangement of code. Writing code that requires subclasses to send super adds an additional dependency; avoid this if you can.
* because Parts now responds to size, each, and all of Enumerable, and obligingly raises errors when you mistakenly treat it like an actual Array, this code may be good enough.
* “Inheritance is specialization.”—Bertrand Meyer, Touch of Class: Learning to Program Well with Objects and Contracts
* “Inheritance is best suited to adding functionally to existing classes when you will use most of the old code and add relatively small amounts of new code.” ——Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software
* “Use composition when the behavior is more than the sum of its parts.”—paraphrase of Grady Booch, Object-Oriented Analysis and Design
* There are two key ways to recognize the existence of a role. First, although an object plays it, the role is not the object’s main responsibility. A bicycle behaves-like-a schedulable but it is-a bicycle. Second, the need is widespread; many otherwise unrelated objects share a desire to play the same role.
* This is-a versus has-a distinction is at the core of deciding between inheritance and composition. The more parts an object has, the more likely it is that it should be modeled with composition. The deeper you drill down into individual parts, the more likely it is that you’ll discover a specific part that has a few specialized variants and is thus a reasonable candidate for inheritance.
* If a test requires painful setup, the code expects too much context. If testing one object drags a bunch of others into the mix, the code has too many dependencies. If the test is hard to write, other objects will find the code difficult to reuse. Tests are the canary in the coal mine; when the design is bad, testing is hard.
* Incoming messages should be tested for the state they return. Outgoing command messages should be tested to ensure they get sent. Outgoing query messages should not be tested.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment