Wie kann verhindert werden, dass Änderungen an einer internen API andere Projekte beschädigen?


8

Wir haben 20 - 30 unabhängige Module / Lösungen. Jedes von diesen hat ungefähr 7 - 10 Projekte mit verschiedenen Klassen, Komponenten usw. Diese werden alle unternehmensintern verwendet.

Unser Problem ist, wenn wir eine Änderung in einem Modul vornehmen, müssen wir sicherstellen, dass alle anderen Module aktualisiert werden, die auf diesen Code zugreifen. Dies ist schwer zu wissen, da es sich um verschiedene Codebasen handelt.

Wie können wir dokumentieren, wo sich alle externen Verwendungen einer API befinden? Oder auf andere Weise verhindern, dass kleine Änderungen andere Module beschädigen?



6
Wie kann verhindert werden, dass API-Änderungen den Code beschädigen? Ähm ... ändere die API nicht. Wirklich, welche Antwort könnte es anders geben?

@ dan1111 was ist, wenn wir Änderungen an der API vornehmen müssen und wir nicht wissen, welche anderen Module wir brechen werden, wie dies vermeidbar sein kann, atm Ich bekomme den Namen der Methode und suche unsere Codebasis-Dateien auf Festplatte, nicht so effizient tun es
Mathematik

Was ist falsch daran, Ihre Codebasis nach Methodenaufrufen zu durchsuchen? Wenn Sie keine Dokumentation darüber haben, was was verwendet, ist dies eine ziemlich gute Möglichkeit, dies zu tun. Sie können leicht ein kleines Skript schreiben, das Ihren gesamten Code nach allen API-Aufrufen durchsucht und darüber berichtet.

1
Können Sie uns weitere Einzelheiten mitteilen? Welche Programmiersprache? Ist die Quellcode-Kompatibilität in Ordnung oder benötigen Sie Binärkompatibilität? Löst "Ändern Sie nicht die vorhandene API-Signatur", sondern fügen Sie nur neue Methodensignaturen hinzu, um Ihr Problem zu lösen? Unterstützt Ihre Sprache "Standardparameter"
k3b

Antworten:


13

Die einfachste Lösung, IMO, besteht darin, für jedes Produkt eine angemessene Anzahl automatisierter Tests durchzuführen. Wenn Sie eine Bibliothek aktualisieren, führen Sie die Testsuite für jedes Produkt aus. Wenn die Tests fehlschlagen, wissen Sie, welche Produkte aktualisiert werden müssen.


5

Ich würde davon abraten, dies (zumindest manuell) zu dokumentieren, als ob die Leute es aktualisieren müssten. Es erfordert ein hohes Maß an Genauigkeit, um richtig zu funktionieren. Aber Sie werden niemals diese Genauigkeit erreichen, da das Hinzufügen dieser Art von Dokumentation ... keinen Spaß machen würde und niemand es tun würde.

Ein paar bessere Optionen:

  • Haben Sie ein Skript, das eine verwendbare Liste aller Methodenaufrufe in allen anderen Modulen basierend auf Suchkriterien generiert. Einfach, roh, aber wahrscheinlich effektiv.
  • Eine Art Versionssystem, bei dem die Abwärtskompatibilität nur bei Hauptversionsnummern unterbrochen wird. Wenn Sie also die Methode foo von Version 2.1 auf 2.2 ändern, funktioniert der gesamte Code, der auf Version 2.X verweist, weiterhin. Wenn Sie diese Kompatibilität unterbrechen müssen, aktualisieren Sie die Hauptversionsnummer (in diesem Fall 3.0) und teilen Sie dies allen Projektbesitzern mit, die für andere Module verantwortlich sind. Abhängig davon, wie Ihr Release-Prozess funktioniert, ist dies möglicherweise einfach oder unglaublich kompliziert zu implementieren.
  • Führen Sie automatisierte Tests oder einen CI-Erstellungsprozess durch, bei dem jedes Mal, wenn Sie Code drücken, Tests erstellt werden. Auf diese Weise können Sie feststellen, wo Probleme auftreten. Ich vermute, mit dem, was Sie als das Problem beschreiben, das Sie noch nicht haben.
  • Eine Art automatisches Dokumentationssystem für alle Ihre Module / Repositories

Sie könnten auch in Betracht ziehen, die APIs langsam umzugestalten, um nicht so spröde zu sein, aber ich gehe davon aus, dass dies außerhalb des Bereichs liegt, den Sie vernünftigerweise erreichen können, wenn Sie eine Einzelperson sind und über 20 große Module verfügen, mit denen Sie arbeiten können.


1
+1 für die Versionierung, plus Link zur semantischen Versionierung
xpy

2

Zunächst sollte sich eine API mit externen Verwendungen nicht ändern.

Wie @BryanOakley erwähnte, ist die Verwendung automatisierter Komponententests in solchen Situationen sehr wichtig und lebensrettend. Darüber hinaus einige Vorschläge, die Ihnen je nach Situation helfen können (oder auch nicht)

  • Viele Sprachen (wie Java und C #) bieten Function/Method Overriding. Sprachen wie Python bieten Ihnen die Möglichkeit, (unbegrenzte Anzahl) Argumente und Schlüsselwortargumente an eine Funktion zu übergeben:

    Java:

    public void disp(char c)
    {
         System.out.println(c);
    }
    
    public void disp(char c, int num)  
    { 
         System.out.println(c + " " + num);
    }
    
    disp("A")
    disp("A", 3)
    

    Python

    def disp(c, *args):
        if args:
            num = args[0]
            print("%s %f" % (c, num))
        else:
            print("%s" % c)
    
    disp("A")
    disp("A", 3)
    
  • Viele Sprachen Angebote public, privateund protectedMethoden. Sie können den Funktionsaufruf in einer publicFunktion bearbeiten und die Arbeit in private/protectedFunktionen erledigen .

    In Python gibt es keine öffentliche / private Definition für Methoden und Funktionen, aber ein führender Unterstrich ( _) gibt an, dass eine Methode privat ist und nicht extern verwendet werden sollte. Externe API-Aufrufe werden von einer Methode übergeben, die für die Außenwelt offen ist, und alle Aufgaben werden in sogenannten lokalen Funktionen ausgeführt:

    def format_input(a, b, *args, **kwargs):
        # This function is open to anyone. so use *args and **kwargs to get
        # all possible available arguments. Do not change this function
        # definition and function parameters
        a = _evaluate_input(a)
        b  =_evaluate_input(b)
        # c is not used by all APIs and may not documented in all external
        # API docs. So chech if it was sent as a keyword argument. If yes
        # evalaute it too
        if "c" in kwargs:
            c  =_evaluate_input(kwargs.get("c"))
        _check_extra_arguments(args)
        _check_extra_keyward_arguments(kwargs)
    
    def _evaluate_input(value):
        # This is a private method thus should not be called from the
        # outside world. You can change this method and parameter structure 
        # to fit your needs and do not care for outside world since no
        # outer API should use this function directly.
        ...
    
    def _check_extra_arguments(value):
        # We will check if any extra argument is passed and handle them accordingly
        ...
    

Wie gesagt, eine API-Definition, die (auch) von externen Anwendungen verwendet wird, sollte nicht so oft geändert werden. Sie können nach Möglichkeiten suchen, Ihre äußeren Funktionen flexibler zu gestalten, damit Sie die Funktionsweise der API ändern können, ohne den aktuellen Status zu beeinträchtigen.


1

Unser Problem ist, wenn wir eine Änderung in einem Modul vornehmen, müssen wir sicherstellen, dass alle anderen Module aktualisiert werden, die auf diesen Code zugreifen. Dies ist schwer zu wissen, da es sich um verschiedene Codebasen handelt.

Ich würde vorschlagen, dass dies unmöglich zu wissen ist.

Sie sind für die Komponenten und ihre Schnittstellen verantwortlich.
Sie sind nicht verantwortlich für alles, was davon Gebrauch machen könnte.

Wie können wir dokumentieren, wo sich alle externen Verwendungen einer API befinden? Oder auf andere Weise verhindern, dass kleine Änderungen andere Module beschädigen?

Kurze Antwort? Tests.

Schreiben Sie Tests, die die veröffentlichten Schnittstellen ausführen. Führen Sie sie erneut aus, wenn Sie Änderungen vornehmen. Solange die Tests "Bestanden" sind, haben Sie nichts kaputt gemacht. Wenn ein Test abbricht (und dies auch tun wird), entweder (a) das Problem finden und beheben oder (b) wenn Sie die Änderung als legitim rechtfertigen können , schreiben Sie den Test neu, um ihn zu berücksichtigen.


0

Ich habe APIs mit Versionsnummern in den Funktionspfaden und / oder Namen gesehen und codiert.

Auf diese Weise können verschiedene API-Versionen verfügbar sein - vollständige APIs und verschiedene Versionen der Funktionen innerhalb einer API.

Auf diese Weise müssen alle API-Versionen im Code für die API beibehalten werden. Es muss kein anderer Anwendungscode geändert werden als der, für den die neue API-Funktion erstellt wurde.

Ich denke, dies ist besonders wichtig, wenn Sie APIs schreiben, die von Anwendungen außerhalb Ihres Unternehmens verwendet werden.

Als Beispiel finden Sie hier ein Codebeispiel zum Senden einer SMS mit der Bulksms-API:

http://developer.bulksms.com/eapi/code-samples/csharp/send_sms/

von dort ist die Linie:

string url = ".../submission/send_sms/2/2.0";

Dabei sind 2 und 2.0 Versionsnummern der API.

Da diese API für die Verwendung durch viele Massen-SMS-Kunden vorgesehen ist, würde eine Änderung dieser API möglicherweise viele Anwendungen beschädigen und das Support-Telefon vom Haken klingeln lassen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.