Πώς φτιάχνω το λογισμικό: κάντε το να λειτουργήσει, κάντε το όμορφο, κλειδώστε το κάτω (ελληνικά (Greek))

Πώς φτιάχνω το λογισμικό: κάντε το να λειτουργήσει, κάντε το όμορφο, κλειδώστε το κάτω

Wednesday, 19 November 2025

//

23 minute read

Γιατί γράφω τεστ τελευταία, και γιατί δεν είναι αυτό που νομίζεις ότι σημαίνει

**Διαφωνική λήψη:**Test-Driven Development είναι μια λαμπρή πρακτική που λύνει το λάθος πρόβλημα για την πιο δημιουργική εργασία.

Εδώ είναι τι λειτουργεί καλύτερα.

Οι τρεις φάσεις του λογισμικού οικοδόμησης (Αυτό λειτουργεί πραγματικά)

Έτσι φτιάχνω λογισμικό.

Είναι απλό, είναι αποτελεσματικό, και κάνει το TDD να καθαρίζει ευγενικά τα φρύδια τους:

Κάνε το να δουλέψει.*Κάνε το όμορφο.*Κλείδωσέ το με εξετάσεις.

graph TB
    Start[New Feature Request] --> P1[Phase 1: Make It Work]

    P1 --> P1_Private[Private Exploration]
    P1_Private --> P1_Sketch["Sketch the solution<br/>Messy code OK<br/>No tests yet<br/>Focus on learning"]
    P1_Sketch --> P1_Run["Run it manually<br/>Try different inputs<br/>See what breaks<br/>Understand the problem"]
    P1_Run --> P1_Decision{Does it work<br/>basically?}
    P1_Decision -->|No| P1_Iterate[Try different approach]
    P1_Iterate --> P1_Sketch
    P1_Decision -->|Yes| P2

    P2[Phase 2: Make It Pretty] --> P2_Refine[Private Refinement]
    P2_Refine --> P2_Clean["Clean up the code<br/>Better names<br/>Type hints/annotations<br/>Clear structure"]
    P2_Clean --> P2_Align["Align with spec<br/>Cover all requirements<br/>Handle edge cases<br/>Polish API surface"]
    P2_Align --> P2_Optimise["Optimise<br/>Performance<br/>Readability<br/>Maintainability"]
    P2_Optimise --> P3

    P3[Phase 3: Lock It Down] --> P3_Share[Public Sharing]
    P3_Share --> P3_Tests["Write comprehensive tests<br/>Full coverage<br/>Edge cases<br/>Error conditions"]
    P3_Tests --> P3_CI["CI/CD Integration<br/>Automated testing<br/>Code review<br/>Documentation"]
    P3_CI --> P3_Deploy["Ready to Share<br/>Commit to main<br/>Deploy to prod<br/>Other devs can use it"]

    P3_Deploy --> Done[Well-Tested,<br/>Well-Designed Code]

    style P1 stroke:#ff6b6b,stroke-width:3px
    style P2 stroke:#4ecdc4,stroke-width:3px
    style P3 stroke:#95e1d3,stroke-width:3px
    style Done stroke:#38ada9,stroke-width:4px

Με αυτή τη σειρά.*Πάντα.*Όχι επειδή είμαι τεμπέλης.

Όχι επειδή δεν εκτιμώ τις δοκιμές.

Αλλά επειδή

Αυτό είναι το πώς δημιουργική εργασία πραγματικά συμβαίνει

Όταν εξερευνάς έναν προβληματικό χώρο δεν καταλαβαίνεις πλήρως ακόμα.

  • Όχι επειδή είμαι τεμπέλης.
  • Όχι επειδή δεν εκτιμώ τις δοκιμές.
  • Αλλά επειδή
  • Αυτό είναι το πώς δημιουργική εργασία πραγματικά συμβαίνει

Όταν εξερευνάς έναν προβληματικό χώρο δεν καταλαβαίνεις πλήρως ακόμα.

Άσε με να σου εξηγήσω.

Φάση 1: Κάντε το να λειτουργήσει (Το Private Sketch)

Αυτό είναι το βρώμικο κομμάτι.Το σημείο που δεν έχω ιδέα τι κάνω.

Προσπαθώ να καταλάβω:

Αυτό το API λειτουργεί πραγματικά με τον τρόπο που ισχυρίζονται οι γιατροί;

Μπορώ να λύσω αυτό το πρόβλημα με τα εργαλεία που έχω;

Τι σημαίνει το "σωστό" σε αυτό το πλαίσιο;*Αυτό είναι ένα πρόβλημα δύο ωρών ή ένα πρόβλημα δύο εβδομάδων;*Αυτό είναι εφεύρεση.

Αυτό είναι εξερεύνηση.

Αυτό είναι τζαζ.

# Ugly, exploratory code
def process_thing(data):
    # TODO: This is terrible, fix later
    result = []
    for item in data:
        # Not sure if this is the right approach...
        x = item.get('value')
        if x:  # Is this even the right condition?
            result.append(x * 2)  # Why multiply by 2? Testing something...
    return result

Και ξέρεις τι σκοτώνει την τζαζ;**Κάποιος που στέκεται πάνω από τον ώμο σου λέει "Γράψε πρώτα το τεστ."**Γιατί Δεν Υπάρχουν Δοκιμασίες Ακόμη;

Επειδή*Το σχήμα είναι ακόμα υγρό.*Φαντάσου ότι είσαι γλύπτης.

Έχεις ένα κομμάτι μάρμαρο και μια αόριστη ιδέα: "Θέλω να χαράξω ένα πουλί."

Το TDD λέει: " Πριν αγγίξετε αυτό το μάρμαρο, γράψτε ακριβώς πώς μοιάζει ένα πουλί.

Ορίστε το άνοιγμα των φτερών του.Καθορίστε τη γωνία κάθε φτερού.

Τώρα χαράξτε αυτές τις προδιαγραφές."*Δεν είναι έτσι τα πουλιά σκαλίζονται. (Ή το λογισμικό γράφεται, όπως αποδεικνύεται.)*Αληθινοί γλύπτες

Πρώτα θα κάνω πρόχειρη τη φόρμα.Σχεδίαζαν.

Φτιάχνουν μακέτες.*Κλέβουν μεγάλα κομμάτια πέτρας για να βρουν το γενικό σχήμα.*Μόνο αργότερα καθαρίζουν τις λεπτομέρειες.

Ο κώδικας είναι ο ίδιος.

Στη Φάση 1, γράφω:

Αυτός ο κώδικας είναι

Στρατιώτη.

Είναι μια συζήτηση με τον εαυτό μου.

Έτσι καταλαβαίνω τι σημαίνει "δουλεύω."

Το να γράφεις τεστ γι' αυτό είναι χειρότερο από άχρηστο.

ενεργά επιβλαβής.

Γιατί κάθε φορά που συνειδητοποιώ ότι "περίμενε, όλη αυτή η προσέγγιση είναι λάθος," θα πρέπει να ξαναγράψω και τα τεστ.

Αυτό δεν είναι ακαμψία.

Αυτό είναι γραφειοκρατία.

Η Ελευθερία να Αποτύχουν Γρήγορα

# Before (Phase 1) - Exploratory code
def process_thing(data):
    result = []
    for item in data:
        x = item.get('value')
        if x:
            result.append(x * 2)
    return result

# After (Phase 2) - Refined code
def extract_doubled_values(items: list[dict]) -> list[int]:
    """Extract 'value' field from items and double each one.

    Only includes items where 'value' is present and truthy.
    """
    return [
        item['value'] * 2
        for item in items
        if item.get('value')
    ]

Η 1η φάση είναι περίπου

// Before (Phase 1) - Exploratory code
public List<int> ProcessThing(List<Dictionary<string, object>> data)
{
    var result = new List<int>();
    foreach (var item in data)
    {
        if (item.ContainsKey("value"))
        {
            var x = item["value"];
            if (x != null)
            {
                result.Add(Convert.ToInt32(x) * 2);
            }
        }
    }
    return result;
}

// After (Phase 2) - Refined code
/// <summary>
/// Extracts 'value' field from items and doubles each one.
/// Only includes items where 'value' is present and non-null.
/// </summary>

public IEnumerable<int> ExtractDoubledValues(IEnumerable<IDictionary<string, object>> items)
{
    return items
        .Where(item => item.ContainsKey("value") && item["value"] != null)
        .Select(item => Convert.ToInt32(item["value"]) * 2);
}

Μαθαίνοντας ταχύτητα.

Πρέπει να δοκιμάσω πέντε διαφορετικές προσεγγίσεις σε μια ώρα.

Πρέπει να ανακαλύψω ότι η βιβλιοθήκη τρίτων που σκέφτηκα να χρησιμοποιήσω... δεν είναι τόσο διαφημισμένη.*Πρέπει να καταλάβω ότι το πρόβλημα που λύνω δεν είναι το πρόβλημα.θα πρέπειΝα λύνουμε.*Οι εξετάσεις επιβραδύνουν αυτό.

Όχι επειδή οι δοκιμές είναι αργές, αλλά επειδή

  • Πρόωρος προσδιορισμός είναι ο θάνατος.
  • Αν γράψω τεστ πριν καταλάβω το πρόβλημα, θα γράψω τεστ για το
  • Λάθος πράγμα.

Τότε έχω επενδύσει συναισθηματικά σε λάθος πράγματα.

Τότε υπερασπίζομαι το λάθος πράγμα στην αναθεώρηση κώδικα.

Καλύτερα να αποτύχουμε γρήγορα, κατ' ιδίαν, χωρίς δοκιμές για να διατηρήσουμε και κανένα εγωισμό για να προστατεύσουμε.Τι σημαίνει "εργασία" στη Φάση 1Σημαίνει: "Το έλεγξα.

Του έδωσα κάποιες πληροφορίες.

# Phase 1: Works, but awkward to use
process_thing(data)

# Phase 2: Clear, flexible, composable
extract_doubled_values(
    items,
    scale_factor=2.0,
    include_zeros=False
)

Παρήγαγε εξόδους που φαίνονται λογικές.

// Phase 1: Works, but awkward to use
ProcessThing(data);

// Phase 2: Clear, flexible, composable
ExtractDoubledValues(
    items,
    scaleFactor: 2.0,
    includeZeros: false
);

// Or even better with a fluent API
items.ExtractValues()
     .Scale(by: 2.0)
     .ExcludingZeros()
     .ToList();

Είμαι 60% σίγουρος ότι καταλαβαίνω το πρόβλημα τώρα."

Αυτό είναι.**Δεν υπάρχουν ακραίες περιπτώσεις.**Κανένας χειρισμός λάθους.

graph LR
    subgraph "Phase 2 Refinement Process"
        A[Rough Code] --> B[Clean Structure]
        B --> C[Add Types]
        C --> D[Polish API]
        D --> E[Static Analysis]
        E --> F{Quality Gates Pass?}
        F -->|No| G[Fix Issues]
        G --> B
        F -->|Yes| H[Ready for Phase 3]
    end

    style A stroke:#ff6b6b,stroke-width:3px
    style H stroke:#95e1d3,stroke-width:3px

Χωρίς κομψότητα.

*Απλά μια καρφίτσα.*Μια απόδειξη της έννοιας.

Ένα σκίτσο.Φάση 2: Κάντε το όμορφο (Ο Αποκλεισμός)

Εντάξει, τώρα καταλαβαίνω το πρόβλημα.Έχω κάτι που λειτουργεί, τουλάχιστον για το ευτυχισμένο μονοπάτι.

Τώρα μπορώ να αρχίσω να νοιάζομαι για την ποιότητα.

  • Φάση 2 είναι όπου I:
  • Καθαρίστε το χάος

Παράδειγμα Python:*C# Παράδειγμα:*Καλύτερο όνομα.

Τύπος σημειώσεων.*Τεκμηρίωση XML.*Καθαρότερη εφαρμογή LINQ.

2.

Ευθυγράμμιση με το Spec

Τώρα που ξέρω τι πραγματικά χτίζω, επιστρέφω στις αρχικές απαιτήσεις και βεβαιώνομαι ότι θα λύσω το πρόβλημα.

Δεξιά

πρόβλημα, όχι μόνο

αΠρόβλημα.

Συχνά αυτό αποκαλύπτει κενά:

"Ω, ήθελαν αυτό να χειριστεί τους αρνητικούς αριθμούς διαφορετικά."

  1. "Περίμενε, υπάρχει μια ακραία περίπτωση όπου η τιμή δεν θα μπορούσε να είναι καμία έναντι 0.""Το spec λέει 'διπλό' αλλά νομίζω ότι εννοούσαν 'κλίμακα από ένα ρυθμιζόμενο παράγοντα'."
  2. **Τα φτιάχνω αυτά.**Μερικές φορές πιέζω πίσω στο spec: "Στην πραγματικότητα, θα πρέπει να κάνουμε X αντ 'αυτού επειδή Y."
  3. **3.**Πολωνικά η επιφάνεια API
  4. Αυτό είναι όπου σκέφτομαι για τοΤηλεφωνητής

εμπειρία.**Python:**Γ#:

Καλύτερα να ονομάσουμε.

  • Λογικές προεπιλογές.
  • Διαμόρφωση όπου έχει σημασία.
  • Αφθονία API, κατά περίπτωση.
  • Αυτό είναι
  • Σκάφος.

Από εδώ προέρχεται το καλό λογισμικό.

Γιατί Ακόμη Δεν Υπάρχουν Δοκιμές;

def test_extract_doubled_values_basic():
    items = [{'value': 5}, {'value': 10}]
    assert extract_doubled_values(items) == [10, 20]

def test_extract_doubled_values_skips_missing_values():
    items = [{'value': 5}, {'name': 'foo'}, {'value': 3}]
    assert extract_doubled_values(items) == [10, 6]

def test_extract_doubled_values_handles_zeros():
    items = [{'value': 0}, {'value': 5}]
    # By default, zeros are excluded (falsy)
    assert extract_doubled_values(items) == [10]

def test_extract_doubled_values_includes_zeros_when_configured():
    items = [{'value': 0}, {'value': 5}]
    assert extract_doubled_values(items, include_zeros=True) == [0, 10]

def test_extract_doubled_values_custom_scale_factor():
    items = [{'value': 5}]
    assert extract_doubled_values(items, scale_factor=3.0) == [15.0]

def test_extract_doubled_values_rejects_negative_scale_factor():
    with pytest.raises(ValueError):
        extract_doubled_values([], scale_factor=-1.0)

def test_extract_doubled_values_handles_empty_list():
    assert extract_doubled_values([]) == []

def test_extract_doubled_values_handles_non_numeric_values():
    items = [{'value': 'not a number'}]
    with pytest.raises(TypeError):
        extract_doubled_values(items)

Το κάνω συνέχεια.

Έχω ανοιχτή μια αναφορά.

  • Δοκιμάζω διαφορετικές εισροές.
  • Ασκώ όλα τα μονοπάτια.
  • Αλλά δεν είμαι.
  • γράφοντας αυτά τα πειράματα ως επίσημες δοκιμές ακόμα.

Γιατί;

Επειδή

# This comment will drift from reality:
# Doubles all numeric values, skipping None

# This test will fail if reality changes:
def test_extract_doubled_values_skips_none_values():
    items = [{'value': None}, {'value': 5}]
    assert extract_doubled_values(items) == [10]

Ακόμα ανακαλύπτω τι αξίζει να δοκιμάσουμε.

Στη Φάση 1, δεν ήξερα αν αυτή η λειτουργία θα υπήρχε καν.Στη Φάση 2, ανακαλύπτω:"Ο συντελεστής κλίμακας δεν μπορεί να είναι αρνητικός.

Αυτό είναι επιβεβαίωση."

"Αν η λίστα είναι άδεια, πρέπει να επιστρέψουμε άδειοι, όχι Κανένας.""Πρέπει να χειριστούμε τις μη αριθμημένες αξίες με χάρη."

Αυτές οι ιδέες

βγαίνει από την αναπαράσταση.

Δεν είναι προφανείς.

  1. **Αν είχα γράψει τεστ στη Φάση 1, θα τα ξαναγράφα τώρα.**Αν τα γράψω εγώ
  2. μετάΕξέτασα την εφαρμογή, θα είναι σωστές την πρώτη φορά.
  3. **Φάση 3: Κλειδώστε το κάτω με τις δοκιμές (η φάση κοινής χρήσης)**Εντάξει, τώρα είναι αληθινό.

Ο κώδικας είναι καθαρός.*Το API βγάζει νόημα.*Έχω καλύψει τις ακραίες περιπτώσεις.

Είμαι σίγουρος γι' αυτό που έφτιαξα.

Τώρα γράφω τεστ.

Πολλές εξετάσεις.

Κοντά σε πλήρη κάλυψη, όπως είναι δυνατόν.Γιατί τώρα;

Επειδή

Οι δοκιμές είναι ένας μηχανισμός ανταλλαγής.Δεν είναι πια για μένα.

Καταλαβαίνω ήδη αυτόν τον κώδικα.

  • Έχω ζήσει σε αυτό για ώρες ή μέρες.
  • Οι δοκιμές αφορούν:
  • Μελλοντικά
  • (που θα ξεχάσει τα πάντα σε τρεις μήνες)Οι συμπαίκτες μου.(που πρέπει να εμπιστεύονται αυτόν τον κώδικα λειτουργεί)

Ο αγωγός CI

(η οποία πρέπει να αποτρέψει οπισθοδρόμηση)

Μελλοντικοί Συντηρητές

(που πρέπει να αναπαραστήσουν με ασφάλεια αυτό)

Δοκιμασίες είναι ηστρώμα παρουσίασης

για την εφαρμογή μου.Καταγράφουν:

Τι κάνει αυτός ο κώδικαςΠοιες είναι έγκυρες οι εισροέςΤι αποτελέσματα να περιμένετε

Τις αιχμές που σκέφτηκα.

Τι υποθέσεις κάνω;

Πλήρης κάλυψη, χωρίς συμβιβασμούς

  • Στη Φάση 3, πάω σκληρά στις δοκιμές:
  • Αυτό είναι το δίχτυ ασφαλείας.
  • Τώρα οι συμπαίκτες μου μπορούν:

Τροποποίηση αυτής της λειτουργίας με αυτοπεποίθηση

  • Κατανοήστε τις ακραίες περιπτώσεις
  • Επιστροφές αλιευμάτων αμέσως
  • Αντιδραστής χωρίς φόβο

Δοκιμές ως τεκμηρίωση

  • Οι καλές δοκιμές είναι καλύτερη τεκμηρίωση από τα σχόλια:*Οι εξετάσεις δεν λένε ψέματα.*Δεν μπορούν να παρασυρθούν.
  • Εάν η συμπεριφορά αλλάξει, η δοκιμή σπάει.
  • Αυτό είναι

εκτελέσιμα έγγραφα.

  • Αυτό κάνει τις εξετάσεις πολύτιμες.
  • Το Κοινό Όριο*Εδώ είναι το κρίσιμο σημείο:*Η 3η φάση συμβαίνει πριν αγγίξει κανείς άλλος τον κωδικό.
  • Δεν μοιράζομαι τον κώδικα χωρίς εξετάσεις.

Ποτέ.

graph TB
    subgraph "Traditional TDD (Red-Green-Refactor)"
        TDD1[Write Failing Test] --> TDD2[Write Minimal Code to Pass]
        TDD2 --> TDD3[Refactor]
        TDD3 --> TDD1
    end

    subgraph "Three-Phase Approach (Explore-Refine-Lock)"
        P1[Explore Solution Space] --> P2[Refine Implementation]
        P2 --> P3[Write Comprehensive Tests]
        P3 --> P4[Share With Team]
    end

    style TDD1 stroke:#ffaa00,stroke-width:2px
    style TDD2 stroke:#ffaa00,stroke-width:2px
    style TDD3 stroke:#ffaa00,stroke-width:2px
    style P1 stroke:#ff6b6b,stroke-width:3px
    style P2 stroke:#4ecdc4,stroke-width:3px
    style P3 stroke:#95e1d3,stroke-width:3px

**Αλλά επίσης δεν γράφω τεστ πριν ο κώδικας είναι έτοιμος να μοιραστεί.**Οι φάσεις είναι:

Ιδιωτική εξερεύνηση(μόνο εγώ, δεν δοκιμές)

Ιδιωτική βελτίωση

(μόνο εγώ, ακόμα δεν δοκιμές) |-----|-------------| Κοινή χρήση του κοινού (Δοκιμές, CI, αναθεώρηση κώδικα, όλα τα εννέα μέτρα) Αυτό προστατεύει και τις δύο δημιουργίες μουκαι | Η λογική των συμμαθητών μου. Γιατί Αυτό Προστατεύει τη Δημιουργικότητα

Οι συνήγοροι του TDD λένε "οι δοκιμές σου δίνουν αυτοπεποίθηση στον αντιδραστή."

Σωστά!Αλλά μόνο αν ξέρεις ήδη τι φτιάχνεις.

Όταν είμαι στη Φάση 1, δεν χρειάζομαι αυτοπεποίθηση για να αντιληφθώ.

Hour 1: Write test for API I haven't designed yet
Hour 2: Realize the API is wrong, rewrite test
Hour 3: Discover a better approach, rewrite both
Hour 4: Finally get it working
Hour 5: Rewrite tests to match what actually works

Χρειάζομαι άδεια να τα πετάξω όλα.

Hour 1: Explore 3 different APIs, settle on the best one
Hour 2: Refine the implementation, handle edge cases
Hour 3: Write comprehensive tests for what I built
Hour 4: All tests pass, commit with confidence

Οι εξετάσεις δημιουργούν ψυχολογικό χρέος.

Μόλις τα γράψω, διστάζω να τα διαγράψω.

Ακόμα κι αν δοκιμάζουν λάθος πράγματα.Αναβάλλοντας τις δοκιμές μέχρι τη Φάση 3, κρατάω τη Φάση 1 και 2

ψυχολογικά φτηνά.

Μπορώ:

  • Δοκίμασε τις άγριες ιδέες.
  • Πετάξτε ολόκληρες προσεγγίσεις
  • Αλλάξτε ριζικά το σχέδιο

Ανακαλύψτε το πρόβλημα είμαιΣτην πραγματικότηταεπίλυση

Όλα αυτά χωρίς την ενοχή του "αλλά εγώ έγραψα όλα αυτά τα τεστ..."

Έτσι λειτουργεί η δημιουργικότητα.

// Test 1: Write test first (but I don't know the right API yet)
[Test]
public void TestProcessData()
{
    var processor = new DataProcessor();
    var result = processor.Process(new[] { 1, 2, 3 });
    Assert.That(result, Is.EqualTo(new[] { 2, 4, 6 }));
}

// Implementation 1: Make it pass
public class DataProcessor
{
    public int[] Process(int[] data) => data.Select(x => x * 2).ToArray();
}

// Later: Realize I need configurability, rewrite test
[Test]
public void TestProcessDataWithFactor()
{
    var processor = new DataProcessor();
    var result = processor.Process(new[] { 1, 2, 3 }, factor: 3);
    Assert.That(result, Is.EqualTo(new[] { 3, 6, 9 }));
}

// Later: Realize I should use IEnumerable, rewrite test again
[Test]
public void TestProcessDataEnumerable()
{
    var processor = new DataProcessor();
    var data = GetLargeDataset(); // This should be lazy
    var result = processor.Process(data, factor: 3);
    Assert.That(result.Take(3), Is.EqualTo(new[] { 3, 6, 9 }));
}

Εσύ σκίτσο χαλαρά πρώτα.

Δεν ξεκινάς με τις λεπτομέρειες.

// Phase 1: Explore (no tests yet)
public int[] ProcessThing(int[] data)
{
    return data.Select(x => x * 2).ToArray();
}
// Try it: var result = ProcessThing(new[] { 1, 2, 3 });
// Hmm, what about configurability? What about lazy evaluation?

// Phase 2: Refine (still no tests)
public static class DataProcessorExtensions
{
    public static IEnumerable<int> Scale(
        this IEnumerable<int> source,
        int factor = 2)
    {
        return source.Select(x => x * factor);
    }
}
// Try it: var result = data.Scale(factor: 3).ToList();
// Much better API!

// Phase 3: Lock it down (NOW write tests, correctly)
[TestFixture]
public class DataProcessorTests
{
    [Test]
    public void Scale_DefaultFactor_DoublesValues()
    {
        var result = new[] { 1, 2, 3 }.Scale();
        Assert.That(result, Is.EqualTo(new[] { 2, 4, 6 }));
    }

    [Test]
    public void Scale_CustomFactor_ScalesCorrectly()
    {
        var result = new[] { 1, 2, 3 }.Scale(factor: 3);
        Assert.That(result, Is.EqualTo(new[] { 3, 6, 9 }));
    }

    [Test]
    public void Scale_LazyEvaluation_DoesNotEnumerateImmediately()
    {
        var enumerated = false;
        var data = GetTestData(() => enumerated = true);
        var scaled = data.Scale(factor: 2);

        Assert.That(enumerated, Is.False, "Should not enumerate yet");

        scaled.ToList();
        Assert.That(enumerated, Is.True, "Should enumerate on materialization");
    }

    [Test]
    public void Scale_EmptySequence_ReturnsEmpty()
    {
        var result = Enumerable.Empty<int>().Scale();
        Assert.That(result, Is.Empty);
    }
}

Πώς Ταιριάζει αυτό με την Αγαθότητα και το XP (Και πού Αναδύεται)

Ας ξεκαθαρίσουμε κάτι:

Αυτό δεν είναι "δοκιμάστε αργότερα ανάπτυξη."

Αυτό είναι

  • "Δοκιμάστε όσο αναπτύσσεστε, αλλά την κατάλληλη στιγμή."Ο συγχρονισμός της
  • όταν

η προσθήκη δοκιμών μονάδας είναι κρίσιμης σημασίας.

  • Πολύ νωρίς και προσδιορίζεις το άγνωστο.
  • Πολύ αργά και στέλνεις χωρίς δίχτυα ασφαλείας.

Οι πρακτικές XP που κρατάω

  • Ακραία Προγραμματισμός έχει λαμπρές πρακτικές που αξίζει να ακολουθήσετε:
  • Συνεχής ενσωμάτωση

Κάθε χαρακτηριστικό περνάει από το CI πριν από τη συγχώνευση

  • Αυτόματη δοκιμή εκτελείται σε κάθε δέσμευση προς την κύριαΚανένα σπασμένο οικοδόμημα δεν είναι ανεκτόΠρογραμματισμός ζεύγους / αναθεώρηση κώδικα
  • Κωδικός Φάσης 3 εξετάζεται πριν από την κοινή χρήση

Οι δοκιμές είναι μέρος του αναθεωρητέου αντικειμένου

Η συνεργατική βελτίωση βελτιώνει το σχεδιασμόΑπλή σχεδίαση

Η φάση 2 είναι

  • όλα τα σχετικά
  • απλούστευση
  • Απομακρύνετε αυτό που δεν χρειάζεστε
  • Κάνε το όσο πιο απλό γίνεται, όχι πιο απλό.

Αναπροσανατολισμός

Η Φάση 2 είναι αφιερωμένος χρόνος αναπαράστασηςΚαθαρίστε τον κωδικόπριν

Το κλείδωμα κάτω

**Οι δοκιμές προστατεύουν τον αναπαραγωγό (στη Φάση 3+)**Πού Ξεφεύγω από την Αυστηρή TDD

Το TDD λέει:"Πρώτα οι εξετάσεις.

Πάντα.Red-Green-Refactor είναι ο μόνος τρόπος."

Λέω:"Δοκιμάζει όταν ξέρεις τι τεστ κάνεις.

Εξερευνήστε-Refine-Lock είναι πιο φυσικό."

Η βασική διαφορά:

Τρεις-Φάζες Τρεις-ΦάζεςΗ δοκιμή καθορίζει τη διεπαφή ~ Εξερεύνηση ορίζει τη διεπαφή ~

  • Κύκλος Red-Green-Refactor-Cycle Explore-Refine-Lock Progress
  • Δοκιμασίες που γράφτηκαν πριν από την εφαρμογή
  • κοινή χρήση

Δοκιμάστε πρώτα για όλα Δοκιμάστε την κατάλληλη στιγμή για κάθε πράγμα

  • Μικροκύκλοι (λεπτά) Μακροφασικές (ώρες/ήμερες)
  • Ο Χρόνος Είναι Κρίσιμος
  • Εδώ είναι η κρίσιμη διορατικότητα:
  • Δεν είναι "τα τεστ τελευταία." Είναι "τα τεστ πριν τα μοιραστούμε."
  • Λάθος συγχρονισμός (πολύ νωρίς):

Σωστός συγχρονισμός (Φάση 3):

Ίδιο αποτέλεσμα ποιότητας.*Το μισό χτύπημα.*Αυτό είναι Αγκιλείο.

Η Αγκίλ λέει:

"Απάντησε να αλλάξεις, ακολουθώντας ένα σχέδιο."Το TDD μπορεί να γίνει η δική του μορφή σχεδίου που ακολουθεί.

Μόλις γράψεις εξετάσεις, είσαι ψυχολογικά αφοσιωμένος σε αυτό το σχέδιο.

  • Η προσέγγισή μου αγκαλιάζει την αλλαγή:
  • Φάση 1: Αλλαγή γρήγορα, ανακαλύψτε τη σωστή λύση
  • Φάση 2: Αλλαγή εσκεμμένα, εκλεπτυσμένη προς την κομψότητα
  • Φάση 3: Αλλαγή προσεκτικά, προστασία ό, τι λειτουργεί

Αυτό είναιΠερισσότερα

ευκίνητος παρά αυστηρός TDD, γιατί αναβάλλει τη δέσμευση μέχρι να έχετε πληροφορίες.

Αντιθέσεις: ένα παράδειγμα C#

Αυστηρή προσέγγιση TDD:

Πρόσεξες το χτύπημα;

Τρεις δοκιμές ξαναγράφτηκαν καθώς εξελίχθηκε το σχέδιο.

  1. **Τριφασική προσέγγιση:**Ένα σετ τεστ.
  2. **Γράφει κάποτε.**Διόρθωσε την πρώτη φορά.
  3. **Επειδή ήξερα τι φτιάχνω.**Η σύνδεση Αγίων Μανιφέστο

Θυμηθείτε τις τιμές:

"Λογισμικό εργασίας πάνω από πλήρη τεκμηρίωση"

Η Φάση 1 φτάνει στο λογισμικό εργασίας

Γρήγορα.

  1. Φάση 3 κάνει δοκιμές η περιεκτική τεκμηρίωση"Απαντάει να αλλάξει πάνω από ακολουθώντας ένα σχέδιο"
  2. Φάσεις 1-2 αγκαλιάζουν την αλλαγήΦάσεις 3 κλειδαριές στον τελικό σχεδιασμό
  3. **"Ιδιώτες και αλληλεπιδράσεις σε διαδικασίες και εργαλεία"**Μην αφήσεις το δόγμα του TDD να παρακάμψει την καλή κρίση.

Συνεργαστείτε όταν βοηθά (Φάση 2-3), εξερευνήστε μόνοι όταν δεν το κάνει (Φάση 1)

"Συνεργασία πελατών για διαπραγμάτευση συμβολαίου"

Η φάση 2 ευθυγραμμίζεται με το spec

μετά

  1. κατανόηση του προβλήματοςΚαλύτερα να παραδώσει ό, τι χρειάζονται από ό, τι ορίζουν
  2. Γιατί Αυτό Μειώνει το Άχρηστο ΧτύπημαΤο βρώμικο μυστικό του TDD:
  3. **οι περισσότερες δοκιμές που γράφτηκαν πριν από την εφαρμογή επαναγράφονται ή διαγράφονται.**Γιατί;

Επειδή:

Παρεξήγησες τις απαιτήσεις.

Δεν ήξερες ακόμα τις ακραίες υποθέσεις.Ανακαλύψατε έναν καλύτερο σχεδιασμό APIΣυνειδητοποιήσατε ότι το χαρακτηριστικό δεν ήταν απαραίτητο.

Κάθε τεστ που γράφεις στη Φάση 1 είναι μάλλον χαμένη προσπάθεια.

Καλύτερα να γράψω.

μία

Σετ δοκιμών στη Φάση 3, όταν ξέρεις τι φτιάχνεις, από το να ξαναγράψεις κατά τη διάρκεια της εξερεύνησης.Υπόσχεση TDD εναντίον ΠραγματικότηταςΤο TDD υπόσχεται:

"Write code that solves the specification.
Don't worry about perfection yet.
Just get it working."

"Οι δοκιμές οδηγούν το σχέδιό σου!

  • Σας βοηθούν να ανακαλύψετε καλά APIs!"
  • TDD πραγματικότητα:
  • "Έγραψα εξετάσεις για ένα API που νόμιζα ότι είχε νόημα.
  • Μετά το εφάρμοσα και συνειδητοποίησα ότι το API ήταν αμήχανο.

Τώρα ξαναγράφω τις εξετάσεις και τον κώδικα."**Αυτό δεν είναι σχέδιο.**Αυτό είναι

thrushing.Η προσέγγισή μου:

Σχεδιάστε μέσω της εφαρμογής, στη συνέχεια κλειδώστε το κάτω με δοκιμές.

  1. Το τελικό αποτέλεσμα είναι ο ίδιος καλά δοκιμασμένος κώδικας.
  2. Αλλά έφτασα εκεί με το μισό χτύπημα.
  3. Γιατί Αυτό Παραδίδει Ακόμα Πειθαρχικό Λογισμικό
  4. Άκου τι είναι αυτή η προσέγγιση.
  5. όχι:
  6. "Cowboy code"

"Όχι δοκιμές"*"Σπρώξε και προσευχήσου"*Μέχρι να τελειώσω με τη Φάση 3, ο κώδικας μου έχει:

Πλήρης κάλυψη των δοκιμώνΥpiοθέσει εκpiοpiή εpiιχειρήσεω

Καθαρή, ευανάγνωστη εφαρμογή

Καθαρισμός σχεδιασμού APIΤεκμηρίωση (μέσω δοκιμών)

Ακριβώς το ίδιο με το TDD.

  1. Η διαφορά είναι

    • όταν
    • Αυτές οι εξετάσεις γράφτηκαν.
    • Η Διαπαιδαγώγηση Προέρχεται από τα Όρια
  2. Ο κανόνας είναι απλός:

    - flake8 (style checking)
    - pylint (code quality)
    - mypy (type checking)
    - black (formatting)
    - radon (complexity analysis)
    
  3. **Κανένας κωδικός δεν φεύγει από τη Φάση 2 χωρίς τη Φάση 3.**Δεν ξέρω.

    for iteration in range(3):
        # Measure current performance
        metrics = measure_performance(code)
    
        # Generate improved version
        better_code = optimise(code, metrics)
    
        # Keep if better, discard if worse
        if better_code.score > code.score:
            code = better_code
    

Μη δοκιμασμένη έκδοση κωδικούΆνοιγμα δημοσίων σχέσεων χωρίς δοκιμέςΣυγχώνευση στο κύριο χωρίς περαστικό CI

  • Ανάπτυξη χωρίς αναφορές κάλυψης
  • Η πειθαρχία δεν είναι στα γραπτά τεστ νωρίς.
  • Είναι μέσα.
  • δεν μοιράζεται τον κώδικα χωρίς δοκιμές.
  • Οι Μεταφορείς της Χειροτεχνίας

Δεν είναι καινούρια ιδέα.Έτσι δούλευε πάντα η δημιουργική δουλειά:

Σκίτσα → Αφαίρεση → Βαρνίς

Οι ζωγράφοι δεν ξεκινούν με τις τελευταίες πινελιές.*Αυτοί:*ΣκίτςCity name (optional, probably does not need a translation)η σύνθεση (Φάση 1)

Χρώμα*τα στρώματα (Φάση 2)*ΒαρνίςCity name (optional, probably does not need a translation)

# Test generation happens AFTER optimisation
def generate_unit_tests(specification, optimized_code):
    """Generate comprehensive tests for refined code.

    This happens in Phase 3, after we know:
    - What the code actually does
    - What edge cases exist
    - What the API surface looks like
    """
    return llm.generate(
        f"""Generate comprehensive unit tests for this code.

Specification: {specification}
Implementation: {optimized_code}

Include tests for:
- Happy path (from spec examples)
- Edge cases (discovered during optimisation)
- Error conditions (based on actual error handling)
- Performance bounds (based on measured metrics)
"""
    )

για την προστασία και την παρουσία (Φάση 3)

  • Το βερνίκι δεν έρχεται πρώτο.
  • Αλλά δεν είναι προαιρετικό.
  • Σχέδιο → Επεξεργασία → Δημοσίευση
  • Οι συγγραφείς δεν επεξεργάζονται το σχέδιο τους.

Αυτοί:Σχέδιομπερδεμένα (Φάση 1)

  1. Επεξεργασία**ανελέητα (Φάση 2)**Δημοσίευση
  2. με αυτοπεποίθηση (Φάση 3)**"Γράψτε μεθυσμένος, επεξεργαστείτε νηφάλιος" είναι τρομερή συμβουλή ζωής, αλλά μεγάλη συμβουλές γραφής.**Πήλινο → Φόρμα → Γλάσο
  3. Οι χελώνες δεν γυαλίζουν πριν σχηματιστούν.**Αυτοί:**Πέτα
  4. ο πηλός (Φάση 1)Κλίμακα και ραφιναρισμένητο έντυπο (Φάση 2)Γλάσο και φωτιά

**για αντοχή (Φάση 3)**Το γλάσο είναι κρίσιμο.

Αλλά έρχεται τελευταίο.

Πώς αυτό Χάρτες για τον αγωγό DiSE CodegenΕδώ είναι που γίνεται ενδιαφέρον: Έχω πραγματικάσε εφαρμογή

Αυτή η φιλοσοφία στο σύστημα DiSE (Directed Synthetic Evolution).

  • Ο αγωγός codegen ενσωματώνει ρητά αυτές τις τρεις φάσεις:
  • Φάση 1 στο DiSE: Το Στάδιο Εξερεύνησης
  • Όταν ζητάτε από το DiSE να λύσει ένα πρόβλημα, δεν άλμα κατ 'ευθείαν στο γράψιμο τέλειο, δοκιμασμένο κώδικα.
  • Αντ' αυτού, η

Γεννήτρια

  • (codentellama ή παρόμοια) παίρνει μια σαφή εντολή:
  • Το σύστημα δημιουργεί διερευνητικό κώδικα:
  • Εστιασμένη στο ευτυχισμένο μονοπάτι
  • Ελάχιστος χειρισμός λάθους

Καμία πρόωρη βελτιστοποίηση

  • Αρκετά για να δοκιμάσω την προσέγγιση.Στη συνέχεια, ηΕκτελεστής
  • Το διευθύνει.*Όχι με επίσημες δοκιμές μονάδας μόνο με τις εισροές από τις προδιαγραφές.*Αν αποτύχει;
  • Κανένα πρόβλημα.Αυτό είναιΜαθαίνοντας.
  • Το σύστημα έχει μια προσαρμοστική κλιμάκωση 6 σταδίων:

Δοκιμάστε με ένα γρήγορο μοντέλο (χαμηλή θερμοκρασία)

Δοκιμάστε ξανά με μεγαλύτερη δημιουργικότητα (υψηλότερη θερμοκρασία)

User: "Calculate fibonacci numbers"

[Phase 1: Exploration - 3 attempts]
  Attempt 1: Works for small inputs, explodes on large ones (no safety limit)
  Attempt 2: Adds safety limit, but inefficient recursive approach
  Attempt 3: Switches to iterative DP (PASS)

[Phase 2: Optimization - 3 iterations]
  Iteration 1: Add type hints, improve naming (Score: 1.05)
  Iteration 2: Optimize memory usage with generator (Score: 1.10)
  Iteration 3: Add input validation (Score: 1.15)

[Phase 3: Testing and Storage]
  Generated 8 unit tests covering:
    - Basic cases (n=0, n=1, n=5, n=10)
    - Edge cases (n=negative, n=100, n=None)
    - Type validation

  All tests pass ✓

  Stored in RAG with quality score: 1.15
  Available for reuse: YES

Σκαρφαλώστε σε ένα πιο ισχυρό μοντέλο

  • Προσθήκη καταγραφής αποσφαλμάτωσης για να κατανοήσετε τις αποτυχίες
  • Δώστε πλήρες πλαίσιο στο ισχυρό μοντέλο
  • Χρησιμοποιήστε το "θεόσπιτο" μοντέλο ως έσχατη λύση
  • Αυτό είναι

*Ακριβώς.*Φάση 1.

Το σύστημα εξερευνεί τον χώρο της λύσης, μαθαίνει τι λειτουργεί, αποτυγχάνει γρήγορα και προσαρμόζεται.

Δεν υπάρχουν δοκιμές που να γράφονται κατά τη διάρκεια αυτής της φάσης.Ο κώδικας είναι ιδιωτικός στη διαδικασία παραγωγής.

Φάση 2 στο DiSE: Το Στάδιο ΒελτιστοποίησηςΜόλις ο κώδικας περάσει τη βασική εκτέλεση, DiSE κινείται σεΒελτιστοποίηση.

  1. **Αυτή είναι η φάση βελτίωσης.**Το σύστημα:
  2. Καθαρίζει την εφαρμογήΑφαίρεση καταγραφής αποσφαλμάτωσης που προστέθηκε κατά τη διάρκεια αποτυχιών
  3. Απλουστεύει υπερβολικά πολύπλοκο κώδικαΒελτιώνει την ονομασία και τη δομή
  4. Λειτουργεί στατική ανάλυσηΒελτιστοποιήσεις σε βάθος

(3 λειτουργίες εξ ορισμού)

Αυτό είναιΑκριβώς.

Φάση 2.

Ο κωδικός είναι ακόμα ιδιωτικός (όχι ακόμα στο μητρώο), αλλά τον γυαλίζουμε:Καλύτερα ονόματα

Υποδείξεις τύπουΚαθαρότερη δομή

Χαμηλότερη πολυπλοκότητα

Καλύτερη απόδοσηΤο σχήμα δεν είναι πλέον υγρό.

Ξέρουμε τι φτιάχνουμε.

  1. **Τώρα θα τα καταφέρουμε.**Ωραία.
  2. Φάση 3 στο DiSE: Το στάδιο δοκιμής και αποθήκευσηςΜόνο
  3. μετάΒελτιστοποίηση δημιουργεί και τρέχει το DiSE

Επίσημες δοκιμές μονάδας.

  • Εδώ είναι το κρίσιμο μέρος: οι δοκιμές παράγονται από το
  • Εκλεπτυσμένη προδιαγραφή και εφαρμογή
  • , όχι την αρχική εξερεύνηση.

Οι δοκιμές καλύπτουν:*Παραδείγματα προδιαγραφών (διορθότητα)*Περιστασιακές περιπτώσεις που ανακαλύφθηκαν κατά τη Φάση 2

Σφάλμα χειρισμού που προστέθηκε κατά τη διάρκεια της βελτίωσης

Χαρακτηριστικά επιδόσεων που έχουν μετρηθείΤότεμόνο εάν περάσουν οι δοκιμές

, ο κωδικός είναι:

Αποθηκευμένο στην

RAG μνήμης@ title: window

# I know what sort() should do. Tests first? Sure!
def test_sort_empty_list():
    assert sort([]) == []

def test_sort_single_element():
    assert sort([5]) == [5]

def test_sort_multiple_elements():
    assert sort([3, 1, 2]) == [1, 2, 3]

(με την ενσωμάτωση)

Προστέθηκε στηνμητρώο κόμβουName:

  1. (ως εκτελέσιμο τεχνούργημα)
  2. Διατίθεται για
  3. επαναχρησιμοποίηση

Στο μέλλον, οι ροές εργασίας

Ανιχνεύθηκε με

βαθμολογίες ποιότητας

Finding related posts...
logo

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