Um das Thema Codesharing erleben wir in Softwareentwicklungseinheiten zum Teil intensive Diskussionen. Auch wenn Wiederverwendbarkeit auf den ersten Blick unstrittig erscheinen mag, ergeben sich bei genauer Betrachtung durchaus Fragen. Welcher Sourcecode sollte wie wiederverwendet werden? Wie kann ich Abhängigkeiten bei einer geteilten Codebasis vermeiden? Und wer kümmert sich eigentlich um die Wartung des verteilten Codes? Wir beleuchten das Thema in diesem Artikel von verschiedenen Seiten.

Übersicht Codesharing

Inhalt:

Einleitung

Eine einmal programmierte Lösung sollte natürlich nicht erneut entwickelt werden, wenn sie sich an anderer Stelle einsetzen lässt. Die einfachste Form der Wiederverwendung ist, die Lösung in eine entsprechende Methode zu überführen und dann bei Bedarf von verschiedenen Stellen aus aufzurufen; Software Engineering Best Practices wie das DRY-Prinzip (Don’t Repeat Yourself) lassen grüßen. Dies setzt technisch i.d.R. allerdings auch voraus, sich im gleichen Prozessraum zu bewegen. Wenn dies nicht gegeben ist, kann man den Code entweder intern kopieren, als Bibliothek einbinden oder eine entsprechend extern entwickelte Routine, sei sie nun kommerziell oder open-source, nutzen. Beim Einsatz externer Bibliotheken sollen im Vergleich zur Eigenentwicklung Einsparungen von 80-99% möglich sein. In Gesprächen zum Thema herrscht dementsprechend häufig auch zunächst Konsens hinsichtlich Codesharing.

Darreichungsform

Wenn es dann aber darum geht, den Code eines Kollegen wirklich zu nutzen, stoßen wir mindestens genauso häufig auf das Not-invented-here-Syndrom bzw. die einem guten Entwickler bekanntermaßen innewohnende Hybris. Die Methode wird dann doch selbst programmiert, denn als Entwickler wollen wir doch das ganze Problem verstehen und können es eh viel besser lösen als der Kollege. Das aus dem Entwickeln einer Lösung erwachsende Verständnis um die Problemdomäne spricht natürlich auch für die Eigenentwicklung und damit gegen Codesharing.

Ab einer bestimmten Stelle »kippt« das Ganze dann häufig wieder. Sobald sich für das Problem bspw. eine Open-Source-Software (OSS) Lösung findet, ist diese i.d.R. dank moderner Paketsysteme wie RubyGems, EasyInstalll oder npm schneller eingebunden, als der Readme-Eintrag auf Github gelesen ist.

Die »Darreichungsform«, ob ich einen Code-Schnipsel kopiere oder eine OSS-Bibliothek nutze, entscheidet also mit über die Bereitschaft zur Wiederverwendung.

Was bei genauer Betrachtung auch nicht weiter verwundert, da Open-Source-Software häufig eine andere Qualität aufweist, als der intern herumgereichte Code-Schnipsel, welcher zunächst vermutlich auch gar nicht zur Wiederverwendung gedacht war. Basisarbeiten wie bspw. Dokumentation, Fehlerbehandlung, Test, etc. fallen für den Eigengebrauch dann doch häufig geringer aus, als für den OSS-Einsatz. Aufgeräumt wird ja häufig auch erst kurz bevor der Besuch kommt. Wobei dies nicht so sein muss. Das npm-Paket oder RubyGem ist grundsätzlich ebenso schnell erstellt, wie eingebunden, so dass es durchaus lohnt, auch kleine Module von wenigen Codezeilen von Anfang mit dem Open Source Gedanken zu entwicklen. Selbst wenn sie nie auf Github landen, helfen die umfangreicheren Basisarbeiten der Software-Qualität insgesamt. Und falls Github aus Wettbewerbsgründen o.ä. keine Option darstellt, so lässt sich Gleiches unternehmensintern bspw. mit Gitlab erreichen.

Verantwortung

Mit der Darreichungsform geht i.d.R. auch die Frage nach der Verantwortung für Pflege und Weiterentwicklung des Codes einher. Beim informellen Kopieren im Unternehmen ist häufig unklar, wer sich um Fehlerbehebung, Anpassung an neue Betriebssystemstände, etc. für die geteilte Codebasis kümmern soll. Als Ersteller wollte ich doch nur schnell einem Kollegen aushelfen und nun habe ich ein dauerhaftes Wartungsthema geerbt? Und wer nutzt den Code überhaupt? Als Nutzer eines kopierten Codeteils kenne ich selbigen doch gar nicht, wie soll ich da Fehler beheben? Ein weiterer Grund, warum Codesharing unternehmensintern häufig eher Mythos denn Realität ist.

Mit jeder Codezeile entsteht für den Entwickler eine langfristige Verpflichtung; je mehr die Codezeile verwendet wird, desto größer ist die Verpflichtung. Aus dieser Verantwortung heraus lohnt es sich, es von Anfang an so zu machen, dass der Code langfristig für einen weiteren Verwendungszweck wartbar ist. Losgelöst von Lizenzthemen ist auch hier der Blick auf die Open Source Mechanik hilfreich, da sich die Verantwortungsfrage hier klar regelt. Als Ersteller und »Maintainer« einer geteilten Codebasis veröffentliche ich bei Bedarf, bspw. wenn es Fehlerbehebungen gibt, an zentraler Stelle eine entsprechend neue Version. Die Verantwortung, sich die neue Version von dort abzuholen, liegt beim Nutzer. Falls es bspw. aus Kompatibilitätsgründen nicht möglich ist, auf die neue Version zu wechseln, so kann der Nutzer dies entscheiden. Gibt es lokalen Anpassungsbedarf, so kann der Nutzer per Pull-Request um Aufnahme in die geteilte Codebasis bitten, oder per Fork einen eigenen Entwicklungszweig aufmachen.

Art des Codes

Aus architektonischer Sicht ist auch die Art des Codes entscheidend für den Grad seiner Wiederverwendung. Je tiefer es in die Infrastruktur geht, desto höher bewerten wir das Potential für Codesharing, allerdings in entsprechender Darreichungsform. Dreht es sich hingegen um Geschäftslogik, so sehen wir nur geringes Potential bzw. auch geringen Bedarf zur Wiederverwendung von Programmteilen.

Unserer Erfahrung nach sind ein Großteil der infrastrukturellen Fragestellungen in halbwegs etablierten Technologien / Sprachen heutzutage bereits gelöst und das in aller Regel auch Open Source – mehrere Millionen Github-Repositories sprechen für sich. Dazu kommt, dass die Mehrzahl der Unternehmen Infrastruktur-Technologie nicht zu ihren Kernkompetenzen zählen dürfte und i.d.R. auch nicht über Entwicklungsbudgets wie Facebook, Google & Co. verfügen. Es ist also betriebswirtschaftlich meist nicht gerechtfertigt, seine eigene Datenbank oder ein proprietäres Netzwerk-Protokoll zu entwickeln. Dementsprechend sollte ich im infrastrukturellen Umfeld gar nicht erst in die Situation kommen, Code-Teile intern kopieren zu müssen. Der Einsatz entsprechender Open-Source-Software ist hier allerdings dringend angezeigt.

Je weiter es hingegen in Richtung der jeweiligen Fach-Domäne geht, dürfte andererseits gar nicht erst der Bedarf zum team-übergreifenden Austausch von Code-Teilen der Geschäftslogik bestehen. Aus makro-architektonischer Sicht spricht bspw. das Domain-Driven Design, wie wir schon an anderer Stelle gezeigt haben, dafür, die fachliche Logik zu isolieren (»Bounded Context«). Fachliche Logik sollte sich also gar nicht erst über System- und Teamgrenzen erstrecken. IBMs bereits in den 90ern gescheitertes Projekt San Francisco hat eindrucksvoll gezeigt, dass Geschäftslogik sich nicht generalisieren lässt. Auf Micro-Ebene führen die bekannten Prinzipien des Software Engineering, wie bspw. eben DRY, Separation of Concerns, Cohesion, etc. dies fort, so das auch innerhalb eines Systems fachlicher Code nur an eine Stelle und somit nicht kopiert gehört.

Abhängigkeiten

Egal ob nun aber OSS-Paket, interne Bibliothek oder ein ad hoc vom Kollegen kopiertes Modul, es entsteht eine Abhängigkeit. Das OSS-Paket setzt vermutlich wiederum auf andere Bibliotheken auf, welche dann ja auch gewisse Versions-Stände anderer Pakete benötigen…willkomen in der Dependency Hell. Dazu kommen OSS-Lizenzfragen, welche wir an anderer Stelle beleuchten; das Left-Pad-Problem hat aber eindrucksvoll gezeigt, was entsprechende Abhängigkeiten in Kombination mit ungeklärten Lizenzfragen bewirken können. Darüber hinaus entsteht eine technologische Bindung an die Programmiersprache: möchte ich über Teams hinaus intensiv Codesharing betreiben, muss ich auch über die Teams hinweg die gleiche Technologie einsetzen. Pattern stellen hier einen eleganten Ausweg dar: ich übernehme die Lösungsschablone, schreibe den Code mit der jeweiligen Technologie aber selbst.

Das informelle Kopieren stellt hinsichtlich organisatorischer Abhängigkeiten sicherlich noch das geringste Übel dar, da ich als Entwickler ja grundsätzlich handlungsfähig bleibe. Oder um es mit Rob Pikes (»The Practice of Programming«, Go, UTF-8) Worten zu sagen:

»A little copying is better than a little dependency.«

Aber was ist, wenn der Kollege, von dem ich den Code kopiert habe, krank ist, ich aber ein Problem mit »seinem« Code habe? Und die oben weiter gezeigte Verantwortungsklärung setzt auch eine Abstimmung ggf. über Organisationsgrenzen hinweg voraus; ist meine Organisation dazu in der Lage? Auf der organisatorischen Haben-Seite steht hier andererseits bspw. das »Lösungs-Sharing« durch informellen oder auch institutionalisierten Austausch zwischen den Beteiligten durch einen »Tech-Friday« o.ä. Foren.

Durch Codesharing entstehen technische und organisatorische Abhängigkeiten. Der Konflikt entsteht dadurch, dass sich die Vorteile der Übernahme fremden Codes, wenn auch in Grenzen, wie weiter oben gezeigt, quantifizieren lassen. Die Abhängigkeiten hingegen sind nur schwer zu greifen und die Reduzierung selbiger ist häufig eine eher strategische oder architektonische Zielstellung qualitativer Natur. Wie sollen die beiden ungleichen Aspekte nun gegeneinander abgewägt werden?

Zusammenfassung

Wenn Codesharing, dann richtig. Unserer Einschätzung nach bedeutet dies, sich an den Open Source Best Practices zu orientieren, wenn Code geteilt werden soll. Bin ich bereit, die dafür notwendigen Basis- und Wartungsarbeiten auf mich zu nehmen? Wenn nicht, sollte ich Codesharing lieber lassen, habe aber auch ein klares Indiz hinsichtlich Vor- und Nachteilen im konkreten Einsatzbereich. Darüber hinaus ist kritisch zu hinterfragen, ob die jeweils vorliegende Art des Codes ein Codesharing überhaupt bedingt, oder nicht evtl. sogar auf architektonische Misstände hinweist. Selbige verfestigen sich durch Kopieren eher als dass sie sich auflösen.

Die Ausführungen sollten aufgezeigt haben, dass auch ein so zunächst vielleicht triviales Thema wie Codesharing durchaus weitreichende Fragestellungen aufwerfen kann. Dementsprechend sollte es in einer Softwareentwicklungseinheit auch eine klare Idee geben, wie damit umzugehen ist. Und es sollte managemement-seitig entsprechend unterstützt werden.

Wie immer öffnet sich nach der Beantwortung einer Frage gleich auch wieder ein ganzes Universum an neuen Fragestellungen. Habe ich mich auf Wiederverwendung von Code eingelassen, sollte ich mir auch Gedanken über das Wiederfinden machen. Sourcegraph und Searchcode stellen hierzu interessante, neue Ansätze dar und werden in einem Folgeartikel betrachtet.