1,350,000
Our vision is
0
Fatal accidents every year globally.
|
The Zenseact Team
600
Employees
150+
Perception Experts
60+
Deep Learning Engineers
10+
World First Active Active
SafetyServices
COMPETENCES
▪ Pure software company with ONE product focus
▪ Global AI and Edge learning center HQ in Sweden
▪ Built around the inventors of Active Safety
▪ 20+ years of production experience worldwide
Shanghai, China
Gothenburg
HQ
California
|
OnePilot: From somewhere to everywhere
ZAS: ONE PILOT
Driver Vehicle
Driver
DRIVE CRUISE RIDE
|
OnePilot Real life example
Towards ZERO
faster.
How to write SOLID C++
...and why it matters!
Join at slido.com
#solid
About me Dimitrios Platis
● Grew up in Rodos, Greece
● Software Engineer @ Zenseact, Sweden
● Course responsible @ DIT112, DAT265
● C++ courses
○ Beginner
○ Advanced
○ Software Design & Architecture
● Interests:
○ Embedded systems
○ Open source software & hardware
○ Robots, Portable gadgets, IoT, 3D printing
● Meetups
○ Embedded@Gothenburg
○ grcpp
● Website: https://platis.solutions
What do you work with?
ⓘ Start presenting to display the poll results on this slide.
How familiar are you with
the SOLID principles?
ⓘ Start presenting to display the poll results on this slide.
Single responsibility principle
Open/closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle
SOLID
SOLID is an acronym for five design
principles intended to make software
designs more understandable,
flexible and maintainable. They are a
subset of many principles promoted by
Robert C. Martin. Though they apply to
any object-oriented design, the SOLID
principles can also form a core
philosophy for agile development.
- https://en.wikipedia.org/wiki/SOLID
High cohesion
● Responsibility over a single
purpose
● The class should only have one
"reason" to change
Single responsibility principle
Open/closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle
struct PhotoUploader {
PhotoUploader(Camera& camera, CloudProvider& cloudProvider);
Image getImage();
void resizeImage(int x, int y, Image& image);
void uploadImage(Image& image);
};
const string kPrefix = "user-";
struct UserManager {
UserManager(Database& database) : db{database} {}
void createUser(string username) {
if (!username.startsWith(kPrefix)) {
username = kPrefix + username;
}
db << "insert into users (name) values (?);" << username;
}
string getUsersReport() {
string users;
db << "select name from users" >> [&users](string user) {
users += user.erase(0, kPrefix.length()) + ",";
};
return users;
}
};
struct DatabaseManager {
virtual ~DatabaseManager() = default;
virtual void addUser(string username) = 0;
virtual vector<string> getAllUsers() = 0;
};
struct MyDatabaseManager : public DatabaseManager {
MyDatabaseManager(Database& database);
void addUser(string username) override;
vector<string> getAllUsers() override;
};
struct UsernameFormatter {
virtual ~UsernameFormatter() = default;
virtual string format(string username) = 0;
virtual string getReadableName(string input) = 0;
};
Abstract interfaces
● Open for extension, closed for
modification
● Add new functionality without
having to change existing code
Single responsibility principle
Open/closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle
enum class SensorModel {
Good,
Better
};
struct DistanceSensor {
DistanceSensor(SensorModel model) : mModel{model} {}
int getDistance() {
switch (mModel) {
case SensorModel::Good :
// Business logic for "Good" model
case SensorModel::Better :
// Business logic for "Better" model
}
}
};
struct DistanceSensor {
virtual ~DistanceSensor() = default;
virtual int getDistance() = 0;
};
struct GoodDistanceSensor : public DistanceSensor {
int getDistance() override {
// Business logic for "Good" model
}
};
struct BetterDistanceSensor : public DistanceSensor {
int getDistance() override {
// Business logic for "Better" model
}
};
Substitutability
● A subclass should satisfy not
only the syntactic but also the
behavioral expectations of the
parents
● The behavior of the various
children of a class should be
consistent
Single responsibility principle
Open/closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle
struct InertialMeasurementUnit {
virtual ~InertialMeasurementUnit() = default;
virtual int getOrientation() = 0;
};
struct Gyroscope : public InertialMeasurementUnit {
/**
* @return orientation in degrees [0, 360)
*/
int getOrientation() override;
};
struct Accelerometer : public InertialMeasurementUnit {
/**
* @return orientation in degrees [-180, 180)
*/
int getOrientation() override;
};
struct InertialMeasurementUnit {
virtual ~InertialMeasurementUnit
() = default;
/**
* Sets the frequency of measurements
* @param frequency (in Hertz)
* @return Whether frequency was valid
*/
virtual bool setFrequency(double frequency) = 0;
};
struct Gyroscope : public InertialMeasurementUnit {
// Valid range [0.5, 10]
bool setFrequency(double frequency) override;
};
struct Accelerometer : public InertialMeasurementUnit {
// Valid range [0.1, 100]
bool setFrequency(double frequency) override;
};
struct InertialMeasurementUnit {
virtual ~InertialMeasurementUnit() = default;
/**
* Sets the frequency of measurements
* @param frequency (in Hertz)
* @throw std::out_of_range exception if frequency is invalid
*/
virtual void setFrequency(double frequency) = 0;
/**
* Provides the valid measurement range
* @return <minimum frequency, maximum frequency>
*/
virtual pair<double, double> getFrequencyRange() const = 0;
};
Low coupling
● No one should depend on
methods they do not use
● Multiple single-purpose
interfaces are better than one
multi-purpose
Single responsibility principle
Open/closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle
struct Runtime {
virtual ~Runtime() = default;
virtual void sendViaI2C(vector<byte> bytesToSend) = 0;
virtual vector<byte> readViaI2C(int numberOfBytesToRead) = 0;
virtual void sendViaUART(vector<byte> bytesToSend) = 0;
virtual vector<byte> readViaUART(int numberOfBytesToRead) = 0;
virtual void setPinDirection(int p, PinDirection d) = 0;
virtual void setPin(int pin) = 0;
virtual void clearPin(int pin) = 0;
};
struct SerialManager {
virtual ~SerialManager() = default;
virtual void registerReceiver(function<void(string)> receiver) = 0;
virtual void send(string message) = 0;
virtual void readLine() = 0;
};
struct MySerialManager : public SerialManager {
void registerReceiver(function<void(string)> receiver) override;
void send(string message) override;
void readLine() override;
};
struct AsynchronousReader {
virtual ~AsynchronousReader() = default;
virtual void registerReceiver(function<void(string)> receiver) = 0;
}
struct SerialClient {
virtual ~SerialClient() = default;
virtual void readLine() = 0;
virtual void send(string message) = 0;
};
struct MySerialManager : public SerialClient, public AsynchronousReader {
void registerReceiver(function<void(string)> receiver) override;
void send(string message) override;
void readLine() override;
};
Loose coupling
● High-level modules should not
depend on low-level modules,
both should depend on
abstractions
● Abstractions should not depend
on, or leak, details from the
implementation domain
Single responsibility principle
Open/closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle
struct AwsCloud {
void uploadToS3Bucket(string filepath) { /* ... */ }
};
struct FileUploader {
FileUploader(AwsCloud& awsCloud);
void scheduleUpload(string filepath);
};
struct Cloud {
virtual ~Cloud() = default;
virtual void uploadToS3Bucket(string filepath) = 0;
};
struct AwsCloud : public Cloud {
void uploadToS3Bucket(string filepath) override { /* ... */ }
};
struct FileUploader {
FileUploader(Cloud& cloud);
void scheduleUpload(string filepath);
};
struct Cloud {
virtual ~Cloud() = default;
virtual void upload(string filepath) = 0;
};
struct AwsCloud : public Cloud {
void upload(string filepath) override { /* ... */ }
};
struct FileUploader {
FileUploader(Cloud& cloud);
void scheduleUpload(string filepath);
};
Single responsibility principle
Open/closed principle
Liskov substitution principle
Interface segregation principle
Dependency inversion principle
Takeaways
● SOLID enables agility
● SOLID is indirectly promoted by
C++ Core guidelines
○ C.120, C.121, I.25 etc
● SOLID results in testable code
● Many of the SOLID principles
can be adopted by non-OOP
languages
How applicable are SOLID
principles in real-life
projects?
ⓘ Start presenting to display the poll results on this slide.
Quiz 1. Go to SOCRATIVE.COM
2. Select Login -> Student login
3. Room name: PLATIS
Let's keep in
touch!
https://www.linkedin.com/in/platisd
dimitris@platis.solutions
@PlatisSolutions
JetBrains lottery
1 year license for any Jetbrains IDE!
1. Go to: http://plat.is/jetbrains
2. If you won, please stick around until I
contact you
3. If you did not win, better luck next time!
Did you know that as a university student you
can get a free JetBrains license anyway?

Writing SOLID C++ [gbgcpp meetup @ Zenseact]

  • 2.
    1,350,000 Our vision is 0 Fatalaccidents every year globally.
  • 3.
    | The Zenseact Team 600 Employees 150+ PerceptionExperts 60+ Deep Learning Engineers 10+ World First Active Active SafetyServices COMPETENCES ▪ Pure software company with ONE product focus ▪ Global AI and Edge learning center HQ in Sweden ▪ Built around the inventors of Active Safety ▪ 20+ years of production experience worldwide Shanghai, China Gothenburg HQ California
  • 4.
    | OnePilot: From somewhereto everywhere ZAS: ONE PILOT Driver Vehicle Driver DRIVE CRUISE RIDE
  • 5.
  • 6.
  • 7.
    How to writeSOLID C++ ...and why it matters! Join at slido.com #solid
  • 8.
    About me DimitriosPlatis ● Grew up in Rodos, Greece ● Software Engineer @ Zenseact, Sweden ● Course responsible @ DIT112, DAT265 ● C++ courses ○ Beginner ○ Advanced ○ Software Design & Architecture ● Interests: ○ Embedded systems ○ Open source software & hardware ○ Robots, Portable gadgets, IoT, 3D printing ● Meetups ○ Embedded@Gothenburg ○ grcpp ● Website: https://platis.solutions
  • 9.
    What do youwork with? ⓘ Start presenting to display the poll results on this slide.
  • 10.
    How familiar areyou with the SOLID principles? ⓘ Start presenting to display the poll results on this slide.
  • 11.
    Single responsibility principle Open/closedprinciple Liskov substitution principle Interface segregation principle Dependency inversion principle SOLID SOLID is an acronym for five design principles intended to make software designs more understandable, flexible and maintainable. They are a subset of many principles promoted by Robert C. Martin. Though they apply to any object-oriented design, the SOLID principles can also form a core philosophy for agile development. - https://en.wikipedia.org/wiki/SOLID
  • 12.
    High cohesion ● Responsibilityover a single purpose ● The class should only have one "reason" to change Single responsibility principle Open/closed principle Liskov substitution principle Interface segregation principle Dependency inversion principle
  • 13.
    struct PhotoUploader { PhotoUploader(Camera&camera, CloudProvider& cloudProvider); Image getImage(); void resizeImage(int x, int y, Image& image); void uploadImage(Image& image); };
  • 14.
    const string kPrefix= "user-"; struct UserManager { UserManager(Database& database) : db{database} {} void createUser(string username) { if (!username.startsWith(kPrefix)) { username = kPrefix + username; } db << "insert into users (name) values (?);" << username; } string getUsersReport() { string users; db << "select name from users" >> [&users](string user) { users += user.erase(0, kPrefix.length()) + ","; }; return users; } };
  • 15.
    struct DatabaseManager { virtual~DatabaseManager() = default; virtual void addUser(string username) = 0; virtual vector<string> getAllUsers() = 0; }; struct MyDatabaseManager : public DatabaseManager { MyDatabaseManager(Database& database); void addUser(string username) override; vector<string> getAllUsers() override; }; struct UsernameFormatter { virtual ~UsernameFormatter() = default; virtual string format(string username) = 0; virtual string getReadableName(string input) = 0; };
  • 16.
    Abstract interfaces ● Openfor extension, closed for modification ● Add new functionality without having to change existing code Single responsibility principle Open/closed principle Liskov substitution principle Interface segregation principle Dependency inversion principle
  • 17.
    enum class SensorModel{ Good, Better }; struct DistanceSensor { DistanceSensor(SensorModel model) : mModel{model} {} int getDistance() { switch (mModel) { case SensorModel::Good : // Business logic for "Good" model case SensorModel::Better : // Business logic for "Better" model } } };
  • 18.
    struct DistanceSensor { virtual~DistanceSensor() = default; virtual int getDistance() = 0; }; struct GoodDistanceSensor : public DistanceSensor { int getDistance() override { // Business logic for "Good" model } }; struct BetterDistanceSensor : public DistanceSensor { int getDistance() override { // Business logic for "Better" model } };
  • 19.
    Substitutability ● A subclassshould satisfy not only the syntactic but also the behavioral expectations of the parents ● The behavior of the various children of a class should be consistent Single responsibility principle Open/closed principle Liskov substitution principle Interface segregation principle Dependency inversion principle
  • 20.
    struct InertialMeasurementUnit { virtual~InertialMeasurementUnit() = default; virtual int getOrientation() = 0; }; struct Gyroscope : public InertialMeasurementUnit { /** * @return orientation in degrees [0, 360) */ int getOrientation() override; }; struct Accelerometer : public InertialMeasurementUnit { /** * @return orientation in degrees [-180, 180) */ int getOrientation() override; };
  • 21.
    struct InertialMeasurementUnit { virtual~InertialMeasurementUnit () = default; /** * Sets the frequency of measurements * @param frequency (in Hertz) * @return Whether frequency was valid */ virtual bool setFrequency(double frequency) = 0; }; struct Gyroscope : public InertialMeasurementUnit { // Valid range [0.5, 10] bool setFrequency(double frequency) override; }; struct Accelerometer : public InertialMeasurementUnit { // Valid range [0.1, 100] bool setFrequency(double frequency) override; };
  • 22.
    struct InertialMeasurementUnit { virtual~InertialMeasurementUnit() = default; /** * Sets the frequency of measurements * @param frequency (in Hertz) * @throw std::out_of_range exception if frequency is invalid */ virtual void setFrequency(double frequency) = 0; /** * Provides the valid measurement range * @return <minimum frequency, maximum frequency> */ virtual pair<double, double> getFrequencyRange() const = 0; };
  • 23.
    Low coupling ● Noone should depend on methods they do not use ● Multiple single-purpose interfaces are better than one multi-purpose Single responsibility principle Open/closed principle Liskov substitution principle Interface segregation principle Dependency inversion principle
  • 24.
    struct Runtime { virtual~Runtime() = default; virtual void sendViaI2C(vector<byte> bytesToSend) = 0; virtual vector<byte> readViaI2C(int numberOfBytesToRead) = 0; virtual void sendViaUART(vector<byte> bytesToSend) = 0; virtual vector<byte> readViaUART(int numberOfBytesToRead) = 0; virtual void setPinDirection(int p, PinDirection d) = 0; virtual void setPin(int pin) = 0; virtual void clearPin(int pin) = 0; };
  • 25.
    struct SerialManager { virtual~SerialManager() = default; virtual void registerReceiver(function<void(string)> receiver) = 0; virtual void send(string message) = 0; virtual void readLine() = 0; }; struct MySerialManager : public SerialManager { void registerReceiver(function<void(string)> receiver) override; void send(string message) override; void readLine() override; };
  • 26.
    struct AsynchronousReader { virtual~AsynchronousReader() = default; virtual void registerReceiver(function<void(string)> receiver) = 0; } struct SerialClient { virtual ~SerialClient() = default; virtual void readLine() = 0; virtual void send(string message) = 0; }; struct MySerialManager : public SerialClient, public AsynchronousReader { void registerReceiver(function<void(string)> receiver) override; void send(string message) override; void readLine() override; };
  • 27.
    Loose coupling ● High-levelmodules should not depend on low-level modules, both should depend on abstractions ● Abstractions should not depend on, or leak, details from the implementation domain Single responsibility principle Open/closed principle Liskov substitution principle Interface segregation principle Dependency inversion principle
  • 30.
    struct AwsCloud { voiduploadToS3Bucket(string filepath) { /* ... */ } }; struct FileUploader { FileUploader(AwsCloud& awsCloud); void scheduleUpload(string filepath); };
  • 31.
    struct Cloud { virtual~Cloud() = default; virtual void uploadToS3Bucket(string filepath) = 0; }; struct AwsCloud : public Cloud { void uploadToS3Bucket(string filepath) override { /* ... */ } }; struct FileUploader { FileUploader(Cloud& cloud); void scheduleUpload(string filepath); };
  • 32.
    struct Cloud { virtual~Cloud() = default; virtual void upload(string filepath) = 0; }; struct AwsCloud : public Cloud { void upload(string filepath) override { /* ... */ } }; struct FileUploader { FileUploader(Cloud& cloud); void scheduleUpload(string filepath); };
  • 33.
    Single responsibility principle Open/closedprinciple Liskov substitution principle Interface segregation principle Dependency inversion principle Takeaways ● SOLID enables agility ● SOLID is indirectly promoted by C++ Core guidelines ○ C.120, C.121, I.25 etc ● SOLID results in testable code ● Many of the SOLID principles can be adopted by non-OOP languages
  • 34.
    How applicable areSOLID principles in real-life projects? ⓘ Start presenting to display the poll results on this slide.
  • 35.
    Quiz 1. Goto SOCRATIVE.COM 2. Select Login -> Student login 3. Room name: PLATIS
  • 36.
  • 37.
    JetBrains lottery 1 yearlicense for any Jetbrains IDE! 1. Go to: http://plat.is/jetbrains 2. If you won, please stick around until I contact you 3. If you did not win, better luck next time! Did you know that as a university student you can get a free JetBrains license anyway?