SlideShare a Scribd company logo
1 of 78
Download to read offline
Refactor Legacy Code Through Pure Functions
Alex Bolboaca, CTO, Trainer and Coach at Mozaic Works
 alexboly  https://mozaicworks.com  alex.bolboaca@mozaicworks.com
. . . . . . . . . . . . . . . . . . . .
The Problem Of Legacy Code
Existing Methods
Disadvantages of existing methods
Step 1: To pure functions
Step 2: Test pure functions
Step 3: Pure functions to classes
Final Thoughts
The Problem Of Legacy Code
Legacy Code is everywhere
Depiction of legacy code
Legacy Code erodes the will of programmers
What is Legacy Code?
Michael Feathers: “Any piece of code that doesn’t have automated tests”
Generalized Definition
Alex Bolboaca: “Any piece of code that you are afraid to change”
Legacy Code leads to the Dark Side
Yoda: “Fear leads to anger. Anger leads to hate. Hate leads to suffering.”
Existing Methods
“Change and pray” method
If it works for you, great. Is it repeatable and transferrable though?
“No more changes” method
Freeze code, nobody touches it. Works with strangler pattern
Strangler Pattern
Strangle the existing code with a new implementation until the new implementation works fine.
Michael Feathers’ Refactoring method
Identify seams -> small, safe refactorings -> write characterization tests -> refactor code to desired design
Mikado method
Disadvantages of existing methods
Legacy Code is Messy
Often multiple methods required, and time consuming
Existing methods require multiple rare skills
• How to identify and “abuse” seams
• How to write characterization tests
• How to imagine a good design solution
• How to refactor in small steps
• Lots of imagination
Learning the methods takes long
Months, maybe years of practice
3 Poor Choices
• Live with the code you’re afraid to change (and slow down development)
• Refactor the code unsafely (spoilers: you will probably fail)
• Use a safe method (spoilers: it’s slow)
I’m proposing a new method
• Refactor code to pure functions
• Write data-driven or property based tests on the pure functions
• Refactor pure functions to classes (or something else)
Step 1: To pure functions
What is a pure function?
• Returns same output values for the same input values
• Does not depend on state
Example of Pure Functions
int add(const int first, const int second){
return first + second;
}
Example of Impure Function
int addToFirst(int& first, const int second){
first+=second;
return first;
}
Example of “Tolerated” Pure Function
int increment(int first){
return first; //state change, local to the function
}
Why pure functions?
When you turn your switch on, the water doesn’t start on your sink
Why pure functions?
• Pure functions are boring
• Pure functions have no dependencies
• Pure functions are easy to test
• Any program can be written as a combination of: pure functions + I/O functions
• We can take advantage of lambda operations with pure functions: functional composition,
currying, binding
Why Pure functions?
The hardest part of writing characterization tests (M. Feathers’ method) is dealing with
dependencies.
Pure functions make dependencies obvious and explicit.
Refactor to pure functions
• Pick a code block
• Extract method (refactoring)
• Make it immutable (add consts)
• Make it static and introduce parameters if needed
• Replace with lambda
Remember: this is an intermediary step. We ignore for now design and performance, we just want
to reduce dependencies and increase testability
Example
Game ::Game() : currentPlayer(0), places{}, purses{} {
for (int i = 0; i < 50; i ) {
ostringstream oss(ostringstream ::out);
oss << ”Pop Question ” << i;
popQuestions.push_back(oss.str());
char str[255];
sprintf(str, ”Science Question %d”, i);
scienceQuestions.push_back(str);
char str1[255];
sprintf(str1, ”Sports Question %d”, i);
sportsQuestions.push_back(str1);
rockQuestions.push_back(createRockQuestion(i));
}
}
1. Pick a code block
ostringstream oss(ostringstream ::out);
oss << ”Pop Question ” << i;
popQuestions.push_back(oss.str());
2. Extract method
void Game ::doSomething(int i) {
ostringstream oss(ostringstream ::out);
oss << ”Pop Question ” << i;
popQuestions.push_back(oss.str());
}
3. Try to make it immutable: const parameter
void Game ::doSomething(const int i) {
ostringstream oss(ostringstream ::out);
oss << ”Pop Question ” << i;
popQuestions.push_back(oss.str());
}
3. Try to make it immutable: const function
void Game ::doSomething(const int i) const {
ostringstream oss(ostringstream ::out);
oss << ”Pop Question ” << i;
//! Compilation Error: state change
popQuestions.push_back(oss.str());
}
Revert change
void Game ::doSomething(const int i) {
ostringstream oss(ostringstream ::out);
oss << ”Pop Question ” << i;
popQuestions.push_back(oss.str());
}
Separate the pure from impure part
void Game ::doSomething(const int i) {
// Pure function
ostringstream oss(ostringstream ::out);
oss << ”Pop Question ” << i;
const string &popQuestion = oss.str();
// State change
popQuestions.push_back(popQuestion);
}
Extract pure function
void Game ::doSomething(const int i) {
string popQuestion = createPopQuestion(i);
popQuestions.push_back(popQuestion);
}
string Game ::createPopQuestion(const int i) const {
ostringstream oss(ostringstream ::out);
oss << ”Pop Question ” << i;
const string &popQuestion = oss.str();
return popQuestion;
}
Inline initial function
Game ::Game() : currentPlayer(0), places{}, purses{} {
for (int i = 0; i < 50; i ) {
const string popQuestion = createPopQuestion(i);
popQuestions.push_back(popQuestion);
...
}
}
Back to the pure function
string Game ::createPopQuestion(const int i) const {
ostringstream oss(ostringstream ::out);
oss << ”Pop Question ” << i;
const string &popQuestion = oss.str();
return popQuestion;
}
Some simplification
string Game ::createPopQuestion(const int i) const {
ostringstream oss(ostringstream ::out);
oss << ”Pop Question ” << i;
return oss.str();
}
Transform to lambda
auto createPopQuestion_Lambda = [](const int i) -> string {
ostringstream oss(ostringstream ::out);
oss << ”Pop Question ” << i;
return oss.str();
};
string Game ::createPopQuestion(const int i) const {
createPopQuestion_Lambda(i);
}
Move lambda up and inline method
Game ::Game() : currentPlayer(0), places{}, purses{} {
for (int i = 0; i < 50; i ) {
popQuestions.push_back(createPopQuestion_Lambda(i));
char str[255];
sprintf(str, ”Science Question %d”, i);
scienceQuestions.push_back(str);
...
}
}
Let’s stop and evaluate
Refactorings: extract method, inline, change signature, turn to lambda
The compiler helps us
The compiler tells us the function dependencies
Mechanical process - or engineering procedure
Mechanical process
The result
// Pure function
// No dependencies
auto createPopQuestion_Lambda = [](const int i) -> string {
ostringstream oss(ostringstream ::out);
oss << ”Pop Question ” << i;
return oss.str();
};
What about state changes?
bool Game ::add(string playerName) {
players.push_back(playerName);
places[howManyPlayers()] = 0;
purses[howManyPlayers()] = 0;
inPenaltyBox[howManyPlayers()] = false;
cout << playerName << ” was added” << endl;
cout << ”They are player number ” << players.size() << endl;
return true;
}
Pick code that makes the state change
bool Game ::add(string playerName) {
// State change
players.push_back(playerName);
// State change
places[howManyPlayers()] = 0;
// State change
purses[howManyPlayers()] = 0;
// State change
inPenaltyBox[howManyPlayers()] = false;
// I/O
cout << playerName << ” was added” << endl;
cout << ”They are player number ” << players.size() << endl;
return true;
}
Extract method
void Game ::addPlayerNameToPlayersList(const string &playerName) {
players.push_back(playerName);
}
Extract initial value
void Game ::addPlayerNameToPlayersList(const string &playerName) {
// Copy initial value of players
vector<string> &initialPlayers(players);
// Modify the copy
initialPlayers.push_back(playerName);
// Set the data member to the new value
players = initialPlayers;
}
Separate pure from impure
void Game ::addPlayerNameToPlayersList(const string &playerName) {
vector<string> initialPlayers = addPlayer_Pure(playerName);
players = initialPlayers;
}
vector<string> Game ::addPlayer_Pure(const string &playerName) const {
vector<string> initialPlayers(players);
initialPlayers.push_back(playerName);
return initialPlayers;
}
Inline computation
void Game ::addPlayerNameToPlayersList(const string &playerName) {
players = addPlayer_Pure(playerName);
}
Inline method
bool Game ::add(string playerName) {
players = addPlayer_Pure(playerName);
places[howManyPlayers()] = 0;
purses[howManyPlayers()] = 0;
inPenaltyBox[howManyPlayers()] = false;
cout << playerName << ” was added” << endl;
cout << ”They are player number ” << players.size() << endl;
return true;
}
Make static
vector<string> Game ::addPlayer_Pure(const string &playerName) {
// Compilation error: players unavailable
vector<string> initialPlayers(players);
initialPlayers.push_back(playerName);
return initialPlayers;
}
Undo static & Introduce parameter
vector<string> Game ::addPlayer_Pure(
const string &playerName,
const vector<string> &thePlayers) {
vector<string> initialPlayers(thePlayers);
initialPlayers.push_back(playerName);
return initialPlayers;
}
Move to lambda
auto addPlayerNameToCollection_Lambda =
[](const string &playerName,
const vector<string> &thePlayers)
-> vector<string> {
vector<string> initialPlayers(thePlayers);
initialPlayers.push_back(playerName);
return initialPlayers;
};
vector<string> Game ::addPlayer_Pure(const string &playerName,
const vector<string> &thePlayers) {
addPlayerNameToCollection_Lambda(playerName, thePlayers);
}
Inline
bool Game ::add(string playerName) {
players = addPlayerNameToCollection_Lambda(playerName, players);
places[howManyPlayers()] = 0;
purses[howManyPlayers()] = 0;
inPenaltyBox[howManyPlayers()] = false;
cout << playerName << ” was added” << endl;
cout << ”They are player number ” << players.size() << endl;
return true;
}
List of mechanics (work in progress)
• extract method -> make const -> make static -> introduce parameter -> turn to lambda
• state change -> newValue = computeNewValue(oldValue)
• if( ...){ ...}else{ ...} -> result = decide( ...)
• if( ...){ ...} -> std ::optional
• I/O -> void outputSomething( ...) or int readSomething( ...)
Step 2: Test pure functions
Data-driven tests
// Groovy and Spock
class MathSpec extends Specification {
def ”maximum of two numbers”(int a, int b, int c) {
expect:
Math.max(a, b) c
where:
a | b | c
1 | 3 | 3
7 | 4 | 7
0 | 0 | 0
}
}
C++ with doctest
// chapter 11, ”Hands-on Functional Programming with C ”
TEST_CASE(”1 raised to a power is 1”){
int exponent;
SUBCASE(”0”){
exponent = 0;
}
SUBCASE(”1”){
exponent = 1;
}
...
CAPTURE(exponent);
CHECK_EQ(1, power(1, exponent));
}
Property-based tests
// chapter 11, ”Hands-on Functional Programming with C ”
TEST_CASE(”Properties”){
cout << ”Property: 0 to power 0 is 1” << endl;
CHECK(property_0_to_power_0_is_1);
...
cout << ”Property: any int to power 1 is the value” << endl;
check_property(
generate_ints_greater_than_0,
prop_any_int_to_power_1_is_the_value, ”generate ints”
);
}
Property
// chapter 11, ”Hands-on Functional Programming with C ”
auto prop_any_int_to_power_1_is_the_value = [](const int base){
return power(base, 1) base;
};
Step 3: Pure functions to classes
Equivalence
A class is a set of partially applied, cohesive pure functions
Example
// Pseudocode
class Player{
string name;
int score;
Player(string name, int score) : name(name), score(score){}
void printName() const {
cout << name << endl;
}
}
Equivalent with
auto printName = [string name]() -> void {
cout << name << endl;
}
auto printName = [](string name) -> void {
cout << name<< endl;
}
Identify cohesive pure functions
// Similarity in names: Player
auto printPlayerName = [](string playerName) -> void {
...
}
auto computePlayerScore = []( ...) -> {
...
}
Identify cohesive pure functions
// Similarity in parameter list
auto doSomethingWithPlayerNameAndScore =
[](string playerName, int playerScore) -> {
...
}
auto doSomethingElseWithPlayerNameAndScore =
[](string playerName, int playerScore) -> {
...
}
Refactoring steps
• Create class
• Move functions into class
• Common parameters -> data members
• Add constructor
• Remember: you have tests now!
Final Thoughts
Evaluation
I believe it can be:
• faster to learn: around 10 - 20 mechanics to practice
• faster to refactor: eliminate dependencies while moving to pure functions
• easier to write tests: fundamentally data tables
• safer to refactor to classes
Careful
• Introducing unexpected side effects
• Temporal coupling
• Global state
Caveats
• discipline & practice is required
• does not solve all the problems
• the resulting design doesn’t follow “Tell, don’t ask”
Is it safe?
More testing required
More Information
“Think. Design. Work Smart.” YouTube Channel
https://www.youtube.com/channel/UCSEkgmzFb4PnaGAVXtK8dGA/
Codecast ep. 1: https://youtu.be/FyZ_Tcuujx8
Video “Pure functions as nominal form for software design” https://youtu.be/l9GOtbhYaJ8
Questions
Win a book (more at “ask the speakers”)
Photo Attribution
https://unsplash.com/@alexagorn?utm_source=unsplash&utm_medium=referral&utm_content=creditCop
https://fthmb.tqn.com/5Jqt2NdU5fjtcwhy6FwNg26yVRg=/1500x1167/filters:fill(auto,1)/yoda-
56a8f97a3df78cf772a263b4.jpg
https://aleteiaen.files.wordpress.com/2017/09/web3-praying-hands-work-computer-desk-office-
prayer-shutterstock.jpg?quality=100&strip=all
https://docs.microsoft.com/en-us/azure/architecture/patterns/_images/strangler.png
https://images.unsplash.com/photo-1526814642650-e274fe637fe7?ixlib=rb-
1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80
https://images.unsplash.com/photo-1536158525388-65ad2110afc8?ixlib=rb-
1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80
https://cdn.pixabay.com/photo/2019/11/25/21/24/switch-4653056_960_720.jpg

More Related Content

What's hot

Next Generation Developer Testing: Parameterized Testing
Next Generation Developer Testing: Parameterized TestingNext Generation Developer Testing: Parameterized Testing
Next Generation Developer Testing: Parameterized TestingTao Xie
 
Making Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVMMaking Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVMRafael Winterhalter
 
Kotlin: Why Do You Care?
Kotlin: Why Do You Care?Kotlin: Why Do You Care?
Kotlin: Why Do You Care?intelliyole
 
つくってあそぼ Kotlin DSL 第2版
つくってあそぼ Kotlin DSL 第2版つくってあそぼ Kotlin DSL 第2版
つくってあそぼ Kotlin DSL 第2版kamedon39
 
Spock Testing Framework - The Next Generation
Spock Testing Framework - The Next GenerationSpock Testing Framework - The Next Generation
Spock Testing Framework - The Next GenerationBTI360
 
Principles of the Play framework
Principles of the Play frameworkPrinciples of the Play framework
Principles of the Play frameworkBernhard Huemer
 
Object Oriented Exploitation: New techniques in Windows mitigation bypass
Object Oriented Exploitation: New techniques in Windows mitigation bypassObject Oriented Exploitation: New techniques in Windows mitigation bypass
Object Oriented Exploitation: New techniques in Windows mitigation bypassSam Thomas
 
Smarter Testing With Spock
Smarter Testing With SpockSmarter Testing With Spock
Smarter Testing With SpockIT Weekend
 
Club of anonimous developers "Refactoring: Legacy code"
Club of anonimous developers "Refactoring: Legacy code"Club of anonimous developers "Refactoring: Legacy code"
Club of anonimous developers "Refactoring: Legacy code"Victor_Cr
 
Important java programs(collection+file)
Important java programs(collection+file)Important java programs(collection+file)
Important java programs(collection+file)Alok Kumar
 
Spock: Test Well and Prosper
Spock: Test Well and ProsperSpock: Test Well and Prosper
Spock: Test Well and ProsperKen Kousen
 
Java 8: the good, the bad and the ugly (Oracle Code Brussels 2017)
Java 8: the good, the bad and the ugly (Oracle Code Brussels 2017)Java 8: the good, the bad and the ugly (Oracle Code Brussels 2017)
Java 8: the good, the bad and the ugly (Oracle Code Brussels 2017)Brian Vermeer
 
Advanced Java Practical File
Advanced Java Practical FileAdvanced Java Practical File
Advanced Java Practical FileSoumya Behera
 

What's hot (19)

Next Generation Developer Testing: Parameterized Testing
Next Generation Developer Testing: Parameterized TestingNext Generation Developer Testing: Parameterized Testing
Next Generation Developer Testing: Parameterized Testing
 
Making Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVMMaking Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVM
 
Kotlin: Why Do You Care?
Kotlin: Why Do You Care?Kotlin: Why Do You Care?
Kotlin: Why Do You Care?
 
つくってあそぼ Kotlin DSL 第2版
つくってあそぼ Kotlin DSL 第2版つくってあそぼ Kotlin DSL 第2版
つくってあそぼ Kotlin DSL 第2版
 
Spock Framework
Spock FrameworkSpock Framework
Spock Framework
 
Es.next
Es.nextEs.next
Es.next
 
Migrating to JUnit 5
Migrating to JUnit 5Migrating to JUnit 5
Migrating to JUnit 5
 
Unit testing concurrent code
Unit testing concurrent codeUnit testing concurrent code
Unit testing concurrent code
 
Spock Testing Framework - The Next Generation
Spock Testing Framework - The Next GenerationSpock Testing Framework - The Next Generation
Spock Testing Framework - The Next Generation
 
java sockets
 java sockets java sockets
java sockets
 
Principles of the Play framework
Principles of the Play frameworkPrinciples of the Play framework
Principles of the Play framework
 
Object Oriented Exploitation: New techniques in Windows mitigation bypass
Object Oriented Exploitation: New techniques in Windows mitigation bypassObject Oriented Exploitation: New techniques in Windows mitigation bypass
Object Oriented Exploitation: New techniques in Windows mitigation bypass
 
Smarter Testing With Spock
Smarter Testing With SpockSmarter Testing With Spock
Smarter Testing With Spock
 
Club of anonimous developers "Refactoring: Legacy code"
Club of anonimous developers "Refactoring: Legacy code"Club of anonimous developers "Refactoring: Legacy code"
Club of anonimous developers "Refactoring: Legacy code"
 
Important java programs(collection+file)
Important java programs(collection+file)Important java programs(collection+file)
Important java programs(collection+file)
 
Kotlin decompiled
Kotlin decompiledKotlin decompiled
Kotlin decompiled
 
Spock: Test Well and Prosper
Spock: Test Well and ProsperSpock: Test Well and Prosper
Spock: Test Well and Prosper
 
Java 8: the good, the bad and the ugly (Oracle Code Brussels 2017)
Java 8: the good, the bad and the ugly (Oracle Code Brussels 2017)Java 8: the good, the bad and the ugly (Oracle Code Brussels 2017)
Java 8: the good, the bad and the ugly (Oracle Code Brussels 2017)
 
Advanced Java Practical File
Advanced Java Practical FileAdvanced Java Practical File
Advanced Java Practical File
 

Similar to Refactor legacy code through pure functions

Paradigma FP y OOP usando técnicas avanzadas de Programación | Programacion A...
Paradigma FP y OOP usando técnicas avanzadas de Programación | Programacion A...Paradigma FP y OOP usando técnicas avanzadas de Programación | Programacion A...
Paradigma FP y OOP usando técnicas avanzadas de Programación | Programacion A...Víctor Bolinches
 
Learn Python 3 for absolute beginners
Learn Python 3 for absolute beginnersLearn Python 3 for absolute beginners
Learn Python 3 for absolute beginnersKingsleyAmankwa
 
Python in 30 minutes!
Python in 30 minutes!Python in 30 minutes!
Python in 30 minutes!Fariz Darari
 
Question 1 1 pts Skip to question text.As part of a bank account.docx
Question 1 1 pts Skip to question text.As part of a bank account.docxQuestion 1 1 pts Skip to question text.As part of a bank account.docx
Question 1 1 pts Skip to question text.As part of a bank account.docxamrit47
 
Unit Testing JavaScript Applications
Unit Testing JavaScript ApplicationsUnit Testing JavaScript Applications
Unit Testing JavaScript ApplicationsYnon Perek
 
FITC '14 Toronto - Technology, a means to an end
FITC '14 Toronto - Technology, a means to an endFITC '14 Toronto - Technology, a means to an end
FITC '14 Toronto - Technology, a means to an endThibault Imbert
 
Technology: A Means to an End with Thibault Imbert
Technology: A Means to an End with Thibault ImbertTechnology: A Means to an End with Thibault Imbert
Technology: A Means to an End with Thibault ImbertFITC
 
ECMAScript.Next ECMAScipt 6
ECMAScript.Next ECMAScipt 6ECMAScript.Next ECMAScipt 6
ECMAScript.Next ECMAScipt 6Kevin DeRudder
 
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...Charles Nutter
 
Extreme Swift
Extreme SwiftExtreme Swift
Extreme SwiftMovel
 
A la découverte de TypeScript
A la découverte de TypeScriptA la découverte de TypeScript
A la découverte de TypeScriptDenis Voituron
 
JavaOne 2012 - JVM JIT for Dummies
JavaOne 2012 - JVM JIT for DummiesJavaOne 2012 - JVM JIT for Dummies
JavaOne 2012 - JVM JIT for DummiesCharles Nutter
 
JS Responsibilities
JS ResponsibilitiesJS Responsibilities
JS ResponsibilitiesBrendan Eich
 
20.1 Java working with abstraction
20.1 Java working with abstraction20.1 Java working with abstraction
20.1 Java working with abstractionIntro C# Book
 
How do you create a programming language for the JVM?
How do you create a programming language for the JVM?How do you create a programming language for the JVM?
How do you create a programming language for the JVM?Federico Tomassetti
 
The Challenge of Bringing FEZ to PlayStation Platforms
The Challenge of Bringing FEZ to PlayStation PlatformsThe Challenge of Bringing FEZ to PlayStation Platforms
The Challenge of Bringing FEZ to PlayStation PlatformsMiguel Angel Horna
 

Similar to Refactor legacy code through pure functions (20)

Paradigma FP y OOP usando técnicas avanzadas de Programación | Programacion A...
Paradigma FP y OOP usando técnicas avanzadas de Programación | Programacion A...Paradigma FP y OOP usando técnicas avanzadas de Programación | Programacion A...
Paradigma FP y OOP usando técnicas avanzadas de Programación | Programacion A...
 
Object calisthenics
Object calisthenicsObject calisthenics
Object calisthenics
 
Learn Python 3 for absolute beginners
Learn Python 3 for absolute beginnersLearn Python 3 for absolute beginners
Learn Python 3 for absolute beginners
 
Python in 30 minutes!
Python in 30 minutes!Python in 30 minutes!
Python in 30 minutes!
 
Question 1 1 pts Skip to question text.As part of a bank account.docx
Question 1 1 pts Skip to question text.As part of a bank account.docxQuestion 1 1 pts Skip to question text.As part of a bank account.docx
Question 1 1 pts Skip to question text.As part of a bank account.docx
 
Unit Testing JavaScript Applications
Unit Testing JavaScript ApplicationsUnit Testing JavaScript Applications
Unit Testing JavaScript Applications
 
Parameters
ParametersParameters
Parameters
 
FITC '14 Toronto - Technology, a means to an end
FITC '14 Toronto - Technology, a means to an endFITC '14 Toronto - Technology, a means to an end
FITC '14 Toronto - Technology, a means to an end
 
Technology: A Means to an End with Thibault Imbert
Technology: A Means to an End with Thibault ImbertTechnology: A Means to an End with Thibault Imbert
Technology: A Means to an End with Thibault Imbert
 
ECMAScript.Next ECMAScipt 6
ECMAScript.Next ECMAScipt 6ECMAScript.Next ECMAScipt 6
ECMAScript.Next ECMAScipt 6
 
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
 
Structure on a freeform world
Structure on a freeform worldStructure on a freeform world
Structure on a freeform world
 
Extreme Swift
Extreme SwiftExtreme Swift
Extreme Swift
 
A la découverte de TypeScript
A la découverte de TypeScriptA la découverte de TypeScript
A la découverte de TypeScript
 
JavaOne 2012 - JVM JIT for Dummies
JavaOne 2012 - JVM JIT for DummiesJavaOne 2012 - JVM JIT for Dummies
JavaOne 2012 - JVM JIT for Dummies
 
JavaTalks: OOD principles
JavaTalks: OOD principlesJavaTalks: OOD principles
JavaTalks: OOD principles
 
JS Responsibilities
JS ResponsibilitiesJS Responsibilities
JS Responsibilities
 
20.1 Java working with abstraction
20.1 Java working with abstraction20.1 Java working with abstraction
20.1 Java working with abstraction
 
How do you create a programming language for the JVM?
How do you create a programming language for the JVM?How do you create a programming language for the JVM?
How do you create a programming language for the JVM?
 
The Challenge of Bringing FEZ to PlayStation Platforms
The Challenge of Bringing FEZ to PlayStation PlatformsThe Challenge of Bringing FEZ to PlayStation Platforms
The Challenge of Bringing FEZ to PlayStation Platforms
 

More from Alexandru Bolboaca (20)

Design Without Types
Design Without TypesDesign Without Types
Design Without Types
 
Thinking in Functions
Thinking in FunctionsThinking in Functions
Thinking in Functions
 
Raising the Bar
Raising the BarRaising the Bar
Raising the Bar
 
The Journey to Master Code Design
The Journey to Master Code DesignThe Journey to Master Code Design
The Journey to Master Code Design
 
What is good software design? And why it matters?
What is good software design? And why it matters?What is good software design? And why it matters?
What is good software design? And why it matters?
 
Functional programming in C++
Functional programming in C++Functional programming in C++
Functional programming in C++
 
Agile Technical Leadership
Agile Technical LeadershipAgile Technical Leadership
Agile Technical Leadership
 
TDD As If You Meant It
TDD As If You Meant ItTDD As If You Meant It
TDD As If You Meant It
 
Usable Software Design
Usable Software DesignUsable Software Design
Usable Software Design
 
Hidden loops
Hidden loopsHidden loops
Hidden loops
 
Removing structural duplication
Removing structural duplicationRemoving structural duplication
Removing structural duplication
 
Continuous delivery
Continuous deliveryContinuous delivery
Continuous delivery
 
Why You Should Start Using Docker
Why You Should Start Using DockerWhy You Should Start Using Docker
Why You Should Start Using Docker
 
Pyramid of-developer-skills
Pyramid of-developer-skillsPyramid of-developer-skills
Pyramid of-developer-skills
 
Applied craftsmanship
Applied craftsmanshipApplied craftsmanship
Applied craftsmanship
 
Pyramid of-developer-skills
Pyramid of-developer-skillsPyramid of-developer-skills
Pyramid of-developer-skills
 
Stay focused
Stay focusedStay focused
Stay focused
 
Kanban intro
Kanban introKanban intro
Kanban intro
 
Unit testing-patterns
Unit testing-patternsUnit testing-patterns
Unit testing-patterns
 
Incremental design, simply explained
Incremental design, simply explainedIncremental design, simply explained
Incremental design, simply explained
 

Recently uploaded

Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...gurkirankumar98700
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGSujit Pal
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 

Recently uploaded (20)

Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
Kalyanpur ) Call Girls in Lucknow Finest Escorts Service 🍸 8923113531 🎰 Avail...
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAG
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 

Refactor legacy code through pure functions

  • 1. Refactor Legacy Code Through Pure Functions Alex Bolboaca, CTO, Trainer and Coach at Mozaic Works  alexboly  https://mozaicworks.com  alex.bolboaca@mozaicworks.com . . . . . . . . . . . . . . . . . . . .
  • 2. The Problem Of Legacy Code Existing Methods Disadvantages of existing methods Step 1: To pure functions Step 2: Test pure functions Step 3: Pure functions to classes Final Thoughts
  • 3. The Problem Of Legacy Code
  • 4. Legacy Code is everywhere Depiction of legacy code
  • 5. Legacy Code erodes the will of programmers
  • 6. What is Legacy Code? Michael Feathers: “Any piece of code that doesn’t have automated tests”
  • 7. Generalized Definition Alex Bolboaca: “Any piece of code that you are afraid to change”
  • 8. Legacy Code leads to the Dark Side Yoda: “Fear leads to anger. Anger leads to hate. Hate leads to suffering.”
  • 10. “Change and pray” method If it works for you, great. Is it repeatable and transferrable though?
  • 11. “No more changes” method Freeze code, nobody touches it. Works with strangler pattern
  • 12. Strangler Pattern Strangle the existing code with a new implementation until the new implementation works fine.
  • 13. Michael Feathers’ Refactoring method Identify seams -> small, safe refactorings -> write characterization tests -> refactor code to desired design
  • 16. Legacy Code is Messy Often multiple methods required, and time consuming
  • 17. Existing methods require multiple rare skills • How to identify and “abuse” seams • How to write characterization tests • How to imagine a good design solution • How to refactor in small steps • Lots of imagination
  • 18. Learning the methods takes long Months, maybe years of practice
  • 19. 3 Poor Choices • Live with the code you’re afraid to change (and slow down development) • Refactor the code unsafely (spoilers: you will probably fail) • Use a safe method (spoilers: it’s slow)
  • 20. I’m proposing a new method • Refactor code to pure functions • Write data-driven or property based tests on the pure functions • Refactor pure functions to classes (or something else)
  • 21. Step 1: To pure functions
  • 22. What is a pure function? • Returns same output values for the same input values • Does not depend on state
  • 23. Example of Pure Functions int add(const int first, const int second){ return first + second; }
  • 24. Example of Impure Function int addToFirst(int& first, const int second){ first+=second; return first; }
  • 25. Example of “Tolerated” Pure Function int increment(int first){ return first; //state change, local to the function }
  • 26. Why pure functions? When you turn your switch on, the water doesn’t start on your sink
  • 27. Why pure functions? • Pure functions are boring • Pure functions have no dependencies • Pure functions are easy to test • Any program can be written as a combination of: pure functions + I/O functions • We can take advantage of lambda operations with pure functions: functional composition, currying, binding
  • 28. Why Pure functions? The hardest part of writing characterization tests (M. Feathers’ method) is dealing with dependencies. Pure functions make dependencies obvious and explicit.
  • 29. Refactor to pure functions • Pick a code block • Extract method (refactoring) • Make it immutable (add consts) • Make it static and introduce parameters if needed • Replace with lambda Remember: this is an intermediary step. We ignore for now design and performance, we just want to reduce dependencies and increase testability
  • 30. Example Game ::Game() : currentPlayer(0), places{}, purses{} { for (int i = 0; i < 50; i ) { ostringstream oss(ostringstream ::out); oss << ”Pop Question ” << i; popQuestions.push_back(oss.str()); char str[255]; sprintf(str, ”Science Question %d”, i); scienceQuestions.push_back(str); char str1[255]; sprintf(str1, ”Sports Question %d”, i); sportsQuestions.push_back(str1); rockQuestions.push_back(createRockQuestion(i)); } }
  • 31. 1. Pick a code block ostringstream oss(ostringstream ::out); oss << ”Pop Question ” << i; popQuestions.push_back(oss.str());
  • 32. 2. Extract method void Game ::doSomething(int i) { ostringstream oss(ostringstream ::out); oss << ”Pop Question ” << i; popQuestions.push_back(oss.str()); }
  • 33. 3. Try to make it immutable: const parameter void Game ::doSomething(const int i) { ostringstream oss(ostringstream ::out); oss << ”Pop Question ” << i; popQuestions.push_back(oss.str()); }
  • 34. 3. Try to make it immutable: const function void Game ::doSomething(const int i) const { ostringstream oss(ostringstream ::out); oss << ”Pop Question ” << i; //! Compilation Error: state change popQuestions.push_back(oss.str()); }
  • 35. Revert change void Game ::doSomething(const int i) { ostringstream oss(ostringstream ::out); oss << ”Pop Question ” << i; popQuestions.push_back(oss.str()); }
  • 36. Separate the pure from impure part void Game ::doSomething(const int i) { // Pure function ostringstream oss(ostringstream ::out); oss << ”Pop Question ” << i; const string &popQuestion = oss.str(); // State change popQuestions.push_back(popQuestion); }
  • 37. Extract pure function void Game ::doSomething(const int i) { string popQuestion = createPopQuestion(i); popQuestions.push_back(popQuestion); } string Game ::createPopQuestion(const int i) const { ostringstream oss(ostringstream ::out); oss << ”Pop Question ” << i; const string &popQuestion = oss.str(); return popQuestion; }
  • 38. Inline initial function Game ::Game() : currentPlayer(0), places{}, purses{} { for (int i = 0; i < 50; i ) { const string popQuestion = createPopQuestion(i); popQuestions.push_back(popQuestion); ... } }
  • 39. Back to the pure function string Game ::createPopQuestion(const int i) const { ostringstream oss(ostringstream ::out); oss << ”Pop Question ” << i; const string &popQuestion = oss.str(); return popQuestion; }
  • 40. Some simplification string Game ::createPopQuestion(const int i) const { ostringstream oss(ostringstream ::out); oss << ”Pop Question ” << i; return oss.str(); }
  • 41. Transform to lambda auto createPopQuestion_Lambda = [](const int i) -> string { ostringstream oss(ostringstream ::out); oss << ”Pop Question ” << i; return oss.str(); }; string Game ::createPopQuestion(const int i) const { createPopQuestion_Lambda(i); }
  • 42. Move lambda up and inline method Game ::Game() : currentPlayer(0), places{}, purses{} { for (int i = 0; i < 50; i ) { popQuestions.push_back(createPopQuestion_Lambda(i)); char str[255]; sprintf(str, ”Science Question %d”, i); scienceQuestions.push_back(str); ... } }
  • 43. Let’s stop and evaluate Refactorings: extract method, inline, change signature, turn to lambda
  • 44. The compiler helps us The compiler tells us the function dependencies
  • 45. Mechanical process - or engineering procedure Mechanical process
  • 46. The result // Pure function // No dependencies auto createPopQuestion_Lambda = [](const int i) -> string { ostringstream oss(ostringstream ::out); oss << ”Pop Question ” << i; return oss.str(); };
  • 47. What about state changes? bool Game ::add(string playerName) { players.push_back(playerName); places[howManyPlayers()] = 0; purses[howManyPlayers()] = 0; inPenaltyBox[howManyPlayers()] = false; cout << playerName << ” was added” << endl; cout << ”They are player number ” << players.size() << endl; return true; }
  • 48. Pick code that makes the state change bool Game ::add(string playerName) { // State change players.push_back(playerName); // State change places[howManyPlayers()] = 0; // State change purses[howManyPlayers()] = 0; // State change inPenaltyBox[howManyPlayers()] = false; // I/O cout << playerName << ” was added” << endl; cout << ”They are player number ” << players.size() << endl; return true; }
  • 49. Extract method void Game ::addPlayerNameToPlayersList(const string &playerName) { players.push_back(playerName); }
  • 50. Extract initial value void Game ::addPlayerNameToPlayersList(const string &playerName) { // Copy initial value of players vector<string> &initialPlayers(players); // Modify the copy initialPlayers.push_back(playerName); // Set the data member to the new value players = initialPlayers; }
  • 51. Separate pure from impure void Game ::addPlayerNameToPlayersList(const string &playerName) { vector<string> initialPlayers = addPlayer_Pure(playerName); players = initialPlayers; } vector<string> Game ::addPlayer_Pure(const string &playerName) const { vector<string> initialPlayers(players); initialPlayers.push_back(playerName); return initialPlayers; }
  • 52. Inline computation void Game ::addPlayerNameToPlayersList(const string &playerName) { players = addPlayer_Pure(playerName); }
  • 53. Inline method bool Game ::add(string playerName) { players = addPlayer_Pure(playerName); places[howManyPlayers()] = 0; purses[howManyPlayers()] = 0; inPenaltyBox[howManyPlayers()] = false; cout << playerName << ” was added” << endl; cout << ”They are player number ” << players.size() << endl; return true; }
  • 54. Make static vector<string> Game ::addPlayer_Pure(const string &playerName) { // Compilation error: players unavailable vector<string> initialPlayers(players); initialPlayers.push_back(playerName); return initialPlayers; }
  • 55. Undo static & Introduce parameter vector<string> Game ::addPlayer_Pure( const string &playerName, const vector<string> &thePlayers) { vector<string> initialPlayers(thePlayers); initialPlayers.push_back(playerName); return initialPlayers; }
  • 56. Move to lambda auto addPlayerNameToCollection_Lambda = [](const string &playerName, const vector<string> &thePlayers) -> vector<string> { vector<string> initialPlayers(thePlayers); initialPlayers.push_back(playerName); return initialPlayers; }; vector<string> Game ::addPlayer_Pure(const string &playerName, const vector<string> &thePlayers) { addPlayerNameToCollection_Lambda(playerName, thePlayers); }
  • 57. Inline bool Game ::add(string playerName) { players = addPlayerNameToCollection_Lambda(playerName, players); places[howManyPlayers()] = 0; purses[howManyPlayers()] = 0; inPenaltyBox[howManyPlayers()] = false; cout << playerName << ” was added” << endl; cout << ”They are player number ” << players.size() << endl; return true; }
  • 58. List of mechanics (work in progress) • extract method -> make const -> make static -> introduce parameter -> turn to lambda • state change -> newValue = computeNewValue(oldValue) • if( ...){ ...}else{ ...} -> result = decide( ...) • if( ...){ ...} -> std ::optional • I/O -> void outputSomething( ...) or int readSomething( ...)
  • 59. Step 2: Test pure functions
  • 60. Data-driven tests // Groovy and Spock class MathSpec extends Specification { def ”maximum of two numbers”(int a, int b, int c) { expect: Math.max(a, b) c where: a | b | c 1 | 3 | 3 7 | 4 | 7 0 | 0 | 0 } }
  • 61. C++ with doctest // chapter 11, ”Hands-on Functional Programming with C ” TEST_CASE(”1 raised to a power is 1”){ int exponent; SUBCASE(”0”){ exponent = 0; } SUBCASE(”1”){ exponent = 1; } ... CAPTURE(exponent); CHECK_EQ(1, power(1, exponent)); }
  • 62. Property-based tests // chapter 11, ”Hands-on Functional Programming with C ” TEST_CASE(”Properties”){ cout << ”Property: 0 to power 0 is 1” << endl; CHECK(property_0_to_power_0_is_1); ... cout << ”Property: any int to power 1 is the value” << endl; check_property( generate_ints_greater_than_0, prop_any_int_to_power_1_is_the_value, ”generate ints” ); }
  • 63. Property // chapter 11, ”Hands-on Functional Programming with C ” auto prop_any_int_to_power_1_is_the_value = [](const int base){ return power(base, 1) base; };
  • 64. Step 3: Pure functions to classes
  • 65. Equivalence A class is a set of partially applied, cohesive pure functions
  • 66. Example // Pseudocode class Player{ string name; int score; Player(string name, int score) : name(name), score(score){} void printName() const { cout << name << endl; } }
  • 67. Equivalent with auto printName = [string name]() -> void { cout << name << endl; } auto printName = [](string name) -> void { cout << name<< endl; }
  • 68. Identify cohesive pure functions // Similarity in names: Player auto printPlayerName = [](string playerName) -> void { ... } auto computePlayerScore = []( ...) -> { ... }
  • 69. Identify cohesive pure functions // Similarity in parameter list auto doSomethingWithPlayerNameAndScore = [](string playerName, int playerScore) -> { ... } auto doSomethingElseWithPlayerNameAndScore = [](string playerName, int playerScore) -> { ... }
  • 70. Refactoring steps • Create class • Move functions into class • Common parameters -> data members • Add constructor • Remember: you have tests now!
  • 72. Evaluation I believe it can be: • faster to learn: around 10 - 20 mechanics to practice • faster to refactor: eliminate dependencies while moving to pure functions • easier to write tests: fundamentally data tables • safer to refactor to classes
  • 73. Careful • Introducing unexpected side effects • Temporal coupling • Global state
  • 74. Caveats • discipline & practice is required • does not solve all the problems • the resulting design doesn’t follow “Tell, don’t ask”
  • 75. Is it safe? More testing required
  • 76. More Information “Think. Design. Work Smart.” YouTube Channel https://www.youtube.com/channel/UCSEkgmzFb4PnaGAVXtK8dGA/ Codecast ep. 1: https://youtu.be/FyZ_Tcuujx8 Video “Pure functions as nominal form for software design” https://youtu.be/l9GOtbhYaJ8
  • 77. Questions Win a book (more at “ask the speakers”)
  • 78. Photo Attribution https://unsplash.com/@alexagorn?utm_source=unsplash&utm_medium=referral&utm_content=creditCop https://fthmb.tqn.com/5Jqt2NdU5fjtcwhy6FwNg26yVRg=/1500x1167/filters:fill(auto,1)/yoda- 56a8f97a3df78cf772a263b4.jpg https://aleteiaen.files.wordpress.com/2017/09/web3-praying-hands-work-computer-desk-office- prayer-shutterstock.jpg?quality=100&strip=all https://docs.microsoft.com/en-us/azure/architecture/patterns/_images/strangler.png https://images.unsplash.com/photo-1526814642650-e274fe637fe7?ixlib=rb- 1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80 https://images.unsplash.com/photo-1536158525388-65ad2110afc8?ixlib=rb- 1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80 https://cdn.pixabay.com/photo/2019/11/25/21/24/switch-4653056_960_720.jpg