Post on 29-Jun-2015
description
Mein Freund,der Legacy-Code
Mathias MeyerPeritor GmbH
self
• Chief Cloud Officer bei Peritor GmbH
• Rubyist
• Asynchronist
• Post-Relationalist
• @roidrage
• http://github.com/mattmatt
Peritor
Amazon Web Services
Ruby on Rails
Scaling
DeploymentPerformance-Tuning/-Reviews
http://dailyawswtf.com
Peritor
Es war einmal
• Eine elegante Programmiersprache
• Ein wunderbar einfaches Web-Framework
Es war einmal
+ =♥
Es war einmal
• Beide erreichten den Mainstream
• Beide wurden von vielen Entwicklern gefunden
• Beide sind keine Garantie für guten Code
Es war einmal
Ruby und Rails im Mainstream = Millionen LOLC*
*LOLC: Lines of Legacy Code
Es war einmal
• Millionen LOLC =
• Legacy-Code ist ein Markt
Legacy-Code?
• Code ohne Tests
Legacy-Code?
• Stuff that other people wrote.
http://www.c2.com/cgi/wiki?LegacyCode
Legacy-Code?
• Technical Debt
Niedrige Kosten/Aufwand am Anfang, im Laufe der Zeit steigend
Legacy-Code?
• Code der in Production ist.
(Mathias Meyer, 2009)
Legacy-Code?
• Ergo:
Code den ihr tagtäglich produziert.
Legacy-Code?
• Code den keiner gern anfässt.
• Code der schwer zu ändern ist.
• Code der fehleranfällig ist.
• Code der stetig verschlimmbessert wird.
Legacy-Code?
• Änderungen werden mit der Zeit exponentiell teurer
• Änderungen führen zu mehr Bugs
• Änderungen brechen existierenden Code
Legacy-Code?
• Negativ vorbelastet
• Riesige Codewürste, unstrukturiert, ungetestet
• Sch***code
• Code-Smells ist noch gelinde ausgedrückt
• Broken-Windows passt schon eher
Legacy-Code?
0
500000
1000000
1500000
2000000
2500000
3000000
3500000
4000000
4500000
5000000
1995 2000 2005 2010
Legacy-Code in Ruby*
LOLC LOTC
* Zahlen frei erfunden
Warum?
• Mangelnde Erfahrung
• Entwickler bringen Java, C, PHP, Perl, etc. in ihren Ruby-Code ein
• Mangelndes Interesse
• “Keine Zeit”
• “Feature-Druck”
Warum?
• Weil Leute immer noch keine Tests schreiben
• Tests: Oftmals schon der halbe Weg zum Glück
• Refactoring ohne Tests: Die Welt des Schmerzes
Eine Geschichte
• Ein Controller
• Er möchte unerkannt bleiben
• Er war die Ausgeburt aller Ängste vor Legacy-Code
Eine Geschichte
• ~1300 Zeilen
• Für mehrere Wochen auf Abspeckkur geschickt
• Auf 200 Zeilen, 3 neue Controller, und den meisten Code ins Model abgeschoben
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
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
Wie?
• Given enough eyeballs, all bugs are shallow.
• And all code will be awesome.
• Nicht immer!
Redmine
• app/controllers/issues_controller.rb:
500 Zeilen, 23.5kb, “Nur” ~1000 Zeilen Tests
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?
Wie?
© http://thisiswhyyourefat.com/
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
Wie?• Know your enemy, because knowing is half the battle
Tools?
Tools?
• Refactoring-Tools in Ruby? Nada
• Gesunder Menschenverstand
• Know when to stop
Wie?
• Code-Metriken
• Code Lesen
• Exploratives Testen
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
Code Lesen
• Use the source, Luke
• Notwendiges Übel
• Knowing!
• Con: Verlieren in Details immer zu einfach
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
Subkategorie: Mocks/Stubs
• Pro: Nützlich gegen unliebsame Abhängigkeiten
• Con: Kann zur Sucht, zum Dauerzustand werden
• Zuviele Mocks verstecken das Wesentliche
• Fantasy Testing
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("TargetofRequest")@reaper=mock("Reaper")Nanite::Reaper.stub!(:new).and_return(@reaper)@request_without_target=mock("Request",:target=>nil,:token=>"Token",:reply_to=>"ReplyTo",:from=>"From",:persistent=>true,:identity=>"Identity")@request_with_target=mock("Request",:target=>"Target",:token=>"Token",:reply_to=>"ReplyTo",: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"shouldforwardrequestswithtargets"do@mapper_with_target.should_receive(:send_request).with(@request_with_target,anything())@cluster_with_target.__send__(:handle_request,@request_with_target)end
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
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
Technik
• Sollbruchstellen finden
• Dependencies idenfizieren, wenn möglich aufbrechen
• Sollbruchstellen mit Tests abdecken
• Refactor!
• Rinse and repeat
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.
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
Technik in Rails
• Dependencies von Controllern nicht vergessen
• Views
• Helper
The Enterprise Way
• Versteck den Legacy-Code hinter noch mehr Legacy-Code
• ESB
• SOA
• EAI
SOAESBEAIOMGWTF!
• SOA: Legacy-Code as a Service
• Wenn schon, dann eine einfache REST-API
• Legacy-Code wird z.B. zum Web-Service
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
SOAESBEAIOMGWTF!• ESB: Enterprise Service Bus
• ESB = EAI + SOA + XML + OMG + Magic
• Unentdecktes Land unter Rubyists
Worauf fokussieren?
Refactoringchen
• Refactor as you go
• Code der angefasst wird, bekommt Tests verpasst und wird aufgeräumt
• Sollte selbstverständlich sein
Gezieltes Aufräumen
• Ein dunkle Stelle anpeilen
• Analysieren
• Testen
• Refaktorieren,
• Nochmals testen
• Sinnvoll bei vielen größeren Code Smells
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
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
Wie verkaufen?
Management Entwickler
Wie verkaufen?
• Management: Wir brauchen mehr Features
• Entwickler: Wir brauchen mehr Zeit zum aufräumen
Wie verkaufen?• Das klassische Vorurteil
• Es gibt auch einen Mittelweg
Wie verkaufen?
• Gar nicht, einfach machen
• Skaliert nicht für große Umbauten
• Hohes Business-Risiko
• Sollte wohl durchdacht sein
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
Danach
Den Beweis antreten
Danach
• Bugs sind kein Weltuntergang, sie kommen vor
• Wenn man sie schneller fixen kann: Win!
Und dann?