
Hallo allerseits!
Unser Unternehmen bietet einen Service zum Speichern und Verarbeiten von Daten von Industriegeräten (Pumpen, Bohrern und anderen Industrieanlagen). Wir speichern die Daten unserer Kunden und bieten Funktionen für deren Analyse: Erstellen von Berichten, Grafiken und vielem mehr.
Im Laufe der Arbeit haben wir festgestellt, dass sich die Integration jedes neuen Kunden stark verzögert und die Anzahl der verschiedenen Fehler ständig zunimmt. Dann wurde klar, dass es Zeit war, sich damit zu befassen. Wie eine Analyse der Situation ergab, entwickelte die IT-Abteilung jedes unserer Kunden eine eigene Lösung, um Daten lokal von Geräten zu sammeln und an unseren Service zu senden. Dies erschwert die Tatsache, dass unter Berücksichtigung der Besonderheiten der Branche nicht immer Zugang zum Internet besteht und Daten lokal gespeichert und so schnell wie möglich gesendet werden müssen. Und es gibt eine ausreichend große Anzahl solcher Nuancen, was zu einer Zunahme der Anzahl von Fehlern führt.
Und dann wurde uns klar, dass die beste Lösung in dieser Situation darin besteht, ein SDK zu entwickeln und es dem Kunden zur Verfügung zu stellen. Sofort begann ich nach Best Practices und Überlegungen zur Entwicklung des SDK zu suchen und war sehr überrascht - es gibt praktisch nichts in RuNet, aber es gibt nur sehr wenige Informationen im Basurmani-Internet und es ist verstreut. Nun, die Aufgabe ist klar, durchdacht und umgesetzt.
Es war jedoch der Mangel an Informationen zu diesem Thema, der den Wunsch weckte, die Community über die Gedanken, Entscheidungen und Schlussfolgerungen zur Entwicklung des SDK zu informieren. Dieser Artikel beschreibt eine Lösung für .NET, aber es handelt sich um ein Konzept, das für viele interessant sein wird. Details unter dem Schnitt!
Es ist Zeit, entschlossen zu sein
Beginnen wir damit, zu definieren, was das SDK ist und warum es möglicherweise benötigt wird.
SDK (aus dem englischen Software Development Kit) ist eine Reihe von Entwicklungstools, mit denen Softwarespezialisten Anwendungen für ein bestimmtes Softwarepaket, eine grundlegende Entwicklungssoftware, eine Hardwareplattform, ein Computersystem, Spielekonsolen, Betriebssysteme und andere Plattformen erstellen können. Das SDK nutzt jede Plattform und reduziert die Integrationszeit.
...
Ein Softwareentwickler erhält normalerweise ein SDK vom Entwickler des Zielsystems.
Das ist logisch. Mit einfachen Worten, das SDK ist ein Paket von Bibliotheken, sodass der Client einfach und schnell mit Ihrem System arbeiten kann (in diesem Artikel werden wir über unseren Service sprechen, aber alles, was im Artikel vorgestellt wird, gilt für andere Arten von SDKs) oder dieselben Aktionen ausführen kann.
Wie jeder Ansatz hat auch der SDK-Pfad Vor- und Nachteile.
Die Vorteile
Hochgeschwindigkeitsintegration eines neuen Clients - Ihre Kunden müssen weniger Code schreiben.
Wiederverwendung von Code - Der gleiche Code wird an mehreren Stellen gleichzeitig verwendet. Wir können sagen, dass dies eine Verdoppelung des vorherigen Absatzes ist, aber wir sprechen über die Tatsache, dass die Logik der Arbeit überall einsam ist, was impliziert
Vorhersagbarkeit des Verhaltens - Die Verwendung derselben Bibliotheken bringt das Verhalten von Systemen auf einen bestimmten Standard, was die Suche und Beseitigung von Fehlern und Schwachstellen erheblich erleichtert.
In der Qualität des Codes sparen viele Menschen gerne beim Testen (entschuldigen Sie das Budget, die Fristen und andere Gründe). Es ist klar, dass es in der realen Welt eine sehr mühsame Aufgabe ist, alle Abschnitte des Projekts mit Tests zu testen. Das qualitative Testen aller SDK-Module und deren anschließende Verwendung ist jedoch eine Möglichkeit, den Prozentsatz der Testabdeckung zu erhöhen, was zu einer Verringerung der Anzahl von Fehlern führt.
Die Dokumentation ist das gleiche Szenario wie bei den Tests. Die Dokumentation des gesamten Projekts ist recht problematisch. Die Wiederverwendung von SDKs erhöht den Prozentsatz der Dokumentationsabdeckung, wodurch die Schwelle für den Eintritt neuer Mitarbeiter in das Projekt gesenkt wird und im Allgemeinen das Leben erleichtert wird.
Alle Vorteile sind in der Tat die Konsequenzen des Wichtigsten: Wir schreiben den Code einmal in sehr hoher Qualität und verwenden ihn dann wieder .
Nachteile
Die hohen Qualitätsanforderungen des SDK-Codes sind das Ergebnis des Hauptvorteils. Ein Fehler im SDK führt auf allen Systemen, die es verwenden, zu Fehlern.
Festlegen von Einschränkungen - Das SDK besteht aus einer Reihe von Bibliotheken zum Implementieren von Standardskripten . Manchmal glauben SDK-Entwickler, dass der Client neben der Implementierung eines der bereitgestellten Szenarien nichts benötigt und es für den Client einfacher ist, alles von Grund auf selbst zu tun, als ein Podest aus Krücken für das SDK zu erstellen.
Abhängigkeitshölle und Aktualisierungen - Wenn Sie die Funktionalität erweitern (z. B. eine Lösung für einen bestimmten Client anpassen), wird eine neue Version der Bibliothek veröffentlicht. Es gibt jedoch Abhängigkeiten, unterschiedliche Sätze von Bibliotheksversionen für unterschiedliche Clients, und Sie müssen die Abwärtskompatibilität oder die strikte Versionierung sorgfältig überwachen.
Wenn das SDK wirklich benötigt wird
Sie haben mehrere Standardszenarien, die von Zeit zu Zeit neu implementiert werden - in unserem Fall sogar.
Interne Entwicklung - Verwenden Sie in verschiedenen Projekten Protokollierungssysteme, Systemkonfigurationen, Arbeiten mit HttpRequest, Datenbanken, Dateien? Erstellen Sie ein internes SDK - eine Reihe von Bibliotheken für den internen Gebrauch. Sie können die SDK-Funktionalität jederzeit erweitern, aber die Geschwindigkeit der Entwicklung neuer Projekte, der Prozentsatz der Abdeckung mit Tests und Dokumentation steigt und der Schwellenwert für die Teilnahme neuer Entwickler sinkt.
Wenn das SDK wahrscheinlich redundant ist
Nutzungsszenarien sind nicht definiert oder ändern sich ständig - überlassen Sie die Implementierung kundenspezifischer Lösungen den Kunden und helfen Sie ihnen. Es ist nicht nötig, ein Wunderkind aus Wunderwaffel zu machen, das nur stört. Sehr relevant für junge Unternehmen und Startups.
Sie wissen nicht, wie Sie es qualitativ machen sollen - ich habe schlechte Nachrichten für Sie: Es ist Zeit zu lernen. Aber einem Kunden eine krumme Entscheidung zu geben, ist sehr, sehr falsch. Kunden müssen schließlich respektiert werden.
Also haben wir entschieden, was das SDK mit seinen Vor- und Nachteilen ist und wann wir es brauchen. Wenn Sie danach festgestellt haben, dass das SDK wirklich benötigt wird, lade ich Sie ein, sich auf den "SDK-Pfad" zu begeben und herauszufinden, was es sein sollte und wie zum Teufel es zu tun ist?
"Liebst du Lego?" - Modularität
Stellen Sie sich alle möglichen Szenarien für die Verwendung des SDK vor (Sie haben bereits entschieden, warum Sie es benötigen, oder?) Und erstellen Sie ein Skript für die Bibliothek. Was ist keine Option? Aber das ist ein schlechter Ansatz, und deshalb werden wir es nicht tun. Und wir werden so sein:
- Teilen Sie alle Skripte in Schritte auf
- gemeinsame Schritte identifizieren
- Erstellen Sie eine Liste von Modulen , die alle möglichen Schritte implementieren (ein Modul ist dafür verantwortlich, etwas Bestimmtes zu implementieren, z. B. mit Konfigurationen zu arbeiten).
Unter Berücksichtigung der Besonderheiten der Aufgabe muss beispielsweise die gesamte Logik aus Konfigurationen festgelegt werden. Wir implementieren das Modul für die Arbeit mit Konfigurationen (Lesen, Schreiben, Aktualisieren, Validieren und Verarbeiten von Konfigurationen) und werden es in allen anderen Modulen verwenden.
Und für die Implementierung von Standardszenarien werden wir wirklich Module erstellen - eine Art "Steuer" -Modul, von dem jedes ein bestimmtes Szenario unter Verwendung anderer Module desselben SDK implementiert. Für die Implementierung von Standardszenarien muss der Client nur das Steuermodul des Skripts verbinden (und er wird alle Abhängigkeiten aufrufen), und für die Implementierung von nicht standardmäßigen verwenden wir die Basismodule und verwenden den Code ebenfalls wieder.
Dies ist genau der Grund, warum das SDK nicht eine Bibliothek sein sollte (obwohl ich es wirklich will, verstehe ich. Wenn sich das gesamte SDK in einer Bibliothek befindet, können Sie schließlich die Abhängigkeiten und alles, was damit verbunden ist, vergessen), sondern eine Reihe von Bibliotheken sein. Ein zusätzlicher Vorteil dieses Ansatzes ist die Reduzierung des "Gewichts" des Client-Programms - es wird ein schweres SDK abgerufen und nur die erforderlichen Module werden aufgerufen.
Sie sollten aber sowieso keine Module produzieren, denn je mehr Module, desto mehr Kopfschmerzen entstehen durch ihre Abhängigkeiten! Das heißt, Es ist wichtig, die Logik korrekt in Module zu unterteilen und ein Gleichgewicht zwischen der Entscheidung "Alles in einem" und "Jedes Modul hat sein eigenes Modul" aufrechtzuerhalten.
"Und so war es möglich ?!" - Vielseitigkeit
Stellen Sie dem Client verschiedene Schnittstellen für die Arbeit mit Ihrer Bibliothek zur Verfügung. Ich werde ein Beispiel geben:
public void LoadConfiguration(string filename); public async Task LoadConfigurationAsync(string filename);
Wenn Sie nur die synchrone Version bereitstellen, wird der Client beim Implementieren einer asynchronen Anwendung gezwungen, asynchrone Wrapper Ihrer synchronen Methode auszuführen. Wenn Sie nur die asynchrone Version angeben, ist die Situation ähnlich. Geben Sie dem Kunden beides und er wird es Ihnen danken.
Generika werden ein schönes Plus sein. Zum Beispiel haben wir eine Klasse für die Arbeit mit Konfigurationen, die Methoden zum Packen einer Konfiguration in eine Zeichenfolge, zum Laden einer Konfiguration aus einer Datei usw. implementiert. Die Konfiguration eines bestimmten Moduls wird von unserer Basisklasse geerbt. Um jedoch mit der neuen Klasse arbeiten zu können, müssen auch Entpackungsmethoden bereitgestellt werden.
class BaseConfiguration{ public BaseConfiguration FromString(string source){...} public BaseConfiguration FromString(string source,Type configurationType){...} public T FromString<T>(string source) where T:BaseConfiguration } class CustomConfiguration : BaseConfiguration{}
Daher haben wir dem Kunden drei Implementierungen zur Verfügung gestellt, die er verwenden kann. Generika sind sehr praktisch, aber wenn Sie mit dynamischen Typen arbeiten, können sie nur durch Reflexion aufgerufen werden, was unrentabel ist. Ich hoffe, das allgemeine Prinzip der Universalität ist klar.
"Elternteil 1, Elternteil 2, Kinder []" - Benennung
Was ist der schwierigste Teil eines Programmierers? Erfinde Namen für Variablen.
Trotzdem ... Die richtige Benennung von Modulen, Klassen, Eigenschaften und Methoden wird denjenigen, die mit Ihrem SDK arbeiten, sehr helfen. Beispiel ohne Kommentare:
Kinect 2.0 SDK-Beispiel
var skeletons = new Skeleton[0]; using (var skeletonFrame = e.OpenSkeletonFrame()) { if (skeletonFrame != null) { skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength]; skeletonFrame.CopySkeletonDataTo(skeletons); } } if (skeletons.Length == 0) { return; } var skel = skeletons.FirstOrDefault(x => x.TrackingState == SkeletonTrackingState.Tracked); if (skel == null) { return; } var rightHand = skel.Joints[JointType.WristRight]; XValueRight.Text = rightHand.Position.X.ToString(CultureInfo.InvariantCulture); YValueRight.Text = rightHand.Position.Y.ToString(CultureInfo.InvariantCulture); ZValueRight.Text = rightHand.Position.Z.ToString(CultureInfo.InvariantCulture);
Aus den Namen der Klassen und Methoden geht alles hervor. Und wenn Ihre IDE Code vervollständigt, ist es oft möglich, nicht in die Dokumentation zu schauen, wenn bereits alles klar ist.
"Ich bin sicher, wenn der Tod wüsste, was Bürokratie ist, würden Menschen niemals sterben und für immer in der Schlange stehen ..." - Dokumentation
Aber selbst wenn alle Module, Klassen, Methoden und Eigenschaften sehr schön und dringend benannt sind, müssen Sie dennoch Dokumentation schreiben. Erstens werden Ihre Nerven erheblich geschont (die Anzahl der Kundenfragen wird um eine Größenordnung reduziert. Alles ist in der Dokumentation enthalten), und zweitens ist immer klar, warum Sie dies getan haben und nicht anders.
Die Dokumentation im SDK ist normalerweise einfach und übersichtlich. Es besteht normalerweise aus zwei Teilen: Tutorial - ein schrittweiser Kurs im Stil von „Bauen Sie eine Stadt in 10 Minuten“ und Abschnitt Referenz - ein Verweis auf alles, was mit diesem SDK möglich ist.
Wir haben den einfachsten Weg gewählt - Zusammenfassung + Artikel. Wir fügen XML-Attribute für Methoden und Klassen hinzu, die in Intellisense als QuickInfos leuchten. Mit Docfx erstellen wir eine Dokumentation zu diesen Attributen und erhalten eine detaillierte und bequeme Dokumentation, die durch Artikel ergänzt wird, die Anwendungsfälle und Beispiele beschreiben.
"- Um es sauber zu halten! - Wie werde ich es mit einer Gabel reinigen?" - Testen
Was kann man über das Testen im Rahmen der Diskussion über das SDK sagen ... Muss man haben! Die beste Lösung wäre TDD (obwohl ich diesen Ansatz negativ finde, habe ich mich in diesem Fall für ihn entschieden). Ja, lange Zeit. Ja, langweilig. Aber in Zukunft werden Sie sich nicht mehr an den ständigen Stürzen des SDK und den Folgen dieses Sturzes festhalten.
Der Hauptgrund für die Situation ist, dass Sie durch die Übergabe des SDK an den Client die Kontrolle verlieren: Sie können den Fehler nicht schnell beheben, es ist schwierig, diesen Fehler zu finden, und Sie werden in einer solchen Situation dumm genug aussehen. Deshalb - testen. Besser testen. Und noch einmal. Und für alle Fälle testen Sie Ihre Tests. Und Testtests. Also, etwas, das mich mitgerissen hat, aber die Wichtigkeit, das SDK zu testen, ist hoffentlich klar.
"Ein Opfer, das ihrer Vergangenheit nicht widerstehen konnte, wurde von ihm verzehrt" - Logi
Da Sie das SDK an ein Drittunternehmen weitergeben, wodurch Sie im Falle eines Fehlers die Kontrolle über die Situation verlieren (in der Testphase haben Sie alle entschieden, dass es funktioniert, oder?), Wartet ein ziemlich langer und schmerzhafter Prozess darauf, dass Sie genau nach diesem Fehler suchen. Hier helfen Ihnen die Protokolle.
Protokollieren Sie alles , absolut alles, und fragen Sie Ihren Client nach Protokollen, wenn ein Fehler auftritt. Auf diese Weise sparen Sie viel Zeit und können Ihr Gesicht nicht vor dem Kunden reiben.
"Alarm! Achtung! Achtung!" - Fehler

Während ich viel über Fehler nachdachte, kam ich zu einem interessanten Ergebnis - keine einzige Methode in Ihrem SDK sollte einen Fehler ergeben, der nicht in der Dokumentation beschrieben ist . Sie müssen zugeben, dass es sehr unangenehm ist, wenn Sie eine Bibliothek eines Drittanbieters für die Arbeit mit HttpRequest verbinden, und es wirft eine NullPointerException und StackTrace auf Sie, die Sie in den Darm der Bibliothek führen. Und Sie müssen in diese „Eingeweide“ eintauchen und versuchen zu verstehen, wie tief das Kaninchenloch ist und was tatsächlich das Problem ist.
Daher schlage ich folgende Lösung vor: Deklarieren Sie eine geschlossene Liste möglicher Ausnahmen und dokumentieren Sie diese. Aber weil Sie können nicht sicher sein, ob Sie alles bereitgestellt haben, die Methode in einen Try-Catch einschließen und den abgefangenen Fehler in den deklarierten. Beispielsweise ist eine ConfigurationException, die eine InnerException enthält, ein abgefangener Fehler. Auf diese Weise kann ein Drittanbieter alle möglichen Fehler abfangen. Wenn jedoch etwas passiert, müssen Sie schnell herausfinden, worum es geht.
Versionen oder "wie man nicht in den Schwanz beißt"
Um zukünftige Probleme zu vermeiden, empfehle ich dringend die strikte Versionierung. Wählen Sie das für Sie geeignete Versionsverwaltungssystem und verwenden Sie es. Wenn die neue Version der Bibliothek jedoch keine Abwärtskompatibilität aufweist, muss dies angegeben werden. Wie man es löst - denken Sie. Aber Sie sollten auf jeden Fall darüber nachdenken.
"Ein Zug, der könnte" - Bereitstellen
Die Notwendigkeit der Relevanz von Dokumentation und Versionen führt zur Anforderung an die Richtigkeit der Bereitstellung. Bei unserer Entscheidung verwenden wir die folgende Lösung (Krücken, aber sie funktionieren).
Wenn eine neue Version veröffentlicht werden muss, zieht der Entwickler den Bat'nik mit der Versionsnummer und anschließend mit der Batch-Datei:
- Release erstellen
- legt alle Bibliotheken im Archiv ab
- Erstellen Sie die neueste Version der Dokumentation (docfx).
- gibt die Release-Version in der Dokumentation und im Namen des Archivs an
- Bringt das Neueste in das Git-Repository
- WebApp unter MS Azure ruft ein neues Git-Hook-Commit auf und veröffentlicht Änderungen
Bei der Ausgabe erhalten wir eine aktualisierte Version der Site mit Dokumentation, von der Sie das Archiv mit der neuesten Version des SDK herunterladen können.
Zukünftige Pläne sehen vor, alles in Nuget-Pakete zu packen und im lokalen Nuget-Repository zu veröffentlichen.
Ich empfehle, auf diesen Punkt zu achten, da Sie die Kopfschmerzen, die durch den Mangel an relevanten Informationen über die neue Version der Bibliothek verursacht werden, erheblich reduzieren können.
Ein wichtiger Punkt in der Dokumentation sind Verwendungsbeispiele. Darüber hinaus ist es häufig erforderlich, keine Bibliothek bereitzustellen, sondern eine Anwendung, die die meisten Standardszenarien implementiert. Ich empfehle, diese Anwendungen mit offenem und gut kommentiertem Quellcode zu erstellen, mit dem Sie zwei Fliegen mit einer Klappe schlagen können - stellen Sie eine funktionierende Anwendung bereit und geben Sie ein Beispiel für die Verwendung des SDK.
Fazit
Die SDK-Entwicklung ist für mich zu einer interessanten neuen Aufgabe geworden, die viele wichtige architektonische Probleme aufgeworfen hat. Viele der im Artikel beschriebenen Dinge sind (für mich) offensichtliche Dinge, aber ich halte es für wichtig, auch die offensichtlichen Dinge anzukündigen, um ein klares Gesamtbild zu erhalten.
PS
Vielen Dank fürs Lesen, ich freue mich über Ihre Kommentare. Ich hoffe, dieser Artikel ist hilfreich für Sie.