SlideShare ist ein Scribd-Unternehmen logo
1 von 46
Downloaden Sie, um offline zu lesen
SOLID OO 
Design 
Tudor Pavel 
1 / 46
Change is inevitable. 
2 / 46
Design prepares you for it. 
3 / 46
Design Stamina Hypothesis 
http://martinfowler.com/bliki/DesignStaminaHypothesis.html 
4 / 46
Principles 
Single Responsibility (SRP) 
Open/Closed (OCP) 
Liskov Substitution (LSP) 
Interface Segregation (ISP) 
Dependency Inversion (DIP) 
5 / 46
Single Responsibility 
A class/method should serve a single purpose. 
There should never be more than one reason for a class/method to change. 
6 / 46
Open/Closed 
A class/method should be open for extension but closed for modification. 
7 / 46
Liskov Substitution 
Subclasses should be substitutable for their base classes. 
8 / 46
Interface Segregation 
Many client-specific interfaces are better than one general-purpose interface. 
9 / 46
Dependency Inversion 
Depend upon abstractions. Do not depend upon concretions. 
10 / 46
Design is all about 
dependencies. 
11 / 46
When you know something, 
you depend on it. 
12 / 46
If it changes, 
you might change. 
13 / 46
Example App 
14 / 46
Requirements 
We are the FBI and our buddies from the NSA 
post some encrypted messages for us in a 
secret RSS feed. 
Our job is to parse the messages from the feed 
and store them in clear text in our DB, since we 
don't understand encryption. 
15 / 46
Encryption 
The NSA are slightly better than us at 
encryption, so they've used e Caesar Cipher to 
encrypt the messages. 
16 / 46
Message model 
class Message < ActiveRecord::Base 
end 
17 / 46
Public interface 
class RSSMessagesParser 
def execute 
messages = fetch_messages 
messages.each { |m| Message.create(text: decrypt(m)) } 
end 
private 
def fetch_messages 
# ... 
end 
def decrypt(message) 
# ... 
end 
end 
18 / 46
Fetching messages 
require 'rss' 
class RSSMessagesParser 
def execute 
messages = fetch_messages 
messages.each { |m| Message.create(text: decrypt(m)) } 
end 
private 
def fetch_messages 
RSS::Parser.parse(open('http://secret.nsa.gov/rss').read).items 
end 
def decrypt(message) 
# ... 
end 
end 
19 / 46
Entire class 
require 'rss' 
class RSSMessagesParser 
def execute 
messages = fetch_messages 
messages.each { |m| Message.create(text: decrypt(m)) } 
end 
private 
def fetch_messages 
RSS::Parser.parse(open('http://secret.nsa.gov/rss').read).items 
end 
def decrypt(message) 
message.split('').map(&:ord).map { |a| a - 3 }.map(&:chr).join 
end 
end 
20 / 46
But what if... 
the "secret" URL changes? 
the encryption method changes? 
reading other RSS feeds is required? 
21 / 46
Knowing when to refactor 
Is it DRY? 
Does it have a single responsibility? 
Does everything in it change at the same 
rate? 
Does it depend on more stable things? 
! The answer needs to be YES for all of them to move on. 
22 / 46
Is it DRY? 
23 / 46
Does it have a single 
responsibility? 
24 / 46
What does RSSMessagesParser do? 
Fetches messages and decrypts them and saves them to the DB. 
Words like and and or are design smells suggesting a violation of SRP. This class 
is doing too much! 
25 / 46
Extracting responsibilities 
class MessagesParser 
def initialize 
@cipher = NSACipher.new 
@rss = RSSMessages.new 
end 
def execute 
messages = @rss.fetch 
messages.each { |m| Message.create(text: @cipher.decrypt(m)) } 
end 
end 
26 / 46
SRP should be applied to 
methods too 
class MessagesParser 
def initialize 
@cipher = NSACipher.new 
@rss = RSSMessages.new 
end 
def execute 
messages = @rss.fetch 
messages.each { |m| parse(m) } 
end 
private 
def parse(message) 
Message.create(text: @cipher.decrypt(m)) 
end 
end 
27 / 46
The NSACipher 
class NSACipher 
def decrypt(message) 
message.split('').map(&:ord).map { |a| a - 3 }.map(&:chr).join 
end 
end 
28 / 46
The RSSMessages class 
require 'rss' 
class RSSMessages 
def fetch 
RSS::Parser.parse(open('http://secret.nsa.gov/rss').read).items 
end 
end 
29 / 46
Is it DRY? 
30 / 46
Does it have a single 
responsibility? 
31 / 46
Does everything in it change 
at the same rate? 
32 / 46
The RSS URL and the Cipher step 
can change more often than the 
classes, because the NSA want to 
stay at least ahead of the novice 
hackers by changing them 
periodically. 
33 / 46
Using Open/Close Principle 
class NSACipher 
def initialize(step=3) 
@step = step 
end 
def decrypt(message) 
message.split('').map(&:ord).map { |a| a - @step }.map(&:chr).join 
end 
end 
Add default step to simplify current calls 
The class is now open for extension and reusability. 
NSACipher is essentially a generic Caesar cipher that can be used to decrypt 
messages, it has nothing to do with NSA, so we can rename it. 
34 / 46
Reusable CaesarCipher 
class CaesarCipher 
def initialize(step=3) 
@step = step 
end 
def decrypt(message) 
message.split('').map(&:ord).map { |a| a - @step }.map(&:chr).join 
end 
end 
35 / 46
The same with RSSFetcher 
require 'rss' 
class RSSFetcher 
def initialize(url='http://secret.nsa.gov/rss') 
@url = url 
end 
def fetch 
RSS::Parser.parse(open(@url).read).items 
end 
end 
36 / 46
Since we're using Rails 4.1 and the 
two defaults are secret values, we 
can move them to secrets.yml. 
development: 
default_caesar_step: 3 
default_rss_url: 'http://secret.nsa.gov/rss' 
def initialize(url=Rails.application.secrets.default_rss_url) 
def initialize(step=Rails.application.secrets.default_caesar_step) 
37 / 46
MessagesParser class 
class MessagesParser 
def initialize 
@cipher = CaesarCipher.new 
@rss = RSSFetcher.new 
end 
def execute 
messages = @rss.fetch 
messages.each { |m| parse(m) } 
end 
private 
def parse(message) 
Message.create(text: @cipher.decrypt(m)) 
end 
end 
38 / 46
Does it depend on more 
stable things? 
39 / 46
Using Dependency Inversion 
class MessagesParser 
def initialize(cipher, fetcher) 
@cipher = cipher 
@fetcher = fetcher 
end 
def execute 
messages = @fetcher.fetch 
messages.each { |m| parse(m) } 
end 
private 
def parse(message) 
Message.create(text: @cipher.decrypt(m)) 
end 
end 
MessagesParser now depends upon abstractions being injected by callers 
40 / 46
Alternative ciphers now 
supported 
AES 
DES 
... 
41 / 46
Alternative fetchers now 
supported 
Files 
Twitter :) 
... 
42 / 46
Conclusions 
The App is easily adaptable to future 
changes because of SOLID Design 
Beautiful and abstract class designs, even 
Design Patterns (next), were discovered by 
refactoring and following basic rules and 
principles 
Learn to trust your nose and to be prepared 
for the inevitable changes that are coming 
43 / 46
References 
SOLID Object-Oriented Design, Sandi Metz, 
https://speakerdeck.com/skmetz/solid-object-oriented- 
design 
44 / 46
Bonus 
To make sure the concept of SRP sinks in: 
http://youtu.be/vlN17gMhnEk 
(get ready for British English and humour) 
45 / 46
Questions? 
46 / 46

Weitere ähnliche Inhalte

Andere mochten auch

Andere mochten auch (6)

Beyond design patterns and principles - writing good OO code
Beyond design patterns and principles - writing good OO codeBeyond design patterns and principles - writing good OO code
Beyond design patterns and principles - writing good OO code
 
SOLID Design principles
SOLID Design principlesSOLID Design principles
SOLID Design principles
 
OOD Principles and Patterns
OOD Principles and PatternsOOD Principles and Patterns
OOD Principles and Patterns
 
Object Oriented Concepts and Principles
Object Oriented Concepts and PrinciplesObject Oriented Concepts and Principles
Object Oriented Concepts and Principles
 
Advanced OOP - Laws, Principles, Idioms
Advanced OOP - Laws, Principles, IdiomsAdvanced OOP - Laws, Principles, Idioms
Advanced OOP - Laws, Principles, Idioms
 
C# OOP Advanced Concepts
C# OOP Advanced ConceptsC# OOP Advanced Concepts
C# OOP Advanced Concepts
 

Ähnlich wie Rupicon 2014 solid

Frivol Ruby on Beer talk, Sept 2010
Frivol Ruby on Beer talk, Sept 2010Frivol Ruby on Beer talk, Sept 2010
Frivol Ruby on Beer talk, Sept 2010
marcheiligers
 
3java Advanced Oop
3java Advanced Oop3java Advanced Oop
3java Advanced Oop
Adil Jafri
 
The PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
The PHP mysqlnd plugin talk - plugins an alternative to MySQL ProxyThe PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
The PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
Ulf Wendel
 

Ähnlich wie Rupicon 2014 solid (20)

TorqueBox: The beauty of Ruby with the power of JBoss. Presented at Devnexus...
TorqueBox: The beauty of Ruby with the power of JBoss.  Presented at Devnexus...TorqueBox: The beauty of Ruby with the power of JBoss.  Presented at Devnexus...
TorqueBox: The beauty of Ruby with the power of JBoss. Presented at Devnexus...
 
More on bpftrace for MariaDB DBAs and Developers - FOSDEM 2022 MariaDB Devroom
More on bpftrace for MariaDB DBAs and Developers - FOSDEM 2022 MariaDB DevroomMore on bpftrace for MariaDB DBAs and Developers - FOSDEM 2022 MariaDB Devroom
More on bpftrace for MariaDB DBAs and Developers - FOSDEM 2022 MariaDB Devroom
 
OOP, Networking, Linux/Unix
OOP, Networking, Linux/UnixOOP, Networking, Linux/Unix
OOP, Networking, Linux/Unix
 
L07 Design Principles
L07 Design PrinciplesL07 Design Principles
L07 Design Principles
 
LectureNotes-02-DSA
LectureNotes-02-DSALectureNotes-02-DSA
LectureNotes-02-DSA
 
Introduction to Apache Spark
Introduction to Apache SparkIntroduction to Apache Spark
Introduction to Apache Spark
 
Introduction to Apache Spark Developer Training
Introduction to Apache Spark Developer TrainingIntroduction to Apache Spark Developer Training
Introduction to Apache Spark Developer Training
 
Frivol Ruby on Beer talk, Sept 2010
Frivol Ruby on Beer talk, Sept 2010Frivol Ruby on Beer talk, Sept 2010
Frivol Ruby on Beer talk, Sept 2010
 
Lecture 12
Lecture 12Lecture 12
Lecture 12
 
Intro to Rails 4
Intro to Rails 4Intro to Rails 4
Intro to Rails 4
 
Unit 4 lecture-3
Unit 4 lecture-3Unit 4 lecture-3
Unit 4 lecture-3
 
130614 sebastiano panichella - mining source code descriptions from develo...
130614   sebastiano panichella -  mining source code descriptions from develo...130614   sebastiano panichella -  mining source code descriptions from develo...
130614 sebastiano panichella - mining source code descriptions from develo...
 
Introduction to Spark
Introduction to SparkIntroduction to Spark
Introduction to Spark
 
3java Advanced Oop
3java Advanced Oop3java Advanced Oop
3java Advanced Oop
 
البرمجة الهدفية بلغة جافا - مفاهيم أساسية
البرمجة الهدفية بلغة جافا - مفاهيم أساسية البرمجة الهدفية بلغة جافا - مفاهيم أساسية
البرمجة الهدفية بلغة جافا - مفاهيم أساسية
 
Wordpress (class,property,visibility,const,destr,inheritence,mysql etc)
Wordpress (class,property,visibility,const,destr,inheritence,mysql etc)Wordpress (class,property,visibility,const,destr,inheritence,mysql etc)
Wordpress (class,property,visibility,const,destr,inheritence,mysql etc)
 
Introduction to Apache Mesos
Introduction to Apache MesosIntroduction to Apache Mesos
Introduction to Apache Mesos
 
Vapor – Swift is not only for iOS anymore
Vapor – Swift is not only for iOS anymoreVapor – Swift is not only for iOS anymore
Vapor – Swift is not only for iOS anymore
 
Writing & Sharing Great Modules - Puppet Camp Boston
Writing & Sharing Great Modules - Puppet Camp BostonWriting & Sharing Great Modules - Puppet Camp Boston
Writing & Sharing Great Modules - Puppet Camp Boston
 
The PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
The PHP mysqlnd plugin talk - plugins an alternative to MySQL ProxyThe PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
The PHP mysqlnd plugin talk - plugins an alternative to MySQL Proxy
 

Mehr von rupicon

Mehr von rupicon (6)

RSpec matchers
RSpec matchersRSpec matchers
RSpec matchers
 
DIY Cartography
DIY CartographyDIY Cartography
DIY Cartography
 
Dr. PostGIS or: How I Learned to Stop Worrying and Love the Docs
Dr. PostGIS or: How I Learned to Stop Worrying and Love the DocsDr. PostGIS or: How I Learned to Stop Worrying and Love the Docs
Dr. PostGIS or: How I Learned to Stop Worrying and Love the Docs
 
Are you tougher than a boy/girl scout?
Are you tougher than a boy/girl scout?Are you tougher than a boy/girl scout?
Are you tougher than a boy/girl scout?
 
Johnny Cache
Johnny CacheJohnny Cache
Johnny Cache
 
U wont bleev wut dis code doez
U wont bleev wut dis code doezU wont bleev wut dis code doez
U wont bleev wut dis code doez
 

Kürzlich hochgeladen

Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Kürzlich hochgeladen (20)

A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 

Rupicon 2014 solid

  • 1. SOLID OO Design Tudor Pavel 1 / 46
  • 3. Design prepares you for it. 3 / 46
  • 4. Design Stamina Hypothesis http://martinfowler.com/bliki/DesignStaminaHypothesis.html 4 / 46
  • 5. Principles Single Responsibility (SRP) Open/Closed (OCP) Liskov Substitution (LSP) Interface Segregation (ISP) Dependency Inversion (DIP) 5 / 46
  • 6. Single Responsibility A class/method should serve a single purpose. There should never be more than one reason for a class/method to change. 6 / 46
  • 7. Open/Closed A class/method should be open for extension but closed for modification. 7 / 46
  • 8. Liskov Substitution Subclasses should be substitutable for their base classes. 8 / 46
  • 9. Interface Segregation Many client-specific interfaces are better than one general-purpose interface. 9 / 46
  • 10. Dependency Inversion Depend upon abstractions. Do not depend upon concretions. 10 / 46
  • 11. Design is all about dependencies. 11 / 46
  • 12. When you know something, you depend on it. 12 / 46
  • 13. If it changes, you might change. 13 / 46
  • 15. Requirements We are the FBI and our buddies from the NSA post some encrypted messages for us in a secret RSS feed. Our job is to parse the messages from the feed and store them in clear text in our DB, since we don't understand encryption. 15 / 46
  • 16. Encryption The NSA are slightly better than us at encryption, so they've used e Caesar Cipher to encrypt the messages. 16 / 46
  • 17. Message model class Message < ActiveRecord::Base end 17 / 46
  • 18. Public interface class RSSMessagesParser def execute messages = fetch_messages messages.each { |m| Message.create(text: decrypt(m)) } end private def fetch_messages # ... end def decrypt(message) # ... end end 18 / 46
  • 19. Fetching messages require 'rss' class RSSMessagesParser def execute messages = fetch_messages messages.each { |m| Message.create(text: decrypt(m)) } end private def fetch_messages RSS::Parser.parse(open('http://secret.nsa.gov/rss').read).items end def decrypt(message) # ... end end 19 / 46
  • 20. Entire class require 'rss' class RSSMessagesParser def execute messages = fetch_messages messages.each { |m| Message.create(text: decrypt(m)) } end private def fetch_messages RSS::Parser.parse(open('http://secret.nsa.gov/rss').read).items end def decrypt(message) message.split('').map(&:ord).map { |a| a - 3 }.map(&:chr).join end end 20 / 46
  • 21. But what if... the "secret" URL changes? the encryption method changes? reading other RSS feeds is required? 21 / 46
  • 22. Knowing when to refactor Is it DRY? Does it have a single responsibility? Does everything in it change at the same rate? Does it depend on more stable things? ! The answer needs to be YES for all of them to move on. 22 / 46
  • 23. Is it DRY? 23 / 46
  • 24. Does it have a single responsibility? 24 / 46
  • 25. What does RSSMessagesParser do? Fetches messages and decrypts them and saves them to the DB. Words like and and or are design smells suggesting a violation of SRP. This class is doing too much! 25 / 46
  • 26. Extracting responsibilities class MessagesParser def initialize @cipher = NSACipher.new @rss = RSSMessages.new end def execute messages = @rss.fetch messages.each { |m| Message.create(text: @cipher.decrypt(m)) } end end 26 / 46
  • 27. SRP should be applied to methods too class MessagesParser def initialize @cipher = NSACipher.new @rss = RSSMessages.new end def execute messages = @rss.fetch messages.each { |m| parse(m) } end private def parse(message) Message.create(text: @cipher.decrypt(m)) end end 27 / 46
  • 28. The NSACipher class NSACipher def decrypt(message) message.split('').map(&:ord).map { |a| a - 3 }.map(&:chr).join end end 28 / 46
  • 29. The RSSMessages class require 'rss' class RSSMessages def fetch RSS::Parser.parse(open('http://secret.nsa.gov/rss').read).items end end 29 / 46
  • 30. Is it DRY? 30 / 46
  • 31. Does it have a single responsibility? 31 / 46
  • 32. Does everything in it change at the same rate? 32 / 46
  • 33. The RSS URL and the Cipher step can change more often than the classes, because the NSA want to stay at least ahead of the novice hackers by changing them periodically. 33 / 46
  • 34. Using Open/Close Principle class NSACipher def initialize(step=3) @step = step end def decrypt(message) message.split('').map(&:ord).map { |a| a - @step }.map(&:chr).join end end Add default step to simplify current calls The class is now open for extension and reusability. NSACipher is essentially a generic Caesar cipher that can be used to decrypt messages, it has nothing to do with NSA, so we can rename it. 34 / 46
  • 35. Reusable CaesarCipher class CaesarCipher def initialize(step=3) @step = step end def decrypt(message) message.split('').map(&:ord).map { |a| a - @step }.map(&:chr).join end end 35 / 46
  • 36. The same with RSSFetcher require 'rss' class RSSFetcher def initialize(url='http://secret.nsa.gov/rss') @url = url end def fetch RSS::Parser.parse(open(@url).read).items end end 36 / 46
  • 37. Since we're using Rails 4.1 and the two defaults are secret values, we can move them to secrets.yml. development: default_caesar_step: 3 default_rss_url: 'http://secret.nsa.gov/rss' def initialize(url=Rails.application.secrets.default_rss_url) def initialize(step=Rails.application.secrets.default_caesar_step) 37 / 46
  • 38. MessagesParser class class MessagesParser def initialize @cipher = CaesarCipher.new @rss = RSSFetcher.new end def execute messages = @rss.fetch messages.each { |m| parse(m) } end private def parse(message) Message.create(text: @cipher.decrypt(m)) end end 38 / 46
  • 39. Does it depend on more stable things? 39 / 46
  • 40. Using Dependency Inversion class MessagesParser def initialize(cipher, fetcher) @cipher = cipher @fetcher = fetcher end def execute messages = @fetcher.fetch messages.each { |m| parse(m) } end private def parse(message) Message.create(text: @cipher.decrypt(m)) end end MessagesParser now depends upon abstractions being injected by callers 40 / 46
  • 41. Alternative ciphers now supported AES DES ... 41 / 46
  • 42. Alternative fetchers now supported Files Twitter :) ... 42 / 46
  • 43. Conclusions The App is easily adaptable to future changes because of SOLID Design Beautiful and abstract class designs, even Design Patterns (next), were discovered by refactoring and following basic rules and principles Learn to trust your nose and to be prepared for the inevitable changes that are coming 43 / 46
  • 44. References SOLID Object-Oriented Design, Sandi Metz, https://speakerdeck.com/skmetz/solid-object-oriented- design 44 / 46
  • 45. Bonus To make sure the concept of SRP sinks in: http://youtu.be/vlN17gMhnEk (get ready for British English and humour) 45 / 46