SlideShare a Scribd company logo
1 of 28
Download to read offline
William Munn, CGFWB - @dubmun
Overview Hands-on coding
 Seed Code is written in C#
 Get it from Github:
https://github.com/KatasForLegacyCode/kCSharp/archive/Step0.zip
 Any version of Visual Studio 2012/2013/2015 that can run
console apps and unit tests.
 An nUnit test runner.
 I recommend nCrunch.
Perception - COBOL
Perception - COBOL Reality – Code W/O Unit tests
Expectation Hyperbole
Legacy Dependency Kata v2.0
Legacy Dependency Kata v2.0
Code Kata
A code kata is an exercise in
programming which helps a us
hone our skills through practice
and repetition.
The word kata is taken from
Japanese arts most traditionally
Martial Arts
Why a code kata? Because we
learn by doing.
Legacy Dependency Kata: V2.0
 Written in C#
 Less tool dependencies
 Better theme
 Easier to read and follow
 Bug fixes
DoItAllTests.cs
Database.cs
DoItAll.cs
UserDetails.cs
ConsoleAdapter.cs
Program.cs
Logger.cs
Existing Files
We Will
Create
Let’s start by getting the existing test running!
 Running the integration test FAILS
 Begin by abstracting and breaking the dependency on Console.Readline()
 We’ll use an adapter, but we could use the Console.SetIn method and a TextReader.
 Create an interface
public interface IConsoleAdapter
{
string GetInput();
}
 Create a class that implements the
interface & implement method to
handle our dependency
public class ConsoleAdapter : IConsoleAdapter
{
public string GetInput()
{
return Console.ReadLine();
}
}
ConsoleAdapter.cs
ConsoleAdapter.cs
DoItAll.cs
Did you know?
In software engineering,
the adapter pattern is a
software design pattern
that allows the interface
of an existing class to be
used as another
interface.
 Create new constructor to accept IConsoleAdapter & set private variable
private readonly IConsoleAdapter _consoleAdapter;
public DoItAll(IConsoleAdapter consoleAdapter)
{
_consoleAdapter = consoleAdapter;
}
 Replace 4 calls to Console.ReadLine() WITH _consoleAdapter.GetInput()
 Replace 2 calls to Console.ReadKey() WITH _consoleAdapter.GetInput()
DoItAll.cs
DoItAll.cs
DoItAll.cs
We have broken instantiations of DoItAll
 Instantiate and pass in our new handler
var doItAll = new DoItAll(new ConsoleAdapter());
Let’s update our integration test or it will also fail.
 Create a new implementation of IConsoleAdapter
public class DoItAllTests
{
[…]
var doItAll = new DoItAll(new FakeConsoleAdapter());
[…]
}
public class FakeConsoleAdapter : IConsoleAdapter
{
public string GetInput()
{
return string.Empty;
}
}
Program.cs
DoItAllTests.cs
 When the test is run we now get a meaningful exception. All of the
dependencies that caused the hang are gone.
 the test is now failing because the password is empty. This is a meaningful
case but let’s just update our fake for now.
public string GetInput()
{
return “someTestString”;
}
 Run the test
AND IT SHOULD BE GREEN!
DoItAllTests.cs
 Following good testing practice,
let’s add an assert:
[Test, Category("Integration")]
public void DoItAll_Does_ItAll()
{
var doItAll = new DoItAll(new FakeConsoleAdapter());
Assert.That(() => doItAll.Do(), Throws.Nothing);
}
 Our test should still pass.
DoItAllTests.cs
Some of our legacy code has no coverage and produces no quantifiable results
 Copy the existing test and rename it DoItAll_Fails_ToWriteToDB
[Test, Category("Integration")]
public void DoItAll_Does_ItAll()
{
[…]
}
[Test, Category("Integration")]
public void DoItAll_Fails_ToWriteToDB()
{
[…]
}
 Change the assert
Assert.That(doItAll.Do(), Is.StringContaining("Database.SaveToLog Exception:”));
 Build will fail because our Do() method returns void.
DoItAllTests.cs
DoItAllTests.cs
 Change Do()’s return type to string
public string Do()
 Add/update return statements in 3 locations:
public string Do()
{
[…]
if (_userDetails.PasswordEncrypted […])
{
[…]
return string.Empty;
}
[…]
{
[…]
using (var writer = new StreamWriter("log.txt", true))
{
[…]
return string.Empty;
}
}
[…]
return string.Empty;
}
DoItAll.cs
DoItAll.cs
 Now create variables to hold the messages to return
public string Do()
{
[…]
if (_userDetails.PasswordEncrypted […])
{
var passwordsDontMatch = "The passwords don't match.";
[…]
}
[…]
{
[…]
using (var writer = new StreamWriter("log.txt", true))
{
var errorMessage = string.Format("{0} - Database.SaveToLog Exception: rn{1}",
message, ex.Message);
[…]
}
}
[…]
}
DoItAll.cs
 Return the new values as appropriate
public string Do()
{
[…]
if (_userDetails.PasswordEncrypted […])
{
[…]
Console.WriteLine(passwordsDontMatch);
Console.ReadKey();
return passwordsDontMatch;
}
[…]
{
[…]
using (var writer = new StreamWriter("log.txt", true))
{
[…]
writer.WriteLine(errorMessage);
return errorMessage;
}
}
}
 Our new DoItAll_Fails_ToWriteToDB() test should pass
DoItAll.cs
Abstract Console completely
 Add a new method stub
void SetOutput(string output);
 Update ConsoleAdapter implementation
public void SetOutput(string output)
{
Console.WriteLine(output);
}
 Update FakeConsoleAdapter implementation
public void SetOutput(string output)
{}
 Update DoItAll Implementation
Replace 6 instances of Console.WriteLine AND Console.Write WITH
_consoleAdapter.SetOutput
ConsoleAdapter.cs
ConsoleAdapter.cs
DoItAllTests.cs
DoItAll.cs
OUR TESTS SHOULD STILL PASS
DoItAll.Do() is trying to do too much. Let’s Refactor!
 Extract logging functionality by creating a new interface
public interface ILogger
{
string LogMessage(string message);
}
 Create a new class implementing ILogger
public class Logger : ILogger
{
public string LogMessage(string message)
{
throw new NotImplementedException();
}
}
 Now extract the code in the try/catch block in DoItAll.Do() into the implementation of ILogger.LogMessage()
 Make sure all paths return a message
 Now update the constructor of DoItAll with an ILogger AND REPLACE TRY/CATCH:
message = _logger.LogMessage(message);
Logger.cs
Logger.cs
 Extract the code in the try/catch block in DoItAll.Do()
into the implementation of Logger.LogMessage()
Make sure all paths return a message
public string LogMessage(string message)
{
try
{
Database.SaveToLog(message);
}
catch (Exception ex)
{
// If database write fails, write to file
using (var writer = new StreamWriter("log.txt", true))
{
message = message + "nDatabase.SaveToLog Exception: " + ex.Message;
writer.WriteLine(message);
}
}
return message;
}
Logger.cs
 Update the constructor of DoItAll with an ILogger
public DoItAll(IOutputInputAdapter ioAdapter, ILogger logger)
{
_ioAdapter = ioAdapter;
_logger = logger;
}
[…]
private readonly ILogger _logger;
 Update the Do() method
public string Do()
{
[…]
_ioAdapter.SetOutput(message);
message = _logger.LogMessage(message);
return message;
}
DoItAll.cs
DoItAll.cs
We have broken instantiations of DoItAll
 Instantiate and pass in our new handler
var doItAll = new DoItAll(new ConsoleAdapter(), new Logger());
Let’s update our tests or they will also fail.
 Create a new implementation of ILogger
public class DoItAllTests
{
[…]
var doItAll = new DoItAll(new FakeConsoleAdapter(), new FakeLogger());
[…]
}
[…]
public class FakeLogger : ILogger
{
public string LogMessage(
string message)
{
return string.Empty;
}
}
Program.cs
DoItAllTests.cs
OUR FIRST TEST PASSES, BUT THE SECOND FAILS
 Copy the second test and rename the copy
DoItAll_Succeeds_WithMockLogging
 Update the copied assert
Assert.That(doItAll.Do(), Is.EqualTo(string.Empty));
 Let the original test remain an integration test by depending on
Logger and it will pass as well
DoItAllTests.cs
DoItAllTests.cs
There is still plenty to refactor in this legacy code.
 What would you do next?
William Munn, CGFWB
@dubmun
dubmun
http://blog.dubmun.com
Resources
Michael Feathers
Roy Osherove
Robert C. Martin
Dave Thomas & Andy Hunt
Legacy Dependency Kata – V2.0

More Related Content

What's hot

Applying TDD to Legacy Code
Applying TDD to Legacy CodeApplying TDD to Legacy Code
Applying TDD to Legacy CodeAlexander Goida
 
The Ring programming language version 1.5.2 book - Part 176 of 181
The Ring programming language version 1.5.2 book - Part 176 of 181The Ring programming language version 1.5.2 book - Part 176 of 181
The Ring programming language version 1.5.2 book - Part 176 of 181Mahmoud Samir Fayed
 
Intro to TDD and BDD
Intro to TDD and BDDIntro to TDD and BDD
Intro to TDD and BDDJason Noble
 
Legacy Dependency Killer - Utah Code Camp 2014
Legacy Dependency Killer - Utah Code Camp 2014Legacy Dependency Killer - Utah Code Camp 2014
Legacy Dependency Killer - Utah Code Camp 2014dubmun
 
The Ring programming language version 1.5.4 book - Part 180 of 185
The Ring programming language version 1.5.4 book - Part 180 of 185The Ring programming language version 1.5.4 book - Part 180 of 185
The Ring programming language version 1.5.4 book - Part 180 of 185Mahmoud Samir Fayed
 
Code Kata: String Calculator in Flex
Code Kata: String Calculator in FlexCode Kata: String Calculator in Flex
Code Kata: String Calculator in FlexChris Farrell
 
Droidcon ES '16 - How to fail going offline
Droidcon ES '16 - How to fail going offlineDroidcon ES '16 - How to fail going offline
Droidcon ES '16 - How to fail going offlineJavier de Pedro López
 
Creating Enterprise Web Applications with Node.js
Creating Enterprise Web Applications with Node.jsCreating Enterprise Web Applications with Node.js
Creating Enterprise Web Applications with Node.jsSebastian Springer
 
JavaFX8 TestFX - CDI
JavaFX8   TestFX - CDIJavaFX8   TestFX - CDI
JavaFX8 TestFX - CDISven Ruppert
 
Rifartek Robot Training Course - How to use ClientRobot
Rifartek Robot Training Course - How to use ClientRobotRifartek Robot Training Course - How to use ClientRobot
Rifartek Robot Training Course - How to use ClientRobotTsai Tsung-Yi
 
TDD and the Legacy Code Black Hole
TDD and the Legacy Code Black HoleTDD and the Legacy Code Black Hole
TDD and the Legacy Code Black HoleNoam Kfir
 
Unit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJSUnit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJSKnoldus Inc.
 
Karate - powerful and simple framework for REST API automation testing
Karate - powerful and simple framework for REST API automation testingKarate - powerful and simple framework for REST API automation testing
Karate - powerful and simple framework for REST API automation testingRoman Liubun
 
Karate - Web-Service API Testing Made Simple
Karate - Web-Service API Testing Made SimpleKarate - Web-Service API Testing Made Simple
Karate - Web-Service API Testing Made SimpleVodqaBLR
 
Angular Optimization Web Performance Meetup
Angular Optimization Web Performance MeetupAngular Optimization Web Performance Meetup
Angular Optimization Web Performance MeetupDavid Barreto
 
Enhanced Web Service Testing: A Better Mock Structure
Enhanced Web Service Testing: A Better Mock StructureEnhanced Web Service Testing: A Better Mock Structure
Enhanced Web Service Testing: A Better Mock StructureCRMScienceKirk
 

What's hot (20)

Applying TDD to Legacy Code
Applying TDD to Legacy CodeApplying TDD to Legacy Code
Applying TDD to Legacy Code
 
The Ring programming language version 1.5.2 book - Part 176 of 181
The Ring programming language version 1.5.2 book - Part 176 of 181The Ring programming language version 1.5.2 book - Part 176 of 181
The Ring programming language version 1.5.2 book - Part 176 of 181
 
Bot builder v4 HOL
Bot builder v4 HOLBot builder v4 HOL
Bot builder v4 HOL
 
Intro to TDD and BDD
Intro to TDD and BDDIntro to TDD and BDD
Intro to TDD and BDD
 
Legacy Dependency Killer - Utah Code Camp 2014
Legacy Dependency Killer - Utah Code Camp 2014Legacy Dependency Killer - Utah Code Camp 2014
Legacy Dependency Killer - Utah Code Camp 2014
 
The Ring programming language version 1.5.4 book - Part 180 of 185
The Ring programming language version 1.5.4 book - Part 180 of 185The Ring programming language version 1.5.4 book - Part 180 of 185
The Ring programming language version 1.5.4 book - Part 180 of 185
 
Code Kata: String Calculator in Flex
Code Kata: String Calculator in FlexCode Kata: String Calculator in Flex
Code Kata: String Calculator in Flex
 
Droidcon ES '16 - How to fail going offline
Droidcon ES '16 - How to fail going offlineDroidcon ES '16 - How to fail going offline
Droidcon ES '16 - How to fail going offline
 
Creating Enterprise Web Applications with Node.js
Creating Enterprise Web Applications with Node.jsCreating Enterprise Web Applications with Node.js
Creating Enterprise Web Applications with Node.js
 
JavaFX8 TestFX - CDI
JavaFX8   TestFX - CDIJavaFX8   TestFX - CDI
JavaFX8 TestFX - CDI
 
Rifartek Robot Training Course - How to use ClientRobot
Rifartek Robot Training Course - How to use ClientRobotRifartek Robot Training Course - How to use ClientRobot
Rifartek Robot Training Course - How to use ClientRobot
 
TDD and the Legacy Code Black Hole
TDD and the Legacy Code Black HoleTDD and the Legacy Code Black Hole
TDD and the Legacy Code Black Hole
 
Unit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJSUnit Testing and Coverage for AngularJS
Unit Testing and Coverage for AngularJS
 
Test driving QML
Test driving QMLTest driving QML
Test driving QML
 
Reactive Java (33rd Degree)
Reactive Java (33rd Degree)Reactive Java (33rd Degree)
Reactive Java (33rd Degree)
 
Karate - powerful and simple framework for REST API automation testing
Karate - powerful and simple framework for REST API automation testingKarate - powerful and simple framework for REST API automation testing
Karate - powerful and simple framework for REST API automation testing
 
Karate - Web-Service API Testing Made Simple
Karate - Web-Service API Testing Made SimpleKarate - Web-Service API Testing Made Simple
Karate - Web-Service API Testing Made Simple
 
Angular Optimization Web Performance Meetup
Angular Optimization Web Performance MeetupAngular Optimization Web Performance Meetup
Angular Optimization Web Performance Meetup
 
Enhanced Web Service Testing: A Better Mock Structure
Enhanced Web Service Testing: A Better Mock StructureEnhanced Web Service Testing: A Better Mock Structure
Enhanced Web Service Testing: A Better Mock Structure
 
Test driving-qml
Test driving-qmlTest driving-qml
Test driving-qml
 

Similar to Legacy Dependency Kata v2.0

OpenDaylight Developer Experience 2.0
 OpenDaylight Developer Experience 2.0 OpenDaylight Developer Experience 2.0
OpenDaylight Developer Experience 2.0Michael Vorburger
 
Tdd is not about testing (OOP)
Tdd is not about testing (OOP)Tdd is not about testing (OOP)
Tdd is not about testing (OOP)Gianluca Padovani
 
Code quality
Code qualityCode quality
Code quality44ue
 
JVM Mechanics: When Does the JVM JIT & Deoptimize?
JVM Mechanics: When Does the JVM JIT & Deoptimize?JVM Mechanics: When Does the JVM JIT & Deoptimize?
JVM Mechanics: When Does the JVM JIT & Deoptimize?Doug Hawkins
 
Of complicacy of programming, or won't C# save us?
Of complicacy of programming, or won't C# save us?Of complicacy of programming, or won't C# save us?
Of complicacy of programming, or won't C# save us?PVS-Studio
 
Swift 2.0: Apple’s Advanced Programming Platform for Developers
Swift 2.0: Apple’s Advanced Programming Platform for DevelopersSwift 2.0: Apple’s Advanced Programming Platform for Developers
Swift 2.0: Apple’s Advanced Programming Platform for DevelopersAzilen Technologies Pvt. Ltd.
 
Google C++ Testing Framework in Visual Studio 2008
Google C++ Testing Framework in Visual Studio 2008Google C++ Testing Framework in Visual Studio 2008
Google C++ Testing Framework in Visual Studio 2008Andrea Francia
 
Journey to JavaScript (from C#)
Journey to JavaScript (from C#)Journey to JavaScript (from C#)
Journey to JavaScript (from C#)Ed Charbeneau
 
AKiOSMagic Manual
AKiOSMagic ManualAKiOSMagic Manual
AKiOSMagic ManualAlex Kir
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Developmentguestc8093a6
 
Gradle plugin, take control of the build
Gradle plugin, take control of the buildGradle plugin, take control of the build
Gradle plugin, take control of the buildEyal Lezmy
 
Presentation slides: "How to get 100% code coverage"
Presentation slides: "How to get 100% code coverage" Presentation slides: "How to get 100% code coverage"
Presentation slides: "How to get 100% code coverage" Rapita Systems Ltd
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to javaciklum_ods
 
New Features Of JDK 7
New Features Of JDK 7New Features Of JDK 7
New Features Of JDK 7Deniz Oguz
 
Javaone2008 Bof 5101 Groovytesting
Javaone2008 Bof 5101 GroovytestingJavaone2008 Bof 5101 Groovytesting
Javaone2008 Bof 5101 GroovytestingAndres Almiray
 
Boosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with GroovyBoosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with GroovyJames Williams
 

Similar to Legacy Dependency Kata v2.0 (20)

OpenDaylight Developer Experience 2.0
 OpenDaylight Developer Experience 2.0 OpenDaylight Developer Experience 2.0
OpenDaylight Developer Experience 2.0
 
Tdd is not about testing (OOP)
Tdd is not about testing (OOP)Tdd is not about testing (OOP)
Tdd is not about testing (OOP)
 
Code quality
Code qualityCode quality
Code quality
 
JVM Mechanics: When Does the JVM JIT & Deoptimize?
JVM Mechanics: When Does the JVM JIT & Deoptimize?JVM Mechanics: When Does the JVM JIT & Deoptimize?
JVM Mechanics: When Does the JVM JIT & Deoptimize?
 
Software Engineering
Software EngineeringSoftware Engineering
Software Engineering
 
Of complicacy of programming, or won't C# save us?
Of complicacy of programming, or won't C# save us?Of complicacy of programming, or won't C# save us?
Of complicacy of programming, or won't C# save us?
 
Swift 2.0: Apple’s Advanced Programming Platform for Developers
Swift 2.0: Apple’s Advanced Programming Platform for DevelopersSwift 2.0: Apple’s Advanced Programming Platform for Developers
Swift 2.0: Apple’s Advanced Programming Platform for Developers
 
Google C++ Testing Framework in Visual Studio 2008
Google C++ Testing Framework in Visual Studio 2008Google C++ Testing Framework in Visual Studio 2008
Google C++ Testing Framework in Visual Studio 2008
 
It's always your fault
It's always your faultIt's always your fault
It's always your fault
 
Journey to JavaScript (from C#)
Journey to JavaScript (from C#)Journey to JavaScript (from C#)
Journey to JavaScript (from C#)
 
AKiOSMagic Manual
AKiOSMagic ManualAKiOSMagic Manual
AKiOSMagic Manual
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
 
Gradle plugin, take control of the build
Gradle plugin, take control of the buildGradle plugin, take control of the build
Gradle plugin, take control of the build
 
Presentation slides: "How to get 100% code coverage"
Presentation slides: "How to get 100% code coverage" Presentation slides: "How to get 100% code coverage"
Presentation slides: "How to get 100% code coverage"
 
Javascript Best Practices
Javascript Best PracticesJavascript Best Practices
Javascript Best Practices
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to java
 
New Features Of JDK 7
New Features Of JDK 7New Features Of JDK 7
New Features Of JDK 7
 
Java bad coding practices
Java bad coding practicesJava bad coding practices
Java bad coding practices
 
Javaone2008 Bof 5101 Groovytesting
Javaone2008 Bof 5101 GroovytestingJavaone2008 Bof 5101 Groovytesting
Javaone2008 Bof 5101 Groovytesting
 
Boosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with GroovyBoosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with Groovy
 

Recently uploaded

Take Advantage of Mx Tracking Flight Scheduling Solutions to Streamline Your ...
Take Advantage of Mx Tracking Flight Scheduling Solutions to Streamline Your ...Take Advantage of Mx Tracking Flight Scheduling Solutions to Streamline Your ...
Take Advantage of Mx Tracking Flight Scheduling Solutions to Streamline Your ...MyFAA
 
MUT4SLX: Extensions for Mutation Testing of Stateflow Models
MUT4SLX: Extensions for Mutation Testing of Stateflow ModelsMUT4SLX: Extensions for Mutation Testing of Stateflow Models
MUT4SLX: Extensions for Mutation Testing of Stateflow ModelsUniversity of Antwerp
 
Practical Advice for FDA’s 510(k) Requirements.pdf
Practical Advice for FDA’s 510(k) Requirements.pdfPractical Advice for FDA’s 510(k) Requirements.pdf
Practical Advice for FDA’s 510(k) Requirements.pdfICS
 
Mobile App Development process | Expert Tips
Mobile App Development process | Expert TipsMobile App Development process | Expert Tips
Mobile App Development process | Expert Tipsmichealwillson701
 
Splashtop Enterprise Brochure - Remote Computer Access and Remote Support Sof...
Splashtop Enterprise Brochure - Remote Computer Access and Remote Support Sof...Splashtop Enterprise Brochure - Remote Computer Access and Remote Support Sof...
Splashtop Enterprise Brochure - Remote Computer Access and Remote Support Sof...Splashtop Inc
 
BusinessGPT - SECURITY AND GOVERNANCE FOR GENERATIVE AI.pptx
BusinessGPT  - SECURITY AND GOVERNANCE  FOR GENERATIVE AI.pptxBusinessGPT  - SECURITY AND GOVERNANCE  FOR GENERATIVE AI.pptx
BusinessGPT - SECURITY AND GOVERNANCE FOR GENERATIVE AI.pptxAGATSoftware
 
8 Steps to Build a LangChain RAG Chatbot.
8 Steps to Build a LangChain RAG Chatbot.8 Steps to Build a LangChain RAG Chatbot.
8 Steps to Build a LangChain RAG Chatbot.Ritesh Kanjee
 
BATbern52 Swisscom's Journey into Data Mesh
BATbern52 Swisscom's Journey into Data MeshBATbern52 Swisscom's Journey into Data Mesh
BATbern52 Swisscom's Journey into Data MeshBATbern
 
Revolutionize Your Field Service Management with FSM Grid
Revolutionize Your Field Service Management with FSM GridRevolutionize Your Field Service Management with FSM Grid
Revolutionize Your Field Service Management with FSM GridMathew Thomas
 
Unlocking AI: Navigating Open Source vs. Commercial Frontiers
Unlocking AI:Navigating Open Source vs. Commercial FrontiersUnlocking AI:Navigating Open Source vs. Commercial Frontiers
Unlocking AI: Navigating Open Source vs. Commercial FrontiersRaphaël Semeteys
 
Leveling Up your Branding and Mastering MERN: Fullstack WebDev
Leveling Up your Branding and Mastering MERN: Fullstack WebDevLeveling Up your Branding and Mastering MERN: Fullstack WebDev
Leveling Up your Branding and Mastering MERN: Fullstack WebDevpmgdscunsri
 
MinionLabs_Mr. Gokul Srinivas_Young Entrepreneur
MinionLabs_Mr. Gokul Srinivas_Young EntrepreneurMinionLabs_Mr. Gokul Srinivas_Young Entrepreneur
MinionLabs_Mr. Gokul Srinivas_Young EntrepreneurPriyadarshini T
 
VuNet software organisation powerpoint deck
VuNet software organisation powerpoint deckVuNet software organisation powerpoint deck
VuNet software organisation powerpoint deckNaval Singh
 
Telebu Social -Whatsapp Business API : Mastering Omnichannel Business Communi...
Telebu Social -Whatsapp Business API : Mastering Omnichannel Business Communi...Telebu Social -Whatsapp Business API : Mastering Omnichannel Business Communi...
Telebu Social -Whatsapp Business API : Mastering Omnichannel Business Communi...telebusocialmarketin
 
Building Generative AI-infused apps: what's possible and how to start
Building Generative AI-infused apps: what's possible and how to startBuilding Generative AI-infused apps: what's possible and how to start
Building Generative AI-infused apps: what's possible and how to startMaxim Salnikov
 
Technical improvements. Reasons. Methods. Estimations. CJ
Technical improvements.  Reasons. Methods. Estimations. CJTechnical improvements.  Reasons. Methods. Estimations. CJ
Technical improvements. Reasons. Methods. Estimations. CJpolinaucc
 
openEuler Community Overview - a presentation showing the current scale
openEuler Community Overview - a presentation showing the current scaleopenEuler Community Overview - a presentation showing the current scale
openEuler Community Overview - a presentation showing the current scaleShane Coughlan
 
03.2024_North America VMUG Optimizing RevOps using the power of ChatGPT in Ma...
03.2024_North America VMUG Optimizing RevOps using the power of ChatGPT in Ma...03.2024_North America VMUG Optimizing RevOps using the power of ChatGPT in Ma...
03.2024_North America VMUG Optimizing RevOps using the power of ChatGPT in Ma...jackiepotts6
 
Large Scale Architecture -- The Unreasonable Effectiveness of Simplicity
Large Scale Architecture -- The Unreasonable Effectiveness of SimplicityLarge Scale Architecture -- The Unreasonable Effectiveness of Simplicity
Large Scale Architecture -- The Unreasonable Effectiveness of SimplicityRandy Shoup
 
Mobile App Development company Houston
Mobile  App  Development  company HoustonMobile  App  Development  company Houston
Mobile App Development company Houstonjennysmithusa549
 

Recently uploaded (20)

Take Advantage of Mx Tracking Flight Scheduling Solutions to Streamline Your ...
Take Advantage of Mx Tracking Flight Scheduling Solutions to Streamline Your ...Take Advantage of Mx Tracking Flight Scheduling Solutions to Streamline Your ...
Take Advantage of Mx Tracking Flight Scheduling Solutions to Streamline Your ...
 
MUT4SLX: Extensions for Mutation Testing of Stateflow Models
MUT4SLX: Extensions for Mutation Testing of Stateflow ModelsMUT4SLX: Extensions for Mutation Testing of Stateflow Models
MUT4SLX: Extensions for Mutation Testing of Stateflow Models
 
Practical Advice for FDA’s 510(k) Requirements.pdf
Practical Advice for FDA’s 510(k) Requirements.pdfPractical Advice for FDA’s 510(k) Requirements.pdf
Practical Advice for FDA’s 510(k) Requirements.pdf
 
Mobile App Development process | Expert Tips
Mobile App Development process | Expert TipsMobile App Development process | Expert Tips
Mobile App Development process | Expert Tips
 
Splashtop Enterprise Brochure - Remote Computer Access and Remote Support Sof...
Splashtop Enterprise Brochure - Remote Computer Access and Remote Support Sof...Splashtop Enterprise Brochure - Remote Computer Access and Remote Support Sof...
Splashtop Enterprise Brochure - Remote Computer Access and Remote Support Sof...
 
BusinessGPT - SECURITY AND GOVERNANCE FOR GENERATIVE AI.pptx
BusinessGPT  - SECURITY AND GOVERNANCE  FOR GENERATIVE AI.pptxBusinessGPT  - SECURITY AND GOVERNANCE  FOR GENERATIVE AI.pptx
BusinessGPT - SECURITY AND GOVERNANCE FOR GENERATIVE AI.pptx
 
8 Steps to Build a LangChain RAG Chatbot.
8 Steps to Build a LangChain RAG Chatbot.8 Steps to Build a LangChain RAG Chatbot.
8 Steps to Build a LangChain RAG Chatbot.
 
BATbern52 Swisscom's Journey into Data Mesh
BATbern52 Swisscom's Journey into Data MeshBATbern52 Swisscom's Journey into Data Mesh
BATbern52 Swisscom's Journey into Data Mesh
 
Revolutionize Your Field Service Management with FSM Grid
Revolutionize Your Field Service Management with FSM GridRevolutionize Your Field Service Management with FSM Grid
Revolutionize Your Field Service Management with FSM Grid
 
Unlocking AI: Navigating Open Source vs. Commercial Frontiers
Unlocking AI:Navigating Open Source vs. Commercial FrontiersUnlocking AI:Navigating Open Source vs. Commercial Frontiers
Unlocking AI: Navigating Open Source vs. Commercial Frontiers
 
Leveling Up your Branding and Mastering MERN: Fullstack WebDev
Leveling Up your Branding and Mastering MERN: Fullstack WebDevLeveling Up your Branding and Mastering MERN: Fullstack WebDev
Leveling Up your Branding and Mastering MERN: Fullstack WebDev
 
MinionLabs_Mr. Gokul Srinivas_Young Entrepreneur
MinionLabs_Mr. Gokul Srinivas_Young EntrepreneurMinionLabs_Mr. Gokul Srinivas_Young Entrepreneur
MinionLabs_Mr. Gokul Srinivas_Young Entrepreneur
 
VuNet software organisation powerpoint deck
VuNet software organisation powerpoint deckVuNet software organisation powerpoint deck
VuNet software organisation powerpoint deck
 
Telebu Social -Whatsapp Business API : Mastering Omnichannel Business Communi...
Telebu Social -Whatsapp Business API : Mastering Omnichannel Business Communi...Telebu Social -Whatsapp Business API : Mastering Omnichannel Business Communi...
Telebu Social -Whatsapp Business API : Mastering Omnichannel Business Communi...
 
Building Generative AI-infused apps: what's possible and how to start
Building Generative AI-infused apps: what's possible and how to startBuilding Generative AI-infused apps: what's possible and how to start
Building Generative AI-infused apps: what's possible and how to start
 
Technical improvements. Reasons. Methods. Estimations. CJ
Technical improvements.  Reasons. Methods. Estimations. CJTechnical improvements.  Reasons. Methods. Estimations. CJ
Technical improvements. Reasons. Methods. Estimations. CJ
 
openEuler Community Overview - a presentation showing the current scale
openEuler Community Overview - a presentation showing the current scaleopenEuler Community Overview - a presentation showing the current scale
openEuler Community Overview - a presentation showing the current scale
 
03.2024_North America VMUG Optimizing RevOps using the power of ChatGPT in Ma...
03.2024_North America VMUG Optimizing RevOps using the power of ChatGPT in Ma...03.2024_North America VMUG Optimizing RevOps using the power of ChatGPT in Ma...
03.2024_North America VMUG Optimizing RevOps using the power of ChatGPT in Ma...
 
Large Scale Architecture -- The Unreasonable Effectiveness of Simplicity
Large Scale Architecture -- The Unreasonable Effectiveness of SimplicityLarge Scale Architecture -- The Unreasonable Effectiveness of Simplicity
Large Scale Architecture -- The Unreasonable Effectiveness of Simplicity
 
Mobile App Development company Houston
Mobile  App  Development  company HoustonMobile  App  Development  company Houston
Mobile App Development company Houston
 

Legacy Dependency Kata v2.0

  • 3.  Seed Code is written in C#  Get it from Github: https://github.com/KatasForLegacyCode/kCSharp/archive/Step0.zip  Any version of Visual Studio 2012/2013/2015 that can run console apps and unit tests.  An nUnit test runner.  I recommend nCrunch.
  • 5. Perception - COBOL Reality – Code W/O Unit tests
  • 9. Code Kata A code kata is an exercise in programming which helps a us hone our skills through practice and repetition. The word kata is taken from Japanese arts most traditionally Martial Arts Why a code kata? Because we learn by doing.
  • 10. Legacy Dependency Kata: V2.0  Written in C#  Less tool dependencies  Better theme  Easier to read and follow  Bug fixes
  • 12. Let’s start by getting the existing test running!  Running the integration test FAILS  Begin by abstracting and breaking the dependency on Console.Readline()  We’ll use an adapter, but we could use the Console.SetIn method and a TextReader.  Create an interface public interface IConsoleAdapter { string GetInput(); }  Create a class that implements the interface & implement method to handle our dependency public class ConsoleAdapter : IConsoleAdapter { public string GetInput() { return Console.ReadLine(); } } ConsoleAdapter.cs ConsoleAdapter.cs DoItAll.cs Did you know? In software engineering, the adapter pattern is a software design pattern that allows the interface of an existing class to be used as another interface.
  • 13.  Create new constructor to accept IConsoleAdapter & set private variable private readonly IConsoleAdapter _consoleAdapter; public DoItAll(IConsoleAdapter consoleAdapter) { _consoleAdapter = consoleAdapter; }  Replace 4 calls to Console.ReadLine() WITH _consoleAdapter.GetInput()  Replace 2 calls to Console.ReadKey() WITH _consoleAdapter.GetInput() DoItAll.cs DoItAll.cs DoItAll.cs
  • 14. We have broken instantiations of DoItAll  Instantiate and pass in our new handler var doItAll = new DoItAll(new ConsoleAdapter()); Let’s update our integration test or it will also fail.  Create a new implementation of IConsoleAdapter public class DoItAllTests { […] var doItAll = new DoItAll(new FakeConsoleAdapter()); […] } public class FakeConsoleAdapter : IConsoleAdapter { public string GetInput() { return string.Empty; } } Program.cs DoItAllTests.cs
  • 15.  When the test is run we now get a meaningful exception. All of the dependencies that caused the hang are gone.  the test is now failing because the password is empty. This is a meaningful case but let’s just update our fake for now. public string GetInput() { return “someTestString”; }  Run the test AND IT SHOULD BE GREEN! DoItAllTests.cs
  • 16.  Following good testing practice, let’s add an assert: [Test, Category("Integration")] public void DoItAll_Does_ItAll() { var doItAll = new DoItAll(new FakeConsoleAdapter()); Assert.That(() => doItAll.Do(), Throws.Nothing); }  Our test should still pass. DoItAllTests.cs
  • 17. Some of our legacy code has no coverage and produces no quantifiable results  Copy the existing test and rename it DoItAll_Fails_ToWriteToDB [Test, Category("Integration")] public void DoItAll_Does_ItAll() { […] } [Test, Category("Integration")] public void DoItAll_Fails_ToWriteToDB() { […] }  Change the assert Assert.That(doItAll.Do(), Is.StringContaining("Database.SaveToLog Exception:”));  Build will fail because our Do() method returns void. DoItAllTests.cs DoItAllTests.cs
  • 18.  Change Do()’s return type to string public string Do()  Add/update return statements in 3 locations: public string Do() { […] if (_userDetails.PasswordEncrypted […]) { […] return string.Empty; } […] { […] using (var writer = new StreamWriter("log.txt", true)) { […] return string.Empty; } } […] return string.Empty; } DoItAll.cs DoItAll.cs
  • 19.  Now create variables to hold the messages to return public string Do() { […] if (_userDetails.PasswordEncrypted […]) { var passwordsDontMatch = "The passwords don't match."; […] } […] { […] using (var writer = new StreamWriter("log.txt", true)) { var errorMessage = string.Format("{0} - Database.SaveToLog Exception: rn{1}", message, ex.Message); […] } } […] } DoItAll.cs
  • 20.  Return the new values as appropriate public string Do() { […] if (_userDetails.PasswordEncrypted […]) { […] Console.WriteLine(passwordsDontMatch); Console.ReadKey(); return passwordsDontMatch; } […] { […] using (var writer = new StreamWriter("log.txt", true)) { […] writer.WriteLine(errorMessage); return errorMessage; } } }  Our new DoItAll_Fails_ToWriteToDB() test should pass DoItAll.cs
  • 21. Abstract Console completely  Add a new method stub void SetOutput(string output);  Update ConsoleAdapter implementation public void SetOutput(string output) { Console.WriteLine(output); }  Update FakeConsoleAdapter implementation public void SetOutput(string output) {}  Update DoItAll Implementation Replace 6 instances of Console.WriteLine AND Console.Write WITH _consoleAdapter.SetOutput ConsoleAdapter.cs ConsoleAdapter.cs DoItAllTests.cs DoItAll.cs OUR TESTS SHOULD STILL PASS
  • 22. DoItAll.Do() is trying to do too much. Let’s Refactor!  Extract logging functionality by creating a new interface public interface ILogger { string LogMessage(string message); }  Create a new class implementing ILogger public class Logger : ILogger { public string LogMessage(string message) { throw new NotImplementedException(); } }  Now extract the code in the try/catch block in DoItAll.Do() into the implementation of ILogger.LogMessage()  Make sure all paths return a message  Now update the constructor of DoItAll with an ILogger AND REPLACE TRY/CATCH: message = _logger.LogMessage(message); Logger.cs Logger.cs
  • 23.  Extract the code in the try/catch block in DoItAll.Do() into the implementation of Logger.LogMessage() Make sure all paths return a message public string LogMessage(string message) { try { Database.SaveToLog(message); } catch (Exception ex) { // If database write fails, write to file using (var writer = new StreamWriter("log.txt", true)) { message = message + "nDatabase.SaveToLog Exception: " + ex.Message; writer.WriteLine(message); } } return message; } Logger.cs
  • 24.  Update the constructor of DoItAll with an ILogger public DoItAll(IOutputInputAdapter ioAdapter, ILogger logger) { _ioAdapter = ioAdapter; _logger = logger; } […] private readonly ILogger _logger;  Update the Do() method public string Do() { […] _ioAdapter.SetOutput(message); message = _logger.LogMessage(message); return message; } DoItAll.cs DoItAll.cs
  • 25. We have broken instantiations of DoItAll  Instantiate and pass in our new handler var doItAll = new DoItAll(new ConsoleAdapter(), new Logger()); Let’s update our tests or they will also fail.  Create a new implementation of ILogger public class DoItAllTests { […] var doItAll = new DoItAll(new FakeConsoleAdapter(), new FakeLogger()); […] } […] public class FakeLogger : ILogger { public string LogMessage( string message) { return string.Empty; } } Program.cs DoItAllTests.cs OUR FIRST TEST PASSES, BUT THE SECOND FAILS
  • 26.  Copy the second test and rename the copy DoItAll_Succeeds_WithMockLogging  Update the copied assert Assert.That(doItAll.Do(), Is.EqualTo(string.Empty));  Let the original test remain an integration test by depending on Logger and it will pass as well DoItAllTests.cs DoItAllTests.cs
  • 27. There is still plenty to refactor in this legacy code.  What would you do next?
  • 28. William Munn, CGFWB @dubmun dubmun http://blog.dubmun.com Resources Michael Feathers Roy Osherove Robert C. Martin Dave Thomas & Andy Hunt Legacy Dependency Kata – V2.0

Editor's Notes

  1. The code is written in C#, so anyone who can write C++ or Java shouldn’t have any trouble following along. However, I don’t have seed code for you. I only bought 5 flash drives in case on network issues… I only expected maybe 10-15 people…
  2. So what IS legacy code? As I gained experience I came to think of legacy code as COBOL, Fortran, PHP… (kidding I know people love PHP somewhere out there). They seemed to fit… How many of you are concerned with maintaining written on COBOL or FORTRAN? 10% 25% 50% MORE? I have a slightly wider and maybe scarier definition. According to Working Effectively with Legacy Code by Michael Feathers: legacy code is code without unit tests.
  3. SO… if you have code without unit tests, it is legacy code because you cannot modify, refactor, or fix it without the very real danger of breaking it. Unit tests add a layer of safety to enable these actions.
  4. Dependency can have a quasi-positive meaning even though Google Image Search disagrees. If you are depending on well maintained libraries, abstract classes and interfaces, professional tooling with good history of support; that isn’t necessarily a bad thing. The alternative is code that may be completely procedural and has little/no abstractions. This kind of dependent code can be addictive to write because it is often quicker and easier to write. It doesn’t require as much thought, but the effects are disastrous to maintainability and extensibility. Not to mention the fact that it is basically impossible to unit test.
  5. This is a dependency graph of a codebase with no abstractions. We can’t easily make sense of this… Who has seen a dependency graph that looks like this or worse (this isn’t HealthEquity’s dependency graph btw). This exists, I’ve seen a couple that were considerably worse at companies I’ve worked for. This is what we are trying to prevent or move away from.
  6. Unfortunately, this isn’t likely to happen.
  7. Go home and practice this kata and your brain will learn how to deal with legacy dependencies. You’ll get so good at it that is will seem like second nature.
  8. At first glance, the class structure may not seem too unreasonable. Data access has it’s own class and so do the UserDetails. Then we see the DoItAll class with the Do() method. Naming aside, this is unfortunately pretty common in several codebases I’ve seen. Someone who touched this code had good intentions. There is a unit test project with a single failing unit test. Probably because they weren’t sure how to deal with the dependency on the console.