Solid scala

2,533 views
2,591 views

Published on

Solid principles with Scala

Published in: Technology

Solid scala

  1. 1. S.O.L.I.D with ScalaOct 23 2012 > Vikas Hazrati > vikas@knoldus.com > @vhazrati
  2. 2. what?Five basic principles of object-orientedprogramming and design.When applied together intend to make it more likely thata programmer will create a system that is easyto maintain and extend over time.
  3. 3. problemsrigid – difficult to add new featuresfragile – unable to identify the impact of the changeimmobile – no reusabilityviscous – going with the flow of bad practices already being present in the code.
  4. 4. solutionsloosely coupled – shouldn’t be too much of dependency between the modules, even if there is a dependency it should be via the interfaces and should be minimal.cohesive code- The code has to be very specific in its operations.context independent code- so that it can be reused.DRY – Dont repeat yourself – Avoid copy-paste of code. Change in the code would have to be made in all the places where its been copied.
  5. 5. single responsibility principle - srpa module should have only one reason to change Avoid side effects Minimize code Increase re-usability touch-pointsSeparate out different responsibilities into different code units
  6. 6. package com.knolxtrait UserService { def changeEmail}class SettingUpdateService extends UserService { def changeEmail ={ checkAccess match { case Some(x) => // do something case None => //do something else } } def checkAccess:Option[Any] = None}
  7. 7. class task{ def downloadFile = {} def parseFile = {} def persistData = {}}
  8. 8. for scala srp applies to functions data structurespackages/ modules of functions
  9. 9. open closed principle - ocpA module should be open for extension but closed for modification Avoid side effects Minimize code touch-points
  10. 10. case class Check(id:Int, bankName:String,amount:Double)class CheckProcessor { val checkList:List[Check] = List(new Check(1,"BoA", 200.0)) def checkProcessor = sendEmail def sendEmail = {}}
  11. 11. case class Check(id:Int, bankName:String, amount:Double)class CheckProcessor { val checkList:List[Check] = List(new Check(1, "BoA",200.0), new Check(2, "Citi", 100.0)) def checkProcessor = for (check <-checkList) if(check.bankName == "BoA") sendEmail else sendFax def sendEmail = {} def sendFax = {}}
  12. 12. trait BankProcess{ def processCheck}class BoABank(name:String) extends BankProcess{ def processCheck = sendEmail def sendEmail = {}}class CitiBank(name:String) extends BankProcess{ def processCheck = sendFax def sendFax = {}}case class Check(id:Int, bank:BankProcess, amount:Double)class CheckProcessor { val checkList:List[Check] = List(new Check(1, newBoABank("BoA"), 200.0), new Check(2, new CitiBank("Citi"),100.0)) def checkProcessor = for (check <-checkList)check.bank.processCheck}
  13. 13. interface segregation principle - ispmany specific interfaces are better than one general purpose interface Avoid side effects Increase re-usability
  14. 14. trait DoorService{ def isOpen def open def close}class Door extends DoorService{ def isOpen = {} def open = {} def close = {}}
  15. 15. trait DoorService{ def isOpen def open def close}trait TimerDoorService{ def closeAfterMinutes(duration:Int)}class Door extends DoorService{ def isOpen = {} def open = {} def close = {}}class TimerDoor extends DoorService with TimerDoorService{ def isOpen = {} def open = {} def close = {} def closeAfterMinutes(duration:Int) = {}}
  16. 16. dependency inversion principle - dipdepend on abstractions, not on concretionsAvoid side effects reduced effort for Increase re-usability adjusting to existing code changes
  17. 17. class TwitterProcessor { def processTweets = new Processor.process(List("1","2"))}class Processor { def process(list:List[String]) = {}}
  18. 18. trait ProcessorService { def process(list:List[String])}class TwitterProcessor { val myProcessor:ProcessorService = new Processor def processTweets = myProcessor.process(List("1","2"))}class Processor extends ProcessorService{ def process(list:List[String]) = process(list, true) def process(list:List[String], someCheck:Boolean) = {}}
  19. 19. for scala becomes less relevant for Scala as we canpass higher order functions to achieve the same behavior
  20. 20. liskov substitution principle - lsp subclasses should be substitutable for their base classes Avoid side effectsa derived class is substitutable for its base class if:1. Its preconditions are no stronger than the base class method.2. Its postconditions are no weaker than the base class method.Or, in other words, derived methods should expect no more and provide no less
  21. 21. trait DogBehavior{ def run}class RealDog extends DogBehavior{ def run = {println("run")}}class ToyDog extends DogBehavior{ val batteryPresent = true def run = { if (batteryPresent) println("run") }}object client {def runTheDog(dog:DogBehavior) = {dog.run}}
  22. 22. object client2 { def runTheDog(dog:DogBehavior) = {if (dog.isInstanceOf[ToyDog] )dog.asInstanceOf[ToyDog].batteryPresent=true; dog.run}} violates ocp now

×