Your SlideShare is downloading. ×
En introduktion till SOLID-principerna
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

En introduktion till SOLID-principerna

2,776
views

Published on

An introduction to the SOLID principles in Swedish that I gave at the EPiServer developers meetup in june 2010. You probably need to read the comments to understand some of the slides.

An introduction to the SOLID principles in Swedish that I gave at the EPiServer developers meetup in june 2010. You probably need to read the comments to understand some of the slides.

Published in: Technology

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,776
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
24
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • Sommaren 2008 var jag och min fru på semester i Egypten. Det var en tvåveckorssemester där vi spenderade en vecka med att kryssa på nilen och en vecka åt sol och bad i Hurghada. En nilenkryssning kanske låter som någonting väldigt avslappnande, iaf om man fokuserar på ordet kryssning. Det kan jag garantera att det inte är! Vi spenderade 14 timmar per dag åt att titta på olika 4000 år gamla tempel och gravar i 40 gradig hetta. Väl i Hurghada kunde vi dock ta det lugnt. Jag har dock ganska svårt att bara ligga på en solstol och inte göra någonting alls så jag hade sett till att ha med mig en bok. Vid den här tidpunkten var jag en hyfsad programmerare som hade hunnit bekanta mig en del med såväl grundläggande datalogi som Java och .NET. Men jag hade på känn att det fanns något mer under ytan och två nyckelord för det verkade vara ”agilt” och ”patterns”. Därför hade jag innan resan begett mig till Adlibris för att beställa en bok.
  • Det slutade med att jag köpte den här boken, Agile Principles, Patterns and Practices in C#. Den innehöll ju trots allt både ordet ”agile” och ordet ”patterns” i titeln så den kunde ju omöjligen vara fel.Jag började läsa boken när vi kom fram till Hurghada och det slutade med att jag läste den från pärm till pärm under den veckan. Med tanke på att den är 700 sidor så blev det inte särskilt mycket badande.Jag hade ju köpt boken med ambitionen att lära mig mera om mitt yrke utöver det rena kodknackandet och den levererade verkligen. I själva verket kom den att ha en väldigt stor påverkan på mig. Dock på ett lite annorlunda sätt än jag hade trott när jag köpte den.
  • Boken som är lite av en tegelsten omfattar väldigt många ämnen. Exempelvis UML, patterns och agila metoder för utveckling. Notera att SCRUM saknas på den här sliden. Det är för att boken är skriven av en utvecklare för utvecklare. Jag menar inte att SCRUM är ointressant för oss utvecklare, men på senare tid har SCRUM och andra projektmetodiker kommit att överskugga vad jag ser som själva fundamentet för agil utveckling, nämligen metoder för att skapa lättrörliga, eller agila, kodbaser.Hur som helst, jag nämnde ju att boken kom att ha en stor påverkan på mig, men på ett lite annorlunda sätt än jag tänkt mig. Jag hade ju köpt boken för att lära mig mera om patterns och också för att lära mig det där agila buzzwordet var för någonting. Som en bok om patterns visade det sig dock att den var ganska medioker. Och även om kapitlen om XP, TDD och så vidare var intressanta beskrev de en verklighet som var så långt ifrån min att det känndes ganska abstrakt. Istället visade det sig att det var kapitlen om designprinciper, främst de för klasser som går under samlingsnamnet SOLID som kom att ha en stor påverkan på mig.
  • Ofta när vi drar igång utvecklingen i ett projekt så är alla entusiastiska vi producerar features i en rask takt. Allt eftersom projektet fortlöper tenderar dock ofta den takten att gradvis avta. Delvis därför att den initiala entusiasmen avtar men också därför att nya funktioner som vi bygger behöver leva i harmoni med de funktioner som vi redan har byggt vilket ofta innebär att vi behöver gå tillbaka och vidareutveckla eller förändra redan levererade funktioner. Sen kanske dessutom några kundkrav ändras och vi behöver återigen modifiera redan existerande funktioner.Om det går riktigt illa ersätts entusiasmen i projektet av en trötthet, och ibland rent av en bitterhet. En bitterhet gentemot kunden för att de ändrar sina krav. Mot leverantörer av ramverk för att de inte gör det enkelt för oss att hantera förändrade krav. Och kanske hyser vi också lite bitterhet gentemot oss själva för att vi var så naiva i början att vi inte förutsåg att kraven skulle ändras.Till slut, ibland redan innan lansering, ibland några år senare, hamnar vi i ett läge där varje estimat för ändringer eller ny funktionalitet som vi ombeds estimera blir löjligt höga eftersom vi upplever systemet som så dåligt.
  • Om vi har tur så arbetar vi med kunder och kollegor som ifrågasätter varför våra estimat är så höga. Vi funderar lite och ofta är svaret att det egentligen inte alls tar så lång tid att göra den förändring som efterfrågas. Men vi är rädda för att andra saker kommer att påverkas om vi genomför förändringen och därför måste ta höjd för de följdfel som kan tänkas uppstå. Dvs vi är rädda att om vi rör funktion A så kommer det att påverka funktion B och kanske även funktion C. Och om vi fixar de följdfel som uppstår kanske de fixarna kommer att orsaka nya följdfel.Enligt min erfarenhet finns det två saker som ofta gör att vi hamnar i den här typen av situationer.
  • Komponenterna, ofta klasser, i vårt system är hårt kopplade till varandra genom att de är beroende av varandra.
  • Vårt system innehåller massor med onödig komplexitet. Ibland har den uppstått genom att vi försökt vara smarta och bygga saker som vi tror oss behöva i framtiden. Ibland genom att kraven, eller vår bild av kraven, har förändrats och vi har implementerat den till synes snabbaste lösningen. Ändrat någon if-sats här. Lagt till ett switch-block där.
  • The Single Responsibility Principle, översatt från engelska, säger att en klass bör ha en och endast en, anledning att ändras.
  • Med andra ord så bör en klass bara göra en sak. Mindre viktiga uppgifter bör delegeras till andra klasser.The Single Responsibility Principle är förmodligen den lättaste av principerna att förstå men i verkligheten visar det sig ofta att det är den svåraste att efterleva. Men det är ofta en förutsättning att man efterlever principen för att kunna efterleva de andra principerna.Ett ganska enkelt sätt som ofta fungerar för att testa om ens klass följer Single Responsibility Principle är att ge den ett namn som beskriver allt som den gör. Om det namnet innehåller ordet ”and” så gör klassen för mycket.
  • The Open/Closed Principle säger att att en klass beteende ska kunna utökas utan att klassen behöver modifieras.Med andra ord så bör vi skriva kod vars beteende vi kan förändra utan att vi behöver ändra i koden. Det finns flera olika sätt att åstadkomma det men normalt sett så menas att det bör gå att förändra en klass beteende genom att ärva från den och overridea en viss metod eller genom att låta vår klass delegera sådant som inte är dess kärnverksamhet till andra klasser och göra dessa utbytbara.Den här principen har tagit mig flera år att förstå, vilket delvis beror på att jag är trög, men också på att den är ganska abstrakt. Låt oss därför titta på ett exempel.
  • The Open/Closed Principle säger att att en klass beteende ska kunna utökas utan att klassen behöver modifieras.Med andra ord så bör vi skriva kod vars beteende vi kan förändra utan att vi behöver ändra i koden. Det finns flera olika sätt att åstadkomma det men normalt sett så menas att det bör gå att förändra en klass beteende genom att ärva från den och overridea en viss metod eller genom att låta vår klass delegera sådant som inte är dess kärnverksamhet till andra klasser och göra dessa utbytbara.Den här principen har tagit mig flera år att förstå, vilket delvis beror på att jag är trög, men också på att den är ganska abstrakt. Låt oss därför titta på ett exempel.
  • Låt oss säga att vi har blivit ombedda att skapa en klass beräknar den totala arean för ett antal rektanglar.
  • Inga problem. Vi skapar en enkel liten klass med en enda metod, Area, som tar en lista med rektanglar som parameter och returnerar deras totala area.
  • Nästa vecka kommer kunden tillbaka till oss och berättar att de har haft ett möte i styrgruppen och det finns även ett behov av att kunna beräkna arean för både rektanglar och cirklar.
  • Inga problem! Vi skapar en basklass för både rektanglar och cirklar kallad shape. Sedan ändrar vi vår Area-metod till att hantera både cirklar och rektanglar.Vår lösning fungerar utmärkt i ytterligare en vecka tills kunden haft ett nytt styrgruppsmöte och det visar sig att man även behöver kunna beräkna arean för trianglar.Så, vi skapar ytterligar en klass som ärver av Shape och gör om vår else-if i Area-metoden till ett switch-block för att hantera alla tre tänkbara figurer.Med den här lösningen behöver vi modifiera vår klass som beräknar areor för figurer varje gång en ny typ av figur läggs till. Vår klass är dessutom beroende av alla typer av figurer som den stödjer vilket innebär att om vi senare vill ta bort en typ av figur eftersom den inte längre används så måste vi återigen ändra i vår klass. Eftersom vi är rädda att det kan leda till buggar tar vi den enkla vägen ut och låter figurtypen som egentligen inte behövs vara kvar. Som resultat har vi en klass i vår applikation som inte används. Men det är det bara vi som vet.Vår klass är inte öppen för utökning och inte stängd för modifiering eftersom det enda sättet att utöka den är genom att modifiera den.
  • En alternativ lösning som satisfierar Open/Closed Principle vore att låta varje form tala om sin egen area och bara summera dem i AreaCalculator. Om vi sedan behöver lägga till, eller ta bort, former så är AreaCalculator lyckligt ovetande om det. Dess beteende är öppet för utökning men stängt för modifiering.
  • Ett exempel på ett ställe i EPiServers API som bryter mot den här principen är DataFactory som implementerar interfacet IPageSource. IPageSource har en property som heter CurrentPage. Anropar man den på DataFactory returneras null.
  • IPageSource implementeras av PageBase, Property, PageControlBase etc. Det implementeras även av DataFactory.GetChildren och GetPage är specifika till ett visst användningsscenario, CurrentPage till ett annat.
  • Transcript

    • 1. Hur uncle Bob förändrade mitt liv
      En introduktion till SOLID principerna
      @joelabrahamsson
    • 2.
    • 3.
    • 4. Agile Principles, Patterns and Practices in C#
      UML (as a sketch)
      Patterns
      Agila arbetssätt som XP, TDD och Refactoring
      Designprinciper för klasser och paket/assemblies
    • 5.
    • 6.
    • 7.
    • 8.
    • 9. Single Responsibility Principle
      Open/Closed Principle
      Liskov Substitution Principle
      Interface Segregation Principle
      Dependency Inversion Principle
    • 10. SOLID
      Fem priciper för objektorienterad utveckling
      Hantera beroenden mellan klasser och reducera onödig komplexitet
      Underlättar testning
      Principer, inte lagar
      Kräver att studeras
    • 11. Single Responsibility Principle
      En klassbör ha en, ochendast en, anledningattändras.
    • 12. Med andra ord...
      En klassskabaragöra en sak.
    • 13. Exempel
      publicclassCustomer
      {
      publicIEnumerable<Order> Orders { get {...} }
      publicboolIsValid() {...}
      publicvoid Save() {...}
      }
    • 14. Single Responsibility Principle
      Är även applicerbar på metoder, paket/assemblies etc.
      Ligger till grund för många av de andra principerna
    • 15.
    • 16. Open/Closed Principle
      Klasserskavaraöppnaförutökning men stängdaförmodifiering.
    • 17. Med andra ord...
      Vi böranvändaarvochpolymorfismförattskrivakodsomintebehöverändrasnärkravengör det.
    • 18. Exempel
      Vi behöver en klasssomberäknarareanförettantalrektanglar.
      publicclassRectangle
      {
      publicdouble Width { get; set; }
      publicdouble Height { get; set; }
      }
    • 19. Let’s do it!
      publicclassAreaCalculator
      {
      publicdouble Area(Rectangle[] shapes)
      {
      double area = 0;
      foreach (var shape in shapes)
      {
      area += shape.Width*shape.Height;
      }
      return area;
      }
      }
    • 20. Ett nytt krav
      Vi glömdeattdetfinnscirklar. Vi behöverberäknaareanförbådecirklarochrektanglar.
    • 21. En basklass och en if-sats -> Done!
      publicabstractclassShape { }
      publicclassAreaCalculator
      {
      publicdouble Area(Shape[] shapes)
      {
      double area = 0;
      foreach (var shape in shapes)
      {
      if (shape isRectangle)
      area += RectangleArea((Rectangle)shape);
      else
      area += CircleArea((Circle) shape);
      }
      return area;
      }
      }
    • 22. En bättre lösning
      publicabstractclassShape
      {
      publicabstractdouble Area();
      }
      publicclassAreaCalculator
      {
      publicdouble Area(Shape[] shapes)
      {
      double area = 0;
      foreach (var shape in shapes)
      {
      area += shape.Area();
      }
      return area;
      }
      }
    • 23.
      • Den viktigasteavprinciperna
      • 24. Kravenändrasständigt…
      • 25. …men vi behöverändåskrivakodsomärstabil
      • 26. Med OO kan vi skapaabstraktioner med stabil design men flexibeltbeteende
      • 27. Närska vi appliceraprincipen?
      Open/Closed Principle
    • 28.
    • 29. Dependency Inversion Principle
      A. Högnivåmodulerskaintevaraberoendeavlågnivåmoduler. Bådaskavaraberoendeavabstraktioner.
      B. Abstraktionerskaintevaraberoendeavdetaljer. Detaljerskavaraberoendeavabstraktioner.
    • 30. Med andra ord...
      Våraklasserskaintevaraberoendeavandraklasser. De skavaraberoendeavabstraktioner.
    • 31. Möjliggör att en klass kan använda en annan komponent utan att känna till vilken specifik implementation det är
      Åstadkoms genom Dependency Injection ellerService Locator
      Inversion of Control
    • 32. Ett exempel
    • 33. IoC leder till flexibel design
    • 34. Den som använder vår klass måste tillhandahålla instanser av de klasser som den behöver
      Constructor Injection
      Property Injection
      Dependency Injection
    • 35. The consumer retrieves the component it depends upon from a third party, a Service Locator
      Use Dependency Injection instead if you can
      Service Locator
    • 36.
    • 37. Liskov Substitution Principle
      Subklassermåstevarautbytbara mot dessbasklasser.
    • 38. Med andra ord...
      Användareavvårsubklassskaintebehövabry sig omhuruvida de användersubklassenellerbasklassen.
    • 39. Ett enkelt exempel
      publicabstractclassAnimal
      {
      publicabstractvoidMakeNoise();
      }
    • 40. Ett enkelt exempel
      publicclassCat : Animal
      {
      publicoverridevoid MakeNoise()
      {
      Console.WriteLine("Mjau");
      }
      }
    • 41. Ett enkelt exempel
      publicclassSnail : Animal
      {
      publicoverridevoid MakeNoise()
      {
      thrownewNotImplementedException();
      }
      }
    • 42. Liskov Substitution Principle
      Detär OK attförsvagaförhandsvillkorochstärkaefterhands-villkori en subklass men intetvärtom.
      Om vi bryter mot LSP såtyderdetpåatt vi behöverrefaktoriseravårklasshierarki
      En princip, inte en lag
    • 43.
    • 44. Interface Segregation Principle
      Användareavett interface skaintetvingasvaraberoendeavmetodersom de inteanvänder.
    • 45. Med andra ord...
      Skapa interface somärsmåochlogisktsammanhängande.
    • 46. Exempel - IPageSource
      publicinterfaceIPageSource
      {
      PageDataCollectionGetChildren(PageReferencepageLink);
      PageDataGetPage(PageReferencepageLink);
      PageDataCurrentPage { get; }
      }
    • 47. Exempel - IPageSource
      publicclassDataFactory : IPageSource
      {
      publicPageDataGetPage(PageReferencepageLink)
      { ... }
      publicPageDataGetChildren(PageReferencepageLink)
      { ... }
      publicPageDataCurrentPage
      {
      get
      {
      returnnull;
      }
      }
      }
    • 48.
    • 49. Mer om SOLID-principerna
      Agile Principles, Patterns and Practices in C#
      butunclebob.com
      blog.objectmentor.com
      Stefan Forsbergs serie på EPiServer World
      www.codingefficiency.com
    • 50. Mer av uncle Bob
    • 51. Sammanfattning
      Uncle Bob, Robert C.Martin, är en författare vi kan lära mycket av
      Läs Agile Principles, Patterns and Practices in C#!
      Läs Clean Code!
      SOLID är fem principer för objekt orienterad utveckling som hjälper oss hantera beroenden och komplexitet
    • 52.
    • 53. @joelabrahamsson
      http://joelabrahamsson.com