solid scala

Post on 26-May-2015

1.852 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

Solid principles with Scala

TRANSCRIPT

S.O.L.I.D with Scala

Oct 23' 2012 > Vikas Hazrati > vikas@knoldus.com > @vhazrati

what?

Five basic principles of object-oriented programming and design.

When applied together intend to make it more likely that a programmer will create a system that is easy to maintain and extend over time.

problems

rigid – difficult to add new features

fragile – unable to identify the impact of the change

immobile – no reusability

viscous – going with the flow of bad practices already being present in the code.

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 – Don't repeat yourself – Avoid copy-paste of code. Change in the code would have to be made in all the places where its been copied.

single responsibility principle - srp

a module should have only one reason to change

Avoid side effects Minimize code touch-points

Increase re-usability

Separate out different responsibilities into different code units

package com.knolx

trait 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

}

class task{ def downloadFile = {} def parseFile = {} def persistData = {}}

for scala

srp applies to

functionsdata structures

packages/ modules of functions

open closed principle - ocp

A module should be open for extension but closed for modification

Avoid side effects Minimize code touch-points

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 = {}}

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 = {}}

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, new BoABank("BoA"), 200.0), new Check(2, new CitiBank("Citi"), 100.0)) def checkProcessor = for (check <-checkList) check.bank.processCheck}

interface segregation principle - isp

many specific interfaces are better than one general purpose interface

Avoid side effects Increase re-usability

trait DoorService{ def isOpen def open def close}

class Door extends DoorService{ def isOpen = {} def open = {} def close = {}}

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) = {}}

dependency inversion principle - dip

depend on abstractions, not on concretions

Avoid side effects reduced effort foradjusting to existing

code changes

Increase re-usability

class TwitterProcessor { def processTweets = new Processor.process(List("1","2"))}

class Processor { def process(list:List[String]) = {}}

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) = {}}

for scala

becomes less relevant for Scala as we can pass higher order functions to achieve the same

behavior

liskov substitution principle - lsp

subclasses should be substitutable for their base classes

Avoid side effects

a 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

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}}

object client2 { def runTheDog(dog:DogBehavior) = {if (dog.isInstanceOf[ToyDog] ) dog.asInstanceOf[ToyDog].batteryPresent=true; dog.run}}

violates ocp now

top related