Share E-Book
Scan to open this page

Scan with your phone to open this page

Author: Mauricio Aniche

Rating No ratings yet

This book is full of patterns and principles for reducing complexity, each one proven in author Mauricio Aniche’s 20-year career in software development. You’ll learn how to tackle code’s natural growth in complexity, and adopt a “good enough” approach that means it’s easy to refactor when requirements change. Written as a collection of practical techniques you can apply in any OO language, it offers tips for concise code, managing dependencies and modules, and designing flexible abstractions. Illuminating figures, real-world examples, and insightful exercises make each principle stick. Readers should be familiar with an object-oriented language like Java, C#, or Python.

AI Reading Assistant

Whole-book reading guide from stratified index samples; jump to passages in the text

AI guide
# Simple Object-Oriented Design: Create Clean, Maintainable Applications ## 【One-Line Pitch】 A practical, pattern-based guide to taming software complexity through "good-enough" object-oriented design, perfect for developers with OO experience who want to build systems that stay maintainable as they evolve. ## 【Book Arc】 - **Opening (~0%–10%)**: Establishes the core problem—software complexity naturally grows unless actively managed—and introduces the book's philosophy of "good-enough" designs over perfection, drawing on Lehman's laws of software evolution. - **Early (~10%–23%)**: Defines what makes a design simple and maintainable, introducing the PeopleGrow! training-management system as a running example and outlining key principles like encapsulation, modularization, and balancing simplicity against over-engineering. - **Early (~23%–32%)**: Dives into making code small and readable, covering techniques for breaking large methods into cohesive units, extracting independent logic, and the continuous search for better names. - **Middle (~32%–48%)**: Explores moving new complexity away from existing classes—giving complex business rules their own classes, breaking down large flows into steps, and keeping domain classes pure by avoiding unnecessary dependencies. - **Middle (~48%–60%)**: Focuses on keeping objects consistent through proper encapsulation, modeling aggregates to protect invariants, and providing only the getters/setters that truly matter. - **Late (~60%–100%)**: Covers managing dependencies—separating high-level from low-level code, avoiding coupling to details, breaking down over-dependent classes, and applying dependency injection (based on the table of contents and excerpt structure). ## 【Key Takeaways】 - **Complexity is the enemy of maintainability** (Early): Systems naturally decay without active effort; recognizing and addressing complexity signs early is cheaper than fixing them later. The goal isn't perfection but "good-enough" designs that are easy to understand and evolve. - **Small units of code are easier to maintain** (Early): Break large methods into smaller pieces, and use the "could this be static?" trick to identify independent logic worth extracting. Test private methods through their public callers, not in isolation. - **Naming is a continuous process, not a one-time event** (Early): Good names mirror business terminology and evolve as you understand the code better. Don't agonize over initial names—move forward and refactor names once the code's purpose becomes clearer. - **Give complex business rules their own class** (Middle): When a rule spans multiple classes or requires many dependencies, isolate it in a dedicated service class. This makes dependencies explicit, reduces cognitive load, simplifies testing, and improves reusability. - **Keep domain classes pure** (Middle): Domain objects should contain only data and methods that operate on that data, avoiding coupling to databases or external systems. Objects should handle all consistency checks they can without external dependencies. - **Encapsulation protects object consistency** (Middle): Objects must control their own state changes—like a Basket that validates additions/removals—to prevent invalid states. Unrestricted access leads to bugs and maintainability problems. - **Move new complexity away from existing classes** (Middle): When adding features, create new classes rather than bloating existing ones. This keeps existing tests stable and allows new features to be tested in isolation. - **Dependency management is design** (Late): Separate high-level from low-level code, avoid coupling to things you don't own, and inject dependencies rather than using static methods for state-changing operations. ## 【Reading Tips】 - **Skim the PeopleGrow! examples** (~10%–60%): The running training-management example appears throughout; skim these for concrete illustrations but focus on the principles they demonstrate. - **Deep-read Chapter 1** (~0%–23%): This foundation chapter defines the book's philosophy and key terms. Understanding "good-enough" design and complexity management here makes later chapters more meaningful. - **Pay attention to the "why" behind patterns** (throughout): Aniche explains not just what to do but why—like why isolating business rules helps testing and reuse. These rationales help you apply the patterns to your own contexts. - **Work through the exercises** (at chapter ends): The exercises are designed to make principles stick; even skimming them helps internalize the decision frameworks. - **Watch for trade-off discussions** (throughout): The book emphasizes balance—like when simple code with if statements beats convoluted interfaces, and when extensibility becomes over-engineering. ## 【Coverage Limits】 This guide covers the book's core philosophy and early-to-middle chapters on code size, naming, encapsulation, and dependency management. The later chapters on advanced dependency patterns and module design are summarized from the table of contents; excerpts do not cover the final chapters' detailed content. ##
Page 11
ce 83 4.4 Inject dependencies, aka dependency injection 86 Avoid static methods for operations that change the state 87 ■ Always inject collaborators: Everyt...
View in text
Excerpt 2
tency. The dome protects the basket. No dome. Anyone can do No one can access it directly! whatever they want, even if it breaks the rules of the basket. I a...
View in text
Excerpt 3
of code only delegate the real work to the CsvParserLibrary class, it’s a different responsibility and will look good in its own class. NOTE In future chapte...
View in text
Excerpt 4
e class, say, WaitingListNotifier. Move the complexity away from existing classes, as I said. That’s what we’ll do. UnenrollEmployeeFromOfferingService now d...
View in text
Excerpt 5
ires several other places to change. Figure 3.4 illustrates. You should avoid shotgun surgeries as much as possible. A breaking change in a class can affect...
View in text
Excerpt 6
. This means the service is coupled to these other classes. We’ve discussed the problems of large classes and the advan- tages of smaller classes. On the one...
View in text
Excerpt 7
g them to be injected. In the past, teams working on highly performant applications avoided dependency injection due to its computational costs. These concer...
View in text
Excerpt 8
c void give(Employee employee) { work with the new classes. new BadgesForTrainings().give(employee); new BadgesForQuantity().give(employee); } } The BadgesFo...
View in text
Tags
AI categories
ProgrammingCodeTechnology
Publish Year: 2024
Language: English
Pages: 191
File Format: PDF
File Size: 766.1 KB
Text Preview (First 20 pages)
Registered users can read the full content for free

Register as a Gaohf Library member to read the complete e-book online for free and enjoy a better reading experience.

Generating text preview…