Showing posts with label Design Patterns. Show all posts
Showing posts with label Design Patterns. Show all posts

Wednesday, 26 June 2019

Software Design

This a collection of both online references and some my thoughts related to Software Design and Development in general.

Main Principles


Code should be correct, clear and efficient.
Prefer simple. Avoid clever.
(taken from https://yourbasic.org/)

Code exposed to be used by others should be written in such way that:
  • it is non-ambiguous so using it comes as intuitive
  • prevents errors when using it

Make MVP working (correctly) first. Release it and analyze feedback. Revenue, not the beauty of the code should drive development...but code should be well-designed if TDD is followed. Refactor evolutionary, not revolutionary.

Software design
SOLID Principles

12 Factor Applications 
Twelve-Factor Apps In node.js
Twelve-Factor App methodology

TDD - Test-Driven Development

I feel comfortable when replacing one implementation of the function with another only if that function is covered by unit tests.

POD - Performance-Oriented Development

Software Product Architecture


Plugins


Break up monolithic application into plugin-based one. Benefits:
  • update single plugin instead of entire application
  • bug in single plugin does not affect other plugins or entire application
  • some plugins can be free, some can be sold

Abstract 3rd Party Dependencies


If your application needs to use some 3rd party API or library, don't wire your code directly to it as it will then become dependent (hard-wired, tightly coupled) on the code you don't have control over. Create an abstraction of that 3rd party component, define an API that your code will call. This generic API is facade behind which you can always silently switch actual implementations in case you decide to use some other 3rd party library.


Metric for Good Source Code


  • how easy (or difficult) is to:
    • navigate the code
    • isolate the code
  • naming (of packages, namespaces, functions, classes, structs, variables etc...)
  • TBC...

Application Configuration (Settings)


Make application as configurable as possible. Application should read configuration from external source e.g. command line arguments, config file, environment variables, user input from stdin. If some settings are missing, application can use their failback values that are hardcoded. 

Example:

if 'SETTING_X' not in os.environ:
    os.environ["SETTING_X"] = "SettingX_default_value"

// use/read os.environ["SETTING_X"] value


When to use environment variables instead of CLI? 

Command-line Arguments



  • To indicate optional arguments, Square brackets are commonly used, and can also be used to group parameters that must be specified together.
  • To indicate required arguments, Angled brackets are commonly used, following the same grouping conventions as square brackets.
  • Exclusive parameters can be indicated by separating them with vertical bars within groups.

Argument passing strategy - environment variables vs. command line

Logical Expressions

Use Boolean Algebra laws to simplify complex conditions (logical expressions).

Global Variables

They should be avoided unless they are static/singletons that represent an object with cross-cutting concern functionality.

Global Variables Are Bad

Functions


Functions should be simple, short and follow SRP principle. E.g. if function has to create a file at some path, don't make it also creating that path (if path does not exist). Create another function which is responsible ONLY for creating paths instead.

If function has to perform a task depending on the value of its argument, move that argument check out of the function - function should do only that task, not to verify whether that task should be performed or not.

Example:

func processAttachment(attachment attachment, ...) error {
  if attachment.MimeType != "application/x-msdownload" {
return nil
}
    // do here something with attachment
}

should be:

if attachment.MimeType == "application/x-msdownload" {
  err := processAttachment(attachment)
}

This is more explicit and function is responsible for one thing only.

Don't make library/package functions asynchronous by default - allow users to choose how they want to consume them - synchronously or asynchronously. They can always create async wrapper around them.

The same stands for functions in Go. We could make them accept sync.WaitGroup argument so they can be awaited...but we should make function only do its main job as fiddling with wait group pollutes function's main functionality and thus break SRP.

func foo(arg1 T1, arg2 T2, ...wg *sync.WaitGroup) {
   wg.Add(1)
   ...
   defer wg.Done()
}

In the same way, don't add logging to library/package functions. Return errors/throw exceptions with error messages/codes instead. User of the library should decide what they want to see in the log output.

If function has multiple parameters and e.g. one parameter is used only in one part of the function, check if this part of the function is doing a task (or...has responsibility for one "thing") that could be extracted into a separate function.

Indentation & Single Point of Return


There are two schools here. The one which recommends that each function should have single point of return and one that allows multiple points of return.

Single point of return:
  • if function is long this increases chances of having multiple levels of nested conditions
  • returned value (error) is assigned at multiple places and at multiple levels
  • it's difficult to track positive execution path
Multiple points of return:
  • prevents deep levels of indentation (such functions usually have only two)
  • it is easy to track which expression would make function to return which error
  • we can use indentation here to visually create positive and error paths: positive path of execution are expressions in the 1st indentation level. Handling errors is in the 2nd (indented) level of indentation (see Code: Align the happy path to the left edge)
Here are some more Tips for a good line of sight from Mat Ryer:
  • Align the happy path to the left; you should quickly be able to scan down one column to see the expected execution flow
  • Don’t hide happy path logic inside a nest of indented braces
  • Exit early from your function
  • Avoid else returns; consider flipping the if statement
  • Put the happy return statement as the very last line
  • Extract functions and methods to keep bodies small and readable
  • If you need big indented bodies, consider giving them their own function

How small function should be?

How small should functions be?
Small Functions considered Harmful
What should be the maximum length of a function?
How can wrapping an expression as a function be Clean Code?

Terminology: Parameters VS Arguments

Parameter is the variable which is part of the method's signature (method declaration).
An argument is an expression used when calling the method.

From MSDN: "...the procedure defines a parameter, and the calling code passes an argument to that parameter. You can think of the parameter as a parking space and the argument as an automobile." 

“Parameter” vs “Argument”

Arguments Validation

Arguments should be validated if their values are coming from the wild outside world and this happens in the public API. Contract validation frameworks can be used.

In private/internal functions we can use assertions (in C++/C#) or no validation at all and allow application to crash.


Structs & Classes


Prefer composition over inheritance.

For data members use their natural types, which are best describing them, rather than types used in their presentation. E.g.

Use

type Directory struct {
   ...
   Created      time.Time
   LastModified time.Time
   ...
}

instead of

type Directory struct {
   ...
   Created      string
   LastModified string
   ...
}

It might be necessary at some point to perform some manipulation with these values e.g. comparisons, period calculations etc...for which an API is provided on Time type. Otherwise we'd first need to convert strings to Time, do manipulation and then convert result back to string.

Perform conversion to string at the point when time values have to be displayed in UI.

Interfaces


Fluent design of the API can make code human readable even more.


Invariants



Know your Invariants!


Logging

Don't use logging as a substitute for proper debugging. Logging is poor man's debugging. Learn how to use debugging and profiling tools relevant for your development stack and IDE.

Think carefully what will go into log. If there is no error, don't make log message like this:

Created symlink ./.../myapp--setup.exe --> myapp-setup.exe. Error: <nil>

When you later analyze log file and look for word "error", you'll get tons of false positives.


Working with Data


Data Access Object (DAO)

Documentation

The older I am the less I like having documentation about the software I write anywhere else but in the source code itself. This reduces information redundancy, duplication and situations when documentation is not in sync with the implementation. Having brief but comprehensive comments and tools (example1) which can extract desired information from them should do the job. Having high unit test coverage (and BDD-style tests if you are kind to non-tech members of the team) should also help as reading test names should be as informative and as easy as reading a requirement specification.


Some Common Patterns and Anti-Patterns



MVC (Model - View - Conroller)



  • Model
    • processes data
  • View
    • shows the results
    • many dynamic languages generate data for views by writing code in static HTML files
  • Controller
    • handles user requests


Producer - Consumer


What is the benefit of writing to a temp location, And then copying it to the intended destination?

TBD...


Resource Management


Resources (data, files, directories, handles etc...) should be managed in a secure manner. Security is based on three (CIA) principles:

confidentiality
  • set of rules that limits access to information

integrity
  • the assurance that the information is trustworthy and accurate
  • involves maintaining the consistency, accuracy, and trustworthiness

availability
  • guarantee of reliable access to the information by authorized people

Unit Testing



Be explicit when using data structures for representing data


Array members should mean the same thing. If an element has a special meaning, move it our from array and make it a member field of some other data structure. Example:


const (
copyFuncName string = "copy"
)

// Function parses CLI arguments and returns a string slice:
//    first element = function name
//    subsequent elements = function arguments
func parseArgs() ([]string, error) {
   ...
}

...and later we have:

switch funcDetails[0] {
case copyFuncName:
err = copy(funcDetails[1], funcDetails[2])
break
...
}


The red flag here was:

switch funcDetails[0]

and

copy(funcDetails[1], funcDetails[2])

When you read it, you are wondering "What is the meaning of that funcDetails[i], what value does it contain?". This should be explicit, something like:

switch funcDetails.Name:

So, we can transform the array into a struct with two fields: Name (string) and Args (array).

type funcInfo struct {
name string
args []string
}

Our switch statement now requires less mental effort to read and understand:

switch funcInfo.name {
case copyFuncName:
err = copy(funcInfo.args[0], funcInfo.args[1])
break
...
}


Meta-Data


It is often useful to add some meta-data to data or services which are consumed by external clients. They help client management. 

Version


If is easier to manage clients if data format or services (e.g. public API) they are consuming are versioned. If we bump version, clients can detect that and request new data or client software update.


Comments






Sunday, 23 April 2017

Strategy Pattern

Problem:

Context has to be able to apply different Algorithms (strategies, actions, behaviours) in the runtime but is coupled with their implementations. It contains all possible concrete implementations of an Algorithm family and has to change if:
  • implementation of some Algorithm has to change
  • a new Algorithm has to be added or some existing has to be removed
This breaks Single Responsibility Principle (Context has to change for more than one reason) and Open-Closed Principle (Context has to be modified if list of Algorithms gets extended).

Solution:

Remove Algorithm implementations out of the Context and separate them in their own classes which implement new interface IStrategy with method DoAlgorithm(). Introduce lookup table (Dictionary) which keeps all IStrategy implementations. When Context receives key from the input, it looks up the Dictionary and calls IStrategy implementation which matches the given key.

References:

Strategy pattern
Applying Strategy Pattern Instead of Using Switch Statements
Strategy

Thursday, 3 May 2012

Observer pattern: from GoF implementation to events and delegates


Let us assume we have some class (Subject) with properties that can be changed. A set of current values of all properties defines Subject's state. Another class (Observer) must be notified each time Subject's state changes (each time some property changes). Observer pattern decouples direct dependencies between (concrete) subject and (concrete) observer by using interfaces.

The following code shows classic (Gang of Four) implementation of the Observer pattern applied to two subjects (PropertyOwner1 and PropertyOwner2) and their observers (PropertyObserver1 and PropertyObserver2):

main.cpp:


Output:


PropertyOwner1: property1's new value is: 1
PropertyObserver1: PropertyOwner1 property1's value is: 1
PropertyObserver2: PropertyOwner1 property2's value is: 0

PropertyOwner1: property2's new value is: 1.2
PropertyObserver1: PropertyOwner1 property1's value is: 1
PropertyObserver2: PropertyOwner1 property2's value is: 1.2

PropertyOwner2: property1's new value is: 1
PropertyObserver1: PropertyOwner2 property2's value is: 0
PropertyObserver2: PropertyOwner2 property1's value is: 1

PropertyOwner2: property2's new value is: 3.4
PropertyObserver1: PropertyOwner2 property2's value is: 3.4
PropertyObserver2: PropertyOwner2 property1's value is: 1

PropertyOwner1: property1's new value is: 2
PropertyObserver2: PropertyOwner1 property2's value is: 1.2

PropertyOwner1: property2's new value is: 4.5
PropertyObserver2: PropertyOwner1 property2's value is: 4.5

As we can see, observer is notified each time any property of the subject changes. E.g. if we look the test where PropertyOwner1's property1 changes to 2 but PropertyObserver2 is notified regardless the fact that it is interested only in PropertyOwner1's property2.

In this model client gets information that the subject's state (some property) has been changed but it does not know exactly which property has been changed. Of course, observer could maintain the history of obtained values for each property and compare new values with the previous ones and thus detect for which property the value has changed but this increases complexity of the observer.

Somehow we need to pass to the observer information about which property has changed. If we assign each property in a system a unique ID we could pass it to the observer as an additional parameter of the Subject::update() method:

main.cpp:

#include
#include
#include

class Subject;

enum PropertyID
{
Property1,
Property2
};

class Observer
{
public:
virtual ~Observer(){}
// pointer to Subject is passed so ConcreteObserver can distinct ConcreteSubjects
virtual void update(Subject*, PropertyID) = 0;
};

class Subject
{
public:
virtual ~Subject(){}

void registerObserver(Observer* const o)
{
std::list::const_iterator it = std::find(observers_.begin(), observers_.end(), o);
if(it != observers_.end())
throw std::runtime_error("Observer already registered");

observers_.push_back(o);
}

void unregisterObserver(Observer* const o)
{
std::list::const_iterator it = std::find(observers_.begin(), observers_.end(), o);
if(it != observers_.end())
observers_.remove(o);
}

void notify(PropertyID propertyID)
{
std::list::const_iterator it = observers_.begin();
for(; it != observers_.end(); ++it)
(*it)->update(this, propertyID);
}

protected:
std::list observers_;
};


// Concrete Subject
class PropertyOwner1 : public Subject
{
int property1_;
float property2_;

public:

PropertyOwner1() : property1_(0), property2_(0.0f){}

void property1(int n)
{
if(n != property1_)
{
property1_ = n;
std::cout << "\nPropertyOwner1: property1's new value is: " << property1_ << std::endl; notify(Property1); } } int property1() const { return property1_;} void property2(float n) { if(n != property2_) { property2_ = n; std::cout << "\nPropertyOwner1: property2's new value is: " << property2_ << std::endl; notify(Property2); } } float property2() const { return property2_;} }; class PropertyOwner2 : public Subject { bool property1_; double property2_; public: PropertyOwner2() : property1_(false), property2_(0.0){} void property1(bool n) { if(n != property1_) { property1_ = n; std::cout << "\nPropertyOwner2: property1's new value is: " << property1_ << std::endl; notify(Property1); } } bool property1() const { return property1_;} void property2(double n) { if(n != property2_) { property2_ = n; std::cout << "\nPropertyOwner2: property2's new value is: " << property2_ << std::endl; notify(Property2); } } double property2() const { return property2_;} }; // Concrete Observer // observes changes in property1 of ConcreteSubject1 and // property2 of ConcreteSubject2 class PropertyObserver1 : public Observer { // ConcreteObserver knows about ConcreteSubjects PropertyOwner1* pPropertyOwner1_; PropertyOwner2* pPropertyOwner2_; public: PropertyObserver1(PropertyOwner1* pConcreteSubject1, PropertyOwner2* pPropertyOwner2) : pPropertyOwner1_(pConcreteSubject1), pPropertyOwner2_(pPropertyOwner2){} void update(Subject* pSubject, PropertyID propertyID) { if(pSubject == pPropertyOwner1_) { if(propertyID == Property1) { int property1 = pPropertyOwner1_->property1();
std::cout << "\tPropertyObserver1: PropertyOwner1 property1's value is: " << property1 << std::endl; } } else if(pSubject == pPropertyOwner2_) { if(propertyID == Property2) { double property2 = pPropertyOwner2_->property2();
std::cout << "\tPropertyObserver1: PropertyOwner2 property2's value is: " << property2 << std::endl; } } } }; // Concrete Observer // observes changes in property2 of ConcreteSubject1 and // property1 of ConcreteSubject2 class PropertyObserver2 : public Observer { PropertyOwner1* pPropertyOwner1_; PropertyOwner2* pPropertyOwner2_; public: PropertyObserver2(PropertyOwner1* pPropertyOwner1, PropertyOwner2* pPropertyOwner2) : pPropertyOwner1_(pPropertyOwner1), pPropertyOwner2_(pPropertyOwner2){} void update(Subject* pSubject, PropertyID propertyID) { if(pSubject == pPropertyOwner1_) { if(propertyID == Property2) { float property2 = pPropertyOwner1_->property2();
std::cout << "\tPropertyObserver2: PropertyOwner1 property2's value is: " << property2 << std::endl; } } else if(pSubject == pPropertyOwner2_) { if(propertyID == Property1) { bool property1 = pPropertyOwner2_->property1();
std::cout << "\tPropertyObserver2: PropertyOwner2 property1's value is: " << property1 << std::endl; } } } };






Output shows that this time each observer knew exactly which property of which subject has been changed:


PropertyOwner1: property1's new value is: 1
PropertyObserver1: PropertyOwner1 property1's value is: 1

PropertyOwner1: property2's new value is: 1.2
PropertyObserver2: PropertyOwner1 property2's value is: 1.2

PropertyOwner2: property1's new value is: 1
PropertyObserver2: PropertyOwner2 property1's value is: 1

PropertyOwner2: property2's new value is: 3.4
PropertyObserver1: PropertyOwner2 property2's value is: 3.4

PropertyOwner1: property1's new value is: 2

PropertyOwner1: property2's new value is: 4.5
PropertyObserver2: PropertyOwner1 property2's value is: 4.5

There is a room for further improvements: notify() (and so observer's update()) function is called each time any property of the subject is changed. Yes, Property ID is passed so observer knows which property has been modified but still - can we avoid calling update() of the observer that is not interested in that particular property?

The solution is to granulate Observer pattern: instead of taking PropertyOwners as concrete subjects, let us move Observer pattern one level down and take PropertyOwners' properties as explicit concrete subjects. This implies that observers will need to register with properties, not with their owning classes - PropertyOwners. Each property will implement Subject interface and maintain its list of observers. When calling notify()/update() it needs to pass information on the type of its owner (PropertyOwner - "implicit concrete subject") so the observer knows which PropertyOwner has changed. On the observer's side we can do the same, granulate the pattern to smaller units which belong to particular class (PropertyObserverOwner - "implicit concrete observer") and which observe particular
property of the particular class. Templates come handy for this implementation:


main.cpp:

#include
#include
#include

// Abstract Observer
template
class PropertyObserver
{
public:
virtual void update(const TPropertyType& newValue) = 0;
};

// Concrete Observer (member of the class that observes a set of properties through a set of
// property concrete observers)
template
class PropertyObserverMember : public PropertyObserver
{
TPropertyObserverOwner* pPropertyObserverOwner_;

typedef void (TPropertyObserverOwner::*TPropertyChangeHandler)(const TPropertyType&);
TPropertyChangeHandler handler_;

public:
PropertyObserverMember(TPropertyObserverOwner* pPropertyObserverOwner, TPropertyChangeHandler handler) :
pPropertyObserverOwner_(pPropertyObserverOwner), handler_(handler){}

void update(const TPropertyType& newValue)
{
(pPropertyObserverOwner_->*handler_)(newValue);
}
};

// Subject
template
class ObservableProperty
{
public:
virtual ~ObservableProperty(){};
void registerObserver(PropertyObserver* const o)
{
std::list* const>::const_iterator it = std::find(observers_.begin(), observers_.end(), o);
if(it != observers_.end())
throw std::runtime_error("Observer already registered");
observers_.push_back(o);
}

void unregisterObserver(PropertyObserver* const o)
{
std::list* const>::const_iterator it = std::find(observers_.begin(), observers_.end(), o);
if(it != observers_.end())
observers_.remove(o);
}

void notify(const TPropertyType& newValue)
{
std::list* const>::const_iterator it = observers_.begin();
for(; it != observers_.end(); ++it)
(*it)->update(newValue);
}

protected:
std::list* const> observers_;
};

// Concrete Subject
template
class Property : public ObservableProperty
{
TPropertyType t_;
TPropertyOwner* owner_;
public:
Property(const TPropertyType& t, TPropertyOwner* owner) : t_(t), owner_(owner){}

void set(const TPropertyType& t)
{
if(t_ != t)
{
t_ = t;

std::cout << typeid(TPropertyOwner).name() << "'s property of type " << typeid(TPropertyType).name() << " has been set to " << t << std::endl; notify(t); } } TPropertyType get() const { return t_; } }; // class that owns concrete subjects struct PropertyOwner1 { Property property1;
Property property2;
//Property property3;

PropertyOwner1() :
property1(0, this),
property2(0.0f, this)/*,
property3("", this)*/
{}
};

// class that owns concrete subjects
struct PropertyOwner2
{
Property property1;
Property property2;

PropertyOwner2() :
property1(false, this),
property2(0.0, this)
{}
};

// class that owns concrete observers and through them
// observes changes in property1 of PropertyOwner1 and property2 of PropertyOwner2
struct PropertyObserverOwner1
{
PropertyObserverMember propertyOwner1_property1_Observer_;
PropertyObserverMember propertyOwner2_property2_Observer_;
//PropertyObserverMember propertyOwner1_property3_Observer_;

PropertyObserverOwner1() :
propertyOwner1_property1_Observer_(this, &PropertyObserverOwner1::OnPropertyOwner1Property1Changed),
propertyOwner2_property2_Observer_(this, &PropertyObserverOwner1::OnPropertyOwner2Property2Changed)/*,
propertyOwner1_property3_Observer_(this, &PropertyObserverOwner1::OnPropertyOwner1Property3Changed)*/
{}

void OnPropertyOwner1Property1Changed(const int& newValue)
{
std::cout << "\tPropertyObserverOwner1::OnPropertyOwner1Property1Changed(): \n\tnew value is: " << newValue << std::endl; } void OnPropertyOwner2Property2Changed(const double& newValue) { std::cout << "\tPropertyObserverOwner1::OnPropertyOwner2Property2Changed(): \n\tnew value is: " << newValue << std::endl; } /* void OnPropertyOwner1Property3Changed(const std::string& newValue) { std::cout << "\tPropertyObserverOwner1::OnPropertyOwner1Property3Changed(): \n\tnew value is: " << newValue << std::endl; } */ }; // class that owns concrete observers and through them // observes changes in property2 of PropertyOwner1 and property1 of PropertyOwner2 struct PropertyObserverOwner2 { PropertyObserverMember propertyOwner1_property2_Observer_;
PropertyObserverMember propertyOwner2_property1_Observer_;

PropertyObserverOwner2() :
propertyOwner1_property2_Observer_(this, &PropertyObserverOwner2::OnPropertyOwner1Property2Changed),
propertyOwner2_property1_Observer_(this, &PropertyObserverOwner2::OnPropertyOwner2Property1Changed){}

void OnPropertyOwner1Property2Changed(const float& newValue)
{
std::cout << "\tPropertyObserverOwner2::OnPropertyOwner1Property2Changed(): \n\tnew value is: " << newValue << std::endl; } void OnPropertyOwner2Property1Changed(const bool& newValue) { std::cout << "\tPropertyObserverOwner2::OnPropertyOwner2Property1Changed() \n\tnew value is: " << newValue << std::endl; } }; int main(int argc, char** argv) { PropertyOwner1 propertyOwner1; PropertyOwner2 propertyOwner2; PropertyObserverOwner1 propertyObserverOwner1; PropertyObserverOwner2 propertyObserverOwner2; // register propertyObserverOwner1's observers propertyOwner1.property1.registerObserver(&propertyObserverOwner1.propertyOwner1_property1_Observer_); propertyOwner2.property2.registerObserver(&propertyObserverOwner1.propertyOwner2_property2_Observer_); // register propertyObserverOwner2's observers propertyOwner1.property2.registerObserver(&propertyObserverOwner2.propertyOwner1_property2_Observer_); propertyOwner2.property1.registerObserver(&propertyObserverOwner2.propertyOwner2_property1_Observer_); propertyOwner1.property1.set(1); propertyOwner1.property2.set(1.2f); propertyOwner2.property1.set(true); propertyOwner2.property2.set(3.4); // unregister propertyObserverOwner1's observers propertyOwner1.property1.unregisterObserver(&propertyObserverOwner1.propertyOwner1_property1_Observer_); propertyOwner2.property2.unregisterObserver(&propertyObserverOwner1.propertyOwner2_property2_Observer_); propertyOwner1.property1.set(2); propertyOwner1.property2.set(4.5f); }






Output shows that this time a single update() call is made for a single property change:

struct PropertyOwner1's property of type int has been set to 1
   PropertyObserverOwner1::OnPropertyOwner1Property1Changed():
   new value is: 1
struct PropertyOwner1's property of type float has been set to 1.2
   PropertyObserverOwner2::OnPropertyOwner1Property2Changed():
   new value is: 1.2
struct PropertyOwner2's property of type bool has been set to 1
   PropertyObserverOwner2::OnPropertyOwner2Property1Changed()
   new value is: 1
struct PropertyOwner2's property of type double has been set to 3.4
   PropertyObserverOwner1::OnPropertyOwner2Property2Changed():
   new value is: 3.4
struct PropertyOwner1's property of type int has been set to 2
struct PropertyOwner1's property of type float has been set to 4.5
   PropertyObserverOwner2::OnPropertyOwner1Property2Changed():
   new value is: 4.5

I don't like the previous implementation. It is too complex and its scalability is questionable.

I was always a big fan of C# events and delegates. It is so easy to bind some event with its handler. I tried to implement something similar in C++ and here is the result:

main.cpp:

#include
#include
#include

// use base class to resolve the problem of how to put into collection objects of different types
template
struct PropertyChangedDelegateBase
{
virtual ~PropertyChangedDelegateBase(){};
virtual void operator()(const TPropertyType& t) = 0;
};

template
struct PropertyChangedDelegate : public PropertyChangedDelegateBase
{
THandlerOwner* pHandlerOwner_;

typedef void (THandlerOwner::*TPropertyChangeHandler)(const TPropertyType&);
TPropertyChangeHandler handler_;

public:
PropertyChangedDelegate(THandlerOwner* pHandlerOwner, TPropertyChangeHandler handler) :
pHandlerOwner_(pHandlerOwner), handler_(handler){}

void operator()(const TPropertyType& t)
{
(pHandlerOwner_->*handler_)(t);
}
};

template
class PropertyChangedEvent
{
public:
virtual ~PropertyChangedEvent(){};

void add(PropertyChangedDelegateBase* const d)
{
std::list* const>::const_iterator it = std::find(observers_.begin(), observers_.end(), d);
if(it != observers_.end())
throw std::runtime_error("Observer already registered");

observers_.push_back(d);
}


void remove(PropertyChangedDelegateBase* const d)
{
std::list* const>::const_iterator it = std::find(observers_.begin(), observers_.end(), d);
if(it != observers_.end())
observers_.remove(d);
}

// notify
void operator()(const TPropertyType& newValue)
{
std::list* const>::const_iterator it = observers_.begin();
for(; it != observers_.end(); ++it)
{
(*it)->operator()(newValue);
}
}

protected:
std::list* const> observers_;
};

// class that owns concrete subjects
class PropertyOwner1
{
int property1_;
float property2_;
public:
PropertyChangedEvent property1ChangedEvent;
PropertyChangedEvent property2ChangedEvent;

PropertyOwner1() :
property1_(0),
property2_(0.0f)
{}

int property1() const {return property1_;}
void property1(int n)
{
if(property1_ != n)
{
property1_ = n;
std::cout << "PropertyOwner1::property1(): property1_ set to " << property1_ << std::endl; property1ChangedEvent(property1_); } } float property2() const {return property2_;} void property2(float n) { if(property2_ != n) { property2_ = n; std::cout << "PropertyOwner1::property2(): property2_ set to " << property2_ << std::endl; property2ChangedEvent(property2_); } } }; // class that owns concrete subjects class PropertyOwner2 { bool property1_; double property2_; public: PropertyChangedEvent property1ChangedEvent;
PropertyChangedEvent property2ChangedEvent;

PropertyOwner2() :
property1_(false),
property2_(0.0)
{}

bool property1() const {return property1_;}
void property1(bool n)
{
if(property1_ != n)
{
property1_ = n;
std::cout << "PropertyOwner2::property1(): property1_ set to " << property1_ << std::endl; property1ChangedEvent(property1_); } } double property2() const {return property2_;} void property2(double n) { if(property2_ != n) { property2_ = n; std::cout << "PropertyOwner2::property2(): property2_ set to " << property2_ << std::endl; property2ChangedEvent(property2_); } } }; // class that observes changes in property1 of PropertyOwner1 and property1 of PropertyOwner2 struct PropertyObserver1 { void OnPropertyOwner1Property1Changed(const int& newValue) { std::cout << "\tPropertyObserver1::OnPropertyOwner1Property1Changed(): \n\tnew value is: " << newValue << std::endl; } void OnPropertyOwner2Property1Changed(const bool& newValue) { std::cout << "\tPropertyObserver1::OnPropertyOwner2Property1Changed(): \n\tnew value is: " << newValue << std::endl; } }; // class that observes changes in property2 of PropertyOwner1 and property2 of PropertyOwner2 struct PropertyObserver2 { void OnPropertyOwner1Property2Changed(const float& newValue) { std::cout << "\tPropertyObserver2::OnPropertyOwner1Property2Changed(): \n\tnew value is: " << newValue << std::endl; } void OnPropertyOwner2Property2Changed(const double& newValue) { std::cout << "\tPropertyObserver2::OnPropertyOwner2Property2Changed(): \n\tnew value is: " << newValue << std::endl; } }; int main(int argc, char** argv) { PropertyOwner1 propertyOwner1; PropertyOwner2 propertyOwner2; PropertyObserver1 propertyObserver1; PropertyObserver2 propertyObserver2; // register observers PropertyChangedDelegate delegate1(&propertyObserver1, &PropertyObserver1::OnPropertyOwner1Property1Changed);
propertyOwner1.property1ChangedEvent.add(&delegate1);

PropertyChangedDelegate delegate2(&propertyObserver2, &PropertyObserver2::OnPropertyOwner1Property2Changed);
propertyOwner1.property2ChangedEvent.add(&delegate2);

PropertyChangedDelegate delegate3(&propertyObserver1, &PropertyObserver1::OnPropertyOwner2Property1Changed);
propertyOwner2.property1ChangedEvent.add(&delegate3);

PropertyChangedDelegate delegate4(&propertyObserver2, &PropertyObserver2::OnPropertyOwner2Property2Changed);
propertyOwner2.property2ChangedEvent.add(&delegate4);

propertyOwner1.property1(1);
propertyOwner1.property2(1.2f);

propertyOwner2.property1(true);
propertyOwner2.property2(3.4);

// unregister PropertyObserver1
propertyOwner1.property1ChangedEvent.remove(&delegate1);
propertyOwner2.property1ChangedEvent.remove(&delegate3);

propertyOwner1.property1(2);
propertyOwner1.property2(4.5f);
}

Output:
PropertyOwner1::property1(): property1_ set to 1
   PropertyObserver1::OnPropertyOwner1Property1Changed():
   new value is: 1
PropertyOwner1::property2(): property2_ set to 1.2
   PropertyObserver2::OnPropertyOwner1Property2Changed():
   new value is: 1.2
PropertyOwner2::property1(): property1_ set to 1
   PropertyObserver1::OnPropertyOwner2Property1Changed():
   new value is: 1
PropertyOwner2::property2(): property2_ set to 3.4
   PropertyObserver2::OnPropertyOwner2Property2Changed():
   new value is: 3.4
PropertyOwner1::property1(): property1_ set to 2
PropertyOwner1::property2(): property2_ set to 4.5
   PropertyObserver2::OnPropertyOwner1Property2Changed():
   new value is: 4.5

This is exactly what I wanted: observer registered with particular property (event), notified when property's changed and with a knowledge of property's owner and a new value.

Thursday, 5 April 2012

Singleton pattern

This pattern:

  • disables creation of more than one instance of a class
  • provides global access to the class

A long time ago I used to be a big fan of singletons. I would have four, five, six...CThisManager and CThatManager "manager" classes that would be used from everywhere throughout the code without any control. But then I run into some funny problems during their construction and destruction if they would use each other and, design-wise, I realized that singletons were nothing more than just fancy global objects. Why would I allow some class to be accessed from everywhere? Why would I allow so many hidden dependencies? Difficult to follow, difficult to test.

Today, I am using only one class implemented as a singleton: a logger. Logger does not depend on any other class and all other classes (or most of them) are using it. Regarding other "manager" classes: I create a single instance and pass it down to its clients through dependency injection. Dependency is visible and under control. Just like objects' lifetimes.

Anyway, just to make this article complete, I am providing typical singleton implementations. There are many debates on their lifetime, thread- and exception-safety but the general conclusion is that they should be used wise, depending on the context.

Non thread-safe implementation:

Output:

main()
Singleton::getInstance()
Singleton::Singleton()
val_ = 0
Singleton::getInstance()
Singleton::getInstance()
val_ = 3

In order to make this class thread-safe, we need to put its construction inside the critical section:

Thread-safe implementation of Singleton class:


Obviously, critical section member must be defined in the source file (e.g. main.cpp):




Links and References:
Singleton Pattern (Wiki)
Dependency Injection (Wiki)
C++ and the Perils of Double-Checked Locking (Scott Meyers, Andrei Alexandrescu)
Is Meyers implementation of Singleton pattern thread safe? (SO)
C++ Singleton design pattern (SO)
Finding C++ static initialization order problems (SO)
Singleton instance declared as static variable of GetInstance method (SO)
Singletons Are Evil
Singleton: How should it be used (SO)
SINGLETON PATTERN - 1. THREAD SAFETY


Friday, 16 December 2011

Finite State Machine in C++

In my article "Finite State Machine in C" I gave a short introduction to Finite State Machines (FSM) and demonstrated two possible implementations of the Car state machine model.

In this article I will show C++ implementation of the same model, by using State Pattern. All state classes are derived from an abstract base class CState and each of them implements public method HandleEvent(EVENT evt). CSMManager class is a State Machine Manager and represents the core of our State Machine: it receives events and dispatches them to the current state for handling. Its private member m_pCurrState is a pointer to the CState base class but it always points to actual state objects. State transition is implemented as its reassignment to a different state object (object's address). This happens when some event occurs. Behaviour of this model is event-driven and, in contrast to C implementations, state transition control is not centralized here - it is not the State Manager who takes care of which state is going to be the next one. Current state decides on that itself, depending on its current conditions and events it receives.

Events.h:



States.h:



State.h:



StateTurnedOff.h:



StateTurnedOff.cpp:



StateIdle.h:



StateIdle.cpp:



StateMoving.h:



StateMoving.cpp:



StateInvalid.h:



StateInvalid.cpp:



SMManager.h:



SMManager.cpp:



main.cpp:



Output:


CStateTurnedOff::OnEntry()
Event received: EVENT_IGNITE
   Whoooa! I'm turned on!
CStateTurnedOff::OnExit()

CStateIdle::OnEntry()
Event received: EVENT_ACCELERATE
   Yipee! I'm accelerating!
CStateIdle::OnExit()

CStateMoving::OnEntry()
Event received: EVENT_BRAKE
   Whoops! Was I too fast?
CStateMoving::OnExit()

CStateIdle::OnEntry()
Event received: EVENT_TURN_OFF
   That was probably enough...
CStateIdle::OnExit()

CStateTurnedOff::OnEntry()
CStateTurnedOff::OnExit()


Note that State Manager's member which refers to the current state (m_pCurrState) is not of reference type (CState&) but a pointer (CState*). This is one of the cases where we MUST use pointer instead of reference because we want to have a variable which reffers to different objects throughout the execution and as re-seating the reference is not allowed, the only option is using a pointer. Please refer Parashift's FAQ on References and this SO question.

The reason for introducing m_prevStateID is that sometimes state machine (or some of its states) needs to know what was its previous state. Variable which keeps track of the previous state should not be of type reference (m_prevState : CState&) or pointer (m_pPrevState : CState*) as current state should not be able to access (members) of other states. It is therefore enough if it holds only the ID of the previous state.

Note that base abstract class CState declares OnEntry() and OnExit() methods - those which are executed when entering and leaving state. Current state executes HandleEvent(EVENT evt) each time it receives some event.

Tuesday, 25 October 2011

Finite State Machine in C

Finite State Machine is a way of modelling behaviour of some entity that can have a (finite) set of states. Depending on the received event, entity performs some action and changes its state (or remains in the current one).

Let's say we want to model a behaviour of some simple car. I call it "simple" as it has only ignition switch, accelerator and brake. Driver can turn it on, then accelerate, brake and, at the end of the journey, turn it off. If not careful, driver can break the car - if tries to turn it on (again) while driving. Driver's actions are events - inputs of our model. Car can be turned off, idling, moving or broken - and this is a set of our car's states. So, car is in some state, it reacts on driver's command (event), performs some action and goes into the next state.

We have a finite set of states and events and can draw a diagram which precisely define state transitions (state transition diagram):


FSM_CarExample_1

Now, how to implement this model and show how this state machine changes states after receiving events?

Each state can be represented as unique number - its code, or ID. The similar thing is with events. As we have finite number of both states and events, we can use enum type to represent them: one variable will be of enum STATE type and contain the ID of the current state and another variable will be of type enum EVENT and will contain the most recent event this system received. Initially, our car is turned off so the state variable will be set to STATE_TURNED_OFF. After this simple initialization we just need to wait for events and handle them in accordance to the given transition diagram. Events can be obtained from a keyboard or some other source and they are usually kept in a queue as sometimes a new event can be received before processing of the previous one is finished. In this example, in order to keep things simple, I'm gonna assume that processing is fast enough and will just create a predefined set of events and put them in an array.

As we have repetitive action - receiving and handling events - we'll put it in a loop. If our events source is keyboard and we don't know how many events will user issue, we can use while-loop and CTRL-C as a loop termination command. In this example, we have an array of events which is of predefined (known in advance) size so we can use for-loop. Inside this loop, we need to place event processing code for each event, received in each state. This means we will have switch-statement inside another switch-statement. So, here's the code:

main.c:



Output:

Whoooa! I'm turned on!
Yipee! I'm accelerating!
Whoops! Was I too fast?
That was probably enough...

Having a switch inside a switch looks a bit complex and difficult to maintain. If we add a new state, we need to add a new case-branch for each event. In the code above it would mean we need to make changes at 4 different places in the code! Not good!

A solution for this is a state transition table. It is basically a table in which each state has its column and each event has its row. Table elements are pairs action/next-state - let's put them in some structure called TRANSITION. If transition table is called trans_tbl its element, trans_tbl[evt][state] is of type TRANSITION and action is a function called during transition and next-state is the state our model goes into for the current event. Code tells this better:

main.c:


Output is the same:

Whoooa! I'm turned on!
Yipee! I'm accelerating!
Whoops! Was I too fast?
That was probably enough...

The code has shrunk and become easier to understand and maintain: if we want to add a new event or a state, we just need to change transition table (trans_tbl) - we don't need to touch the code in a loop!

My article "Finite State Machine in C++" shows how to use OOP and State design pattern in order to implement FSM described here.

Links and references:
Finite-state machine (Wikipedia)
UML Tutorial: Finite State Machines

Thursday, 30 June 2011

Modified Command Pattern

Recently I came across a problem of how to implement common interface for executing commands on objects of different types. Only one command can be assigned to each object. Each command has different implementation for each type of object but commands are accessed on each object through same interface. I wanted to have something like this:

I came up with the solution which uses abstract class (CCommand) in order to achieve common interface (Execute()) and command classes templated on actual object type in order to specialize Execute() implementation for each type.

Command.h:



CommandAdd.h:


CommandRemove.h:


UpdateGroupsCollection.h:


CUpdateFilesCollection.h:


main.cpp:


Output:

Group1 added to Update Groups
File1 added to Update Files
Group1 removed from Update Groups
File1 removed from Update Files

To avoid having SetCommand()/GetCommand() code repeated in all client classes, we can use intermediate class, let's call it CCommandManager. This simplifies client classes - they just need to contain one instance of CCommandManager and perform all command-related actions through it:

CommandManager.h:


UpdateGroupsCollection.h:


CUpdateFilesCollection.h:


main.cpp:


Templated commands can be avoided if commands become inner classes of all classes they need to be performed on. E.g.

UpdateGroupsCollection.h:


main.cpp: