SlideShare a Scribd company logo
Effective engineering
Principles and c++ tools and techniques
Jorge Martinez <jms@hpe.com>
10/16/2015
Principles
▸ Focus on high leverage activities
▹ Leverage = Impact / Time
▸ Increase your leverage by:
▹ Reducing the time to complete a task
▹ Increasing the impact of an activity
▹ Shifting to higher-leverage activities
Leverage
3
▸ Optimize for learning
▸ Invest in iteration speed
▸ Measure what you want to improve
▸ Balance quality with pragmatism
▸ Invest in your team’s growth
High-leverage activities
4
Design
3rd party libs
▸ Do not reinvent the wheel
▸ boost/Facebook/Google …
▸ https://github.com/fffaraz/awesome-cpp
6
Design patterns
▸ Factory
▸ Observer
▸ Decorator
▸ ...
7
Design patterns - Factory
class Reader {
public:
virtual ~Reader() {}
virtual void read() = 0;
};
class LocalReader : public Reader {
public:
void read() {
std::cout << "Reading from local FS" << std::endl;
}
};
class HdfsReader : public Reader {
public:
void read() {
std::cout << "Reading from HDFS" << std::endl;
}
};
8
Design patterns - Factory
class ReaderFactory {
public:
static std::unique_ptr<Reader> makeReader(const std::string& type) {
if (type == "local") {
return std::unique_ptr<Reader>(std::make_unique<LocalReader>());
}
else if (type == "hdfs") {
return std::unique_ptr<Reader>(std::make_unique<HdfsReader>());
}
else {
throw std::runtime_error("Unsupported type");
}
}
};
int main() {
auto reader1 = ReaderFactory::makeReader("local");
reader1->read();
auto reader2 = ReaderFactory::makeReader("hdfs");
reader2->read();
} 9
Design patterns - Observer
using GenericMap = std::unordered_map<std::string, boost::any>;
class INotifiable {
public:
virtual ~INotifiable() {}
virtual void onEvent(const GenericMap& data) const = 0;
};
class EventLogger : public INotifiable {
public:
void onEvent(const GenericMap& data) const {
const std::string& text = boost::any_cast<std::string>(data.at("text"));
std::cout << text << std::endl;
}
};
10
Design patterns - Observer
class Reader {
public:
void addObserver(INotifiable* observer) {
observers_.push_back(observer);
}
void read() const {
GenericMap map;
map["text"] = std::string("FYI");
for (auto i : boost::irange(0,1)) {
for (auto observer: observers_) observer->onEvent(map);
}
}
private:
std::vector<INotifiable*> observers_;
};
int main() {
EventLogger ev1;
EventLogger ev2;
Reader r;
r.addObserver(static_cast<INotifiable*>(&ev1));
r.addObserver(static_cast<INotifiable*>(&ev2));
r.read();
} 11
Design patterns - Decorator
class IDownloader {
public:
virtual ~IDownloader() {}
virtual void download() = 0;
};
class SimpleDownloader : public IDownloader {
public:
void download() {
std::cout << "Downloading ..." << std::endl;
}
};
12
class LoggingDownloader : public IDownloader {
public:
LoggingDownloader(std::unique_ptr<IDownloader> downloader) {
downloader_ = std::move(downloader);
}
void download() {
std::cout << "begin log" << std::endl;
downloader_->download();
std::cout << "end log" << std::endl;
}
private:
std::unique_ptr<IDownloader> downloader_;
};
int main () {
auto simpleDownloader(std::unique_ptr<IDownloader>(std::make_unique<SimpleDownloader>()));
auto loggingDownloader(std::unique_ptr<IDownloader>(std::make_unique<LoggingDownloader>(
std::unique_ptr<IDownloader>(std::make_unique<SimpleDownloader>()))));
simpleDownloader->download();
loggingDownloader->download();
}
Design patterns - Decorator
13
Techniques
Smart pointers
class A {
public:
~A() {
std::cout << "In destructor" << std::endl;
}
};
int main() {
auto ptr1(make_unique<A>());
// auto ptr2 = ptr1; // doesn't compile
auto ptr3(make_shared<A>());
std::cout << ptr3.use_count() << std::endl;
auto ptr4 = ptr3;
std::cout << ptr3.use_count() << std::endl;
}
15
▸ Help a lot with memory
management
▹ Errors
▹ Leaks
▸ unique_ptr
▸ shared_ptr
c++11/14 features
int main() {
auto myvec = {“hola”,”adios”};
cout << myvec.size() << endl;
auto anothervec = std::move(myvec);
atomic<uint64_t> counter;
counter.store(0);
auto incr = [&] () {
for (auto i : boost::irange(0,1000000)) {
++counter;
}
};
thread t1(incr);
thread t2(incr);
t1.join();
t2.join();
cout << counter.load() << endl;
return 0;
}
16
▸ Auto: less typing
▸ Lambdas
▸ Moving semantics
▸ Smart pointers
▸ ...
boost::variant
class LoggingVisitor : public boost::
static_visitor<>
{
public:
void operator()(const int& i) const {
cout << "Visiting int" <<endl;
}
void operator()(const string& str) const {
cout << "Visiting string" <<endl;
}
};
int main() {
boost::variant<int,std::string> variant1 = 6;
auto int1 = boost::get<int>(variant1); // ok
try {
auto str1 =
boost::get<std::string>(variant1); //fails
}
catch (const boost::bad_get& e) {
std::cout << "fails" << std::endl;
}
boost::apply_visitor(LoggingVisitor(), variant1);
boost::variant<int,std::string> variant2 = "hola";
boost::apply_visitor(LoggingVisitor(), variant2);
}
▸ Return multiple known types
17
boost::any
#include <boost/any.hpp>
int main() {
boost::any any1(static_cast<uint64_t>(0));
uint64_t int1 = boost::any_cast<uint64_t>(any1); // ok
boost::any any2(static_cast<uint64_t>(0));
try {
int int2 = boost::any_cast<int>(any2); // fails
}
catch (const boost::bad_any_cast& e) {
std::cout << "fail" << std::endl;
}
}
▸ Return any type
▸ Better type safety than void *
18
Tooling
Clang
▸ Faster compilation
▸ Better error codes
▸ Clang tools
20
Cmake
▸ Cross-platform
▸ Automatic discovery and configuration of the
toolchain
▸ Automatic discovery and configuration of
dependencies
▸ Debug/Release modes
▹ $ cmake -DCMAKE_BUILD_TYPE=Release ..
▹ $ cmake -DCMAKE_BUILD_TYPE=Debug ..
▸ ...
21
Debugging
▸ Debugging from your IDE
▸ Attaching to a remote process
22
Testing with Gtest
Testing: gives you confidence to make changes
▸ Unit testing
▸ Integration testing
▸ Performance testing
23
Testing with Gtest
class Calculator {
public:
static uint64_t sum(const uint64_t op1, const uint64_t op2) {
return op1 + op2;
}
static uint64_t mul(const uint64_t op1, const uint64_t op2) {
return op1 * op2;
}
};
struct MyConfig {
MyConfig(const uint64_t op1,
const uint64_t op2) : op1_(op1), op2_(op2) {
}
const uint64_t op1_;
const uint64_t op2_;
};
::std::ostream& operator<<(::std::ostream& os, const MyConfig& config) {
return os << "op1: " << config.op1_ << " op2: " << config.op2_;
} 24
class MyTest : public ::testing::TestWithParam<MyConfig> {
};
TEST_P(MyTest, Sum) {
const MyConfig& conf = GetParam();
EXPECT_EQ(Calculator::sum(conf.op1_,conf.op2_), conf.op1_ + conf.
op2_);
}
TEST_P(MyTest, Multiply) {
const MyConfig& conf = GetParam();
EXPECT_EQ(Calculator::mul(conf.op1_,conf.op2_), conf.op1_ * conf.
op2_);
}
INSTANTIATE_TEST_CASE_P(MyValues, MyTest, ::testing::Values(
MyConfig(1,2),
MyConfig(3,4)
));
Testing with Gtest
25
Testing with Gtest
Useful things:
▸ Use parameterized tests
▸ Run only some tests with --gtest-filter=<pattern>
▸ List all tests: --gtest_list_tests
▸ Exclude certain tests by prepending DISABLED_ to
the test name
26
Mocking with Gmock
Reason for mocking:
▸ Real object not implemented yet.
▸ Real object complex to set up (e.g. needs a TCP
connection …).
27
#include <gmock/gmock.h>
#include <gtest/gtest.h>
class ICalculator {
public:
virtual uint64_t sum (const uint64_t op1, const uint64_t op2) = 0;
virtual uint64_t mul (const uint64_t op1, const uint64_t op2) = 0;
};
class OnlineCalculator : public ICalculator {
public:
uint64_t sum(const uint64_t op1, const uint64_t op2) {
throw std::runtime_error("Unimplemented");
}
uint64_t mul(const uint64_t op1, const uint64_t op2) {
throw std::runtime_error("Unimplemented");
}
};
Mocking with Gmock
28
class MockCalculator : public ICalculator {
public:
MOCK_METHOD2(sum, uint64_t(const uint64_t, const uint64_t));
MOCK_METHOD2(mul, uint64_t(const uint64_t, const uint64_t));
};
TEST(testcase, test) {
using ::testing::Return;
using ::testing::_;
MockCalculator c;
EXPECT_CALL(c, sum(_,_)).Times(2).WillOnce(Return(3)).WillOnce(Return(7));
EXPECT_CALL(c, mul(_,_)).Times(2).WillOnce(Return(2)).WillOnce(Return(12));
EXPECT_EQ(c.sum(1,2), 3);
EXPECT_EQ(c.sum(3,4), 7);
EXPECT_EQ(c.mul(1,2), 2);
EXPECT_EQ(c.mul(3,4), 12);
}
Mocking with Gmock
29
Address sanitizer
Fast memory error detector.
int main() {
int array[10];
array[10] = 123;
}
[32, 72) 'array' <== Memory access at offset 72 overflows this variable
30
Thread sanitizer
ThreadSanitizer is a tool that detects data races.
int main()
{
uint64_t counter = 0;
auto incr = [&] () {
for (auto i : boost::irange(0,1000000)) {
++counter;
}
};
std::thread t1(incr);
std::thread t2(incr);
t1.join();
t2.join();
std::cout << counter << std::endl;
return 0;
}
WARNING: ThreadSanitizer: data
race (pid=79195)
Write of size 8 at
0x7fffa50a2a60 by thread T2:
Previous write of size 8 at
0x7fffa50a2a60 by thread T1:
31
Folly benchmark
BENCHMARK(copy) {
vector<uint64_t> v;
v.resize(128*1024*1024);
FOR_EACH_RANGE (i, 0, 1) {
vector<uint64_t> v2(v);
}
}
BENCHMARK(move) {
vector<uint64_t> v;
v.resize(128*1024*1024);
FOR_EACH_RANGE (i, 0, 1) {
vector<uint64_t> v2(std::move(v));
}
}
int main() {
runBenchmarks();
}
Copy: 4.51 secs
Move: 925 msecs
32
Profiling with Gperftools
Pretty good profiler
Tells you where cycles go (including network, IO …)
$ CPUPROFILE=/tmp/$PROFILENAME.prof
LD_PRELOAD=/usr/local/lib/libprofiler.so:/usr/lib/libtcmalloc.so
$BINARY $ARGS
$ pprof --gv $BINARY /tmp/$PROFILENAME.prof
33
Linting with cpplint.py or clang tidy
$ cpplint.py <files>
$ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
$ clang-tidy --checks=google-* ../linting/tolint.cpp
34
Docker for testing
// Dockerfile for centos
FROM centos
COPY factory /tmp/
CMD /tmp/factory
// Dockerfile for ubuntu
FROM ubuntu
COPY factory /tmp/
CMD /tmp/factory
ubuntu:
cd ubuntu; sudo docker build -t ubuntu-chalktalk .
centos:
cd centos; sudo docker build -t centos-chalktalk .
run:
sudo docker run --name ubuntu-chalktalk-001 ubuntu-chalktalk
sudo docker run --name centos-chalktalk-001 centos-chalktalk
clean:
sudo docker rm -f ubuntu-chalktalk-001 centos-chalktalk-001
35
Integration with CI (Jenkins)
▸ All the tooling presented before should be
integrated with CI
▹ Test on all platforms with docker
▹ Check code for memory and threading
problems (asan/tsan)
▹ Run test suites (gtest)
▹ Check for style, linting
▹ Coverage
▹ Metrics/ track improvement
▹ ...
36
Others
▸ Master a scripting language (e.g. Python)
▸ Master the command line
▸ Master your IDE
▸ Automate everything
▸ Shorten release cycles (continuous delivery)
37
Conclusions
Always be learning and improving!
The code:
https://github.com/jorgemarsal/modern-cpp-chalktalk
38
Thanks!
Questions?
jms@hpe.com
39

More Related Content

PDF
4Developers 2018: Evolution of C++ Class Design (Mariusz Łapiński)
PROIDEA
 
PDF
Architecture for Massively Parallel HDL Simulations
DVClub
 
PDF
Работа с реляционными базами данных в C++
corehard_by
 
PDF
How to make a large C++-code base manageable
corehard_by
 
PDF
Refactoring for testability c++
Dimitrios Platis
 
PPTX
Дмитрий Демчук. Кроссплатформенный краш-репорт
Sergey Platonov
 
PDF
Job Queue in Golang
Bo-Yi Wu
 
PPTX
C++17 now
corehard_by
 
4Developers 2018: Evolution of C++ Class Design (Mariusz Łapiński)
PROIDEA
 
Architecture for Massively Parallel HDL Simulations
DVClub
 
Работа с реляционными базами данных в C++
corehard_by
 
How to make a large C++-code base manageable
corehard_by
 
Refactoring for testability c++
Dimitrios Platis
 
Дмитрий Демчук. Кроссплатформенный краш-репорт
Sergey Platonov
 
Job Queue in Golang
Bo-Yi Wu
 
C++17 now
corehard_by
 

What's hot (20)

PDF
The Ring programming language version 1.5.4 book - Part 8 of 185
Mahmoud Samir Fayed
 
PDF
用 Go 語言打造多台機器 Scale 架構
Bo-Yi Wu
 
PDF
Алексей Кутумов, Coroutines everywhere
Sergey Platonov
 
PDF
Qt Rest Server
Vasiliy Sorokin
 
PDF
Checking the Source SDK Project
Andrey Karpov
 
PDF
Compose Async with RxJS
Kyung Yeol Kim
 
PDF
The Ring programming language version 1.5.1 book - Part 7 of 180
Mahmoud Samir Fayed
 
PDF
#JavaFX.forReal() - ElsassJUG
Thierry Wasylczenko
 
PDF
Clang tidy
Yury Yafimachau
 
PDF
Checking Notepad++: five years later
PVS-Studio
 
PDF
The Ring programming language version 1.5.3 book - Part 8 of 184
Mahmoud Samir Fayed
 
PDF
Construire une application JavaFX 8 avec gradle
Thierry Wasylczenko
 
PDF
Антон Наумович, Система автоматической крэш-аналитики своими средствами
Sergey Platonov
 
PDF
TensorFlow XLA RPC
Mr. Vengineer
 
PDF
Writing native bindings to node.js in C++
nsm.nikhil
 
PDF
The Ring programming language version 1.8 book - Part 77 of 202
Mahmoud Samir Fayed
 
PDF
Checking the Cross-Platform Framework Cocos2d-x
Andrey Karpov
 
PPTX
Using openCV 3.2.0 with CodeBlocks
Wei-Wen Hsu
 
PPT
Евгений Крутько, Многопоточные вычисления, современный подход.
Platonov Sergey
 
PDF
The Ring programming language version 1.7 book - Part 75 of 196
Mahmoud Samir Fayed
 
The Ring programming language version 1.5.4 book - Part 8 of 185
Mahmoud Samir Fayed
 
用 Go 語言打造多台機器 Scale 架構
Bo-Yi Wu
 
Алексей Кутумов, Coroutines everywhere
Sergey Platonov
 
Qt Rest Server
Vasiliy Sorokin
 
Checking the Source SDK Project
Andrey Karpov
 
Compose Async with RxJS
Kyung Yeol Kim
 
The Ring programming language version 1.5.1 book - Part 7 of 180
Mahmoud Samir Fayed
 
#JavaFX.forReal() - ElsassJUG
Thierry Wasylczenko
 
Clang tidy
Yury Yafimachau
 
Checking Notepad++: five years later
PVS-Studio
 
The Ring programming language version 1.5.3 book - Part 8 of 184
Mahmoud Samir Fayed
 
Construire une application JavaFX 8 avec gradle
Thierry Wasylczenko
 
Антон Наумович, Система автоматической крэш-аналитики своими средствами
Sergey Platonov
 
TensorFlow XLA RPC
Mr. Vengineer
 
Writing native bindings to node.js in C++
nsm.nikhil
 
The Ring programming language version 1.8 book - Part 77 of 202
Mahmoud Samir Fayed
 
Checking the Cross-Platform Framework Cocos2d-x
Andrey Karpov
 
Using openCV 3.2.0 with CodeBlocks
Wei-Wen Hsu
 
Евгений Крутько, Многопоточные вычисления, современный подход.
Platonov Sergey
 
The Ring programming language version 1.7 book - Part 75 of 196
Mahmoud Samir Fayed
 
Ad

Similar to Modern c++ (20)

PDF
C++ Restrictions for Game Programming.
Richard Taylor
 
PDF
Effective Object Oriented Design in Cpp
CodeOps Technologies LLP
 
PDF
Bjarne essencegn13
Hunde Gurmessa
 
PDF
Design Patterns in Modern C++
Dmitri Nesteruk
 
PDF
Industry - Program analysis and verification - Type-preserving Heap Profiler ...
ICSM 2011
 
PPTX
Дмитрий Нестерук, Паттерны проектирования в XXI веке
Sergey Platonov
 
PPTX
C++ idioms.pptx
Janani Anbarasan
 
PPTX
Evgeniy Muralev, Mark Vince, Working with the compiler, not against it
Sergey Platonov
 
PDF
PPU Optimisation Lesson
slantsixgames
 
ODP
Preventing Complexity in Game Programming
Yaser Zhian
 
PDF
C Design Patterns And Derivatives Pricing 2nd Edition M S Joshi
pepezgwiltni
 
PPTX
Data oriented design and c++
Mike Acton
 
PPTX
Compiler optimizations based on call-graph flattening
CAFxX
 
PPTX
C traps and pitfalls for C++ programmers
Richard Thomson
 
PDF
C++ Training
SubhendraBasu5
 
PDF
OO Design and Design Patterns in C++
Ganesh Samarthyam
 
PPTX
#GDC15 Code Clinic
Mike Acton
 
PPTX
C++11: Feel the New Language
mspline
 
PPTX
Whats New in Visual Studio 2012 for C++ Developers
Rainer Stropek
 
C++ Restrictions for Game Programming.
Richard Taylor
 
Effective Object Oriented Design in Cpp
CodeOps Technologies LLP
 
Bjarne essencegn13
Hunde Gurmessa
 
Design Patterns in Modern C++
Dmitri Nesteruk
 
Industry - Program analysis and verification - Type-preserving Heap Profiler ...
ICSM 2011
 
Дмитрий Нестерук, Паттерны проектирования в XXI веке
Sergey Platonov
 
C++ idioms.pptx
Janani Anbarasan
 
Evgeniy Muralev, Mark Vince, Working with the compiler, not against it
Sergey Platonov
 
PPU Optimisation Lesson
slantsixgames
 
Preventing Complexity in Game Programming
Yaser Zhian
 
C Design Patterns And Derivatives Pricing 2nd Edition M S Joshi
pepezgwiltni
 
Data oriented design and c++
Mike Acton
 
Compiler optimizations based on call-graph flattening
CAFxX
 
C traps and pitfalls for C++ programmers
Richard Thomson
 
C++ Training
SubhendraBasu5
 
OO Design and Design Patterns in C++
Ganesh Samarthyam
 
#GDC15 Code Clinic
Mike Acton
 
C++11: Feel the New Language
mspline
 
Whats New in Visual Studio 2012 for C++ Developers
Rainer Stropek
 
Ad

Recently uploaded (20)

PDF
Build Multi-agent using Agent Development Kit
FadyIbrahim23
 
PDF
49785682629390197565_LRN3014_Migrating_the_Beast.pdf
Abilash868456
 
PPT
Activate_Methodology_Summary presentatio
annapureddyn
 
PDF
Become an Agentblazer Champion Challenge Kickoff
Dele Amefo
 
PDF
49784907924775488180_LRN2959_Data_Pump_23ai.pdf
Abilash868456
 
PPTX
Smart Panchayat Raj e-Governance App.pptx
Rohitnikam33
 
PDF
QAware_Mario-Leander_Reimer_Architecting and Building a K8s-based AI Platform...
QAware GmbH
 
PDF
Protecting the Digital World Cyber Securit
dnthakkar16
 
PPT
Why Reliable Server Maintenance Service in New York is Crucial for Your Business
Sam Vohra
 
PDF
The Role of Automation and AI in EHS Management for Data Centers.pdf
TECH EHS Solution
 
PPTX
GALILEO CRS SYSTEM | GALILEO TRAVEL SOFTWARE
philipnathen82
 
PPTX
oapresentation.pptx
mehatdhavalrajubhai
 
PDF
Key Features to Look for in Arizona App Development Services
Net-Craft.com
 
PPTX
Contractor Management Platform and Software Solution for Compliance
SHEQ Network Limited
 
PDF
IEEE-CS Tech Predictions, SWEBOK and Quantum Software: Towards Q-SWEBOK
Hironori Washizaki
 
PPTX
Visualising Data with Scatterplots in IBM SPSS Statistics.pptx
Version 1 Analytics
 
PDF
Become an Agentblazer Champion Challenge
Dele Amefo
 
PPTX
Role Of Python In Programing Language.pptx
jaykoshti048
 
PDF
Salesforce Implementation Services Provider.pdf
VALiNTRY360
 
PPTX
Presentation about variables and constant.pptx
safalsingh810
 
Build Multi-agent using Agent Development Kit
FadyIbrahim23
 
49785682629390197565_LRN3014_Migrating_the_Beast.pdf
Abilash868456
 
Activate_Methodology_Summary presentatio
annapureddyn
 
Become an Agentblazer Champion Challenge Kickoff
Dele Amefo
 
49784907924775488180_LRN2959_Data_Pump_23ai.pdf
Abilash868456
 
Smart Panchayat Raj e-Governance App.pptx
Rohitnikam33
 
QAware_Mario-Leander_Reimer_Architecting and Building a K8s-based AI Platform...
QAware GmbH
 
Protecting the Digital World Cyber Securit
dnthakkar16
 
Why Reliable Server Maintenance Service in New York is Crucial for Your Business
Sam Vohra
 
The Role of Automation and AI in EHS Management for Data Centers.pdf
TECH EHS Solution
 
GALILEO CRS SYSTEM | GALILEO TRAVEL SOFTWARE
philipnathen82
 
oapresentation.pptx
mehatdhavalrajubhai
 
Key Features to Look for in Arizona App Development Services
Net-Craft.com
 
Contractor Management Platform and Software Solution for Compliance
SHEQ Network Limited
 
IEEE-CS Tech Predictions, SWEBOK and Quantum Software: Towards Q-SWEBOK
Hironori Washizaki
 
Visualising Data with Scatterplots in IBM SPSS Statistics.pptx
Version 1 Analytics
 
Become an Agentblazer Champion Challenge
Dele Amefo
 
Role Of Python In Programing Language.pptx
jaykoshti048
 
Salesforce Implementation Services Provider.pdf
VALiNTRY360
 
Presentation about variables and constant.pptx
safalsingh810
 

Modern c++

  • 1. Effective engineering Principles and c++ tools and techniques Jorge Martinez <[email protected]> 10/16/2015
  • 3. ▸ Focus on high leverage activities ▹ Leverage = Impact / Time ▸ Increase your leverage by: ▹ Reducing the time to complete a task ▹ Increasing the impact of an activity ▹ Shifting to higher-leverage activities Leverage 3
  • 4. ▸ Optimize for learning ▸ Invest in iteration speed ▸ Measure what you want to improve ▸ Balance quality with pragmatism ▸ Invest in your team’s growth High-leverage activities 4
  • 6. 3rd party libs ▸ Do not reinvent the wheel ▸ boost/Facebook/Google … ▸ https://github.com/fffaraz/awesome-cpp 6
  • 7. Design patterns ▸ Factory ▸ Observer ▸ Decorator ▸ ... 7
  • 8. Design patterns - Factory class Reader { public: virtual ~Reader() {} virtual void read() = 0; }; class LocalReader : public Reader { public: void read() { std::cout << "Reading from local FS" << std::endl; } }; class HdfsReader : public Reader { public: void read() { std::cout << "Reading from HDFS" << std::endl; } }; 8
  • 9. Design patterns - Factory class ReaderFactory { public: static std::unique_ptr<Reader> makeReader(const std::string& type) { if (type == "local") { return std::unique_ptr<Reader>(std::make_unique<LocalReader>()); } else if (type == "hdfs") { return std::unique_ptr<Reader>(std::make_unique<HdfsReader>()); } else { throw std::runtime_error("Unsupported type"); } } }; int main() { auto reader1 = ReaderFactory::makeReader("local"); reader1->read(); auto reader2 = ReaderFactory::makeReader("hdfs"); reader2->read(); } 9
  • 10. Design patterns - Observer using GenericMap = std::unordered_map<std::string, boost::any>; class INotifiable { public: virtual ~INotifiable() {} virtual void onEvent(const GenericMap& data) const = 0; }; class EventLogger : public INotifiable { public: void onEvent(const GenericMap& data) const { const std::string& text = boost::any_cast<std::string>(data.at("text")); std::cout << text << std::endl; } }; 10
  • 11. Design patterns - Observer class Reader { public: void addObserver(INotifiable* observer) { observers_.push_back(observer); } void read() const { GenericMap map; map["text"] = std::string("FYI"); for (auto i : boost::irange(0,1)) { for (auto observer: observers_) observer->onEvent(map); } } private: std::vector<INotifiable*> observers_; }; int main() { EventLogger ev1; EventLogger ev2; Reader r; r.addObserver(static_cast<INotifiable*>(&ev1)); r.addObserver(static_cast<INotifiable*>(&ev2)); r.read(); } 11
  • 12. Design patterns - Decorator class IDownloader { public: virtual ~IDownloader() {} virtual void download() = 0; }; class SimpleDownloader : public IDownloader { public: void download() { std::cout << "Downloading ..." << std::endl; } }; 12
  • 13. class LoggingDownloader : public IDownloader { public: LoggingDownloader(std::unique_ptr<IDownloader> downloader) { downloader_ = std::move(downloader); } void download() { std::cout << "begin log" << std::endl; downloader_->download(); std::cout << "end log" << std::endl; } private: std::unique_ptr<IDownloader> downloader_; }; int main () { auto simpleDownloader(std::unique_ptr<IDownloader>(std::make_unique<SimpleDownloader>())); auto loggingDownloader(std::unique_ptr<IDownloader>(std::make_unique<LoggingDownloader>( std::unique_ptr<IDownloader>(std::make_unique<SimpleDownloader>())))); simpleDownloader->download(); loggingDownloader->download(); } Design patterns - Decorator 13
  • 15. Smart pointers class A { public: ~A() { std::cout << "In destructor" << std::endl; } }; int main() { auto ptr1(make_unique<A>()); // auto ptr2 = ptr1; // doesn't compile auto ptr3(make_shared<A>()); std::cout << ptr3.use_count() << std::endl; auto ptr4 = ptr3; std::cout << ptr3.use_count() << std::endl; } 15 ▸ Help a lot with memory management ▹ Errors ▹ Leaks ▸ unique_ptr ▸ shared_ptr
  • 16. c++11/14 features int main() { auto myvec = {“hola”,”adios”}; cout << myvec.size() << endl; auto anothervec = std::move(myvec); atomic<uint64_t> counter; counter.store(0); auto incr = [&] () { for (auto i : boost::irange(0,1000000)) { ++counter; } }; thread t1(incr); thread t2(incr); t1.join(); t2.join(); cout << counter.load() << endl; return 0; } 16 ▸ Auto: less typing ▸ Lambdas ▸ Moving semantics ▸ Smart pointers ▸ ...
  • 17. boost::variant class LoggingVisitor : public boost:: static_visitor<> { public: void operator()(const int& i) const { cout << "Visiting int" <<endl; } void operator()(const string& str) const { cout << "Visiting string" <<endl; } }; int main() { boost::variant<int,std::string> variant1 = 6; auto int1 = boost::get<int>(variant1); // ok try { auto str1 = boost::get<std::string>(variant1); //fails } catch (const boost::bad_get& e) { std::cout << "fails" << std::endl; } boost::apply_visitor(LoggingVisitor(), variant1); boost::variant<int,std::string> variant2 = "hola"; boost::apply_visitor(LoggingVisitor(), variant2); } ▸ Return multiple known types 17
  • 18. boost::any #include <boost/any.hpp> int main() { boost::any any1(static_cast<uint64_t>(0)); uint64_t int1 = boost::any_cast<uint64_t>(any1); // ok boost::any any2(static_cast<uint64_t>(0)); try { int int2 = boost::any_cast<int>(any2); // fails } catch (const boost::bad_any_cast& e) { std::cout << "fail" << std::endl; } } ▸ Return any type ▸ Better type safety than void * 18
  • 20. Clang ▸ Faster compilation ▸ Better error codes ▸ Clang tools 20
  • 21. Cmake ▸ Cross-platform ▸ Automatic discovery and configuration of the toolchain ▸ Automatic discovery and configuration of dependencies ▸ Debug/Release modes ▹ $ cmake -DCMAKE_BUILD_TYPE=Release .. ▹ $ cmake -DCMAKE_BUILD_TYPE=Debug .. ▸ ... 21
  • 22. Debugging ▸ Debugging from your IDE ▸ Attaching to a remote process 22
  • 23. Testing with Gtest Testing: gives you confidence to make changes ▸ Unit testing ▸ Integration testing ▸ Performance testing 23
  • 24. Testing with Gtest class Calculator { public: static uint64_t sum(const uint64_t op1, const uint64_t op2) { return op1 + op2; } static uint64_t mul(const uint64_t op1, const uint64_t op2) { return op1 * op2; } }; struct MyConfig { MyConfig(const uint64_t op1, const uint64_t op2) : op1_(op1), op2_(op2) { } const uint64_t op1_; const uint64_t op2_; }; ::std::ostream& operator<<(::std::ostream& os, const MyConfig& config) { return os << "op1: " << config.op1_ << " op2: " << config.op2_; } 24
  • 25. class MyTest : public ::testing::TestWithParam<MyConfig> { }; TEST_P(MyTest, Sum) { const MyConfig& conf = GetParam(); EXPECT_EQ(Calculator::sum(conf.op1_,conf.op2_), conf.op1_ + conf. op2_); } TEST_P(MyTest, Multiply) { const MyConfig& conf = GetParam(); EXPECT_EQ(Calculator::mul(conf.op1_,conf.op2_), conf.op1_ * conf. op2_); } INSTANTIATE_TEST_CASE_P(MyValues, MyTest, ::testing::Values( MyConfig(1,2), MyConfig(3,4) )); Testing with Gtest 25
  • 26. Testing with Gtest Useful things: ▸ Use parameterized tests ▸ Run only some tests with --gtest-filter=<pattern> ▸ List all tests: --gtest_list_tests ▸ Exclude certain tests by prepending DISABLED_ to the test name 26
  • 27. Mocking with Gmock Reason for mocking: ▸ Real object not implemented yet. ▸ Real object complex to set up (e.g. needs a TCP connection …). 27
  • 28. #include <gmock/gmock.h> #include <gtest/gtest.h> class ICalculator { public: virtual uint64_t sum (const uint64_t op1, const uint64_t op2) = 0; virtual uint64_t mul (const uint64_t op1, const uint64_t op2) = 0; }; class OnlineCalculator : public ICalculator { public: uint64_t sum(const uint64_t op1, const uint64_t op2) { throw std::runtime_error("Unimplemented"); } uint64_t mul(const uint64_t op1, const uint64_t op2) { throw std::runtime_error("Unimplemented"); } }; Mocking with Gmock 28
  • 29. class MockCalculator : public ICalculator { public: MOCK_METHOD2(sum, uint64_t(const uint64_t, const uint64_t)); MOCK_METHOD2(mul, uint64_t(const uint64_t, const uint64_t)); }; TEST(testcase, test) { using ::testing::Return; using ::testing::_; MockCalculator c; EXPECT_CALL(c, sum(_,_)).Times(2).WillOnce(Return(3)).WillOnce(Return(7)); EXPECT_CALL(c, mul(_,_)).Times(2).WillOnce(Return(2)).WillOnce(Return(12)); EXPECT_EQ(c.sum(1,2), 3); EXPECT_EQ(c.sum(3,4), 7); EXPECT_EQ(c.mul(1,2), 2); EXPECT_EQ(c.mul(3,4), 12); } Mocking with Gmock 29
  • 30. Address sanitizer Fast memory error detector. int main() { int array[10]; array[10] = 123; } [32, 72) 'array' <== Memory access at offset 72 overflows this variable 30
  • 31. Thread sanitizer ThreadSanitizer is a tool that detects data races. int main() { uint64_t counter = 0; auto incr = [&] () { for (auto i : boost::irange(0,1000000)) { ++counter; } }; std::thread t1(incr); std::thread t2(incr); t1.join(); t2.join(); std::cout << counter << std::endl; return 0; } WARNING: ThreadSanitizer: data race (pid=79195) Write of size 8 at 0x7fffa50a2a60 by thread T2: Previous write of size 8 at 0x7fffa50a2a60 by thread T1: 31
  • 32. Folly benchmark BENCHMARK(copy) { vector<uint64_t> v; v.resize(128*1024*1024); FOR_EACH_RANGE (i, 0, 1) { vector<uint64_t> v2(v); } } BENCHMARK(move) { vector<uint64_t> v; v.resize(128*1024*1024); FOR_EACH_RANGE (i, 0, 1) { vector<uint64_t> v2(std::move(v)); } } int main() { runBenchmarks(); } Copy: 4.51 secs Move: 925 msecs 32
  • 33. Profiling with Gperftools Pretty good profiler Tells you where cycles go (including network, IO …) $ CPUPROFILE=/tmp/$PROFILENAME.prof LD_PRELOAD=/usr/local/lib/libprofiler.so:/usr/lib/libtcmalloc.so $BINARY $ARGS $ pprof --gv $BINARY /tmp/$PROFILENAME.prof 33
  • 34. Linting with cpplint.py or clang tidy $ cpplint.py <files> $ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .. $ clang-tidy --checks=google-* ../linting/tolint.cpp 34
  • 35. Docker for testing // Dockerfile for centos FROM centos COPY factory /tmp/ CMD /tmp/factory // Dockerfile for ubuntu FROM ubuntu COPY factory /tmp/ CMD /tmp/factory ubuntu: cd ubuntu; sudo docker build -t ubuntu-chalktalk . centos: cd centos; sudo docker build -t centos-chalktalk . run: sudo docker run --name ubuntu-chalktalk-001 ubuntu-chalktalk sudo docker run --name centos-chalktalk-001 centos-chalktalk clean: sudo docker rm -f ubuntu-chalktalk-001 centos-chalktalk-001 35
  • 36. Integration with CI (Jenkins) ▸ All the tooling presented before should be integrated with CI ▹ Test on all platforms with docker ▹ Check code for memory and threading problems (asan/tsan) ▹ Run test suites (gtest) ▹ Check for style, linting ▹ Coverage ▹ Metrics/ track improvement ▹ ... 36
  • 37. Others ▸ Master a scripting language (e.g. Python) ▸ Master the command line ▸ Master your IDE ▸ Automate everything ▸ Shorten release cycles (continuous delivery) 37
  • 38. Conclusions Always be learning and improving! The code: https://github.com/jorgemarsal/modern-cpp-chalktalk 38