Mein Freund Der Legacy Code

3,562 views

Published on

Slides (in German) from my talk on legacy code at the German Rails-Konferenz.

Published in: Technology
  • Be the first to comment

Mein Freund Der Legacy Code

  1. 1. Mein Freund, der Legacy-Code Mathias Meyer Peritor GmbH
  2. 2. self • Chief Cloud Officer bei Peritor GmbH • Rubyist • Asynchronist • Post-Relationalist • @roidrage • http://github.com/mattmatt
  3. 3. Peritor Ruby on Rails Deployment Performance-Tuning/-Reviews Amazon Web Services Scaling http://dailyawswtf.com
  4. 4. Peritor
  5. 5. Es war einmal • Eine elegante Programmiersprache • Ein wunderbar einfaches Web-Framework
  6. 6. Es war einmal + =
  7. 7. Es war einmal • Beide erreichten den Mainstream • Beide wurden von vielen Entwicklern gefunden • Beide sind keine Garantie für guten Code
  8. 8. Es war einmal Ruby und Rails im Mainstream = Millionen LOLC* *LOLC: Lines of Legacy Code
  9. 9. Es war einmal • Millionen LOLC = • Legacy-Code ist ein Markt
  10. 10. Legacy-Code? • Code ohne Tests
  11. 11. Legacy-Code? • Stuff that other people wrote. http://www.c2.com/cgi/wiki?LegacyCode
  12. 12. Legacy-Code? • Technical Debt Niedrige Kosten/Aufwand am Anfang, im Laufe der Zeit steigend
  13. 13. Legacy-Code? • Code der in Production ist. (Mathias Meyer, 2009)
  14. 14. Legacy-Code? • Ergo: Code den ihr tagtäglich produziert.
  15. 15. Legacy-Code? • Code den keiner gern anfässt. • Code der schwer zu ändern ist. • Code der fehleranfällig ist. • Code der stetig verschlimmbessert wird.
  16. 16. Legacy-Code? • Änderungen werden mit der Zeit exponentiell teurer • Änderungen führen zu mehr Bugs • Änderungen brechen existierenden Code
  17. 17. Legacy-Code? • Negativ vorbelastet • Riesige Codewürste, unstrukturiert, ungetestet • Sch***code • Code-Smells ist noch gelinde ausgedrückt • Broken-Windows passt schon eher
  18. 18. Legacy-Code? Legacy-Code in Ruby* 5000000 LOLC LOTC 4500000 4000000 3500000 3000000 2500000 2000000 1500000 1000000 500000 0 1995 2000 2005 2010 * Zahlen frei erfunden
  19. 19. Warum? • Mangelnde Erfahrung • Entwickler bringen Java, C, PHP, Perl, etc. in ihren Ruby-Code ein • Mangelndes Interesse • “Keine Zeit” • “Feature-Druck”
  20. 20. Warum? • Weil Leute immer noch keine Tests schreiben • Tests: Oftmals schon der halbe Weg zum Glück • Refactoring ohne Tests: Die Welt des Schmerzes
  21. 21. Eine Geschichte • Ein Controller • Er möchte unerkannt bleiben • Er war die Ausgeburt aller Ängste vor Legacy- Code
  22. 22. Eine Geschichte • ~1300 Zeilen • Für mehrere Wochen auf Abspeckkur geschickt • Auf 200 Zeilen, 3 neue Controller, und den meisten Code ins Model abgeschoben
  23. 23. Das will ich auch! • Legacy-Code muss nichts schlechtes sein • Auch wenn er so aussieht • Legacy-Code kann schlimm aussehen, aber es liegt an euch wie ihr ihn hinterlasst • TODOs im Code vermeiden, lieber fixen
  24. 24. Wie? • Offensichtliches • Test all the fucking time, as much and as widely as you can • Refactor like a pr0n star • Pair a lot of the time • Agile, XP, Scrum, oh my! • Man kann es nicht oft genug sagen
  25. 25. Wie? • Given enough eyeballs, all bugs are shallow. • And all code will be awesome. • Nicht immer!
  26. 26. Redmine • app/controllers/issues_controller.rb: 500 Zeilen, 23.5kb, “Nur” ~1000 Zeilen Tests
  27. 27. Wie? • Wie gehe ich mit solchem Code um? • Wie gehe ich ein Refactoring an? • Wie ziehe ich eine Test-Suite auf? • Wie rechtfertige ich große Änderungen?
  28. 28. Wie? © http://thisiswhyyourefat.com/
  29. 29. Halbwahrheiten • Der große Wurf wird nicht auf einmal gelingen • Ein großes Refactoring einplanen ist der Weg ins Verderben • Stetige Verbesserung ist der Weg der Weisen
  30. 30. Wie? • Know your enemy, because knowing is half the battle
  31. 31. Tools?
  32. 32. Tools? • Refactoring-Tools in Ruby? Nada • Gesunder Menschenverstand • Know when to stop
  33. 33. Wie? • Code-Metriken • Code Lesen • Exploratives Testen
  34. 34. Code-Metriken • Mit Statistiken stark riechende Stellen finden • Hohe Signal-Noise-Ratio • Zu einfach den Fokus zu verlieren • Einzig nützlich: Test-Coverage als Peildaumen
  35. 35. Code Lesen • Use the source, Luke • Notwendiges Übel • Knowing! • Con:Verlieren in Details immer zu einfach
  36. 36. Exploratives Testen • Spezifische Teile des Codes mit Tests abdecken • Zeile für Zeile, Feature für Feature • Pro: Test-Suite wächst und ist bereit zum Refactoring • Sehr hoher Lerneffekt, viele Wtf-Momente garantiert
  37. 37. Subkategorie: Mocks/Stubs • Pro: Nützlich gegen unliebsame Abhängigkeiten • Con: Kann zur Sucht, zum Dauerzustand werden • Zuviele Mocks verstecken das Wesentliche • Fantasy Testing
  38. 38. Too. Many. Mocks. before(:each)
do 

@fanout
=
mock("fanout") 

@binding
=
mock("binding",
:subscribe
=>
true) 

@queue
=
mock("queue",
:bind
=>
@binding,
:publish
=>
true) 

@amq
=
mock("AMPQueue",
:queue
=>
@queue,
:fanout
=>
@fanout) 

@serializer
=
mock("Serializer",
:dump
=>
"dumped_value") 

@target
=
mock("Target
of
Request") 

@reaper
=
mock("Reaper") 

Nanite::Reaper.stub!(:new).and_return(@reaper) 

@request_without_target
=
mock("Request",
:target
=>
nil,
:token
=>
"Token", 


:reply_to
=>
"Reply
To",
:from
=>
"From",
:persistent
=>
true,
:identity
=>
"Identity") 

@request_with_target
=
mock("Request",
:target
=>
"Target",
:token
=>
"Token", 


:reply_to
=>
"Reply
To",
:from
=>
"From",
:persistent
=>
true) 

@mapper_with_target
=
mock("Mapper",
:identity
=>
"id") 

@mapper_without_target
=
mock("Mapper",
:request
=>
false,
:identity
=>
@request_without_target.identity) 

@cluster_with_target
=
Nanite::Cluster.new(@amq,
32,
"the_identity",
@serializer,
@mapper_with_target) 

@cluster_without_target
=
Nanite::Cluster.new(@amq,
32,
"the_identity",
@serializer,
@mapper_without_target) 

Nanite::Cluster.stub!(:mapper).and_return(@mapper) end it
"should
forward
requests
with
targets"
do 

@mapper_with_target.should_receive(:send_request).with(@request_with_target,
anything()) 

@cluster_with_target.__send__(:handle_request,
@request_with_target) end
  39. 39. Parallele Welten • Notfallwaffe • Code auseinandernehmen und parallel neu aufbauen (aus existierendem) • Ja, zuerst auch ohne Tests, wenn’s sein muss • Test-Suite aufbauen mit den verschobenen Code-Teilen • Eltern haften für ihre Kinder
  40. 40. Test-Suite Aufbauen • Jetzt? Ja! • Für die ganze Code-Basis? Nein! • Klein anfangen,Vorher Hände waschen! • Tests schreiben für Funktionalität die durch neue Features zerbrechen kann • Skaliert nicht bei großen Geschwüren
  41. 41. Technik • Sollbruchstellen finden • Dependencies idenfizieren, wenn möglich aufbrechen • Sollbruchstellen mit Tests abdecken • Refactor! • Rinse and repeat
  42. 42. Technik in Rails • RESTful als Guideline, nicht als Mantra • Controller aufbrechen • Zuviele Actions bedeuten zuviele potentielle Ressourcen • Code raus aus den Controllern, sie müssen dumm sein • resource_controller, make_resourceful, etc.
  43. 43. Technik in Rails • Tests von oben nach unten • Controller-Tests decken das wichtigste ab • Views nicht vergessen • Unit-Tests sollten daraus entstehen • Models != ActiveRecord • Neue Models braucht das Land
  44. 44. Technik in Rails • Dependencies von Controllern nicht vergessen • Views • Helper
  45. 45. The Enterprise Way • Versteck den Legacy-Code hinter noch mehr Legacy-Code • ESB • SOA • EAI
  46. 46. SOAESBEAIOMGWTF! • SOA: Legacy-Code as a Service • Wenn schon, dann eine einfache REST-API • Legacy-Code wird z.B. zum Web-Service
  47. 47. SOAESBEAIOMGWTF! • EAI: Enterprise Application Integration • Versteckt Code hinter Messaging-Backends • Dröger Name, großer Effekt • Entkoppelt alten von neuem Code • Erspart nicht das Refactoring, macht es aber potentiell einfacher
  48. 48. SOAESBEAIOMGWTF! • ESB: Enterprise Service Bus • ESB = EAI + SOA + XML + OMG + Magic • Unentdecktes Land unter Rubyists
  49. 49. Worauf fokussieren?
  50. 50. Refactoringchen • Refactor as you go • Code der angefasst wird, bekommt Tests verpasst und wird aufgeräumt • Sollte selbstverständlich sein
  51. 51. Gezieltes Aufräumen • Ein dunkle Stelle anpeilen • Analysieren • Testen • Refaktorieren, • Nochmals testen • Sinnvoll bei vielen größeren Code Smells
  52. 52. The Big Refactoring • Sowas wie ein Big Refactoring existiert nicht • Refactoring ist ein Prozess • In jeder Iteration Zeit einplanen zum Aufräumen alten Codes, mit spezifischem Ziel • Aber: Es ist eine Alternative
  53. 53. The Big Rewrite • Beliebt bei Entwicklern • Unbeliebt beim Management, zu Recht • Funktioniert so gut wie nie • Oftmals voller Stop der Entwicklung • Kulmuliert neuen Legacy-Code • Ergebnis bleibt meist weit hinter Erwartungen zurück
  54. 54. Wie verkaufen? Management Entwickler
  55. 55. Wie verkaufen? • Management: Wir brauchen mehr Features • Entwickler: Wir brauchen mehr Zeit zum aufräumen
  56. 56. Wie verkaufen? • Das klassische Vorurteil • Es gibt auch einen Mittelweg
  57. 57. Wie verkaufen? • Gar nicht, einfach machen • Skaliert nicht für große Umbauten • Hohes Business-Risiko • Sollte wohl durchdacht sein
  58. 58. Wie verkaufen? • Argumente sammeln • Code-Änderungen werden teurer • Neue Features fließen langsamer • Leidenschaftlich, aber nicht trotzig, Konsens ist trotzdem wichtig • Wenn gar nichts mehr geht, Notbremse ziehen
  59. 59. Danach Den Beweis antreten
  60. 60. Danach • Bugs sind kein Weltuntergang, sie kommen vor • Wenn man sie schneller fixen kann: Win!
  61. 61. Und dann?
  62. 62. Fin mathias.meyer@peritor.com

×