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

<datetime class="hidden">2025-11-19T10:00</datetime>

<!-- category -- Software Development, Testing, TDD, Craftsmanship, Best Practices -->
**Γιατί γράφω τεστ τελευταία, και γιατί δεν είναι αυτό που νομίζεις ότι σημαίνει**

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

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

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

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

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

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

```mermaid
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
```

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

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

[TOC]

## Αλλά επειδή

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

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

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

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

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

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

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

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

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

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

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

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

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

```python
# 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, γράφω:

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

Στρατιώτη.

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

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

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

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

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

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

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

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

```python
# 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η φάση είναι περίπου**

```csharp
// 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*Σημαίνει: "Το έλεγξα.

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

```python
# 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
)
```

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

```csharp
// 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% σίγουρος ότι καταλαβαίνω το πρόβλημα τώρα."

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

```mermaid
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:
- 1.
- Καθαρίστε το χάος

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

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

## 2.

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

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

**Δεξιά**

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

α**Πρόβλημα.**

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

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

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

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

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

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

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

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

```python
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)
```

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

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

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

### Γιατί;

Επειδή

```python
# 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η φάση συμβαίνει πριν αγγίξει κανείς άλλος τον κωδικό.
- Δεν μοιράζομαι τον κώδικα χωρίς εξετάσεις.

### Ποτέ.

```mermaid
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**

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

Μπορώ:

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

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

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

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

```csharp
// 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 }));
}
```

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

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

```csharp
// 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.**Δεν ξέρω.
   
   ```python
   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)

```python
# 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

```python
# 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. επαναχρησιμοποίηση

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

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

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