Session goals:
Our goal was to identify questions that, when routinely asked of oneself or others, lead toward simpler design. We also consider specific words and techniques that are helpful in eliciting simple design.
We collected raw input that has been organized below. Please help filter this down to the TopQuestionsThatDriveTowardSimpleDesign.
There was a whole session on the meaning of "simple", but here is one definition that is a variation on KentBecksFourCriteriaOfASimpleSystem :
A simple design:
- fulfills its intended purpose
- is comprehensible by those who need to work with it (not just the original author)
- has an "optimal" number of classes/methods (balancing flexibility with clarity of intent)
In the session, we addressed two broad contexts:
- Eliciting "needs" from customers, with the goal of separating the essential purpose/need from the "nice to have" and "that's the way we've always done it."
- Developers writing code, with the goal of code that fulfills its purpose with clarity and flexibility.
Some questions are relevant in both contexts, but may be worded differently for developers and users. A question's wording is critical to its effectiveness, so we explore alternate wordings for some questions.
The questions are organized into several sections, only the first of which deals directly with the customer. Within each section, the goal is to order questions/techniques by "likelihood of steering towards simplicity". Please re-order, add questions, edit questions, etc.
Finding purpose. Eliciting essential needs from customers.
(We avoid the word "requirement" because it often leads the customer toward thinking in terms of implementation, which we want to avoid.)
- Listen first, and use the customer's terminology.
- Ask 5 times: "why?"
- How will this make money?
- IRACIS: Increase Revenue, Avoid Cost, Increase Service
- How will this increase revenue?
- How will this avoid cost?
- How will this increase service?
- What is the next-most-important feature for the system...
... that has not yet been implemented?
... that has not been captured in our story cards?
- If these 3 features were in a 2 person life-raft, which of them would you throw overboard?
- Can you give me an example?
- Can you introduce me to the real user? Show me their environment? Have them show me what they do, now?
- Where does the user spend the most time?
- What is the most catastrophic failure that we need to plan for?
- What is the desired outcome (not implementation)?
- Given story cards...
- What are the risks associated with this card?
- How much money is it worth to design the system to deal with that risk?
- How bad are the consequences if the potential bad thing happens?
- How confident are you of the need for this card?
- Create CRC Cards with customers - this valuable technique facilitates communication and is a good venue for asking the right questions.
Now we switch focus to the "developers writing code" context, although some of these questions could also be used with the customer.
Does this code fulfill the purpose?
- Is this worth doing?
Ask these questions before writing tests/code.
- Which user story does this address?
- Which human(s) will care or even notice whether I do this or not (other than me)?
- Does it carry its weight?
Ask these questions when evaluating existing code.
- If I removed this, what tests would fail?
- Could I replace this with something simpler, without breaking any tests?
- Name two examples where this extensibility/configurability/flexibility will be used.
- Does it make a test pass?
- Which user story does this test support?
- Are you really gonna need it? Are you sure? Really? For what?
Does the code communicate its intent?
Principle: Look at everything from the "outsider's" perspective: from the caller's perspective, from the perspective of a colleague maintaining the code, or of a future you who has forgotten what you wrote 3 months ago.
- Names
- Does this method name express the desired outcome to the "outsider"?
- What does this name mean to an "outsider"?
- Ask a colleague "Hey, if you saw a class/method named X, what would you guess it would do?"
- Does this class's name explicitly reveal the classes's intended role in the system, to the "outsider"?
- Don't force the reader to infer what it might be used for. If the name is not enough, add a comment using it in a sentence that includes its primary collaborator(s).
- Does this name unnecessarily reveal anything about its implementation?
- Code
- Could my colleagues understand this code with no explanation? What would my colleague need to know to make sense of this?
- Am I making it quick/easy for me to write the code this once, at the expense of comprehensibility for many readers of the code, over time?
Code is "write once, read many"
- Is there a metaphor for this?
- Is it small enough to grasp? To see on a screen?
Controversially, some folks say to aim for 7 active lines per method: http://en.wikipedia.org/wiki/The_Magical_Number_Seven%2CPlus_or_Minus_Two
Does the code avoid waste?
- Am I duplicating anything?
DRY: Don't repeat yourself
- Has someone already done this?
In our code, on the web, in a third-party product or library?
- What is the simplest example of doing this sort of thing?
- What, here, is waste?
- Is this "smelly" code?
http://en.wikipedia.org/wiki/Code_smell
Does the code have the optimal number of "parts"?
- Is the code violating any of the well-established design principles?
- http://c2.com/cgi-bin/wiki?OoDesignPrinciples
- http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf
- Does this class or method have more than one reason that it is likely to change?
If it does, it is violating the single responsibility principle.
- What are the "difficult" or controversial (most likely to change) decisions you see in the design?
Isolate them, encapsulate them, create abstractions/interfaces for them.
"...it is almost always incorrect to begin the decomposition of a system into modules on the basis of a flowchart. We propose instead that one begins with a list of difficult design decisions or design decisions which are likely to change. Each module is then designed to hide such a decision from the others" http://en.wikipedia.org/wiki/David_Parnas
- What behavior, structure, and data in the system needs to vary, right now?
- Do the boundaries of my classes correspond to the "fault lines" for varying behaviors, data, and structures/relationships in the design?
- Have I isolated and encapsulated the main sources of change?
- What is most likely to vary, in the future?
- In the next iteration/sprint? next release? beyond? The further away, the less you should care.
Remember YAGNI: look for business reasons for why it probably won't change rather than dreaming of reasons why it might possibility change.
- What are my dependencies? Are they "good" dependencies that fulfill the purpose and deliver business value or "bad" dependencies on plumbing that add rigidity and viscosity?
Are we done, yet?
- Ask "owner", customer, or their representative "Is this good enough?"
- Does the code accomplish the essential intent of the story?
- Would further work be non-essential "icing on the cake" that is less important than the essentials of the next story?
- What are the acceptance criteria?
- Are the acceptance tests complete and passing?
- What is the smallest thing I could do to be "done" today?