Back to "Spela med kod: En effektiv agil strategi"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

Agile Best Practices Craftsmanship Software Development

Spela med kod: En effektiv agil strategi

Sunday, 23 November 2025

Varför behandla din gren som en sandlåda – och spela som legitimt arbete – producerar bättre programvara med mindre stress.

Varm take: De flesta utvecklare försöker vara perfekta i varje utvecklingsstadium, och det dödar både deras kreativitet och deras produktivitet. Här är ett bättre sätt.

Inledning

Jag har byggt programvara professionellt för... Tja, låt oss bara säga att jag minns när "Agile" var en ny idé och inte ett företags vråord vapen av projektledare för att motivera fler standups.

Under årens lopp har jag märkt något: den bästa koden jag någonsin skrivit kom från projekt där jag kände behörighet att spela. – Den värsta koden kom från projekt där varje tangenttryckning kändes som om den granskades, där jag försökte skriva "produktionsklar" kod från första minuten.

Det här är inte en tillfällighet. Kreativitet och tryck blandas inte bra.

Så jag har utvecklat ett tillvägagångssätt som skiljer den röriga, kreativa utforskningen från den polerade, produktionsklara leveransen. Jag kallar det "Få det att fungera, gör det vackert, lås ner det" - men egentligen, det handlar om att ge dig själv tillåtelse att experimentera utan tyngden av perfektion hängande över dig.

De tre faserna

Låt mig vara tydlig: detta handlar inte om att vara slarvig eller undvika disciplin. tillämpa rätt disciplin vid rätt tidpunkt.

graph LR
    subgraph "Phase 1: Make It Work"
        A[New Requirement] --> B[Explore & Experiment]
        B --> C{Does It Work?}
        C -->|No| D[Try Different Approach]
        D --> B
        C -->|Yes| E[Basic Solution]
    end

    subgraph "Phase 2: Make It Pretty"
        E --> F[Refactor & Clean]
        F --> G[Apply SOLID Pragmatically]
        G --> H[Get Stakeholder Feedback]
        H --> I[Polished Solution]
    end

    subgraph "Phase 3: Lock It Down"
        I --> J[Add Tests]
        J --> K[Security Review]
        K --> L[Add Monitoring]
        L --> M[Production Ready]
    end

    style A stroke:#f59e0b,stroke-width:3px
    style E stroke:#0ea5e9,stroke-width:3px
    style I stroke:#8b5cf6,stroke-width:3px
    style M stroke:#10b981,stroke-width:4px

Fas 1: Få det att fungera

Mantrat: Spela först, bekräfta dina antaganden, få igång något.

Detta är den fas där din gren är en sandlåda. Messy kod är bra. Döda ändar är bra. Från och med tre gånger är *Bra.*Du bygger ingen katedral här, du ritar på en servett.

Vad du försöker lista ut:

  • Uppför sig detta API faktiskt hur dokumenten hävdar? (Spoiler: det sällan gör)
  • Kan jag ens lösa detta problem med de verktyg jag har?
  • Vilka är de faktiska kraven, inte de som står skrivna i biljetten?
  • Är det två timmars problem eller två veckors problem?

Den kritiska insikten: Tills du höjer en PR, din gren är din. Det är ditt experimentella laboratorium. Ingen behöver se dina falska starter, din kommenterade felsökningskod, din "TODO: detta är fruktansvärt, fixa senare" kommentarer. Men checka in OFTEN – varje gång du har något som fungerar, begå och push. Haka in i din CI pipeline; en bra pipeline kommer att ge dig mer information (integration tester, bryta förändringar någon annanstans, etc.). Det är roligt att checka in fula, knappt sydda ihop franken-kod. Det är POINT. Även som en tre-decade veteran, gör jag fortfarande detta. Det befriar mitt sinne.

Sidofördelar: Frekvent engagemang är ett hjärtslag. I fjärr-/async-team, ett stadigt spår av "ful men fortskridande" engagerar alla som arbetar rör sig – utan att du måste utföra produktivitet i Slack.

Denna psykologiska frihet är nödvändig. När du vet att du kan kasta bort allt och börja om på nytt, du gör djärvare beslut. Du försöker att konstigt tillvägagångssätt som förmodligen inte kommer att fungera. Ibland fungerar det lysande. Ibland måste du läsa en artikel, titta på en YouTube-video, tänka ett tag. Kom ihåg: ditt jobb är att leverera bra programvara och bra beslut, inte för att skriva snabbt. Bra chefer förstår att du är INTE EN TYPIST.

// Phase 1 code looks like this - and THAT'S OKAY
public async Task<Result> ProcessThing(Request req)
{
    // TODO: what if this is null?
    var data = await _api.GetSomething(req.Id);

    // This probably isn't right but let's see what happens
    var transformed = data.Items
        .Where(x => x.Status != "deleted") // Is this the right filter?
        .Select(x => new Thing { Name = x.Name }); // Missing loads of fields

    // HACK: hardcoded for now
    return new Result { Items = transformed.ToList(), Total = 42 };
}

Är detta produktionskod? Gud nej. Är det användbart? Absolut. Det talar om för dig om din strategi är ens genomförbar innan du investerar timmar polera något som inte kommer att fungera.

En anmärkning om återkoppling: Du kan få feedback på någon av följande egenskaper: punkt i fas 1 – nyckeln är att välja som ger det. Målet är att bygga den bästa funktionen, inte att följa en stel process.

Bygga ett API som ett annat team kommer att konsumera? Få dem involverade tidigt. En snabb "gör denna form vettigt?" konversation kan spara dagar av omarbete. Bygga något användaransikte? Kanske vänta med att visa affärsintressenten tills det är mindre tufft-en del människor får hänga upp sig på hur något utseende snarare än om det bygg- och anläggningsarbeten. Det är bra; de ger feedback i fas 2.

Använd ditt omdöme. Ibland behöver du feedback till förtydliga, inte att godkänna - spec redan gjorde det. "Spec säger "hantera fel graciöst" - betyder det försök tre gånger, eller misslyckas snabbt och meddela?" Det är en fas 1 konversation.

Om en intressent input är kritisk men de skulle kämpa med grov kod, bygga en trivial demo. En hårdkodad happy-path som visar konceptet kan låsa upp värdefull feedback utan distraktion av saknade kant fall.

Målet är det bästa draget, inte processens renhet.

Fas 2: Gör det vackert

Mantrat: Nu när du vet vad du bygger, gör det Bra..

Du har bekräftat att tillvägagångssättet fungerar, du förstår problemets form och du har nog upptäckt ett dussinkantiga fall som den ursprungliga biljetten inte nämnde.

Nu städar du upp:

// Phase 2: Same logic, but actually maintainable
public async Task<ProcessingResult> ProcessItemsAsync(
    ProcessingRequest request,
    CancellationToken cancellationToken = default)
{
    ArgumentNullException.ThrowIfNull(request);

    var items = await _itemRepository.GetActiveItemsAsync(
        request.AccountId,
        cancellationToken);

    var processedItems = items
        .Where(item => item.Status != ItemStatus.Deleted)
        .Select(item => _mapper.ToProcessedItem(item))
        .ToList();

    return new ProcessingResult
    {
        Items = processedItems,
        TotalCount = processedItems.Count,
        ProcessedAt = _timeProvider.UtcNow
    };
}

Det är här du:

  • Tillämpa SOLID-principer pragmatiskt (känn dem, men dyrka dem inte)
  • Ge saker och ting riktiga namn
  • Lägg till typtips och XML- dokumentation
  • Tänk på API-ytan från uppringarens perspektiv
  • Hantera kanterna du upptäckte i fas 1

Detta är den bästa tiden för icke-tekniska intressenters feedback. Funktionen är nu synlig och användbar, men du har ännu inte investerat timmar skriva tester för det. Om de säger "faktiskt, vi ville att det skulle göra X istället," kan du svänga utan hjärtesorgen av att ta bort en omfattande testsvit.

Fas 3: Lås ner den

Mantrat: Hårda den, testa den, gör den motståndskraftig.

Nu – och först nu – skriver du dina tester. Lägg till säkerhetskontroller. Implementera korrekt felhantering för fall med produktionskanter. Lägg till övervakning och skyddsräcken.

Varför vänta tills nu? Du vet äntligen vad du testar..

Tester skrivna i Fas 1 skulle ha varit fel – du förstod inte problemet ännu. Tester skrivna i Fas 2 skulle ha churn – du var fortfarande förfina API. Tester skrivna i Fas 3 är korrekt, eftersom genomförandet är stabilt.

[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(100)]
public async Task ProcessItemsAsync_WithValidRequest_ReturnsCorrectCount(
    int itemCount)
{
    // Arrange
    var items = _fixture.CreateMany<Item>(itemCount).ToList();
    _mockRepository
        .Setup(r => r.GetActiveItemsAsync(It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
        .ReturnsAsync(items);

    // Act
    var result = await _sut.ProcessItemsAsync(
        new ProcessingRequest { AccountId = Guid.NewGuid() });

    // Assert
    result.TotalCount.Should().Be(itemCount);
    result.Items.Should().HaveCount(itemCount);
}

[Fact]
public async Task ProcessItemsAsync_WithNullRequest_ThrowsArgumentNullException()
{
    // Act & Assert
    await _sut.Invoking(s => s.ProcessItemsAsync(null!))
        .Should().ThrowAsync<ArgumentNullException>();
}

[Fact]
public async Task ProcessItemsAsync_ExcludesDeletedItems()
{
    // Arrange
    var items = new[]
    {
        new Item { Status = ItemStatus.Active },
        new Item { Status = ItemStatus.Deleted },
        new Item { Status = ItemStatus.Active }
    };
    _mockRepository
        .Setup(r => r.GetActiveItemsAsync(It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
        .ReturnsAsync(items);

    // Act
    var result = await _sut.ProcessItemsAsync(
        new ProcessingRequest { AccountId = Guid.NewGuid() });

    // Assert
    result.Items.Should().HaveCount(2);
}

Denna fas omfattar även följande:

  • Säkerhetsgranskning (autentisering, godkännande, validering av indata)
  • Konkursöverväganden (vad händer under belastning?)
  • Fellägesanalys (tänk om databasen är långsam? Tänk om API-tiden är ute?)
  • Övervakning (hur vet vi om detta bryter i produktionen?)

Återkoppling Koreografi

Missförstå det här och du drunknar i friktion.

graph TB
    subgraph "Phase 1: Technical Voices"
        P1[Make It Work] --> T1[Senior Dev Review]
        T1 --> T2["Does the approach<br/>make sense?"]
        T2 --> T3["Any obvious<br/>architectural issues?"]
    end

    subgraph "Phase 2: Non-Technical Voices"
        P2[Make It Pretty] --> N1[Product Owner Demo]
        N1 --> N2["Does it meet<br/>the requirement?"]
        N2 --> N3["Is the UX<br/>intuitive?"]
    end

    subgraph "Phase 3: Ops/Security Voices"
        P3[Lock It Down] --> O1[Security Review]
        O1 --> O2[Operations Review]
        O2 --> O3["Will it hold up<br/>in production?"]
    end

    T3 --> P2
    N3 --> P3

    style T1 stroke:#3b82f6,stroke-width:2px
    style N1 stroke:#8b5cf6,stroke-width:2px
    style O1 stroke:#ef4444,stroke-width:2px

Steg 1: Tekniska röster bara – senior devs, arkitekter. De kan se förbi röran till formen av lösningen. Icke-tekniska intressenter kommer att panik på grov kod och fråga om knapp färger när du fortfarande räkna ut datamodellen.

Steg 2: Icke-tekniska röster välkomna. Funktionen är användbar, knappar gör saker. Få produktägare och designers involverade nu – förändringar är fortfarande billiga, du har inte skrivit tester ännu.

Steg 3: Ops och säkerhetsröster. "Tänk om detta får 10x trafik?" "Tänk om någon passerar skadlig ingång?" Detta gäller bara när funktionen faktiskt fungerar.

Filialer som sandlådor

Här är det som förändrade mitt utvecklingsliv: tills du höjer en PR, din gren är helt privat.

Det låter kanske självklart, men jag ser utvecklare som behandlar varje åtagande som det går på deras permanenta skiva. De är rädda för att experimentera. Rädd för att skriva ful kod. Rädd för att bryta saker.

Jag vill att du tänker på din funktionsgren som en sandlåda, en lekplats, ett laboratorium där explosioner förväntas och ingen skadas.

graph TD
    A[Feature Branch Created] --> B[Experiment Freely]
    B --> C{Did it work?}
    C -->|No| D[Try Something Else]
    D --> B
    C -->|Yes| E[Clean Up the Mess]
    E --> F[Interactive Rebase]
    F --> G[Squash to Clean Commits]
    G --> H[Raise PR]
    H --> I[Public Code Review]

    style B stroke:#f59e0b,stroke-width:3px
    style D stroke:#f59e0b,stroke-width:2px
    style H stroke:#10b981,stroke-width:3px

    subgraph "Private - Go Mental"
        B
        C
        D
        E
    end

    subgraph "Public - Be Professional"
        H
        I
    end

I praktiken innebär detta följande:

  • Komma ofta, även om koden inte kompilerar
  • Skriv FIXME och TODO kommentarer överallt
  • Lämna felsökningskoden på plats medan du utforskar
  • Har flera "försök detta tillvägagångssätt" åtaganden
  • Oroa dig inte för att begå meddelanden (du squash senare)

Sedan, innan du höjer en PR:

  1. Rensa upp koden (fas 2)
  2. Lägg till tester (fas 3)
  3. Interactive rebase för att mosa all den röriga historien
  4. Skriv ett riktigt åtagandemeddelande

PR-recensenterna ser ren, professionell kod med en tydlig berättelse. De ser inte de sex falska starter, 3am "varför inte detta blodiga arbete" begår, eller "oavgjort ångra" historia.

Sandlådan förblir privat. Det polerade arbetet blir offentligt.

Varför detta minskar stressen

Traditionell "var professionell hela tiden" utveckling är förkrossande. Varje linje känns permanent. Varje beslut känns följdriktigt. Detta tillvägagångssätt tar bort trycket genom att hålla inne kaoset: lek är legitimt arbete I Fas 1, feedback kommer när pivoting är billigt i Fas 2, och tester skrivs en gång korrekt i Fas 3 eftersom du äntligen vet vad du testar.

"Spela är legitimt arbete."

TDD fungerar briljant när domänen är väl förstådd eller du sätter fast en känd bugg. Men när problemet fortfarande är suddigt, skriva tester först ofta innebär att testa fel sak tre gånger i rad. Detta tillvägagångssätt sidosteg som: utforska först, testa när stabil.

Pragmatic SOLID (och DRY s smutsiga hemlighet)

Så vad gör detta trefastänkande med dina designprinciper? Kort sagt: det dödar dogm. Så här förändrar det mitt tänkande om SOLID, DRY och gränssnitt i C#.

Jag nämnde att tillämpa SOLID principer "pragmatically" i fas 2. Låt mig vara specifik om vad jag menar.

SOLID är en bra uppsättning principer. Jag lär dem. Jag använder dem. Men jag har sett team försvinna ned abstraktion kanin hål i namnet Single Responsibility eller Open/Closed, skapa system så flexibla de är obegripliga.

Här är min heuristiska:

Applicera SOLID när:

  • Du har bevis för att du behöver flexibiliteten.
  • Abstractionen gör koden tydligare
  • Du bygger något som andra kommer att använda

Använd inte SOLID när:

  • Du spekulerar om framtida krav
  • Abstractionen ökar komplexiteten utan klarhet
  • Du bygger en intern kod som bara du upprätthåller.

Tre liknande rader av kod är bättre än en för tidig abstraktion. Du kan alltid extrahera senare när du ser mönstret tydligt. Du kan inte lätt ångra en abstraktion som är bakad i din arkitektur.

// Over-engineered SOLID worship
public interface IThingProcessor { }
public interface IThingProcessorFactory { }
public class ThingProcessorFactory : IThingProcessorFactory { }
public class ThingProcessor : IThingProcessor { }
public class ThingProcessorDecorator : IThingProcessor { }
public class ThingProcessorValidationDecorator : IThingProcessor { }

// What you probably actually need
public class ThingProcessor
{
    public async Task<Result> ProcessAsync(Thing thing)
    {
        // Just do the thing
    }
}

Om du behöver flexibiliteten senare, refaktoring är billigt. Over-engineering i förskott är dyrt eftersom du behåller abstraktion lager som inte tjänar sin hållbarhet.

TRY-fällan

Och medan vi dödar heliga kor, låt oss prata om DRÖJS (Repetera inte dig själv). Det är kanske den mest dogmatiskt tillämpade principen i vår bransch, och när den tillämpas utan tanke, orsakar den mer skada än nytta.

Problemet är följande: Inte alla dubblering är samma typ av dubblering.

När två kodbitar ser likadana ut men tjänar olika syften, extraherar dem till en delad abstraktion par saker som bör utvecklas självständigt. Nu när en användning fall behöver ändras, du är antingen:

  1. Lägga till parametrar och villkor för att hantera båda fallen (att göra abstraktionen värre)
  2. Bryt det andra användningsfallet
  3. Kopierar den delade koden tillbaka ut och redigerar den (antagande av DRY var fel här)
// "DRY" solution - looks clever, causes pain
public async Task<Result> ProcessEntity<T>(
    T entity,
    bool validateFirst = true,
    bool sendNotification = false,
    Func<T, bool>? customFilter = null,
    Action<T>? preProcess = null,
    Action<T>? postProcess = null) where T : IEntity
{
    // 50 lines of conditional spaghetti trying to handle
    // "processing" for Users, Orders, and Products
    // because they all had 3 similar lines once
}

// What you probably actually need
public async Task<Result> ProcessUser(User user) { /* 15 clear lines */ }
public async Task<Result> ProcessOrder(Order order) { /* 15 clear lines */ }
public async Task<Result> ProcessProduct(Product product) { /* 15 clear lines */ }

Ja, det finns lite duplicering i den andra metoden, men varje metod är:

  • Lätt att förstå isolerat
  • Lätt att ändra utan biverkningar
  • Lätt att ta bort när den enhetstypen försvinner
  • Lätt att testa med tydliga ingångar och utgångar

DRY-versionen är en mardröm att underhålla eftersom den försöker vara allt för alla som ringer. Varje förändring kräver förståelse för alla användningsfall. Varje felrättning riskerar att bryta något annat.

Min regel: Tolerera dubblering tills du har sett samma tre gånger och du är säker på att det representerar samma Koncept som kommer att utvecklas tillsammans. Tills dess, lite kopieringssmak är bra. Det är inte ett moraliskt misslyckande; det är lämplig försiktighet.

Duplicering är mycket billigare än fel abstraktion. Du kan alltid deduplicera senare när mönstret är klart. Du kan inte lätt ångra en dålig abstraktion som är vävd genom din kodbas.

Gränssnittsproblemet i C#

Här är en annan helig ko som behöver slaktas: "Varje klass behöver ett gränssnitt" mönster.

Förr i tiden av .NET beroende injektion, någon beslutat att för att göra kod testable, du behövde injicera gränssnitt överallt. Logiken var: du kan inte håna en betong klass, så varje tjänst behöver IService och ServiceImpl. Plötsligt var varje C#-kodbas täckt med ett enda implementation gränssnitt som fanns enbart för testning.

// The interface tax - early 2010s style
public interface IUserService { }
public interface IOrderService { }
public interface IEmailService { }
public interface INotificationService { }
public interface IPaymentProcessor { }
public interface IInventoryManager { }

// Each with exactly ONE implementation
public class UserService : IUserService { }
public class OrderService : IOrderService { }
// ... you get the idea

Detta var last kult programmering. Vi betalade en komplicerad skatt för teoretisk Testbarhet. teoretisk framtida flexibilitet som sällan förverkligats.

Du behöver inte den här längre.

Moderna hånfulla ramar som N Substitute Ordförande och Moq Ordförande ännu viktigare är att ASP.NET Cores DI-behållare fungerar perfekt med betongtyper:

// Modern approach - just register the concrete type
services.AddScoped<UserService>();
services.AddScoped<OrderService>();
services.AddScoped<EmailService>();

// In your controller or service
public class OrderController(OrderService orderService, UserService userService)
{
    // Primary constructor injection - clean and simple
}

Inga gränssnitt. IOrderService. Bara den service du behöver, injiceras direkt.

"Men hur är det med tester?" Jag hör dig gråta.

För enhetstester har du följande alternativ:

  1. Gör nyckelmetoder virtual och använda en hånande ram
  2. Använd den verkliga tjänsten med en testdatabas (integrationstester är ofta mer värdefulla ändå)
  3. Lägg till ett gränssnitt när du faktiskt behöver det för att testa

Den tredje punkten är av avgörande betydelse: refaktoring verktyg är utomordentligt bra på att extrahera gränssnitt.

I Rider eller Visual Studio, är det bokstavligen Ctrl+. → "Extrahera gränssnitt" och du är klar. Varje metod blir extraherad, klassen blir uppdaterad för att genomföra det, och du kan hitta / ersätta alla användningsområden om det behövs. Det tar sekunder.

// Phase 1 & 2: Just write the class
public class OrderService
{
    public async Task<Order> CreateOrderAsync(CreateOrderRequest request) { ... }
    public async Task<Order?> GetOrderAsync(int orderId) { ... }
    public async Task CancelOrderAsync(int orderId) { ... }
}

// Phase 3: Need to mock it for testing? Extract interface in 2 seconds
public interface IOrderService
{
    Task<Order> CreateOrderAsync(CreateOrderRequest request);
    Task<Order?> GetOrderAsync(int orderId);
    Task CancelOrderAsync(int orderId);
}

public class OrderService : IOrderService { ... }

Mitt arbetsflöde nu: gränssnitt finns i fas 3, inte fas 1.

Under "få det att fungera" och "göra det vackert", skriver jag bara klasser. Ingen för tidig abstraktion. Ingen gränssnittsskatt på varje typ. Koden är enklare, lättare att navigera (inget hopp mellan IFoo och Foo), och snabbare att skriva.

När jag slog "låsa ner" och måste skriva prov, och Jag bestämmer vilka tjänster som faktiskt behöver hånas. Vanligtvis är det färre än du skulle tro – ofta bara externa integrationer som HTTP-klienter, databaser och meddelandeköer.

För interna affärslogik tjänster? Hälften av tiden jag bara testa dem direkt med verkliga beroenden. Testerna är mer värdefulla ändå eftersom de testar det faktiska beteendet, inte ett hån mot vad jag tänk beteendet bör vara.

// Services I typically DO extract interfaces for (external boundaries)
public interface IPaymentGateway { }      // Third-party API
public interface IEmailSender { }         // External service
public interface IBlobStorage { }         // Cloud storage

// Services I typically DON'T need interfaces for (internal logic)
public class OrderValidator { }           // Pure logic, test directly
public class PriceCalculator { }          // Pure logic, test directly
public class OrderService { }             // Test with real repo + in-memory DB

Poängen är: Sluta skriva gränssnitt framåt "just in case". Skriv betongklasser. Om du behöver ett gränssnitt för att testa eller äkta polymorfism senare, extrahera en tar bokstavligen sekunder med moderna verktyg.

Din kodbas kommer att vara enklare, mer navigatorisk, och du kommer inte att ha underhållsbördan av att hålla gränssnitt i synk med implementationer utan nytta.

Den agila förbindelsen

Ironiskt nog är detta tillvägagångssätt mer i linje med original Agile manifest än de flesta "Agile" processer jag har stött på. Arbeta programvara snabbt (fas 1). Svara på förändring (Phases 1-2). Kundsamarbete när funktionen är påvisbar (fas 2). Inga sprintpunkter, ingen hastighetsspårning, inga blodig burndown diagram.

Moderna "Agile" har fångats av processentusiaster som har lagt till så många ceremonier det finns ingen tid kvar för utforskning. Detta tillvägagångssätt ger tillbaka spelet – inte som en njutning, utan som en legitim fas av kreativt arbete.

När du inte ska använda den här metoden

Jag ska vara ärlig: detta är inte alltid rätt tillvägagångssätt.

Felrättningar: När du fixar en känd bugg, TDD stil är mer vettigt. Skriv ett test som reproducerar buggen, fixa det, gjort.

Välförståeliga problem: Om du implementerar en standardalgoritm eller ett mönster du har använt hundra gånger, behöver du inte en utforskande fas.

Täta tidsfrister med kända krav: Om du verkligen vet exakt vad du bygger och när det behöver skeppas, kan du hoppa över fas 1 prospektering.

Högreglerade miljöer: Om varje åtagande behöver skrivas av, är sandlåda svårare. Även om du fortfarande kan göra utforskningen lokalt innan du trycker.

Men för de flesta funktionsutveckling – där kraven är lite suddiga, det tekniska tillvägagångssättet är inte uppenbart, och du behöver utrymme att tänka – detta tillvägagångssätt fungerar lysande.

En anteckning för juniorutvecklare

Om du är tidig i din karriär, kan du känna tryck för att visa "perfekt" kod hela tiden. Du behöver inte. Använd denna trefas strategi-bara vara tydlig om vilken fas du är i, och alltid avsluta jobbet hela vägen till fas 3. Ingen kommer att klandra dig för rörig prospekteringskod om det leder till polerad, testad, produktionsklar kod i slutet.

Nedre raden

Få det att fungera, gör det vackert, lås ner det.

Börja enkelt. Design med förutseende men inte spekulation. Iterera snabbt. Lägg bara till komplexitet när det lönar sig.

"Duplikation är mycket billigare än fel abstraktion."

Utforskningsfasen är inte en skyldig hemlighet – det är en definierad del av processen. Din gren är din sandlåda tills du höjer en PR. Teknisk feedback kommer tidigt, icke-teknisk feedback kommer mitt, ops och säkerhetsfeedback kommer sent.

Detta håller kreativiteten vid liv, minskar stressen och skapar system som skalas elegant – eftersom du förstod problemet innan du engagerade dig i lösningen.

Sluta försöka vara perfekt från första minuten. Ge dig själv tillåtelse att spela.


Relaterad läsning

Om detta genljuder, kan du också njuta av dessa relaterade inlägg:

logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.