Mein Freund Der Legacy Code

64
Mein Freund, der Legacy-Code Mathias Meyer Peritor GmbH

description

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

Transcript of Mein Freund Der Legacy Code

Page 1: Mein Freund Der Legacy Code

Mein Freund,der Legacy-Code

Mathias MeyerPeritor GmbH

Page 2: Mein Freund Der Legacy Code

self

• Chief Cloud Officer bei Peritor GmbH

• Rubyist

• Asynchronist

• Post-Relationalist

• @roidrage

• http://github.com/mattmatt

Page 3: Mein Freund Der Legacy Code

Peritor

Amazon Web Services

Ruby on Rails

Scaling

DeploymentPerformance-Tuning/-Reviews

http://dailyawswtf.com

Page 4: Mein Freund Der Legacy Code

Peritor

Page 5: Mein Freund Der Legacy Code

Es war einmal

• Eine elegante Programmiersprache

• Ein wunderbar einfaches Web-Framework

Page 6: Mein Freund Der Legacy Code

Es war einmal

+ =♥

Page 7: Mein Freund Der Legacy Code

Es war einmal

• Beide erreichten den Mainstream

• Beide wurden von vielen Entwicklern gefunden

• Beide sind keine Garantie für guten Code

Page 8: Mein Freund Der Legacy Code

Es war einmal

Ruby und Rails im Mainstream = Millionen LOLC*

*LOLC: Lines of Legacy Code

Page 9: Mein Freund Der Legacy Code

Es war einmal

• Millionen LOLC =

• Legacy-Code ist ein Markt

Page 10: Mein Freund Der Legacy Code

Legacy-Code?

• Code ohne Tests

Page 11: Mein Freund Der Legacy Code

Legacy-Code?

• Stuff that other people wrote.

http://www.c2.com/cgi/wiki?LegacyCode

Page 12: Mein Freund Der Legacy Code

Legacy-Code?

• Technical Debt

Niedrige Kosten/Aufwand am Anfang, im Laufe der Zeit steigend

Page 13: Mein Freund Der Legacy Code

Legacy-Code?

• Code der in Production ist.

(Mathias Meyer, 2009)

Page 14: Mein Freund Der Legacy Code

Legacy-Code?

• Ergo:

Code den ihr tagtäglich produziert.

Page 15: Mein Freund Der Legacy Code

Legacy-Code?

• Code den keiner gern anfässt.

• Code der schwer zu ändern ist.

• Code der fehleranfällig ist.

• Code der stetig verschlimmbessert wird.

Page 16: Mein Freund Der Legacy Code

Legacy-Code?

• Änderungen werden mit der Zeit exponentiell teurer

• Änderungen führen zu mehr Bugs

• Änderungen brechen existierenden Code

Page 17: Mein Freund Der Legacy Code

Legacy-Code?

• Negativ vorbelastet

• Riesige Codewürste, unstrukturiert, ungetestet

• Sch***code

• Code-Smells ist noch gelinde ausgedrückt

• Broken-Windows passt schon eher

Page 18: Mein Freund Der Legacy Code

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

Page 19: Mein Freund Der Legacy Code

Warum?

• Mangelnde Erfahrung

• Entwickler bringen Java, C, PHP, Perl, etc. in ihren Ruby-Code ein

• Mangelndes Interesse

• “Keine Zeit”

• “Feature-Druck”

Page 20: Mein Freund Der Legacy Code

Warum?

• Weil Leute immer noch keine Tests schreiben

• Tests: Oftmals schon der halbe Weg zum Glück

• Refactoring ohne Tests: Die Welt des Schmerzes

Page 21: Mein Freund Der Legacy Code

Eine Geschichte

• Ein Controller

• Er möchte unerkannt bleiben

• Er war die Ausgeburt aller Ängste vor Legacy-Code

Page 22: Mein Freund Der Legacy Code
Page 23: Mein Freund Der Legacy Code
Page 24: Mein Freund Der 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

Page 25: Mein Freund Der Legacy Code

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

Page 26: Mein Freund Der Legacy Code

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

Page 27: Mein Freund Der Legacy Code

Wie?

• Given enough eyeballs, all bugs are shallow.

• And all code will be awesome.

• Nicht immer!

Page 28: Mein Freund Der Legacy Code

Redmine

• app/controllers/issues_controller.rb:

500 Zeilen, 23.5kb, “Nur” ~1000 Zeilen Tests

Page 29: Mein Freund Der Legacy Code

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?

Page 30: Mein Freund Der Legacy Code

Wie?

© http://thisiswhyyourefat.com/

Page 31: Mein Freund Der Legacy Code

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

Page 32: Mein Freund Der Legacy Code

Wie?• Know your enemy, because knowing is half the battle

Page 33: Mein Freund Der Legacy Code

Tools?

Page 34: Mein Freund Der Legacy Code

Tools?

• Refactoring-Tools in Ruby? Nada

• Gesunder Menschenverstand

• Know when to stop

Page 35: Mein Freund Der Legacy Code

Wie?

• Code-Metriken

• Code Lesen

• Exploratives Testen

Page 36: Mein Freund Der Legacy Code

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

Page 37: Mein Freund Der Legacy Code

Code Lesen

• Use the source, Luke

• Notwendiges Übel

• Knowing!

• Con: Verlieren in Details immer zu einfach

Page 38: Mein Freund Der Legacy Code

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

Page 39: Mein Freund Der Legacy Code

Subkategorie: Mocks/Stubs

• Pro: Nützlich gegen unliebsame Abhängigkeiten

• Con: Kann zur Sucht, zum Dauerzustand werden

• Zuviele Mocks verstecken das Wesentliche

• Fantasy Testing

Page 40: Mein Freund Der Legacy Code

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

Page 41: Mein Freund Der Legacy Code

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

Page 42: Mein Freund Der Legacy Code

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

Page 43: Mein Freund Der Legacy Code

Technik

• Sollbruchstellen finden

• Dependencies idenfizieren, wenn möglich aufbrechen

• Sollbruchstellen mit Tests abdecken

• Refactor!

• Rinse and repeat

Page 44: Mein Freund Der Legacy Code

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.

Page 45: Mein Freund Der Legacy Code

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

Page 46: Mein Freund Der Legacy Code

Technik in Rails

• Dependencies von Controllern nicht vergessen

• Views

• Helper

Page 47: Mein Freund Der Legacy Code

The Enterprise Way

• Versteck den Legacy-Code hinter noch mehr Legacy-Code

• ESB

• SOA

• EAI

Page 48: Mein Freund Der Legacy Code

SOAESBEAIOMGWTF!

• SOA: Legacy-Code as a Service

• Wenn schon, dann eine einfache REST-API

• Legacy-Code wird z.B. zum Web-Service

Page 49: Mein Freund Der Legacy Code

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

Page 50: Mein Freund Der Legacy Code

SOAESBEAIOMGWTF!• ESB: Enterprise Service Bus

• ESB = EAI + SOA + XML + OMG + Magic

• Unentdecktes Land unter Rubyists

Page 51: Mein Freund Der Legacy Code

Worauf fokussieren?

Page 52: Mein Freund Der Legacy Code

Refactoringchen

• Refactor as you go

• Code der angefasst wird, bekommt Tests verpasst und wird aufgeräumt

• Sollte selbstverständlich sein

Page 53: Mein Freund Der Legacy Code

Gezieltes Aufräumen

• Ein dunkle Stelle anpeilen

• Analysieren

• Testen

• Refaktorieren,

• Nochmals testen

• Sinnvoll bei vielen größeren Code Smells

Page 54: Mein Freund Der Legacy Code

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

Page 55: Mein Freund Der Legacy Code

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

Page 56: Mein Freund Der Legacy Code

Wie verkaufen?

Management Entwickler

Page 57: Mein Freund Der Legacy Code

Wie verkaufen?

• Management: Wir brauchen mehr Features

• Entwickler: Wir brauchen mehr Zeit zum aufräumen

Page 58: Mein Freund Der Legacy Code

Wie verkaufen?• Das klassische Vorurteil

• Es gibt auch einen Mittelweg

Page 59: Mein Freund Der Legacy Code

Wie verkaufen?

• Gar nicht, einfach machen

• Skaliert nicht für große Umbauten

• Hohes Business-Risiko

• Sollte wohl durchdacht sein

Page 60: Mein Freund Der Legacy Code

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

Page 61: Mein Freund Der Legacy Code

Danach

Den Beweis antreten

Page 62: Mein Freund Der Legacy Code

Danach

• Bugs sind kein Weltuntergang, sie kommen vor

• Wenn man sie schneller fixen kann: Win!

Page 63: Mein Freund Der Legacy Code

Und dann?