• Noser.com
facebook
linkedin
twitter
youtube
  • NOSERmobile
    • Android
    • HTML 5
    • Hybrid Apps
    • iOS
    • Windows Phone
  • NOSERembedded
    • Medizintechnik
  • NOSERprojektmanagement
  • NOSERtesting
  • NOSERlifecycle
    • .NET Allgemein
    • Application Lifecylce Management
    • Apps
    • Architektur
    • ASP.NET
    • Azure
    • Cleancode
    • Cloud
    • Silverlight
    • Visual Studio / Team Foundation Server
    • Windows 8
    • Windows Presentation Foundation
  • NOSERinnovation
    • Big Data
    • Cloud
    • IoT
    • Operations Research
    • Augmented Reality
    • RFID, NFC, Bluetooth LE

Keine Angst vor Branching und Merging

20. Februar 2014
Nathalie Kellenberger
0
Branch, Branching, Merge, Merging, Multiple Checkout, Patch, Release, TFS

Meist nutzen wir nur einen Bruchteil der Möglichkeiten des Team Foundation Servers (TFS) im Entwickleralltag. In diesem Beitrag möchte ich näher auf Branching und Merging eingehen. Als ich an meiner ersten Stelle an der Produktentwicklung beteiligt war und mit Releases und Patches gearbeitet habe, war das ein selbstverständlicher Begriff. Ich weiss noch gut, dass ich bei jedem Merging feuchte Hände bekam. Seither habe ich hauptsächlich auf Projektbasis gearbeitet und kam meist ohne Branching und Merging aus. Allenfalls wurde Multiple Checkout aktiviert, wenn mehrere Personen an derselben Codebasis arbeiteten.

So lange also alle am gleichen Projekt, für denselben Release und im gleichen Team arbeiten, mag ein Codestrang mit Single oder allenfalls Multiple Checkout ausreichen. Sobald aber mehrere Teams am gleichen Code arbeiten müssen und Releases ins Spiel kommen, sieht es etwas anders aus. Dies war vor über einem Jahr in meinem aktuellen Team der Fall. Es gab zwei Scrum Teams und ein Kanban Team. Die Scrum Teams lieferten jeden Sprint Code aus, der in eben diesem Sprint-Zyklus verteilt wurde. Beim Kanban Team verhielt es sich so, dass alles verteilt wurde, was zu diesem Zeitpunkt abgenommen war. Da es sich beim Kanban Team nicht abschätzen liess, wann eine Story abgeschlossen sein würde, konnte es passieren, dass es Codeanpassungen gab, die noch nicht live gehen durften. Wir haben uns daher überlegt, wie wir mit diesen unterschiedlichen Teams und Release-Zyklen umgehen wollen und eine Strategie des Branching und Mergings entwickelt. Über das letzte Jahr haben wir diese Strategie verfeinert und mehrfach erprobt, so dass ich sie gerne an dieser Stelle präsentiere.

Branches

Wir haben zwei Haupt-Branches ausgemacht, je einen für

  • den aktuellen Release, der gerade live ist (CurrentRelease-Branch)
  • die aktuelle Weiterentwicklung (NextRelease-Branch)

 

Wenn Patches für ältere Releases vonnöten sind, behält man die Branches älterer Releases auf, ansonsten löscht man sie, wenn ein neuer Release live geht, respektive der neue Release Branch erstellt wird.

Auf dem Release-Strang können jederzeit akute Fehler, die auf dem System auftreten, behoben werden, während am zweiten Strang weiterentwickelt wird für den nächsten Release. Der knifflige Branch ist klar der für den nächsten Release, weil an diesem alle Teams entwickeln. Wir haben daher beschlossen, zusätzlich für jede Story einen eigenen Branch zu erstellen. Der Story-Branch wird vom NextRelease-Branch aus erstellt und auf ihm die gesamte Story entwickelt. Wenn die Entwicklung abgeschlossen ist, wird der Story-Branch auf das Testsystem verteilt und abgenommen. Erst nach der Abnahme wird der Story-Branch in den NextRelease-Branch gemerged, damit sich in diesem wirklich nur Code wiederfindet, der auch tatsächlich live gehen wird beim nächsten Release und für alle weiteren Storys als Basis dient.

Der Lebenszyklus eines Story-Branchs sieht dann wie folgt aus:

Branching-Merging-Process

Was, wenn jetzt aber eine Story grundlegende Elemente ändert, so dass weitere Branches auf ihren Codestand angewiesen sind? Dann gilt es die Storys zu gliedern. Die, nennen wir sie Basis-Story, muss vor allen folgenden abgenommen werden. Das heisst aber auch, dass sie als Basis für alle folgenden vorausgesetzt werden kann. Der jeweilige Codestand kann daher in die anderen Story-Branches gemerged werden. Aber noch nicht in den NextRelease-Branch!

Das Mergen von einem Story-Branch zum andern ist nicht so angenehm, da der TFS nicht erkennt, dass die beiden Branches dieselbe Basis haben, da sie nicht direkt voneinander abhängen. Er vergleicht daher alle Files, checkt auch alle aus und es treten meist mehr Konflikte auf. Damit das beim normalen Ablauf nicht passiert, sollte man ein Auge auf die Vererbung von Branches haben.

Vererbung

Welcher Branch wird von welchem erstellt? Der TFS unterstützt mich am besten beim Merging des Branches zurück zu demjenigen, von dem aus er erstellt wurde. Daher haben wir in unserem Prozess die häufigsten Merging Schritte ausgemacht und uns überlegt, von welchen Strängen jeweils ein Branch gezogen werden soll.

Story-Branches werden jeweils zurück zum NextRelease-Branch gemerged, Hotfixes für das Livesystem zurück in den CurrentRelease-Branch und den NextRelease-Branch. Ansonsten tritt der Bug nach dem nächsten Release wieder auf. Merging zwischen Story-Branches gibt es nur in Ausnahmefällen bei Abhängigkeiten. Damit das Merging also jeweils angenehm verläuft und der TFS nur die Files als geändert vermerkt, die wir in dem Branch auch geändert haben, sollten alle Branches vom NextRelease-Branch aus erstellt werden. Eine Ausnahme gibt es, die Hotfixes, auf die komme ich gleich noch zu sprechen. Dabei ist der Zeitpunkt der Erstellung eines Branches entscheidend! Der CurrentRelease-Branch wird zum Zeitpunkt des Codefreeze für den Release vom NextRelease-Branch erstellt. Story-Branches hingegen, wenn eine neue Story begonnen wird.

Branching-Merging-Releases

Das heisst aber auch, dass Branches für Hotfixes vom aktuellen Release vom CurrentRelease-Branch aus erstellt und in diesen gemerged werden. Denn sie dürfen nur die Codebasis verwenden, die derzeit live ist. Nun könnte man den Hotfix-Branch einmal in den CurrentRelease-Branch und einmal in den NextRelease-Branch mergen, das macht aber wegen der Vererbung der Branches wenig Sinn. Daher sollte der Hotfix immer zuerst in den CurrentRelease-Branch gemerged und dann der CurrentRelease-Branch in den NextRelease-Branch germerged werden. So haben wir die volle Unterstützung des TFS und merken erst noch, dass vielleicht sogar Code am CurrentRelease-Branch geändert wurde, der noch gar nicht in den NextRelease-Branch gemerged wurde.

Daher Vorsicht!

Feuchte Hände hin oder her, ein bisschen Konzentration ist durchaus vonnöten beim Merging. Denn gern geht vergessen, die Änderung für den Hotfix auch in den NextRelease-Branch zu mergen. Auch bei Konflikten ist Vorsicht geboten! Nicht dass eine Änderung plötzlich wieder rückgängig gemacht wird, die von einer anderen Story kam. Ich habe mir bei einem Kollegen abgeschaut, vor jedem Checkin nochmals alle Änderungen mit der letzten Version zu vergleichen. Dabei fallen mir Fehler eher auf. Gerade beim Merging habe ich mir so schon oft den Kopf aus der Schlinge gezogen.

Der TFS kann uns jedoch noch besser unterstützen. Dazu können bspw. Regeln erfasst werden, die uns zwingen in die richtigen Branches zu mergen. Die meisten Fehler beim Branching und Merging sind Benutzerfehler. Da wir eben alle Fehler machen und vergesslich sind, sollte man so viele Fälle wie möglich mit dem Tool abdecken. Wenn der Prozess von allen verinnerlicht wird, ist das unter Umständen nicht nötig.

Auch keine Angst vor Undo und Rollback

Heute habe ich keine feuchten Hände mehr beim Merging, ich bin jetzt ein alter Hase. Aber eigentlich gibt es auch keinen Grund dazu. Schliesslich checkt Visual Studio alle geänderten Files beim Merging erst einmal aus. Sollte irgendetwas schief gelaufen sein oder aber wir ein schlechtes Gefühl beim Auflösen eines Konflikts haben, dann können wir einfach nochmals Undo Checkout drücken und eben nochmals Mergen. Ist ja nicht weiter schlimm!

Und was, wenn schon eingecheckt wurde und doch etwas nicht stimmt? Dann gibt es immer noch die schöne Funktion Rollback Entire Changeset, die vermutlich auch nicht gerade oft angewendet wird und deswegen auch feuchte Hände auslöst.

Aufräumen nicht vergessen!

So. Jetzt entwickeln wir fleissig Storys und es gibt immer mehr und mehr Story-Branches und irgendwann wissen wir selbst nicht mehr, ob die Branches noch gebraucht werden oder nicht. Dann läuft es meist so wie mit auskommentiertem Code: man löscht ihn nicht, denn er könnte ja noch gebraucht werden. Falsch!

Die Zahl der Branches sollte klein gehalten werden. Wenn der neue CurrentRelease-Branch vom NextRelease-Branch gezogen wird, sollten alle alten Story-Branches gelöscht werden, denn diese sind ja jetzt live und werden bei Bedarf auf dem CurrentRelease-Branch gefixt. Dies ist im ersten Bild zum Lebenszyklus des Story-Branches in unserem Prozess so aufgeführt. Ich habe dazu immer die aktuellen Storys auf meinem Board aufgelistet. Dort steht, ob sie schon gemerged oder gelöscht sind und dort steht auch, welche Story derzeit auf welchem System verteilt ist. Dort hängt auch immer ein Ausdruck der beiden Bilder unseres Branching-Merging-Prozesses.

Board

Jetzt kann eigentlich nichts mehr schief gehen. Zumindest nicht, wenn man sich für die Dauer des Merging konzentriert. Branching ist ja ein Kinderspiel, sofern man vom richtigen Branch aus den neuen erstellt und sich das Leben damit auch wirklich leichter macht. Und wenn man oft genug merged, gibt es irgendwann auch keine feuchten Hände mehr.

Die Sherlocks der IT

13. Dezember 2013
Nathalie Kellenberger
0
Bug, Bugfixing, Krimi, Sherlock, Software-Entwickler

sherlock

So kurz vor Weihnachten will ich mich einem Thema widmen, das zum Daily Business von uns Entwicklern zählt: Bugfixing!

Womit wir Entwickler uns schnell abfinden sollten, ist: Fehler macht jeder. Perfektionisten haben es in unserem Beruf schwer. Zwar gibt es ausgeklügelte Qualitätssicherungsstrategien, aber auch die können nicht jeden Fehler aufdecken. Den Zeigefinger sollte sich daher ein Entwickler am besten gar nicht erst angewöhnen, sonst hat er bald sehr viele Zeigefinger auf sich selbst gerichtet. Daher mag ich den Teamgedanken aus Scrum sehr. Dort wird ein Bug gemeldet und das Team kümmert sich darum. Von wem der Bug stammt, spielt dabei keine Rolle.
Wir sagen es am besten nochmals alle gemeinsam: Wir machen Fehler! Befreiend, nicht? Und wir machen dies sicher nicht mit Absicht. Fehler kommen einfach vor. Abhängig von der Tagesform, den Anzahl Unterbrechungen bei der Arbeit, dem heutigen Horoskop, egal, es lassen sich nicht alle vermeiden, aber die schlimmsten mit einem guten Testing und QS im Vorfeld finden.

Ich erkläre meinen Nachbarn gern, dass ich für meine Arbeit ausreichend Schlaf brauche, wenn diese mal wieder nachts waschen oder mit Möbeln jonglieren. Nicht, weil ich sensible Maschinen bediene oder Arzt bin, sondern weil meine Arbeit einfach eine hohe Konzentration erfordert und ohne diese sich mehr Fehler einschleichen. Das beeindruckt meine Nachbarn jetzt nicht wahnsinnig. Da hilft der Hinweis, dass ich alles Mögliche programmiere, vielleicht ihre nächste Waschmaschine oder ihr Auto.

Als nebenberuflicher Autor springt mir die Nähe von Bugfixing zu Krimis praktisch täglich ins Auge.

Wenn mir ein Bug gemeldet wird, komme ich als Kommissar an den Tatort. Im ersten Moment gilt es, anhand des Tatorts Indizien zu sammeln, die den Kreis der Verdächtigen einschränken. Das kann ganz im Sinne von Sherlock durch kognitive Schlussfolgerungen geschehen oder mit CSI Methoden. Ich persönlich fühle mich Sherlock näher, da unser Hauptinstrument der Verstand bleibt, auch wenn wir unser persönliches Labor (Debugging Umgebung, Dumps, etc.) zur Verfügung haben.
Wenn der Tatort gesichert ist, kann der Kommissar die Hintergründe des Opfers miteinbeziehen, persönliche Situation, Beziehungen, Feinde. In unserem Fall sind das die beteiligten Klassen und Methoden, Frameworks, Laufzeitumgebung.

Jetzt gibt es verschiedene Vorgehensmodelle, von denen ich zwei sehr allgemeine sehr häufig anwende. Die Vorgehen sind davon abhängig, welcher Art der Fehler ist. Wenn ich eine schöne Fehlermeldung – sprich eine Exception mit Stacktrace und allem Pipapo – habe, kenne ich zumindest schon die Mordwaffe und den Tatort. Daher beginne ich beim Tatort und verfolge den Weg des Opfers zurück.

message box

1) Die Spur (zurück-)verfolgen
Wer kennt das noch von früher? Messageboxen einbauen, um zu sehen, ob der entsprechende Code überhaupt durchlaufen wird? Debugging ist heute die elegantere Art, den Weg abzuschreiten. Dank Breakpoints und Step by Step Debugging lässt sich der Weg bis zum Opfer leicht nachvollziehen und die Ursache des Fehlers ist meist schnell gefunden.
Einzig bei Javascript Fehlern, pflasterte ich den Weg noch lange mit Alerts, zum Glück lässt sich das heute ebenfalls debuggen, dank Visual Studio und den neuen Browsern (im IE integriert, in Firefox durch FireBug).

Ich kenne keine Statistiken, aber ich bin mir ziemlich sicher, dass die Null Reference Exception, die mit Abstand häufigste ist. Die liesse sich an sich gut umgehen. Vor jedem Zugriff auf ein Objekt, eine if-Abfrage vorschalten.

Manchmal wurde das Opfer jedoch ganz woanders um die Ecke gebracht und nur am vermeintlichen Tatort, sprich dem Fundort abgeladen, von der Tatwaffe keine Spur. Dies ist der Fall, wenn keine Fehlermeldung auftritt. Ich hatte gerade so einen Fall, da liess sich ein Formular in allen Browsern speichern, bloss in Firefox nicht. Das Formular wurde ganz normal abgeschickt (sichtbarer Postback durch das Neuladen der Seite), aber die Daten blieben unverändert. Der Fehler trat erst seit dem neuen Design auf. Für mich gab es also zwei mögliche Szenarien: Entweder war das neue Control Schuld oder die neue Umgebung. Also habe ich das neue Control in die alte Umgebung eingebaut. Funktionierte wunderbar, auch in Firefox. Das alte Control in der neuen Umgebung verursachte denselben Fehler. Die Masterpage war recht gross mit vielen Javascripts, Controls und Css. Das bringt mich zum:

mindsweeper

2) Ausschlussverfahren
Bei dieser Methode werfe ich alles der Reihe nach raus, bis der Fehler nicht mehr auftritt. Meist heisst das, dass ich einfach keinen Schimmer einer Ahnung habe, was die Tatwaffe, der Tatort, geschweige denn das Motiv ist. Mutmassungen und ein gutes Bauchgefühl, das sich meist aus der Erfahrung und der geschärften Intuition eines Sherlocks ergibt, helfen weiter. Methodik ist auch in diesem Verfahren angesagt, denn wenn ich zu viel rauswerfe, so dass gar nichts mehr funktioniert, finde ich den Fehler bestimmt nicht.

Im Falle meines Firefox Bugs habe ich die Masterpage soweit „ausgezogen“, bis nur noch das Formular Control, Javascripts und Css darauf zu finden waren. Als auch das Javascript rausflog, speicherte auf einmal auch der Firefox wieder. Aha! Tatwaffe gefunden. Das hätte ich mir gleich denken können (wo war da die geschärfte Intuition?). Also beginne ich beim Javascript-File wieder von vorn und schmeisse einfach von Beginn weg alles Stück für Stück raus, bis der Firefox speichert und ich den Tatort ebenfalls gefunden habe. Mit Tatwaffe und Tatort ist das Motiv schnell gefunden, mit dem sich auf den Täter rückschliessen lässt. Der Täter ist für uns jedoch gar nicht so wichtig, denn das wäre ja wieder einer von uns (oder sogar wir selbst). Ausserdem liegt der Spass beim Bugfixing im Tüfteln und Analysieren, ganz in Sherlock Manier eben. Der schönste Moment ist, wenn man die Ursache gefunden und (fast wichtiger!) auch verstanden hat. Der Weg dahin ist oftmals qualvoll und überhaupt nicht spassig. Noch schöner ist es, wenn man durch das eigene logische Denken auf die Lösung gekommen ist.

Natürlich gibt es noch weitere, feinere Verfahren. Aber mit diesen zwei komme ich meist einen guten Schritt weiter. Gerade wenn viele Unbekannte im Spiel sind.

In seltenen Fällen kommt es vor, dass Bugs sich von selber lösen, sprich einfach nicht mehr auftreten. Für uns sicher der frustrierendste Fall, weil wir die Lösung nie erfahren! Wenn Bugs plötzlich und ohne ersichtliche Veränderung des Systems auftreten, spricht man auch von Gremlins. Wenn Bugs sich plötzlich in Luft auflösen, spreche ich gerne von Heinzelmännchen.

Aktuell habe ich eine aussergewöhnlich harte Knacknuss gefasst. Es sieht so aus, als wären Tatwaffe und Tatort bekannt. Nach Rücksprache mit dem User kann ich den Fehlerfall sogar regelmässig (aber nicht jedes Mal und nicht in jeder Umgebung!) nachstellen, dennoch werde ich das Gefühl nicht los, dass der Tatort ein ganz anderer ist.
Beim Debugging den Fehler nachzustellen, klappt selten, aber ich habe es geschafft. Leider kommt eine Messagebox, dh. der Fehler ist abgefangen und ich sehe nirgends eine Exception oder einen Hinweis im Log. Die Codeanalyse hat mir ebenfalls keine Erkenntnisse gebracht. Ich fürchte jedoch, dass Ursache und Wirkung weit auseinander liegen. Also gehe ich weit, weit zurück und suche erst mal nach der Meldung der Messagebox im Code (ist vermutlich übersetzt, aber hey, ich könnte ja Glück haben!) und dann eben in Google. Da die Meldung jedoch sehr allgemein gehalten ist (Session Timeout) habe ich wenig Hoffnung. Einige Hinweise finde ich in den Foren des Herstellers. Vielleicht ist da etwas dabei. Ich bleibe dran.

Was war euer härtester Fall? Was ist eure häufigste und erfolgreichste Methode? Schreibt sie mir gern als Kommentar auf diesen Eintrag.

In diesem Sinne wünsche ich all den Sherlocks der IT da draussen happy Bugfixing und merry Christmas!

bug

1234

Tag Cloud

.NET android Angular AngularJs Arduino ASP.Net automated testing Azure Big Data C# C++ Cloud continuous integration Elm Embedded Führung gRPC Internet of Things IoT Java Javascript M2M OWASP Projektmanagement protobuf Python Raspberry Pi Reactive Programming REST Scrum Security Softwarequalität SPA Testen testing Testmanagement Teststrategie UX Visual Studio WebAPI windows WPF Xamarin Xamarin.Android Xamarin.Forms

Archive

Current Posts

  • Akzente setzen mit der Android Splash Screen API unter .NET MAUI
  • Do You have Your Personal Space?
  • Automated provisioning with ARM Templates
  • Asynchrone Beobachtungen und Versprechungen in Angular
  • Simplify Your Automated Tests With Fluent Syntax

Last Comments

  • Hans Reinsch bei Der Safety-Plan: Die wichtigsten Antworten mit Checkliste
  • George H. Barbehenn bei Modeling Optocouplers with Spice
  • Noser Blog Touch-Actions in Xamarin.Forms - Noser Blog bei Mach mehr aus Animationen in Xamarin.Forms mit SkiaSharp
  • Noser Blog Focus on the Secure Storage service of Trusted Firmware (TFM) - Noser Blog bei First run of the Trusted Firmware (TFM) application
  • Noser Blog First run of the Trusted Firmware (TFM) application - Noser Blog bei Focus on the Secure Storage service of Trusted Firmware (TFM)

Popular Posts

Xamarin.Android Code Obfuscation

6 Comments

ManuScripts: Wenn jemand eine Reise tut... Funktionale Programmierung mit Elm - Teil 1 - Aufbruch

5 Comments

ManuScripts: Wenn jemand eine Reise tut... Funktionale Programmierung mit Elm - Teil 2 - Kein Picknick

4 Comments

Contact us

  1. Name *
    * Please enter your name
  2. Email *
    * Please enter a valid email address
  3. Message *
    * Please enter message
© 2013 NOSER ENGINEERING AG. All rights reserved. Datenschutz | Cookie-Richtlinie