Arbeiten an Legacy Codebases (oder das Leben eines Auftragnehmers) (Deutsch (German))

Arbeiten an Legacy Codebases (oder das Leben eines Auftragnehmers)

Comments

NOTE: Apart from English (and even then it's questionable, I'm Scottish). These are machine translated in languages I don't read. If they're terrible please contact me.
You can see how this translation was done in this article.

Wednesday, 06 November 2024

//

Less than a minute

Einleitung

Als freiberuflicher Entwickler muss man schnell lernen, wie man auf bestehenden Codebases effektiv arbeitet. Ich hatte das Glück, eine Reihe von... Kratzsystemen gebaut zu haben; das ist ein JOY als erfahrener Entwickler, aber es ist nicht immer der Fall.

Die Herausforderungen

Legacy-Systeme haben erhebliche Herausforderungen; vor allem, wenn die wichtigsten Entwickler / Architekten (wenn Sie das Glück haben, sie zu haben) weitergezogen sind.

Dokumentation

Dies wird vor allem in kleineren Unternehmen oft übersehen. Im Allgemeinen benötigen Sie 4 Schlüsseltypen der Dokumentation:

  1. Anleitung für neue Entwickler so wie führen Sie das Projekt lokal (mehr dazu in einer Minute), welche Überlegungen gibt es (wenn man zum Beispiel einen anderen Rahmen als aktuell braucht, besonders bei Node leider).
  2. Dok.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr.-Nr. in diesen Tagen, wenn CI/CD als Gold-Standard der Bereitstellung gesehen wird, wird oft übersehen, dass Sie wissen müssen, wie das System manuell zu implementieren. Dies gilt vor allem, wenn Sie an einem System arbeiten, das für eine Weile da ist und viele manuelle Schritte hat.
  3. Verfahren zur Problemlösung; Was tun Sie, wenn das System untergeht? Wen rufen Sie an? Was sind die wichtigsten Dinge zu überprüfen? Dies wird oft übersehen, ist aber CRUCIAL in einem Produktionssystem.
  4. Architektur / System-Design Docs; wie funktioniert das System? Was sind die wichtigsten Komponenten? Was sind die wichtigsten Abhängigkeiten? Betrachten Sie dies als Ihre Roadmap, wenn Sie ein neues System lernen. Es bietet einen Überblick auf hohem Niveau, wie das System funktioniert, was kritisch sein kann (besonders in größeren, verteilten Systemen). Diese SHOULD beinhalten, welche Quellcode-Repositorien verwendet werden, welche CI/CD-Systeme verwendet werden, welche Datenbanken für jedes Element der Anwendung verwendet werden. Dies kann alles umfassen, von einem einfachen Diagramm bis hin zu einem vollständigen UML-Diagramm jeder Komponente des Systems. Zum Beispiel würde dies in einer React-Anwendung typischerweise ein Diagramm der Komponenten enthalten und wie sie miteinander und alle Backend-Dienste interagieren. In einer.NET Core Anwendung würde dies ein Diagramm der Dienste und wie sie miteinander interagieren (und das Frontend & andere Backend-Systeme) und möglicherweise ASP.NET Ansichten und welche Dienste sie verwenden können.

Dokumentation ist eines der Dinge, die wir als Entwickler oft hassen zu tun (es ist NICHT Code), aber es ist entscheidend. Wie Sie sehen können ICH LIEBE Markdown, mit den Beispielen Mermaid und PlantUML können Sie einige wirklich schöne Diagramme und Flussdiagramme erstellen, die in Ihrer Dokumentation enthalten sein können.

Es muss CURRENT sein; Entwickler sprechen oft über Bit-Rot; wo die Abhängigkeiten eines Projekts veraltet werden / geradezu Sicherheitsrisiken. Dies gilt auch für die Dokumentation; wenn sie nicht aktuell ist, ist sie nicht nützlich.

Es gibt unterschiedliche Ebenen der Dokumentation, aber im Allgemeinen wann immer Sie Code ändern, auf den in einem Dokument verwiesen wird, sollten Sie dieses Dokument aktualisieren.

Betrieb des Systems vor Ort

Dies ist oft eine Herausforderung, vor allem, wenn das System schon eine Weile da ist. Sie müssen wissen, welche Version von Node /.NET etc., welche Version der Datenbank, welche Version des Frameworks etc. Dies wird oft übersehen, aber ist CRUCIAL, um schnell aufzustehen und zu laufen.

Ich habe oft gesehen, Entwickler sagen, dass dies in diesen Tagen von Cloud-Systemen und großen verteilten Anwendungen nicht relevant ist, aber ich bin nicht einverstanden; Sie müssen in der Lage sein, das System lokal, um Probleme schnell und effektiv zu debuggen.

  1. Profiling - dies scheint eine "fortgeschrittene Entwickler nur" Fähigkeit geworden zu sein, aber es ist entscheidend, in der Lage zu sein, Ihren Code zu profilieren, um zu sehen, wo die Engpässe sind. Dies gilt vor allem in einem Legacy-System, wo Sie möglicherweise nicht den Luxus haben, das System von Grund auf neu zu schreiben. Werkzeuge wie dotTrace und dotMemorysind hier von unschätzbarem Wert. Besonders in ASP.NET-Anwendungen; die größten Probleme sind in der Regel "Leaks" im System; Speicherlecks, Verbindungslecks etc. Während Ihre App scheint, FINE für ein bisschen laufen Sie plötzlich feststellen, es ist abstürzt / mit bis den ganzen Speicher auf dem Server.
  2. Probleme im Debugger finden - Gefällt mir oder nicht Response.Write in Classic ASP sind vorbei. Für eine noch bescheiden komplexe Anwendung (besonders solche, die Sie nicht geschrieben haben) ist es entscheidend, durch den Code zu gehen. Um einer Anfrage von Anfang an durch den Dienst zu folgen, um festzustellen, was MIGHT passiert, welche Ausnahmen möglicherweise nicht gefangen werden usw.
  3. Logging - Wieder oft übersehen (sorry aber kein ASP.NET Core Ausnahmefilter an der Spitze des Stapels ist nicht genug). Ich beziehe mich auf meine vorheriger Beitrag, Protokollierung ist ein kritischer Teil bei der Arbeit in Code LOCALLY. Denken Sie daran, können Sie Kunden-Logging-Typen (zum Beispiel mit dem Protokollierung von Quellengeneratoren) im ASP.NET Core. Sie können dann festlegen, welche Ereignistypen protokolliert werden sollen und welche nicht. Dies ist entscheidend in einem Legacy-System, wo Sie möglicherweise nicht den Luxus haben, das System von Grund auf neu zu schreiben. Für Application Insights können Sie Benutzerreisen und andere Funktionen wünschen; jedoch beachten dies wird teuer schnell bei Verwendung von LogInformation für jede Anfrage. Möglicherweise möchten Sie einen benutzerdefinierten Telemetrie-Prozessor verwenden, um Anfragen herauszufiltern, die Sie nicht loggen möchten.
  4. Testing - Zu oft sehe ich Entwickler 'Testen in Preprod' oder denken, dass Unit Test dann Check-in ist ENOUGH in Bezug auf Tests. Seine RARELY IST, gibt es eine Menge Wert in beiden mit einem Werkzeug wie Resharper / NCrunch, um automatisch Einheitentests durchzuführen; jedoch erinnern Unit Tests sind genau das; sie testen eine 'Einheit' von Code. Sie müssen die Sichtbarkeit behalten, wie das System tatsächlich in Übereinstimmung mit anderen Komponenten läuft. Hier kommen Integrationstests ins Spiel; sie testen, wie das System als Ganzes läuft. Sie können ein Werkzeug wie SpecFlow diese Tests in einem menschenlesbaren Format zu schreiben. Wieder; entscheidend in einem Legacy-System, wo Sie vielleicht nicht den Luxus haben, das System von Grund auf neu zu schreiben.

Im ALLEN Projekt arbeite ich im ersten Schritt daran, das System (oder einen großen Teil davon) lokal laufen zu lassen. Wenn Sie den Code sehen, den Code ausführen, den Code debuggen, können Sie ein Gefühl für das Funktionieren des Systems bekommen.

Die Codebasis

In jedem System ist dies Ihr Quelle der WahrheitEgal, was die Ärzte sagen, was andere Ihnen darüber erzählen, wie es funktionieren soll, ist, wie es funktioniert.

Diese oft herausfordernde, es ist wie finden Sie Ihren Weg in einer neuen Stadt ohne Roadmap. Zum Glück haben Sie in Anwendungen einen Einstiegspunkt (eine Seite laden / ein Frontend API-Aufruf etc.) Wählen Sie einen Punkt und beginnen Sie dort.

Verwenden Sie alles, was Sie brauchen, um damit zu interagieren, ob PostMan, Rider's HttpClient oder sogar eine Webseite. Haken Sie sich in Ihrem Debugger, machen Sie den Anruf und folgen Sie ihm durch. Spülen und wiederholen Sie für jeden Teil des Systems.

Refaktorisierung

Im Allgemeinen LEAVE DIESES UND SIE DAS SYSTEM VERSTÄNDEN. Es ist IMMER verlockend, "es wegzuwerfen und wieder anzufangen" aber dieser Versuchung zu widerstehen. Speziell für ein laufendes System ES ARBEITET Wiederaufbau / sogar Refactoring eines Systems ist ein großes Risiko. Ja, es ist FUN, aber für jede Codezeile, die Sie ändern, riskieren Sie, neue snd spannende Bugs einzuführen.

Wie alles andere (besonders beim Kontraktieren) müssen Sie die Arbeit rechtfertigen, die Sie an einem System durchführen. Entweder muss sich diese Begründung auf einen der folgenden Punkte konzentrieren:

  1. Leistung - das System ist langsam und muss beschleunigt werden (Seien Sie wieder vorsichtig, was Sie langsam finden, kann sein, wie das System entwickelt wird, um zu funktionieren). Ein Teil des Rauchens schnell zu machen kann Probleme weiter unten im System einführen. Werden Sie den Datenbankserver 'töten', wenn Sie zu viele Anfragen stellen, haben Sie einen Mechanismus, der keine kaskadierenden Ausnahmen verursacht?
  2. Sicherheit - das System ist unsicher und muss gesichert werden. Dies ist ein schwieriges, vor allem in einem Legacy-System. Bei Bit-Rot können Sie feststellen, dass das System alte Versionen von Bibliotheken verwendet, die bekannte Sicherheitsprobleme haben. Dies ist eine gute Rechtfertigung für die Arbeit; aber seien Sie sich bewusst, dass Sie möglicherweise eine LOT des Systems refaktorieren müssen, um es auf dem neuesten Stand zu erhalten; wieder zu der "neuen Bugs" Problem führen.
  3. Erhaltungsfähigkeit - das System ist schwer zu pflegen und muss leichter zu warten sein. Im Allgemeinen wird dies zu einer Menge Arbeit; rechtfertigt die aktuelle Lebensdauer der Codebase dies? Wenn Sie mehr Zeit damit verbringen, diese Änderungen vorzunehmen, um die Wartungsfähigkeit zu verbessern, als Sie jemals für den Kunden sparen würden, dann lohnt es sich nicht (und wieder, geänderter Code == neue Bugs).
  4. Benutzererfahrung - Ich priorisiere diese Fragen im Allgemeinen. Für eine Benutzer Es spielt keine Rolle, ob Ihr Code 1% besser ist; sie sind diejenigen, die für die Arbeit ZAHLEN, die Sie am Ende tun. Wenn Sie ihre Erfahrung besser machen können, als es im Allgemeinen wert ist. Beachten Sie jedoch, dass dies eine 'rutschige Neigung' von Änderungen sein kann; Sie können feststellen, dass Sie eine LOT des Systems ändern, um eine kleine Änderung für den Benutzer vorzunehmen.

Das Geschäft der Arbeit an Vermächtnissystemen

Dies wird oft übersehen; vor allem von Entwicklern. Sie müssen in der Lage sein, Ihre Arbeit an einem System zu rechtfertigen. Dies gilt vor allem in einer vertraglichen Umgebung, wo Sie von der Stunde bezahlt werden. Am Ende ist es nicht Ihr Code und nicht Ihr Geld. Das WARUM Sie eine Änderung vornehmen, ist oft wichtiger als die Änderung selbst.

Ich habe seit über einem Jahrzehnt als Auftragnehmer gearbeitet, es ist nicht EASY; als Auftragnehmer jede Stunde Ihrer Zeit ist ein "Kosten" für den Kunden. Sie müssen verschieben Wert auf das System als Sie Kosten hinzufügen. Wenn Sie nicht sind, dann werden Sie schnell nach einem neuen Vertrag suchen.

Als Entwickler neigen wir dazu, beschissene Geschäftsleute zu sein, die wir auf "Perfektion" bei jeder Runde konzentrieren. In Wirklichkeit brauchen Sie kein System "perfekt" zu machen (ich würde argumentieren, dass es keine solche Sache gibt); Sie müssen nur Wert an den Kunden liefern.

Bei einem längerfristigen Engagement dieses INCLUDES sicherstellen, dass neu Code ist wartungsfähig und kosteneffizient zu betreiben. In Legacy-Systemen ist dies MUCH HARDER. Man muss oft durch einen Sumpf waten, weil man besorgt ist, dass man beim Lernen des Systems keinen großen Wert hat. I'm not making any changes du denkst I'm just learning the system. Dies ist ein Trugschluss; Sie lernen das System, es besser zu machen. Du lernst das System, um es effizienter zu machen. Du lernst das System, um es wartungsfähiger zu machen. Wenn ein Kunde diesen Schritt nicht akzeptieren kann, dann müssen Sie sehr vorsichtig sein, wie Sie dies kommunizieren (oder einen neuen Vertrag suchen).

Das Volk

Wieder oft übersehen, eine Menge von der Zeit, die Sie als Auftragnehmer gebracht werden, weil einige Schlüsselperson verlassen hat (nicht in die Politik dieser engagieren; es ist nicht Ihre Angelegenheit). Sie müssen in der Lage sein, mit den Menschen zu arbeiten, die dort sind, um die Ziele des Projekts zu erreichen. In einem Vertrag haben Sie in der Regel die Bedingungen Ihres Engagements festgelegt (in meinem aktuellen Vertrag ist es "Verbesserung der Zuverlässigkeit und Reduzierung der laufenden Kosten"); konzentrieren Sie sich auf dies. Wenn Sie nicht sicher sind, was das bedeutet, dann ASK.

Denken Sie daran, wer Ihr direkter Kontakt ist; besonders in den ersten paar Monaten. Halten Sie sie auf dem Laufenden (Sie haben wahrscheinlich keine neuen Funktionen zu prahlen, wie Sie auf, wie das System funktioniert gesponnen erhalten). In der Regel schicke ich jede Woche / zwei Wochen eine zusammenfassende E-Mail an meinen direkten Kontakt; dies ist ein guter Weg, um sie über das, was Sie tun und was Sie finden, auf dem Laufenden zu halten.

Denken Sie daran, dies ist die Person, die Ihre Rechnung zu genehmigen; es sollte keine Überraschungen bei der Rechnung Zeit. Sobald Sie anfangen, den Code regelmäßig zu überprüfen, ist dies weniger ein Problem; Sie haben eine Aufzeichnung darüber, was Sie genau getan haben und welche Auswirkungen es hatte. Bis dahin müssen Sie sie auf dem Laufenden halten. Sie müssen wissen, was du getan hast und warum sie dich dafür bezahlen sollten.

Zuverlässigkeit

Wieder zurück zum Legacy-Code; wenn Sie eine Änderung im Allgemeinen vornehmen, müssen Sie ihn bereitstellen.Selbst das Beste von uns wird von Zeit zu Zeit FUCK DIES up, vor allem in Legacy-Code-Systemen wird es etwas geben Du konntest es nicht wissen. wenn Sie sich entledigen. Dies geht zurück zum Protokollieren - wenn Sie einen Staging-Server haben, der eine LOT protokolliert (aber für einen kurzen Zeitraum beibehalten) dann, wenn Sie zu DIESEM bereitstellen, können Sie mehr Informationen darüber sammeln, was fehlgeschlagen ist.

Egal, wie gut Sie sind, wie viel lokale Tests Sie gemacht haben, wir sind alle menschlich. Dies ist ein wesentlicher Teil der "nicht am Freitag einsetzen" Regel; erwarten, dass eine Bereitstellung ein neues Problem auf einem System verursachen. Bereiten Sie sich auf die Arbeit vor, bis sie gelöst ist. Wenn Sie nicht WISSEN, warum es fehlgeschlagen ist, fügen Sie weitere Tests hinzu, um das Problem zu reproduzieren und mehr Protokollierung, um sicherzustellen, dass Sie ähnliche Probleme in der Zukunft fangen.

Speziell für Produktionssysteme darf Ihr Staging-System nicht 1:1 sein (besonders wenn es um Last geht), Werkzeug wie K6 kann Ihnen helfen, Last zu simulieren (noch besser lokal, wo Sie das richtige Profiling machen können, wie bereits erwähnt).

Einsatz

Wieder oft übersehen im Eifer für CI/CD ist das WARUM von diesen. Einfach, du wirst aufwachen. Mit einem sehr schnellen und effizienten Weg, um ein System zu implementieren, bedeutet, dass, wenn Sie es brechen, können Sie es auch schneller beheben. Wenn Ihr CI-Code-Review-System bedeutet, dass es 2 Tage dauert, um eine PR zusammengeführt zu bekommen, dann ist das das schnellste, das Sie vernünftigerweise ein System bedienen können. Wenn Ihr CD-System bedeutet, dass Sie das laufende System herunternehmen; gewöhnen Sie sich an LONG-Nächte.

Für eine effiziente Entwicklungspipeline ist ein effizienter Mechanismus zur Fixierung und Bereitstellung von Code unerlässlich. Wenn es länger dauert, um einen Fix zu implementieren, als es dauerte, um diesen Fix im Code zu finden und zu implementieren, dann sind Sie weniger wahrscheinlich, um Sachen zu beheben.

'Vermächtnis-Apps füllen'

Ich habe dies in Zitate gesetzt, da dies ein Problem ist; für Legacy-Anwendungen (besonders wenn großformatige Nacharbeit außerhalb der Grenzen liegt) gibt es zwei Hauptansätze.

  • Patches ausführen

Dies ist der Prozess der einfachen Fixierung vorhandener Code; wieder sicherstellen, dass Sie gründlich testen und haben Prozesse an Ort und Stelle, um alle Korrekturen rückgängig zu machen / schnell neu zu machen. Ich werde nicht lügen, dass diese Art von Entwicklung selten FUN ist, da Sie wahrscheinlich immer noch durch den Sumpf der bestehenden Codebase waten. Allerdings ist es in vielen Fällen ein notwendiges Übel.

Wie üblich sollten Sie sicherstellen, dass Sie SOME FORM of test haben, um den aktuellen Code zu erfahren; im Idealfall sollte es auch auf Fehler für das Problem testen, das Sie versuchen, BEFORE zu lösen, machen Sie die Lösung . Sie IDYLL dafür ist eine Unit-Test, die genau auf den Bereich des Codes, die Sie beheben müssen, aber dies ist oft außerhalb des Arbeitsbereichs für große, verteilte Systeme.

Ich würde in der Regel ein System von Tests in dieser Reihenfolge der Präferenz:

  1. Unit Tests - wieder werden diese bevorzugt, da Sie diese gezielt nur den Code ausüben können, an dem Sie arbeiten. In einem Legacy-System sind diese jedoch oft nicht vorhanden & extrem schwer nachzurüsten (z.B. in einem System mit vielen externen Anrufen / das chaotisch ist, wie es konstruiert; nicht mit DI zum Beispiel).
  2. Integrationstests - Dies ist ein überlasteter Begriff, da er alles abdecken kann, von einem Unit-Test, der durch mehrere Schichten von Code geht (diese werden am besten vermieden), um die Verwendung der gleichen der ausgezeichnet Überprüfen bis hin zu Selen-Tests. Im Allgemeinen möchten Sie das System als Ganzes testen; aber beachten Sie, dass diese Tests langsam und spröde sein können. Die Verwendung von Verify kann oft ein großartiger Ansatz für Legacy-Systeme sein, da Sie zumindest "verifizieren" können, dass Sie die API-Oberfläche des Systems nicht brechen.
  3. Manuelle Tests - JEDER Entwickler sollte versuchen, manuelle Tests für jedes Code Checkin durchzuführen. Dies stellt nur sicher, dass das, was Sie vom 'Benutzer' erwarten (das kann ein tatsächlicher Benutzer oder eine andere Komponente des Systems sein, das mit Ihrem Code interagiert) zu sehen ist, was sie tatsächlich sehen. Dies kann so einfach sein, wie das System lokal laufen zu lassen und die Ausgabe einer Seite zu überprüfen oder so komplex wie eine ganze Reihe von Tests auf einem Staging-Server durchzuführen.
  • Zwiebelhautbildung Für die Arbeit an Legacy-Systemen haben Sie in der Regel nicht den Luxus einer kompletten Nacharbeit. Hier verwende ich den Ansatz der Zwiebelhäutung.

Damit Sie PARTS eines Systems aktualisieren können, können Sie Komponenten identifizieren, die von einem bestehenden Monolithen in einen Mikroservice (für einen gewissen Wert von'micro') aufgeteilt werden können. Dies kann ein guter Weg sein, um ein System zu modernisieren, ohne dass die Gefahr einer vollständigen Überarbeitung besteht. Häufige Beispiele könnten darin bestehen, API-Endpunkte in neue Projekte aufzuspalten, die mehr aktualisierte Elemente verwenden. Der Terror von DRY kann hier jedoch ins Spiel kommen. Eine schlecht strukturierte Lösung hat oft viele 'Helfer' oder 'Service' Komponenten, die wirklich in verschiedenen Projekten (oder sogar in Nuget-Paketen für mehr globale Wiederverwendung) sein sollten.

Ich werde diesen Ansatz weiter in einem zukünftigen Artikel abdecken, da es ein Schlüsselelement ist, wie ich auf Legacy-Systemen arbeite und nicht offensichtlich für viele Entwickler.

Bezahlen

Nun, da wir all dies draußen haben, kommt das dornige Problem der Bezahlung. Ich habe eine allgemeine Regel:

Alle Zahlungsprobleme, die ich suche, um weiter zu gehen

Wenn sie zu spät zahlen; hängt von Ihrem Vertrag, aber bei LEAST innerhalb von 30 Tagen, aber in der Regel näher an 7; dies ist ein schlechtes Zeichen. Wenn es Quibbles über Ihre Rechnung (Nickle-and-Dimeing) darüber nachdenken, ob das Unternehmen in der Lage ist, für Ihre Dienstleistungen auf einer kontinuierlichen Basis zu bezahlen.

Machen Sie sich nicht damit herum; wenn Sie Ihren Job getan haben, müssen Sie rechtzeitig bezahlt werden. Es spielt keine Rolle, wie sehr Sie es genießen; wenn ein schlechter Kunde KANN Sie ausnutzen, werden sie. Das ist es nie wert.

Seien Sie ehrlich; nur für die Zeit, die Sie tatsächlich gearbeitet haben; stellen Sie sicher, dass es klar ist, was Sie getan haben und warum Sie es getan haben.

Ich habe Teams von Entwicklern geführt und ich war ein Entwickler; Ich war ein Auftragnehmer und ich war ein Kunde. Ich habe alle Seiten davon gesehen und kann es Ihnen sagen; wenn Sie nicht pünktlich bezahlt werden, dann müssen Sie weiterziehen. Auf der Flip-Seite, wenn Sie einen Auftragnehmer (oder eine FTE) haben, die nicht liefert, dann müssen Sie dies schnell ansprechen. Jeder hat persönliche Kämpfe, aber vor allem in einer Vertragsumgebung müssen Sie liefern Wert oder nicht für die Zeit aufladen, wenn Sie nicht sind.

Was die Rate anbetrifft; Sie werden Ihr Niveau finden; persönlich rechne ich mehr für Projekte, in denen ich mehr Verantwortung habe (oder die nicht nach Spaß aussehen). Ich rechne weniger für Projekte, in denen ich eine neue Technologie lerne oder für Startups. Ich habe auch weniger Tage gearbeitet, aber meine Rate stabil gehalten. Aber akzeptieren Sie nicht einen niedrigen Ball-Rate; Sie sind ein Profi und Sie sollten als solche bezahlt werden.

Schlussfolgerung

Das war's. Ich bin heute und morgen auf der Arbeit für die Beerdigung meiner Oma und offen gesagt in Panik, dass ich ein HUGE Legacy-System zu lernen, so dachte ich, ich würde meine Gedanken über die Arbeit an diesen Systemen wie & die Herausforderungen erbrechen.

logo

©2024 Scott Galloway