SlideShare a Scribd company logo
Iterative Architecture
How SOLID Principals, Design Patterns, and
Unit Testing work together to reduce tech debt iteratively.
It’s dangerous to go alone! Take this.
• Single Responsibility
• Open-Close
• Liskov Substitution
• Interface Segregation
• Dependency Inversion
Let’s code a digital library…
class Book
{
string getTitle()…
string getText()…
string getAuthor()…
bool print()…
}
Single Responsibility Principal
• Each class should do ONE
thing and only ONE thing.
• Classes should be as small
as possible. Then make
them smaller.
How do we fix it?
class Book
{
string getTitle()…
string getText()…
string getAuthor()…
bool print() {
return Printer.print(currentPage);
}
}
class Printer
{
bool print(string text)…
}
class Visitor
{
bool read(book)…
}
Interface Segregation Principal
• Interfaces should not be
“fat”.
• If you implement an
interface, it should mean
that you need the whole
thing.
Better…
class Book
{
string getTitle()…
string getText()…
string getAuthor()…
}
class Printer
{
bool print(string text)…
}
class BookPrinter
{
bool printBook(Book book) {
return Printer.print(book.getText()));
}
}
Dependency Inversion Principal
• Classes should depend on
abstractions, not
implementations.
• Basically, depend on
Interfaces, Base Classes,
Abstract Classes, etc…
The Bridge Pattern
interface PrinterBridge
{
Document document
Printer printer;
bool printDocument()…
}
class Book: Document {…
class BookPrinterBridge: PrinterBridge
{
Book document;
Printer printer;
bool printDocument() {
return printer.print(book.getText()));
}
}
Design Patterns
• The most correct solution to a
problem.
• Should anticipate future issues, so
you don’t have to.
• They fit together like building
blocks!
Which is better?
class BookPrinterBridge: PrinterBridge
{
Book book;
Printer printer;
bool printDocument() {
return printer.print(book.getText()));
}
}
…
class Book
{
string getTitle()…
string getText()…
string getAuthor()…
bool print()…
}
What if we test it?
class BookTests
{
Book target;
bool BookCanPrintBook() {
return target.printBook();
}
}
class Printer
{
bool print(string text) {
throw Exception(“there is a bug…”);
}
}
class BookPrinterTests
{
BookPrinter target;
bool BookPrinterCanPrintBook() {
return target.printBook();
}
}
Checks and Balances
Unit Testing
• Writing tests helps guarantee that
your code follows good design.
• Tests should be simple enough to
inspire confidence.
• Testing should increase your
development speed.
Have you ever had to write tests like this?
class EmailServiceTests
{
bool canUpdateEmail() {
var mockUsers = new Mock<UserService>();
mockUsers.add(new User() {
Name = “Test”,
Id = 1,
Login = “test”,
Password = “*****”
});
var mockRoles = new Mock<RoleService>();
mockRoles.add(new Role() {
Name = “Test”,
Id = 1
});
var mockPermissions = new Mock<PermissionService>();
mockPermissions.add(new Permission() {
Name = “CanTest”,
Id = 1
});
…
target = new EmailService()
return target.updateEmail(
“test@test.test”,
“Because reasons…”,
new User() {
Name = “Test”,
Id = 1
}
);
}
}
What would good tests look like?
class EmailServiceTests
{
EmailService target;
bool canUpdateEmail() {
return target.updateEmail(userId: 1, email: “test”);
}
}
class AuthenticationServiceTests
{
AuthenticationService target;
bool testIsAuthenticated() {
var mockRoles = new Mock<RoleService>();
mockRoles.add(new Role() {
Name = “Test”,
Id = 1
});
var mockPermissions = new Mock<PermissionService>();
mockPermissions.add(new Permission() {
Name = “CanTest”,
Id = 1
});
return target.isAuthenticated(userId: 1, “CanTest”);
}
}
class EmailAuthenticatorTests
{
EmailAuthenticatorService target;
bool canUpdateEmailWithAuth() {
return target.updateEmail(userId: 1, email: “test”);
}
}
The Decorator Pattern
class AuthenticationDecoratorTests
{
AuthenticationDecorator target;
bool callsAuthBefore() {
var mockService = new Mock<SomeService>();
target.decorates(mockService);
return target.someMethod();
}
}
…
[Authorize]
void someMethod() {…
Checks and Balances
Lets start with some requirements…
• You are a developer for your favorite project management
software!
• You are trying to populate the dropdown that lets you select a
story’s status.
• You want to add safeguards so that story cards cannot change
state without passing certain checks.
Some examples…
Backlog > Ready > In-Progress > QA > Done
• Stories must have UI mock-ups to move from Backlog to Ready.
• Stories must get PO sign off to move to Done from anywhere.
• Stories can go back to InProgress if they fail QA.
• Stories can skip to Done if that story is a bug that is not reproducible.
We need to populate this:
So you come across this…
class StatusOptions
{
string[] getStatuses(storyCard) {
if (STATUS) {
if (CONDITION) {
return [“Done”, “QA”];
}
} else if (STATUS or STATUS) {
…
}
}
}
• Violates SRP and Open-Close
• Does not fit any design patterns
• Requires many tests to cover all
scenarios
Open-Closed Principal
• Classes should be open for
extension, but closed for
modification.
• If you add functionality, you
should be able to add code,
not change existing code.
The better solution
interface StatusOption
{
string[] getValidMoves(storyCard);
}
• Satisfies SRP and
Open-Close (mostly).
• Starting to look like a
pattern…
• Can test conditions
granularly, instead of
in combinations.
class InProgressStatusOption: StatusOption
{
string[] getValidMoves(storyCard) {
if (storyCard.isDone()) {
return [“QA”];
}
return [“Backlog”, “InProgress”];
}
}
How do we process the options?
class StatusOptionsProcessor
{
string[] getStatuses(storyCard) {
var opt = getOption(storyCard);
return opt.getValidMoves(storyCard);
}
StatusOption getOption(storyCard) {
…
}
}
• Still violates Open-Close
• Almost follows a design pattern
• Tests still reveal some overlap…
The Rule Engine
interface StatusRule
{
bool canHandle(storyCard)
string[] getValidMoves(storyCard);
}
class StatusRuleProcessor
{
StatusOption[] options;
string[] getStatuses(storyCard) {
string[] statuses = [];
foreach (option in options) {
if (option.canHandle(storyCard)
statuses.add(option.getValidMoves);
}
return statuses;
}
}
We could make…
• MovesForInProgressRule
• MovesForQARule
• AllowMoveToDoneRule
• FailQARule
Checks and Balances
Story time…
• Benefits are immediate.
• The value should not be underestimated.
• Good code is worth doing, even in an emergency.
Summary
• SOLID Principals, Design Patterns, and Unit Testing form a system
of feedback loops to help you write good code.
• You can use these feedback loops to improve your code
incrementally.
• This allows you to reduce tech debt over time.
Josh Rizzo
Principal Consultant at Improving
Josh.Rizzo@Improving.com
Presentation link: tx.ag/YAlGNqm

More Related Content

PPTX
Unit testing patterns for concurrent code
PPTX
Building unit tests correctly
PPTX
3 Ways to test your ColdFusion API - 2017 Adobe CF Summit
PDF
Solid scala
PDF
Unit test-using-spock in Grails
PPTX
Grails Spock Testing
PDF
C# Advanced L03-XML+LINQ to XML
ODP
Grails unit testing
Unit testing patterns for concurrent code
Building unit tests correctly
3 Ways to test your ColdFusion API - 2017 Adobe CF Summit
Solid scala
Unit test-using-spock in Grails
Grails Spock Testing
C# Advanced L03-XML+LINQ to XML
Grails unit testing

What's hot (20)

PPTX
Typed? Dynamic? Both! Cross-platform DSLs in C#
PPTX
TDD & BDD
KEY
Ceylon - the language and its tools
PDF
Why Your Test Suite Sucks - PHPCon PL 2015
PPTX
Intro to TDD and BDD
PDF
"Real-time Collaborative Text Editing on Grammarly’s Front-End Team" Oleksii...
PDF
BDD Testing and Automating from the trenches - Presented at Into The Box June...
PDF
Java Programming - 04 object oriented in java
PDF
Mockist vs. Classicists TDD
PDF
SAP Testing Training
PDF
Java Programming - 05 access control in java
PDF
TDD, BDD and mocks
PDF
React Native: JS MVC Meetup #15
PDF
Testing for Pragmatic People
PDF
Clean code & design patterns
PPTX
Refactoring
PDF
Basic java for Android Developer
PDF
Java for beginners
PDF
Working Effectively with Legacy Code: Lessons in Practice
Typed? Dynamic? Both! Cross-platform DSLs in C#
TDD & BDD
Ceylon - the language and its tools
Why Your Test Suite Sucks - PHPCon PL 2015
Intro to TDD and BDD
"Real-time Collaborative Text Editing on Grammarly’s Front-End Team" Oleksii...
BDD Testing and Automating from the trenches - Presented at Into The Box June...
Java Programming - 04 object oriented in java
Mockist vs. Classicists TDD
SAP Testing Training
Java Programming - 05 access control in java
TDD, BDD and mocks
React Native: JS MVC Meetup #15
Testing for Pragmatic People
Clean code & design patterns
Refactoring
Basic java for Android Developer
Java for beginners
Working Effectively with Legacy Code: Lessons in Practice
Ad

Similar to Iterative architecture (20)

PDF
EKON28 - Beyond Legacy Apps with mORMot 2
PDF
Breaking Dependencies to Allow Unit Testing
PDF
Breaking Dependencies To Allow Unit Testing - Steve Smith | FalafelCON 2014
PDF
2024 DAPUG Conference Arnaud Bouchez From Classes to Interfaces
PPTX
Refactoring Applications using SOLID Principles
PDF
Keeping code clean
PPTX
Improving the Design of Existing Software
PPTX
How Functional Programming Made Me A Better Developer
PDF
Twins: Object Oriented Programming and Functional Programming
PPTX
GoF Design patterns I: Introduction + Structural Patterns
PPTX
Principles and patterns for test driven development
PPTX
Improving the Quality of Existing Software
ODP
Evolutionary Design Solid
PPTX
The good, the bad and the SOLID
PPTX
Why certain code is hard to test?
PPTX
Improving the Quality of Existing Software
PPTX
Test Driven Development:Unit Testing, Dependency Injection, Mocking
PPTX
Improving the Quality of Existing Software - DevIntersection April 2016
PDF
The maze of Design Patterns & SOLID Principles
PDF
Unit testing legacy code
EKON28 - Beyond Legacy Apps with mORMot 2
Breaking Dependencies to Allow Unit Testing
Breaking Dependencies To Allow Unit Testing - Steve Smith | FalafelCON 2014
2024 DAPUG Conference Arnaud Bouchez From Classes to Interfaces
Refactoring Applications using SOLID Principles
Keeping code clean
Improving the Design of Existing Software
How Functional Programming Made Me A Better Developer
Twins: Object Oriented Programming and Functional Programming
GoF Design patterns I: Introduction + Structural Patterns
Principles and patterns for test driven development
Improving the Quality of Existing Software
Evolutionary Design Solid
The good, the bad and the SOLID
Why certain code is hard to test?
Improving the Quality of Existing Software
Test Driven Development:Unit Testing, Dependency Injection, Mocking
Improving the Quality of Existing Software - DevIntersection April 2016
The maze of Design Patterns & SOLID Principles
Unit testing legacy code
Ad

Recently uploaded (20)

PDF
medical staffing services at VALiNTRY
PPTX
ManageIQ - Sprint 268 Review - Slide Deck
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PDF
Digital Strategies for Manufacturing Companies
PDF
top salesforce developer skills in 2025.pdf
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PPTX
CHAPTER 12 - CYBER SECURITY AND FUTURE SKILLS (1) (1).pptx
PDF
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
PPTX
Operating system designcfffgfgggggggvggggggggg
PPT
Introduction Database Management System for Course Database
PPTX
Odoo POS Development Services by CandidRoot Solutions
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PPTX
Transform Your Business with a Software ERP System
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PPTX
history of c programming in notes for students .pptx
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
medical staffing services at VALiNTRY
ManageIQ - Sprint 268 Review - Slide Deck
Navsoft: AI-Powered Business Solutions & Custom Software Development
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
Digital Strategies for Manufacturing Companies
top salesforce developer skills in 2025.pdf
Upgrade and Innovation Strategies for SAP ERP Customers
CHAPTER 12 - CYBER SECURITY AND FUTURE SKILLS (1) (1).pptx
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
Operating system designcfffgfgggggggvggggggggg
Introduction Database Management System for Course Database
Odoo POS Development Services by CandidRoot Solutions
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
VVF-Customer-Presentation2025-Ver1.9.pptx
How to Choose the Right IT Partner for Your Business in Malaysia
Transform Your Business with a Software ERP System
2025 Textile ERP Trends: SAP, Odoo & Oracle
history of c programming in notes for students .pptx
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...

Iterative architecture

  • 1. Iterative Architecture How SOLID Principals, Design Patterns, and Unit Testing work together to reduce tech debt iteratively.
  • 2. It’s dangerous to go alone! Take this. • Single Responsibility • Open-Close • Liskov Substitution • Interface Segregation • Dependency Inversion
  • 3. Let’s code a digital library… class Book { string getTitle()… string getText()… string getAuthor()… bool print()… }
  • 4. Single Responsibility Principal • Each class should do ONE thing and only ONE thing. • Classes should be as small as possible. Then make them smaller.
  • 5. How do we fix it? class Book { string getTitle()… string getText()… string getAuthor()… bool print() { return Printer.print(currentPage); } } class Printer { bool print(string text)… } class Visitor { bool read(book)… }
  • 6. Interface Segregation Principal • Interfaces should not be “fat”. • If you implement an interface, it should mean that you need the whole thing.
  • 7. Better… class Book { string getTitle()… string getText()… string getAuthor()… } class Printer { bool print(string text)… } class BookPrinter { bool printBook(Book book) { return Printer.print(book.getText())); } }
  • 8. Dependency Inversion Principal • Classes should depend on abstractions, not implementations. • Basically, depend on Interfaces, Base Classes, Abstract Classes, etc…
  • 9. The Bridge Pattern interface PrinterBridge { Document document Printer printer; bool printDocument()… } class Book: Document {… class BookPrinterBridge: PrinterBridge { Book document; Printer printer; bool printDocument() { return printer.print(book.getText())); } }
  • 10. Design Patterns • The most correct solution to a problem. • Should anticipate future issues, so you don’t have to. • They fit together like building blocks!
  • 11. Which is better? class BookPrinterBridge: PrinterBridge { Book book; Printer printer; bool printDocument() { return printer.print(book.getText())); } } … class Book { string getTitle()… string getText()… string getAuthor()… bool print()… }
  • 12. What if we test it? class BookTests { Book target; bool BookCanPrintBook() { return target.printBook(); } } class Printer { bool print(string text) { throw Exception(“there is a bug…”); } } class BookPrinterTests { BookPrinter target; bool BookPrinterCanPrintBook() { return target.printBook(); } }
  • 14. Unit Testing • Writing tests helps guarantee that your code follows good design. • Tests should be simple enough to inspire confidence. • Testing should increase your development speed.
  • 15. Have you ever had to write tests like this? class EmailServiceTests { bool canUpdateEmail() { var mockUsers = new Mock<UserService>(); mockUsers.add(new User() { Name = “Test”, Id = 1, Login = “test”, Password = “*****” }); var mockRoles = new Mock<RoleService>(); mockRoles.add(new Role() { Name = “Test”, Id = 1 }); var mockPermissions = new Mock<PermissionService>(); mockPermissions.add(new Permission() { Name = “CanTest”, Id = 1 }); … target = new EmailService() return target.updateEmail( “test@test.test”, “Because reasons…”, new User() { Name = “Test”, Id = 1 } ); } }
  • 16. What would good tests look like? class EmailServiceTests { EmailService target; bool canUpdateEmail() { return target.updateEmail(userId: 1, email: “test”); } } class AuthenticationServiceTests { AuthenticationService target; bool testIsAuthenticated() { var mockRoles = new Mock<RoleService>(); mockRoles.add(new Role() { Name = “Test”, Id = 1 }); var mockPermissions = new Mock<PermissionService>(); mockPermissions.add(new Permission() { Name = “CanTest”, Id = 1 }); return target.isAuthenticated(userId: 1, “CanTest”); } } class EmailAuthenticatorTests { EmailAuthenticatorService target; bool canUpdateEmailWithAuth() { return target.updateEmail(userId: 1, email: “test”); } }
  • 17. The Decorator Pattern class AuthenticationDecoratorTests { AuthenticationDecorator target; bool callsAuthBefore() { var mockService = new Mock<SomeService>(); target.decorates(mockService); return target.someMethod(); } } … [Authorize] void someMethod() {…
  • 19. Lets start with some requirements… • You are a developer for your favorite project management software! • You are trying to populate the dropdown that lets you select a story’s status. • You want to add safeguards so that story cards cannot change state without passing certain checks.
  • 20. Some examples… Backlog > Ready > In-Progress > QA > Done • Stories must have UI mock-ups to move from Backlog to Ready. • Stories must get PO sign off to move to Done from anywhere. • Stories can go back to InProgress if they fail QA. • Stories can skip to Done if that story is a bug that is not reproducible.
  • 21. We need to populate this:
  • 22. So you come across this… class StatusOptions { string[] getStatuses(storyCard) { if (STATUS) { if (CONDITION) { return [“Done”, “QA”]; } } else if (STATUS or STATUS) { … } } } • Violates SRP and Open-Close • Does not fit any design patterns • Requires many tests to cover all scenarios
  • 23. Open-Closed Principal • Classes should be open for extension, but closed for modification. • If you add functionality, you should be able to add code, not change existing code.
  • 24. The better solution interface StatusOption { string[] getValidMoves(storyCard); } • Satisfies SRP and Open-Close (mostly). • Starting to look like a pattern… • Can test conditions granularly, instead of in combinations. class InProgressStatusOption: StatusOption { string[] getValidMoves(storyCard) { if (storyCard.isDone()) { return [“QA”]; } return [“Backlog”, “InProgress”]; } }
  • 25. How do we process the options? class StatusOptionsProcessor { string[] getStatuses(storyCard) { var opt = getOption(storyCard); return opt.getValidMoves(storyCard); } StatusOption getOption(storyCard) { … } } • Still violates Open-Close • Almost follows a design pattern • Tests still reveal some overlap…
  • 26. The Rule Engine interface StatusRule { bool canHandle(storyCard) string[] getValidMoves(storyCard); } class StatusRuleProcessor { StatusOption[] options; string[] getStatuses(storyCard) { string[] statuses = []; foreach (option in options) { if (option.canHandle(storyCard) statuses.add(option.getValidMoves); } return statuses; } } We could make… • MovesForInProgressRule • MovesForQARule • AllowMoveToDoneRule • FailQARule
  • 28. Story time… • Benefits are immediate. • The value should not be underestimated. • Good code is worth doing, even in an emergency.
  • 29. Summary • SOLID Principals, Design Patterns, and Unit Testing form a system of feedback loops to help you write good code. • You can use these feedback loops to improve your code incrementally. • This allows you to reduce tech debt over time.
  • 30. Josh Rizzo Principal Consultant at Improving Josh.Rizzo@Improving.com Presentation link: tx.ag/YAlGNqm

Editor's Notes

  • #2: Tech debt suxorz Should we stop and take care of it?
  • #3: Could substitute your favorite coding practices here.
  • #4: What SOLID principal does this violate? THIS IS CALLED A “CODE SMELL”. There is nothing broken about this, and it’s not causing any problems, but it violates SOLID principals.
  • #5: - Printing could arguably be part of a book’s responsibilities, but it doesn’t have to be, so it shouldn’t.
  • #6: We now have smaller pieces, but the interface is wrong. We can see another SOLID principal here - Does the Visitor need the print functionality to read a book in the Library? Smells like this could violate ISP.
  • #7: - Similar to SRP
  • #8: Could call this a Librarian Take the unneeded behavior out of the Book. I would approve this PR. Now it smells like it violates DI though (Printer reference). You may be able to see what pattern we are working towards now.
  • #9: Things should be pluggable so you can refactor more easily.
  • #10: This is the Bridge Pattern! Assume Book and Printer are abstractions for simplicity, and we are using property injection of some kind for DI. Use the name in the class/interface titles. Should we use Book in the interface? Can create new Bridges to print other types of documents. Could define a more generic interface for the Document. We have anticipated future requirements without having to guess.
  • #11: If something doesn’t fit the pattern correctly, it could be a smell. Look at previous example… Can expand this pattern with more bridges, as stated earlier. Can add an Adapter pattern to Book or Printer to use other objects.
  • #12: - You might write the one on the left in a hurry, but hold on to that thought…
  • #13: What if there is an error in the Printer? This is another smell… If TDD, you would have to write two classes for this test. You can use unit tests to think about SRP and DI.
  • #14: SOLID principals informed us of the correct design pattern, which made things more testable, and tests make us follow SOLID principals. We don’t do this for its own sake; it generates value! Let’s look at another example…
  • #15: Notice the previous test was very simple. Tests point out code smells. We do not refactor code to make unit tests. So testing and SOLID principals revealed some smells, but what is the correct solution?
  • #16: This is an SRP violation, and an ISP violation
  • #17: Maybe we don’t need the User at all? Authenticator can still have some setup. Do we use Bridge here? [reveal]
  • #18: There are a number of ways this could be implemented… Attribute Decorators in C#
  • #19: We can do this entire feedback loop from the unit tests. This is the actual value of unit tests.
  • #20: - (3) Hide the status if you can’t change to it.
  • #21: Mostly linear flow Can go backwards Can skip steps
  • #24: Ever had to add one class, but you had to wire it up in a dozen places? OCP violation. Route files Project files Dependency injectors
  • #25: Definitely an improvement, but… But what does the processor look like?
  • #26: What about this? This would be good enough, most of the time! [reveal check] Pretty close to a Strategy Pattern Could assume we get the options from the dependency injector to satisfy DI. Could design the getOption method several ways. [reveal problems] [on last reveal] Requirements will still be problematic! What if any story can move back to Backlog if it needs more requirements (skip backwards)?
  • #27: This is a more obscure pattern. Why add canHandle()? Can just run checks to validate moves Will have to handle overlap somehow Could make guard rules or allow rules [reveal] You can get to this from the last one. I once did this under a hard deadline, and it paid off the next print in spades.
  • #28: The pattern was derived from SOLID principals and made testing easier. This also gave us the flexibility to cover more scenarios.
  • #29: Tell example of using Rule Engine on USLS Job Statuses. Started with something that was “better”. Was in crunch time. Got real value next sprint.