Table of Contents
- Topic 8: The Essence of Good Design
- Topic 9: DRY - The Evils of Duplication
- Topic 10: Orthogonality
- Topic 11: Reversibility
- Topic 12: Tracer Bullets
- Topic 13: Prototypes and Post-it Notes
- Topic 14: Domain Languages
- Topic 15: Estimating
Topic 8: The Essence of Good Design
Author's Suggestion
Something is well-designed if it adapts to the user. For code, this means that it's adaptable to change. This is where the ETC principle -- Easier To Change -- comes into play.
Every Design Principle can be seen as a specific application of the ETC Principle.
My Application
I aim to apply the ETC Principle whenever I write code, always making it adaptable to change.
ETC Is a Value, Not a Rule
Author's Suggestion
A value is something that helps you make decisions. When writing code, the ETC Principle serves as a guide, helping you choose between different paths. Like any other value, it should live in your subconscious -- but to get there, you may need some conscious reinforcement.
Take time to reflect on whether the changes you've made actually make the code easier to change -- even something as small as saving a file can be a good moment for that reflection.
ETC has an implicit premise: it assumes the person knows which path will allow smoother future changes. Common sense is often enough, but not always. When it isn't, consider these two approaches:
- Modify the code so it can be easily replaced in the future.
- Write down the situation -- the options for change you see, and your assumptions about how adaptable the code would be for each. Keep a reference in the source code so you can revisit and verify your reasoning later.
My Application
In my day-to-day work as a coder, I aim to always ask myself: Does this change make the code more adaptable to future changes?
I rely on common sense by default, and when the answer isn't clear, I either modify the code so it can be easily replaced or make my best guess, later tracking whether I was accurate.
Reflections
- Yes, Open for Extension, Closed for Modification Principle allows for easier changes because it enables adding new features without breaking existing code.
- Let's analyze how well the following paradigms work with ETC:
- OOP
- Positives for ETC: Encapsulation and polymorphism isolate changes.
- Negatives for ETC: Deep inheritance and over-abstraction create rigidity.
- Summary: Flexible if composition is favored over inheritance.
- Functional
- Positives for ETC: Pure, composable, immutable code is safe to refactor.
- Negatives for ETC: Harder to manage side effects and shared state.
- Summary: Excellent for logic; awkward for stateful systems.
- Event-Driven
- Positives for ETC: Decoupled via events; easy to add handlers.
- Negatives for ETC: Complex callback chains; hard to trace flows.
- Summary: Good for dynamic systems if structured.
- Reactive
- Positives for ETC: Data flows automatically propagate changes.
- Negatives for ETC: Debugging asynchronous data streams can be tricky.
- Summary: Excellent for live data and continuous updates.
- Procedural
- Positives for ETC: Simple and direct for small programs.
- Negatives for ETC: Global mutable state is fragile for large systems.
- Summary: Low ETC in large systems.
- Component/Modular
-
Positives for ETC: Clear boundaries enable replacement and reuse.
-
Negatives for ETC: Integration and versioning overhead.
-
Summary: High ETC if interfaces remain stable.
-
When coding, I can eliminate the negatives by avoiding actions that make code harder to change. To accentuate the positives, I aim for situations that support the ETC principle.
-
Remember: use your editor to provide reminders whenever you save your code to check if it remains easy to change.
Topic 9: DRY - The Evils of Duplication
DRY Is More Than Code
Author's Suggestion
Programmers work with knowledge through software development lifecycle (SDLC), and document it in specifications that come alive in code or during testing.
Maintenance is not a reaction to bugs; it is a routine part of the SDLC. When maintaining software, we often need to update the way knowledge is represented. This can easily introduce duplication in specifications, processes, or code, making maintenance more difficult -- even before the application is live.
The key to developing reliable software and making it easier to understand and maintain is the DRY principle. DRY is not just about avoiding repeated code; it is about avoiding repeated knowledge and intent. For example, if a single change requires modifying many parts of the code, that signals a DRY violation.
Every knowledge must be a single source of truth within a system.
My Application
I used to think DRY applied only to repeated code, but I now understand it also applies to repeated knowledge.
Duplication in Code
Author's suggestion
Whenever possible, identify actions repeated across your code that serve the same intention and consolidate them.
Not all Code Duplication Is Knowledge Duplication
The functions with identical code do not necessarily violate DRY if their intentions differ.
My Application
I used to create functions automatically when I saw duplicate code. Now, I first check whether the code truly duplicates knowledge or if it has a different purpose.
Duplication in Documentation
Author's suggestion
Let the code explain itself. Avoid overusing comments.
Dry Violations in Data
Identify if a field can be calculated from other fields. If so, make it a calculated field; storing it separately would violate DRY.
Sometimes, it is acceptable to violate DRY intentionally, such as when caching data for performance.
My Application
I strive to write self-explanatory code so that comments are minimal and meaningful.
Representation Duplication
Author's suggestion
Code often interacts with external systems, so some duplication is natural when working with APIs, external services, or external data sources.
Mitigation strategies:
-
Duplication Across Internal APIs: Use tools to define APIs in a neutral format.
-
Duplication Across External APIs: Import the API specification into your local tools (e.g., via OpenAPI) to integrate reliably with the service.
-
Duplication with Data Sources: Let persistence frameworks generate containers directly from the schema or use a dictionary-like structures with table-driven validation to ensure the data matches the required format leveraging your API documentation tool.
My Application
I embrace a single-source-of-truth mindset when working with interfaces, both internally and externally. For data sources, I avoid redundant DTOs and rely on dictionaries with table-driven validation, or schema-generated containers to stay DRY.
Interdeveloper Duplication
Author's suggestion
When multiple developers work on a project, duplication in the code base is almost guaranteed. One way to mitigate this is to designate a project librarian who:
- Manages common scripts in the source tree.
- Reviews documentation and source code for duplication.
- Supports other developers in following the same approach. The goal is to make reuse easy and avoid unnecessary duplication.
My Application
I proactively define common functionalities within the team and maintain documentation that is unique, clear, and easy to use.