Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Single Responsibility Principle

Single Responsibility Principle

An overview with examples of the Single Responsibility Principle and what you can expect from it.

Rich Dammkoehler

July 20, 2016
Tweet

More Decks by Rich Dammkoehler

Other Decks in Programming

Transcript

  1. What is it? The notion that any class or module

    should have only one reason to change Alternately: Things that change for the same reasons should be together. Things that change for different reasons should be kept apart.
  2. Why should I care? Robustness of design (easy maintenance) Isolation

    of functionality (portability/reuse) Design Simplification (fewer moving parts) Easier to Test (only one thing to worry about)
  3. How do I do it? Think about responsibilities in terms

    of a person who controls or uses it Any module should be responsible to only one person (or role) Consider, how to build code such that changes requested by different roles do not break or change code written for a different role e.g. Changing page layout should not impact Business Rules about valid data
  4. Real(istic) Example class DataLoader:
 def load_data(self):
 with DB.connect('mydb@localhost') as db:


    with open('/etc/passwd', 'r') as input:
 for line in input.readlines():
 if not line.startswith('#'):
 parts = line.split(':')
 struct = {
 'login_name': parts[0],
 'password': parts[1],
 'uid': parts[2],
 'gid': parts[3],
 'user_name': parts[4],
 'home_dir': parts[5],
 'shell': parts[6]
 }
 db.write(struct)
  5. With proper SRP: class DataLoader:
 def __init__(self):
 self.loader = FileLoader()


    self.transformer = Transformer()
 self.writer = DB()
 
 def load_data(self):
 for record in self.loader.load_file('/etc/passwd'):
 self.writer.write(self.transformer.transform(record))
 
 
 class FileLoader:
 def load_file(self, filename):
 with open(filename, 'r') as input:
 for line in input:
 yield line
 
 
 class Transformer:
 def transform(self, line):
 if not line.startswith('#'):
 parts = line.split(':')
 return {
 'login_name': parts[0],
 'password': parts[1],
 'uid': parts[2],
 'gid': parts[3],
 'user_name': parts[4],
 'home_dir': parts[5],
 'shell': parts[6]
 }
  6. What is this good for again? Because each module is

    independent of the other you can change it without affecting the other parts You can test each module in total isolation No matter what you do, as long as the input/output structures don’t change you can modify code to your hearts content Each module is easily reused You don’t have to think nearly as hard about things (because they are simple and focused)
  7. Stuff you might notice Fewer methods per class Interesting question,

    how many methods should a class have? Fewer arguments to methods/functions How many is too many? What do you do about that? Test are considerably easier to write
  8. Know it when you see it Classes have few dependencies

    Methods have few parameters Tests are simple and straightforward Code is short Changes to the code do not effect other modules/code
  9. Additional Materials: Uncle Bob - SRP, Norwegian Developers Conference 2012

    https://youtu.be/Gt0M_OHKhQE Uncle Bob - The Single Responsibility Principle https://blog.8thlight.com/uncle-bob/2014/05/08/ SingleReponsibilityPrinciple.html DZone - The Single Responsibility Principle https://dzone.com/articles/single-responsibility