Varje dag, varje ögonblick under vår ingenjörskarriär, stöter vi på många olika problem av olika komplexitet och situationer där vi behöver fatta ett beslut eller skjuta upp det på grund av brist på data. Närhelst vi bygger nya tjänster, konstruerar infrastruktur eller till och med formar utvecklingsprocesser, berör vi en enorm värld av olika utmaningar.
Det är utmanande, och kanske till och med omöjligt, att lista alla problem. Du kommer bara att stöta på några av dessa problem om du arbetar inom en specifik nisch. Å andra sidan finns det många som vi alla måste förstå hur vi ska lösa, eftersom de är avgörande för att bygga IT-system. Med stor sannolikhet kommer du att stöta på dem i alla projekt.
I den här artikeln kommer jag att dela mina erfarenheter av några av de problem jag har stött på när jag skapade program.
Om vi tittar på Wikipedia hittar vi följande definition
Inom aspektorienterad mjukvaruutveckling är övergripande problem aspekter av ett program som påverkar flera moduler, utan möjlighet att vara inkapslade i någon av dem. Dessa problem kan ofta inte dekomponeras rent från resten av systemet i både design och implementering, och kan resultera i antingen spridning (kodduplicering), trassling (betydande beroenden mellan system) eller båda.
Det beskriver mycket vad det är, men jag vill utöka och förenkla det lite:
Ett övergripande problem är ett koncept eller en komponent i systemet/organisationen som påverkar (eller "skär över") många andra delar.
De bästa exemplen på sådana problem är systemarkitektur, loggning, säkerhet, transaktionshantering, telemetri, databasdesign och det finns många andra. Vi kommer att utveckla många av dem senare i den här artikeln.
På kodnivån implementeras ofta övergripande problem med hjälp av tekniker som Aspect-Oriented Programming (AOP) , där dessa problem är modulariserade till separata komponenter som kan tillämpas genom hela applikationen. Detta håller affärslogiken isolerad från dessa problem, vilket gör koden mer läsbar och underhållbar.
Det finns många möjliga sätt att klassificera aspekter genom att segmentera dem med olika egenskaper som omfattning, storlek, funktionalitet, betydelse, mål och andra, men i den här artikeln kommer jag att använda en enkel omfattningsklassificering. Med detta menar jag var denna specifika aspekt riktas oavsett om det är hela organisationen, ett visst system eller en specifik del av det systemet.
Så jag ska dela upp aspekter i makro och mikro .
Med makroaspekt menar jag främst överväganden vi följer för hela systemet som vald systemarkitektur och dess design (monolitisk, mikrotjänster, tjänsteorienterad arkitektur), teknologistack, organisationsstruktur etc. Makroaspekter är främst relaterade till strategiska och högnivåiga aspekter beslut.
Under tiden är mikroaspekten mycket närmare kodnivån och utvecklingen. Till exempel vilket ramverk som används för att interagera med databasen, projektstrukturen för mappar och klasser, eller till och med specifika objektdesignmönster.
Även om denna klassificering inte är idealisk, hjälper den till att strukturera en förståelse av möjliga problem och vikten och effekten av lösningar vi tillämpar på dem.
I den här artikeln kommer mitt primära fokus att ligga på makroaspekterna.
När jag precis började lära mig om mjukvaruarkitektur läste jag många intressanta artiklar om Conways lag och dess inverkan på organisationsstrukturen. Speciellt den här . Så den här lagen säger det
Varje organisation som designar ett system (brett definierat) kommer att producera en design vars struktur är en kopia av organisationens kommunikationsstruktur.
Jag har alltid trott att detta koncept verkligen är väldigt universellt och representerar den gyllene regeln.
Sedan började jag lära mig Eric Evans's Domain-Driven Design (DDD) tillvägagångssätt för modelleringssystem. Eric Evans betonar vikten av Bounded Context-identifiering. Detta koncept innebär att dela upp en komplex domänmodell i mindre, mer hanterbara sektioner, var och en med sin egen begränsade kunskapsuppsättning. Detta tillvägagångssätt hjälper till med effektiv teamkommunikation, eftersom det minskar behovet av omfattande kunskap om hela domänen och minimerar kontextbyten, vilket gör konversationerna mer effektiva. Kontextbyte är det värsta och mest resurskrävande någonsin. Även datorer kämpar med det. Även om det är osannolikt att man uppnår en fullständig frånvaro av kontextbyte, tror jag att det är det vi bör sträva efter.
För att återgå till Conways lag har jag hittat flera problem med den.
Det första problemet jag har stött på med Conways lag, som antyder att systemdesign speglar organisationsstruktur, är potentialen för att forma komplexa och omfattande Bounded Contexts. Denna komplexitet uppstår när organisationsstrukturen inte är anpassad till domängränser, vilket leder till Bounded Contexts som är starkt beroende av varandra och laddade med information. Det leder till frekvent kontextbyte för utvecklingsteamet.
En annan fråga är att organisatorisk terminologi läcker till kodnivå. När organisationsstrukturer förändras, kräver det kodbasmodifieringar, vilket förbrukar värdefulla resurser.
Följande Inverse Conway Maneuver hjälper alltså till att bygga systemet och organisationen som uppmuntrar önskad mjukvaruarkitektur. Det är dock anmärkningsvärt att säga att detta tillvägagångssätt inte kommer att fungera särskilt bra i redan bildade arkitekturer och strukturer eftersom förändringar i detta skede är förlängda, men det är exceptionellt presterande i startups eftersom de är snabba att införa ändringar.
Detta mönster eller "anti-mönster" driver att bygga ett system utan någon arkitektur. Det finns inga regler, inga gränser och ingen strategi för hur man ska kontrollera den oundvikliga växande komplexiteten. Komplexitet är den mest formidabla fienden på resan för att bygga mjukvarusystem.
För att undvika att konstruera en sådan typ av system måste vi följa specifika regler och begränsningar.
Det finns otaliga definitioner för mjukvaruarkitektur. Jag gillar många av dem eftersom de täcker olika aspekter av det. Men för att kunna resonera kring arkitektur behöver vi naturligtvis forma några av dem i våra sinnen. Och det är anmärkningsvärt att säga att denna definition kan utvecklas. Så, åtminstone för nu, har jag följande beskrivning för mig själv.
Software Architecture handlar om beslut och val du gör varje dag som påverkar det byggda systemet.
För att fatta beslut du måste ha i din "väska" principer och mönster för att lösa uppkommande problem, är det också viktigt att konstatera att förståelse av kraven är nyckeln till att bygga vad ett företag behöver. Men ibland är kraven inte transparenta eller till och med inte definierade, i det här fallet är det bättre att vänta för att få mer förtydligande eller lita på din erfarenhet och lita på din intuition. Men hur som helst, du kan inte fatta beslut ordentligt om du inte har principer och mönster att lita på. Det är där jag kommer till definitionen av Software Architecture Style.
Software Architecture Style är en uppsättning principer och mönster som anger hur man bygger programvara.
Det finns många olika arkitektoniska stilar fokuserade på olika sidor av den planerade arkitekturen, och att tillämpa flera av dem samtidigt är en normal situation.
Till exempel, som:
Monolitisk arkitektur
Domändriven design
Komponentbaserat
Mikrotjänster
Rör och filter
Händelsestyrd
Mikrokärna
Serviceinriktad
och så vidare…
Naturligtvis har de sina fördelar och nackdelar, men det viktigaste jag har lärt mig är att arkitekturen utvecklas gradvis och beror på faktiska problem. Att börja med den monolitiska arkitekturen är ett utmärkt val för att minska operativa komplexiteter, mycket troligt kommer denna arkitektur att passa dina behov även efter att ha nått produkt-marknadsanpassning (PMI) stadiet för att bygga produkten. I stor skala kan du överväga att gå mot ett händelsedrivet tillvägagångssätt och mikrotjänster för att uppnå oberoende distribution, heterogen teknisk stackmiljö och mindre kopplad arkitektur (och mindre transparent under tiden på grund av karaktären av händelsedrivna och pub-sub-metoder om dessa antas). Enkelhet och effektivitet ligger nära och har stor inverkan på varandra. Vanligtvis påverkar komplicerade arkitekturer utvecklingshastigheten för nya funktioner, stöder och underhåller befintliga och utmanar systemets naturliga utveckling.
Men komplexa system kräver ofta komplex och omfattande arkitektur, vilket är oundvikligt.
Rättvist, detta är ett väldigt brett ämne, och det finns många bra idéer om hur man strukturerar och bygger system för naturlig evolution. Baserat på mina erfarenheter har jag utarbetat följande tillvägagångssätt:
Det är också viktigt att förstå siffrorna och mätvärdena som DAU (Daily Active Users), MAU (Monthly Active Users), RPC (Request Per Second) och TPC (Transaction Per Second) eftersom det kan hjälpa dig att göra val eftersom arkitektur för 100 aktiva användare och 100 miljoner aktiva användare är olika.
Som en sista anmärkning skulle jag säga att arkitektur har en betydande inverkan på produktens framgång. Dåligt utformad arkitektur för produkterna krävs vid skalning, vilket med stor sannolikhet leder till misslyckanden eftersom kunderna inte väntar medan du skalar systemet, de kommer att välja en konkurrent, så vi måste ligga före potentiell skalning. Även om jag erkänner att det ibland inte kunde vara ett slankt tillvägagångssätt, är tanken att ha ett skalbart men inte redan skalat system. Å andra sidan, att ha ett mycket komplicerat och redan skalat system utan kunder eller planer på att skaffa många av dem kommer att kosta dig pengar på ditt företag för ingenting.
Att välja en teknikstack är också ett beslut på makronivå eftersom det påverkar anställning, systemets naturliga utvecklingsperspektiv, skalbarhet och systemprestanda.
Det här är listan över grundläggande överväganden för att välja en teknikstack:
Hur kan det påverka affärstillväxten att ha flera teknikstackar?
Ur ett perspektiv kan införandet av ytterligare en stack skala din anställning, men å andra sidan medför det extra underhållskostnader eftersom du behöver stödja båda stackarna. Så, som jag sa tidigare, enligt min synvinkel borde bara extra behov vara ett argument för att införliva fler teknikstackar.
Men vad handlar om principen att välja det bästa verktyget för ett specifikt problem?
Ibland har du inget annat val än att ta med nya verktyg för att lösa ett specifikt problem baserat på samma överväganden som ovan, i sådana fall är det vettigt att välja den bästa lösningen.
Att skapa system utan hög koppling till en specifik teknik kan vara en utmaning. Ändå är det bra att sträva efter ett tillstånd där systemet inte är tätt kopplat till tekniken och det inte kommer att dö om imorgon ett specifikt ramverk eller verktyg blir sårbart eller till och med utfasas.
En annan viktig faktor är relaterad till öppen källkod och proprietära mjukvaruberoenden. Proprietär programvara ger dig mindre flexibilitet och möjlighet att anpassas. Ändå är den farligaste faktorn leverantörslåsning, där du blir beroende av en leverantörs produkter, priser, villkor och färdplan. Detta kan vara riskabelt om leverantören ändrar riktning, höjer priserna eller slutar tillverka produkten. Programvara med öppen källkod minskar denna risk, eftersom en enda enhet inte kontrollerar den. Att eliminera en enda punkt av misslyckande på alla nivåer är nyckeln till att bygga tillförlitliga system för tillväxt.
En enda punkt av fel (SPOF) hänvisar till vilken del av ett system som helst som, om det misslyckas, kommer att få hela systemet att sluta fungera. Att eliminera SPOF på alla nivåer är avgörande för alla system som kräver hög tillgänglighet. Allt, inklusive kunskap, personal, systemkomponenter, molnleverantörer och internetkablar, kan misslyckas.
Det finns flera grundläggande tekniker vi kan använda för att eliminera enstaka felpunkter:
I den här artikeln täckte vi flera viktiga makroaspekter och hur vi kan hantera deras komplexitet.
Tack för att du läser! Vi ses nästa gång!