General Design Advice and Code Smells - GitHub Pages · General Design Advice and Code Smells :...

Post on 17-Jun-2020

10 views 0 download

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