General Design Advice and Code Smells - GitHub Pages · General Design Advice and Code Smells :...
Transcript of General Design Advice and Code Smells - GitHub Pages · General Design Advice and Code Smells :...
General Design Advice and Code Smells
Stephen P Levitt
School of Electrical and Information EngineeringUniversity of the Witwatersrand
2019
Outline
1 Class-Level AdviceStandalone ClassesBase ClassesInterfacesCode Smells (Indicators of Poor Design)
Monolithic ClassData Class
Abstractions at Different Levels
2 Architecture AdviceLayeringProtecting The Domain Layer
General Design Advice and Code Smells 1 / 18
Be Clear About What Kind of Class You Are Writing
The design rules for base classes and standalone classes are very different, and clientcode treats base classes very differently from standalone classes.
Decide what kind of class you need before you design it.
General Design Advice and Code Smells : Class-Level Advice 2 / 18
Standalone Classes
Standalone classes:have a public destructor, copy constructor and assignment operator with valuesemanticshave no virtual functionsare usually instantiated on the stack or as a directly held member of another class(direct composition)are not intended to be used as a base class
General Design Advice and Code Smells : Class-Level Advice : Standalone Classes 3 / 18
Base Classes
Base classes should:establish interfaces which are as simple as possible while still effectively modellinga role in the problem domainhave a destructor which is public and virtualshield code from knowing about the actual type(s) being operated on, by beingused as:
reference parameters of functionsthe type for instantiating smart pointers, or vectors of smart pointers
General Design Advice and Code Smells : Class-Level Advice : Base Classes 4 / 18
Pay Attention to Your Interfaces
“ The most important thing to get right is the interface. Everything elsecan be fixed later. Get the interface wrong and you may never be allowedto fix it.” — Sutter’s Law of Second Chances
“ Interfaces, like diamonds, are forever.”General Design Advice and Code Smells : Class-Level Advice : Interfaces 5 / 18
class Flight {public:Flight(Aircraft plane,Place orig, Place dest);unsigned int GetMaxSpeed() const;void ScheduleTakeOff(const Time& time);Time GetFlyingTime() const;void AdjustFlightPath(Paths other);
void AddPassenger(const Person& p);void RemovePassenger(const Person& p);vector<Person> GetPassengerList() const;Clearance SecurityCheckPassenger(const Person& p) const;
unsigned int EstimateNoInflightMeals() const;void SetMealTypeAndNumber(MealType meal, unsigned int num);Rands TotalMealCost() const;
};
General Design Advice and Code Smells : Class-Level Advice : Code Smells (Indicators of Poor Design) 6 / 18
Monolithic or Large Class
Catalog of Refactoring — Shvetshttps://refactoring.guru/smells/large-class
General Design Advice and Code Smells : Class-Level Advice : Code Smells (Indicators of Poor Design) 7 / 18
Avoid Monolithic Classes, Prefer Minimal Classes
A minimal class is easier to comprehend and more likely to be used and reused ina variety of situationsA minimal class embodies one concept at the right level of granularity. Amonolithic class is likely to embody several separate concepts and using oneimplies understanding all of the othersMonolithic classes dilute encapsulationMonolithic classes are harder to make correct and error-safe because they tacklemultiple responsibilities
Divide and conquer: small, focused classes are easier to write, get right, testand use.
General Design Advice and Code Smells : Class-Level Advice : Code Smells (Indicators of Poor Design) 8 / 18
Beware the Data Class
Catalog of Refactoring — Shvetshttps://refactoring.guru/smells/data-class
Lots of getter and setter methods but no real behaviour.Consequences:
Clients are forced to define the behaviour ⇒ duplicated codeLittle encapsulation ⇒ if the internal representation of the data class ischanged, clients will have to change
General Design Advice and Code Smells : Class-Level Advice : Code Smells (Indicators of Poor Design) 9 / 18
Abstractions at Different Levels
Classes and their objects are the building blocks of an applicationHigh-level abstractions build upon lower-level abstractions
General Design Advice and Code Smells : Class-Level Advice : Abstractions at Different Levels 10 / 18
Source: Object-Oriented Analysis and Design, 2nd ed., G. Booch, 1994
General Design Advice and Code Smells : Class-Level Advice : Abstractions at Different Levels 11 / 18
Application Layers
PresentationDomainDataLayering — Fowlerhttps://www.martinfowler.com/bliki/PresentationDomainDataLayering.html
General Design Advice and Code Smells : Architecture Advice : Layering 12 / 18
Layer Responsibilities
Presentation Display of information (e.g., in Windows or HTML, handling of userrequests (mouse clicks, keyboard hits), HTTP requests, command-lineinvocations, batch API)
Domain/Logic Logic unique to the systemData Access Communication with databases,other persistent data stores, messaging
systems, transaction managers
General Design Advice and Code Smells : Architecture Advice : Layering 13 / 18
Why Separate Layers?
Understandability, each layer has a coherent set of responsibilities, concerns areseparatedSubstitutability, e.g. easy to substitute different front ends or data storesTestabilitySupports parts of the system changing at different ratesTeam specialisation
General Design Advice and Code Smells : Architecture Advice : Layering 14 / 18
Why Separate Layers?
Understandability, each layer has a coherent set of responsibilities, concerns areseparatedSubstitutability, e.g. easy to substitute different front ends or data storesTestabilitySupports parts of the system changing at different ratesTeam specialisation
General Design Advice and Code Smells : Architecture Advice : Layering 14 / 18
Which Layer’s Code Is The Most Valuable?
The domain layer contains the business IPPresentation and data access layers are typically built from, and use, standardcomponents and frameworks
The domain layer is special ⇒ isolate and protect this layer
General Design Advice and Code Smells : Architecture Advice : Layering 15 / 18
Which Layer’s Code Is The Most Valuable?
The domain layer contains the business IPPresentation and data access layers are typically built from, and use, standardcomponents and frameworks
The domain layer is special ⇒ isolate and protect this layer
General Design Advice and Code Smells : Architecture Advice : Layering 15 / 18
Domain Layer Isolation and Protection
The domain layer shouldmake use of a ubiquitous language (this part of the system should reflect theproblem domain in a very literal way, so the mapping is obvious)contain a clean, expressive domain model unpolluted by infrastructure concernsbe free of (ignorant of)
code for drawing windows, buttons and widgetscode for accessing the database or file systemcode for sending messages (email/SMS)etc.
have limited exposure to external components beyond the team’s control — theserepresent risk if the components change (eg. Web API’s)
General Design Advice and Code Smells : Architecture Advice : Protecting The Domain Layer 16 / 18
Domain Layer Isolation in Practice
“ “You don’t want the domain model to depend on anything that talks toany kind of external system”” — Mathias Verraes
Isolation from the presentation layer happens by default if the dependencies arerightIsolation from the data access layer, and other services, requires you to write yourown classes or interfaces which shield your domain from these externalcomponents
General Design Advice and Code Smells : Architecture Advice : Protecting The Domain Layer 17 / 18
Using Third-Party Libraries Within The Domain Layer
Avoid re-inventing the wheelIt makes sense to use third-party libraries and classes which
are well-written, stable, tested and maintainedare potentially replaceable
Be wary of frameworks and libraries that force you to compromise your designUse library classes as is if they represent genuinely useful abstractions
boost::scoped_ptr was the forerunner of unique_ptrIf necessary, wrap library classes (using composition) to make them meaningful forthe domain, and to expose only the methods that the domain requires
In a “shipping and delivery” domain create a DeliveryDate class which internallyuses the boost date_time library in order to exclude delivery dates on weekends
General Design Advice and Code Smells : Architecture Advice : Protecting The Domain Layer 18 / 18