Mein Freund Der Legacy Code

Preview:

DESCRIPTION

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

Citation preview

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?

Recommended