Waarom het te vroeg splitsen van je codebase de snelheid van je team kan vernietigen - en wat te doen in plaats daarvan.
Waarom het te vroeg splitsen van je codebase de snelheid van je team kan vernietigen - en wat te doen in plaats daarvan.
In een startup,your survival depends on how quickly you can iterate, ship features, and deliver value to end-usersDit is waar de fundamentele architectuur van uw startup een grote rol speelt; bovendien, dingen zoals uw tech stack en de keuze van de programmeertaal direct van invloed op de snelheid van uw team.
Ik heb deze ervaring gehad bij het werken aan greenfield-projecten voor startups in de vroege fase, waar twijfelachtige beslissingen werden genomen met betrekking tot softwarearchitectuur die leidde tot halve voltooide diensten enBroze, overontwikkelde en gebroken lokale instellingenendemoralized teamsWie worstelt met het behouden van onnodige complexiteit.
Voordat je in specifieke valstrikken duikt, is hier wat je eigenlijk aanmeldt bij het voortijdig introduceren van microservices:
Microservices Early On: What You’re Paying For
Pain Point |
Real-World Manifestation |
Developer Cost |
---|---|---|
Deployment Complexity |
Orchestrating 5+ services for a single feature |
Hours lost per release |
Local Dev Fragility |
Docker sprawl, broken scripts, platform-specific hacks |
Slow onboarding, frequent breakage |
CI/CD Duplication |
Multiple pipelines with duplicated logic |
Extra toil per service |
Cross-Service Coupling |
"Decoupled" services tightly linked by shared state |
Slower changes, coordination tax |
Observability Overhead |
Distributed tracing, logging, monitoring |
Weeks to instrument properly |
Test Suite Fragmentation |
Tests scattered across services |
Brittle tests, low confidence |
De complexiteit van de implementatie
Orchestreren van 5+ diensten voor een enkele functie
Hours lost per release
Lokale Dev Fragility
Docker spreads, gebroken scripts, platformspecifieke hacks
Slow onboarding, frequent breakage
CI/CD Duplicatie
Meerdere pijpleidingen met dubbele logica
Extra toil per service
Cross-service koppeling
"Uitgeschakelde" diensten nauw met elkaar verbonden door gedeelde staat
Slower changes, coordination tax
Overhead observatie
gedistribueerde tracking, logging, monitoring
Weeks to instrument properly
Test Suite Fragmentatie
Tests verspreid over diensten
Brittle tests, low confidence
Laten we uitpakken waarom microservices vaak vroeg terugvallen, waar ze echt helpen en hoe u de systemen van uw startup kunt structureren voor snelheid en overleving.
Monolithen zijn niet de vijand
Als u een SaaS-product bouwt, kan zelfs een eenvoudige SQL-database wrapper uiteindelijk veel interne complexiteit brengen in de manier waarop uw bedrijfslogica werkt; bovendien kunt u verschillende integraties en achtergrondtaken krijgen die u toelaten om een reeks gegevens naar een andere te transformeren.
Na verloop van tijd, soms onnodige functies, is het onvermijdelijk dat uw app rot kan worden.Monoliths, even when messy, keep your team focused on what matters most:
- Levend blijven
- Levering van klantwaarde
Over het algemeen worden dergelijke projecten gebouwd rond bestaande frameworks – het zou Django voor Python kunnen zijn,Het ASP.NETvoor C#, Nest.js voor Node.js-apps, etc. Wanneer je vasthoudt aan monolithische architectuur, krijg je het grootste voordeel ten opzichte van fancy microservices - een brede ondersteuning van de open source-gemeenschap en projectbeheerders die deze frameworks voornamelijk ontwierpen om als een enkel proces te werken, monolithische app.
Bij een vastgoedstart waar ik het front-end team leidde en af en toe het backendteam raadpleegde over technologische keuzes, hadden we een interessante evolutie van een op Laravel gebaseerde app.
Na verloop van tijd ontwikkelde het zich tot een feature-rijke suite die honderden gigabytes documenten verwerkt en geïntegreerd met tientallen services van derden.
Het team vertrouwde sterk op de beste praktijken die door de Laravel-gemeenschap werden aanbevolen.Deze discipline heeft zich uitbetaald, we konden de mogelijkheden van de applicatie aanzienlijk uitbreiden en tegelijkertijd voldoen aan de behoeften en verwachtingen van het bedrijf.
Interessant is dat we het systeem nooit hoefden te ontkoppelen in microservices of meer complexe infrastructuurpatronen aan te nemen. We hebben veel toevallige complexiteit op die manier vermeden. De eenvoud van de architectuur gaf ons hefboomwerking.‘Majestic Monolith’Dit laat zien waarom eenvoud al vroeg een superkracht is.
Mensen wijzen vaak erop dat het moeilijk is om monolieten schaalbaar te maken, maar het is slechte modularisatieBinneninDe monolith die dergelijke problemen kan veroorzaken.
Takeaway: A well-structured monolith keeps your team focused on shipping, not firefighting.
Maar zijn microservices niet ‘beste praktijken’?
Veel ingenieurs bereiken vroeg voor microservices, denken dat ze "de juiste manier" zijn en zeker - op schaal, kunnen ze helpen.
Microservices betalen alleen uit als je echte schaalbarrières, grote teams of onafhankelijk evoluerende domeinen hebt.SegmentEindelijkDe microservice split omgekeerdOm deze exacte reden – te veel kosten, niet genoeg waarde.
Takeaway: Microservices are a scaling tool — not a starting template.
Waar microservices verkeerd gaan (vooral vroeg op)
In een vroeg stadium team dat ik adviseerde, de beslissing om diensten te splitsen creëerde meer PM-engineering coördinatie overhead dan technische winst. architectuur vormde niet alleen code, maar hoe we gepland, geschat en verzonden.
Hier zijn de meest voorkomende anti-patterns die in het begin kruipen.
1. willekeurige service grenzen
In theorie zie je vaak suggesties over het splitsen van je toepassingen per business logic domein - gebruikersservice, productservice, orderservice, enzovoort. Dit wordt vaak geleend van Domain-Driven Design of Clean Architecture concepten - die zinvol zijn op schaal, maar in de vroege fase producten kunnen ze de structuur voortijdig ossify, voordat het product zelf stabiel is of gevalideerd.
- Gedeelde databases
- Cross-service vraagt om eenvoudige workflows
- Coupling vermomd als ‘separatie’
In een project zag ik een team dat gebruikers, authenticatie en autorisatie scheidde in afzonderlijke services, wat leidde tot de complexiteit van de implementatie en moeilijkheden bij de servicecoördinatie voor elke API-operatie die ze bouwden.
Voortijdige scheiding kan het systeem kwetsbaarder maken en vaak moeilijk om snel veranderingen in te voeren.
In plaats daarvan isoleer de bottlenecks chirurgisch - gebaseerd op echte schaalpijn, niet op theoretische elegantie.
Toen ik teams in de vroege stadia trainde, gebruikten we soms interne vlaggen of implementatieschakelaars om toekomstige service splitsingen te simuleren - zonder de onmiddellijke operationele last.
Takeaway: Don’t split by theory — split by actual bottlenecks.
Repository en Infrastructuur Sprawl
Bij het werken aan de applicatie is meestal een volgende reeks dingen belangrijk:
- Code stijl consistentie (linting)
- Testinfrastructuur, met inbegrip van integratietests
- Lokale omgeving configuratie
- Documentatie
- Configuratie CI/CD
Als uw project is gestructureerd als een monorepo, kunt u uw leven vereenvoudigen door een centrale CI/CD-configuratie te hebben (wanneer u werkt met GitHub Actions of GitLab CI).
Context schakelen tussen repositories en tooling voegt toe aan de ontwikkeltijd van elke functie die wordt verzonden.
Problemen verminderen met behulp van monorepos en een enkele programmeertaal
Er zijn verschillende manieren om dit probleem te verminderen.Voor vroege projecten is het belangrijkste ding om uw code in een monorepo te houden.Dit zorgt ervoor dat er een enkele versie van de code is die bestaat op prod, en het is veel gemakkelijker om code-reviews te coördineren en samen te werken voor kleinere teams.
Voor Node.js-projecten raad ik ten zeerste aan om een monorepo-tool te gebruiken zoalsnx
ofturborepo
Beide zijn:
- Simplificeer de CI/CD-configuratie in subprojecten
- Ondersteuning van dependency graph-based build caching
- Laten we interne services behandelen als TypeScript-bibliotheken (via ES6-importen)
Deze hulpmiddelen besparen tijd die anders wordt besteed aan het schrijven van lijmcode of het opnieuw uitvinden van orchestratie.
- Complexe afhankelijkheidsbomen kunnen snel groeien
- CI performance tuning is niet triviaal
- Je hebt mogelijk snellere tooling nodig (zoals bun) om de bouwtijden naar beneden te houden
Om samen te vatten: Tooling likenx
ofturborepo
geeft kleine teams monorepo-snelheid - als je bereid bent te investeren in het schoon houden.
Wanneer ontwikkelengo
-gebaseerde microservices, een goed idee vroeg in de ontwikkeling is om een enkele go
Werkruimte met dereplace
richtlijn ingo.mod
Uiteindelijk, als de software schaalt, is het mogelijk om moeiteloos te scheiden go
Modules in afzonderlijke repositories.
Takeaway: A monorepo with shared infra buys you time, consistency, and sanity.
Broken Local Dev = gebroken snelheid
If it takes three hours, a custom shell script, and a Docker marathon just to run your app locally, you've already lost velocity.
Vroege projecten lijden vaak aan:
- Ontbrekende documentatie
- Oudere afhankelijkheden
- OS-specifieke hacks (hello, Linux-only installaties)
In mijn ervaring, toen ik projecten van eerdere ontwikkelteams ontving, werden ze vaak ontwikkeld voor een enkel besturingssysteem. Sommige ontwikkelaars hebben de voorkeur gegeven aan het bouwen op macOS en hebben nooit moeite gehad met het ondersteunen van hun shell scripts op Windows. In mijn eerdere teams had ik ingenieurs die op Windows-machines werkten, en vaak was het nodig om shell scripts opnieuw te schrijven of volledig te begrijpen en omgekeerde engineering het proces om de lokale omgeving te laten draaien. Na verloop van tijd hebben we omgevingsinstellingen in de ontwikkelingssystemen gestandaardiseerd om aan boord wrijving te verminderen - een kleine investering die uren per nieuwe ingenieur bespaarde.
In een ander project had een solo-ontwikkelaar een fragiele microservice-installatie gemaakt, waarbij de workflow van het uitvoeren van Docker-containers werd gemonteerd op een lokaal bestandssysteem.
Maar aan boord van een nieuwe front-end-developer met een oudere Windows-laptop veranderde het in een nachtmerrie. ze moesten tien containers opzetten om alleen de UI te bekijken. Alles brak - volumes, netwerken, containercompatibiliteit - en de installatie was zeer slecht gedocumenteerd.
We hebben uiteindelijk een Node.js-proxy gehackt die de nginx/Docker-configuratie zonder containers imiteerde. Het was niet elegant, maar het liet de ontwikkelaar ontgrendelen en beginnen bij te dragen.
Takeaway: If your app only runs on one OS, your team’s productivity is one laptop away from disaster.
Tip:Idealiter gericht opgit clone <repo> && make up
Als het niet mogelijk is, dan is het handhaven van een up-to-date README-bestand met instructies voor Windows/macOS/Linux een must. Tegenwoordig zijn er een aantal programmeertaal en toolchains die niet goed werken op Windows (zoals OCaml), maar de moderne veelgebruikte stack werkt gewoon goed op elk algemeen gebruikte besturingssysteem; door uw lokale installatie te beperken tot een enkel besturingssysteem, is het vaak een symptoom van onderinvestering in DX.
Technische mismatch
Naast de architectuur vormt uw techstack ook hoe pijnlijke microservices worden - niet elke taal schijnt in een microservice-architectuur.
- Node.js en Python: geweldig voor snelle iteratie, maar het beheren van bouwen van artefacten, versies van afhankelijkheid en runtime-consistentie over services wordt pijnlijk snel.
- Go: compileert naar statische binaries, snelle bouwtijden en lage operationele overhead.
Als je op zoek bent naar prestaties, zoek misschien naar de JVM en zijn ecosysteem en de mogelijkheid om artefacten op schaal te implementeren en ze in microservice-gebaseerde architecturen uit te voeren.
Het is heel vaak voor teams om te beseffen dat er grote problemen zijn met hun keuze van technologie die in eerste instantie niet duidelijk waren, en ze moesten de prijs betalen van het opnieuw opbouwen van de back-end in een andere programmeertaal (zoalsDie jongenswerd gedwongen om iets te doen over de legacy Python 2 codebase en migreerde naar Go).
Maar andersom, als je het echt nodig hebt, kun je meerdere programmeertalen met protocollen zoalsgRPCOf asynchrone berichtencommunicatie. En het is vaak de manier om over dingen te gaan. Wanneer je het punt bereikt dat je je feature set wilt verrijken met Machine Learning-functionaliteit of ETL-gebaseerde banen, zou je gewoon afzonderlijk je ML-gebaseerde infrastructuur in Python bouwen, vanwege het rijke ecosysteem van domeinspecifieke bibliotheken, dat natuurlijk elke andere programmeertaal ontbreekt. Maar dergelijke beslissingen moeten worden genomen wanneer er genoeg hoofdrekening is om dit onderneming te rechtvaardigen; anders zal het kleine team eeuwig worden getrokken in de eindeloze complexiteit van het samenbrengen van meerdere software stacks.
Takeaway: Match the tech to your constraints, not your ambition.
Verborgen complexiteit: communicatie en monitoring
Microservices introduceert een onzichtbaar web van behoeften:
- Service ontdekking
- API versie
- Retries, circuitbreakers en fallbacks
- gedistribueerde tracking
- Gecentraliseerd loggen en waarschuwen
In een gedistribueerd systeem, is het "waarom faalt service A wanneer de implementatie van B C met 30 seconden vertraagt?" U zou moeten grondig investeren in uw waarnemingsstack. Om het "goed" te doen, vereist het het instrumenteren van uw toepassingen op specifieke manieren, bijvoorbeeld het integreren van OpenTelemetry om tracking te ondersteunen, of vertrouwen op hulpmiddelen van uw cloudprovider zoals AWS XRay als u gaat met een complex serverloos systeem.actuallyfunctioneren in de productie.
Natuurlijk is een deel van de observatie-instrumentatie nodig om op monolith-apps uit te voeren, maar het is veel eenvoudiger dan dat te doen in termen van het aantal diensten op een consistente manier.
Tip:Begrijp datdistributed systems Niet vrij zijn.Ze zijn een toewijding aan een hele nieuwe klasse van technische uitdagingen.
Niet vrij zijn.Wanneer microservicesDo vanMaak zin
Do vanOndanks de genoemde moeilijkheden met microservices, zijn er tijden waarin de ontkoppeling op serviceniveau eigenlijk zeer gunstig is.
- Workload isolatie: een gebruikelijk voorbeeld hiervan zou zijn in de beste praktijken van AWS met betrekking tot het gebruik van S3-evenementmeldingen - wanneer een afbeelding wordt geladen op S3, een beeldverandering / OCR-proces wordt veroorzaakt, enz. Waarom het nuttig is: we kunnen obscure gegevensverwerkingsbibliotheken loskoppelen in een zelf-geïsoleerde service en maken het een API die zich uitsluitend richt op beeldverwerking en het genereren van output van de geüpload gegevens.
- Divergente schaalbaarheidsbehoeften: — Stel je voor dat je een AI-product bouwt. Een deel van het systeem (web-API) dat ML-werkbelastingen veroorzaakt en vorige resultaten weergeeft, is niet resource-intensief, het is lichtgewicht, omdat het voornamelijk met de database interageert. Integendeel, het ML-model dat op GPU's draait, is eigenlijk zwaar om te draaien en vereist speciale machines met GPU-ondersteuning met extra configuratie.
- Verschillende runtime-eisen: — Laten we zeggen dat u een aantal erfelijke deel van de code geschreven in C++ hebt. U hebt 2 keuzes — magisch om te zetten in uw kern programmeertaal of manieren te vinden om het te integreren met een codebase. Afhankelijk van de complexiteit van die erfelijke app, zou je lijmcode moeten schrijven, het implementeren van aanvullende netwerk / protocollen om interacties met die service te vestigen, maar de onderliggende regel is — je zult waarschijnlijk deze app moeten scheiden als een aparte dienst vanwege runtime-incompatibiliteiten.
Grote engineering organisaties hebben met soortgelijke uitdagingen te maken gehad.Bijvoorbeeld, het engineering team van Uberhun verschuiving naar een domein-georiënteerde microservice-architectuur gedocumenteerd— niet uit theoretische zuiverheid, maar in reactie op echte complexiteit over teams en schaalbare grenzen. hun post is een goed voorbeeld van hoe microservices kunnen werken wanneer je de organisatorische volwassenheid en operationele overhead hebt om ze te ondersteunen.
Bij een project, dat ook een onroerend goed is, hadden we code van een eerder team dat Python-gebaseerde analytics-workloads uitvoerde die gegevens in MS-SQL db laadt, we vonden dat het een verspilling zou zijn om een Django-app erop te bouwen.De code had verschillende runtime-afhankelijkheden en was vrij zelf-geïsoleerd, dus we hielden het apart en herzien het alleen als iets niet werkte zoals verwacht.
Takeaway: Use microservices when workloads diverge — not just because they sound clean.
Praktische richtlijnen voor startups
Als u uw eerste product verzendt, hier is het spelboek dat ik zou aanbevelen:
- Begin monolithisch. Kies een gemeenschappelijk framework en focus op het maken van de functies. Alle bekende frameworks zijn meer dan goed genoeg om een aantal API's of websites te bouwen en de gebruikers te dienen. Volg de hype niet, houd je aan de saaie manier van dingen doen; je kunt jezelf later bedanken.
- Single repo. Maak je geen zorgen over het splitsen van je code in meerdere repositories. Ik heb met oprichters gewerkt die de repo wilden scheiden om het risico te verminderen dat aannemers IP kopiëren - een geldige zorg. Maar in de praktijk voegde het meer wrijving toe dan beveiliging: langzamer builds, gefragmenteerde CI / CD's en slechte zichtbaarheid over teams. De marginale IP-bescherming was de operationele drag niet waard, vooral als de juiste toegangscontroles binnen een monorepo gemakkelijker te beheren waren.
- Maak make-up werk. Als het meer kost, wees zeer specifiek over de stappen, maak een video / Loom en voeg screenshots toe. Als je code wordt uitgevoerd door een intern of junior developer, zullen ze waarschijnlijk een wegblokkade raken, en je zult tijd besteden aan het uitleggen hoe je een probleem oplost. Ik ontdekte dat het documenteren van elk mogelijk probleem voor elk besturingssysteem de tijd elimineert die wordt besteed aan het verduidelijken waarom bepaalde dingen in een lokale setup niet werkten.
- Investeer vroeg in CI/CD. Zelfs als het een eenvoudige HTML is die je gewoon handmatig naar een server zou kunnen scp, kun je dit automatiseren en vertrouwen op broncode met CI/CD om dit te doen.Wanneer de installatie goed geautomatiseerd is, vergeet je gewoon over je continue integratie-infrastructuur en focus op functies.Ik heb veel teams en oprichters gezien bij het werken met outsourced teams vaak goedkoop zijn op CI/CD, en dat resulteert in het team dat gedemoraliseerd en geïrriteerd wordt door manuele implementatieprocessen.
- Split chirurgisch. Split alleen als het duidelijk een pijnlijke bottleneck oplost. Anders investeren in modulariteit en testen binnen de monoliet - het is sneller en gemakkelijker te onderhouden.
En vooral:optimize for developer velocity.
Velocity is your startup’s oxygen.Voortijdige microservices lekken die zuurstof langzaam - totdat je op een dag niet kunt ademen.
Takeaway: Start simple, stay pragmatic, and split only when you must.
Als u een microservice-gebaseerde aanpak
Ik had micro-service-gebaseerde projecten eerder gemaakt dan ze hadden moeten worden gedaan, en hier zijn de volgende aanbevelingen die ik daarover kon geven:
- Evalueer uw technische stack die uw micro-service-gebaseerde architectuur ondersteunt. Investeer in ontwikkelaarservaringstool. Wanneer u service-gebaseerde scheiding hebt, moet u nu nadenken over het automatiseren van uw microservice-stack, het automatiseren van configuraties in zowel lokale als productieomgevingen. In sommige projecten moest ik een afzonderlijke CLI bouwen die administratieve taken uitvoert op het monorepository. Een project dat ik 15-20 microservice-implementaties had, en voor de lokale omgeving moest ik een cli-tool maken om docker-compose.yml-bestanden dynamisch te genereren tot naadloos een-opdrachtstart voor de reguliere ontwikkelaar.
- Concentreer je op betrouwbare communicatieprotocollen rond servicecommunicatie. Als het asynchrone berichten is, zorg ervoor dat je berichtschema's consistent en gestandaardiseerd zijn. Als het REST is, concentreer je op OpenAPI-documentatie. Inter-service-communicatie-clients moeten veel dingen implementeren die niet uit de doos komen: retries met exponentiële backoff, timeouts. Een typische gRPC-client met blote botten vereist dat je die extra dingen handmatig factoren om ervoor te zorgen dat je niet last hebt van voorbijgaande fouten.
- Zorg ervoor dat uw eenheid, integratie-tests en end-to-end-tests stabiel zijn en scalen met de hoeveelheid service-level scheidingen die u invoert in uw codebase.
- Op kleinere projecten die op micro-services gebaseerde workloads gebruiken, zou u waarschijnlijk standaard een gedeelde bibliotheek met gemeenschappelijke helpers gebruiken om uw observatie- en communicatiecode op een consistente manier te instrumenteren.
- Voeg gestructureerde JSON-logs toe en creëer verschillende correlatie-ID's voor het debuggen van dingen zodra uw app is geïmplementeerd. Zelfs basishelpers die rijke loginformatie produceren (totdat u uw app hebt geïnstalleerd met de juiste log / tracking-faciliteiten) besparen vaak tijd bij het uitzoeken van flake gebruikersstromen.
Samenvattend: als u nog steeds gaat voor microservices, moet u van tevoren begrijpen welke belasting u gaat betalen in termen van extra ontwikkeltijd en onderhoud om de installatie werkbaar te maken voor elke ingenieur in uw team.
Takeaway: If you embrace complexity, invest fully in making it manageable.
Conclusie
Premature microservices are a tax you can’t afford. Stay simple. Stay alive.Splits alleen als de pijn het duidelijk maakt.
Survive first. Scale later. Choose the simplest system that works — and earn every layer of complexity you add.
Gerelateerde middelen
- Monolith First van Martin Fowler
- De Majestueuze Monoliet - DHH / Basecamp
- Afscheid Microservices: Van 100s van probleemkinderen tot 1 superster - Segment Eng.
- Deconstrueer de Monolith - Shopify Eng.
- Domain-Oriented Microservice Architecture – Uber Eng.
- Go + Services = One Goliath Project - Khan Academy