# Cómo construyo software: Hacer que funcione, hacerlo bonito, bloquearlo

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

<!-- category -- Software Development, Testing, TDD, Craftsmanship, Best Practices -->
**¿Por qué escribo las últimas pruebas, y por qué eso no es lo que crees que significa**

> **Toma controversial:**Test-Driven Development es una práctica brillante que resuelve el problema equivocado para la mayoría del trabajo creativo.

## Esto es lo que funciona mejor.

Las tres fases del software de construcción (que realmente funciona)

**Así es como construyo el software.**

Es simple, es efectivo, y hace que los puristas de TDD frunzan educadamente sus cejas:

Haz que funcione.*Que sea bonito.*Enciérrenlo con pruebas.

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

En ese orden.*Siempre.*No porque sea perezoso.

No porque no valoro las pruebas.

[TOC]

## Pero porque

así es como el trabajo creativo realmente sucede

Cuando estás explorando un espacio problemático aún no lo entiendes completamente.

- No porque sea perezoso.
- No porque no valoro las pruebas.
- Pero porque
- así es como el trabajo creativo realmente sucede

**Cuando estás explorando un espacio problemático aún no lo entiendes completamente.**

Déjame explicarte.

### Fase 1: Hacer que funcione (El bosquejo privado)

Esta es la parte desordenada.**La parte en la que no tengo ni idea de lo que estoy haciendo.**

Estoy tratando de entender:

¿Esta API realmente funciona de la manera en que los documentos afirman?

¿Puedo incluso resolver este problema con las herramientas que tengo?

¿Qué significa "corregir" incluso en este contexto?*¿Es un problema de dos horas o un problema de dos semanas?*Esto es invención.

**Esto es exploración.**

Esto es jazz.

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

¿Y sabes lo que mata el jazz?**Alguien parado sobre tu hombro diciendo "escribe la prueba primero".**¿ Por qué no hay pruebas todavía?

Porque*la forma sigue siendo fluida.*Imagínate que eres escultor.

Tienes un bloque de mármol y una vaga idea: "Quiero tallar un pájaro".

### TDD dice: "Antes de tocar ese mármol, escriba exactamente cómo es un pájaro.

Define su envergadura.**Especifique el ángulo de cada pluma.**

Ahora esculpe esas especificaciones".*Así... no es como se tallan los pájaros. (O el software se escribe, como resulta.)*Escultores reales

Primero desbaratar la forma.**Ellos dibujan.**

Hacen maquetas.*Cortan grandes pedazos de piedra para encontrar la forma general.*Sólo después refinan los detalles.

El código es el mismo.

### En la Fase 1, estoy escribiendo:

Este código es

privado.

Es una conversación conmigo misma.

Así es como me doy cuenta de lo que significa "trabajar".

## Escribir pruebas para esto es peor que inútil — es

activamente perjudiciales.

**Porque cada vez que me doy cuenta de "oh espera, todo este enfoque está mal", tendría que reescribir las pruebas también.**

Eso no es rigor.

### Eso es burocracia.

**La libertad de fallar rápidamente**

```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')
    ]
```

**La fase 1 es sobre**

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

velocidad de aprendizaje.

### Necesito probar cinco enfoques diferentes en una hora.

Necesito descubrir que la biblioteca de terceros que pensé usar... no es tan publicitada.*Necesito darme cuenta que el problema que estoy resolviendo no es el problema.*debe*resolverlo.*Las pruebas ralentizan esto.

No porque las pruebas sean lentas, sino porque

- especificación prematura es la muerte.
- Si escribo pruebas antes de entender el problema, estoy escribiendo pruebas para el
- cosa equivocada.

Entonces estoy emocionalmente invertido en lo incorrecto.

### Entonces estoy defendiendo lo equivocado en la revisión de código.

Es mejor fallar rápido, en privado, sin pruebas para mantener y sin ego para proteger.*Lo que significa "trabajar" en la fase 1*Significa: "Yo lo hice.

**Le di algunas entradas.**

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

**Produjo productos que parecen razonables.**

```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();
```

Tengo un 60% de confianza en que entiendo el problema ahora".

Eso es.**No hay casos de ventaja.**No hay manejo de errores.

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

### Sin elegancia.

*Sólo un pico.*Una prueba de concepto.

Un sketch.*Fase 2: Hacerlo bonito (el refinamiento)*

Vale, ahora entiendo el problema.**Tengo algo que funciona, al menos para el camino feliz.**

Ahora puedo empezar a preocuparme por la calidad.

- La fase 2 es donde yo:
- 1.
- Limpiar el desorden

Ejemplo de Python:*C# Ejemplo:*Mejor nombre.

Anotaciones de tipo.*Documentación XML.*Implementación de LINQ más limpia.

## 2.

Alinearse con el espectro

Ahora que sé lo que estoy construyendo, vuelvo a los requisitos originales y me aseguro de que estoy resolviendo el problema.

**derecha**

### problema, no sólo

a**problema.**

A menudo esto revela lagunas:

"Querían que esto manejara los números negativos de manera diferente".

1. **"Espera, hay un caso de borde donde el valor podría ser Ninguno vs. 0."**"La especificación dice 'doble' pero creo que significa 'escala por un factor configurable.'"
2. **Arreglaré esto.**A veces me retracto en la especificación: "En realidad, deberíamos hacer X en su lugar porque Y."
3. **3.**Polaco de la superficie API
4. **Aquí es donde pienso en el**Llamador

experiencia.**Python:**C#:

Mejor nombre.

- Defaults sensibles.
- Configuración donde importa.
- APIs fluidas cuando proceda.
- Esto es
- artesanado.

### Aquí es de donde viene el buen software.

¿ Por qué todavía no hay pruebas?

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

**Oh, lo estoy manejando constantemente.**

Tengo una REPL abierta.

- Estoy probando diferentes entradas.
- Estoy ejercitando todos los caminos.
- Pero no lo soy.
- Escribiendo esos experimentos como pruebas formales todavía.

### ¿Por qué?

Porque

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

Todavía estoy descubriendo lo que vale la pena probar.

En la Fase 1, no sabía si esta función existiría.**En la Fase 2, estoy descubriendo:**"El factor escala no puede ser negativo.

### Eso es una validación".

"Si la lista está vacía, deberíamos volver vacía, no Ninguno."**"Necesitamos manejar los valores no numéricos con gracia".**

Estos puntos de vista

emergen de la refactorización.

No son obvios por adelantado.

1. **Si hubiera escrito pruebas en la Fase 1, las estaría reescribiendo ahora.**Si los escribo
2. **después**He perfeccionado la implementación, serán correctos la primera vez.
3. **Fase 3: Bloquearlo con pruebas (la fase de compartir)**Bien, ahora es real.

El código está limpio.*La API tiene sentido.*He cubierto los estuches del borde.

## Estoy seguro de lo que he construido.

Ahora escribo pruebas.

Muchas pruebas.

Pruebas tan cercanas a la cobertura completa como sea posible.**¿Por qué ahora?**

Porque

las pruebas son un mecanismo de compartir.*Ya no son para mí.*

Ya entiendo este código íntimamente.

- He vivido en ella durante horas o días.
- Las pruebas son para:
- Futura yo
- (que se olvidará de todo en tres meses)*Mis compañeros de equipo*(que necesitan confiar en este código funciona)

El oleoducto CI

**(que necesita evitar regresiones)**

Encargados del futuro

## (que necesitan refactorizar esto con seguridad)

Las pruebas son las siguientes:**capa de presentación**

para mi implementación.**Documentan:**

¿Qué hace este código?*Qué entradas son válidas*Qué productos esperar

### ¿Qué casos de borde he considerado

¿Qué suposiciones estoy haciendo?

**Cobertura completa, sin compromisos**

- En la Fase 3, me esforzo mucho en las pruebas:
- Esta es la red de seguridad.
- Ahora mis compañeros de equipo pueden:

**Modificar esta función con confianza**

- Entender los casos de borde
- Regresiones de capturas inmediatamente
- Refactorizar sin miedo

**Pruebas como documentación**

- Las buenas pruebas son mejor documentación que comentarios:*Las pruebas no mienten.*No pueden irse a la deriva.
- Si el comportamiento cambia, la prueba se rompe.
- Eso es.

**documentación ejecutable.**

- Eso es lo que hace que las pruebas sean valiosas.
- La frontera compartida*Este es el punto crucial:*La fase 3 ocurre antes de que alguien más toque el código.
- No comparto código sin pruebas.

### Nunca.

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

**Pero tampoco escribo pruebas antes de que el código esté listo para compartir.**Las fases son las siguientes:

**Exploración privada**(solo yo, sin pruebas)

Refinamiento privado

(solo yo, todavía no hay pruebas)
|-----|-------------|
Participación del público
(pruebas, CI, revisión de código, los nueve yardas enteros)
Esto protege tanto mi creatividad*y* |
La cordura de mis compañeros.
Por qué esto protege la creatividad

### Los defensores de TDD dicen que "las pruebas te dan confianza para refactorizar".

¡Es verdad!**Pero sólo si ya sabes lo que estás construyendo.**

**Cuando estoy en la Fase 1, no necesito confianza para refactorizar.**

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

**Necesito permiso para tirar todo por la borda.**

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

Las pruebas crean deuda psicológica.

### Una vez que los he escrito, soy reacio a borrarlos.

Incluso si están probando la cosa equivocada.**Aplazando las pruebas hasta la fase 3, mantengo las fases 1 y 2**

psicológicamente barato.

Puedo:

- Prueba ideas salvajes
- Deseche enfoques enteros
- Cambiar radicalmente el diseño

Descubre el problema que soy*En realidad*resolver el problema

### Todo sin la culpa de "pero escribí todas esas pruebas..."

**Así es como funciona la creatividad.**

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

Usted bosqueja flojamente primero.

**No empiezas con los detalles.**

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

Cómo encaja esto con Agile y XP (y dónde se desvía)

### Seamos claros sobre algo:

esto no es "prueba de desarrollo posterior".

**Esto es**

- "probar mientras se desarrolla, pero en el momento adecuado."*El calendario de*
- cuando

**para añadir pruebas unitarias es crítico.**

- Demasiado pronto y estás especificando lo desconocido.
- Demasiado tarde y vas a enviar sin redes de seguridad.

**Las prácticas de XP que mantengo**

- Extreme Programming tiene prácticas brillantes que vale la pena seguir:
- Integración continua

**Cada característica pasa por CI antes de fusionarse**

- Pruebas automatizadas en cada commit a main*No se toleran construcciones rotas*Programación por parejas / Revisión de código
- Fase 3 código se revisa antes de compartir

## Las pruebas son parte del artefacto revisable

El refinamiento colaborativo mejora el diseño**Diseño sencillo**

La fase 2 es

- todo sobre
- simplificación
- Quitar lo que no necesita
- Hacerlo tan simple como sea posible, no más simple

Refactorización

Fase 2 es tiempo de refactorización dedicado*Limpiar el código*antes

### cerrándolo.

**Los ensayos protegen la refactorización (en la fase 3+)**Donde me desvío de la estricta TDD

**TDD dice:**"Primero las pruebas.

Siempre.*Red-Green-Refactor es la única manera".*

**Yo digo:**"Pruebas cuando sabes lo que estás probando.

Explore-Refine-Lock es más natural".

## La diferencia clave:

TDD  Tres fases*La prueba define la interfaz La exploración define la interfaz*

- Ciclo rojo-verde-refactor  Explore-Refine-Lock progresión
- Pruebas escritas antes de la implementación  Pruebas escritas antes
- compartir

Prueba primero para todo Prueba en el momento adecuado para cada cosa

- Microciclos (minutos) Macrofases (horas/días)
- El tiempo es crítico
- Aquí está la visión crucial:
- No son "pruebas últimas". Son "pruebas antes de compartir".
- Momento equivocado (demasiado temprano):

*Momento adecuado (etapa 3):*

El mismo resultado de calidad.*La mitad del churn.*Esto es ágil.

### Agile dice:

"Responda a cambiar siguiendo un plan."**La TDD puede convertirse en su propia forma de seguimiento de planes.**

Una vez que has escrito pruebas, estás comprometida psicológicamente con ese diseño.

- Mi enfoque abarca el cambio:
- Fase 1: Cambiar rápidamente, descubrir la solución correcta
- Fase 2: Cambiar deliberadamente, refinar hacia la elegancia
- Fase 3: Cambiar cuidadosamente, proteger lo que funciona

Esto es*más*

## ágil que estricta TDD, porque aplaza el compromiso hasta que tenga información.

Enfoques de contraste: Un ejemplo de C#

### Estricto enfoque TDD:

¿Te fijas en el churn?

Tres reescrituras de prueba a medida que el diseño evolucionó.

1. **Enfoque de tres fases:**Un conjunto de pruebas.
2. **Escrita una vez.**Corregir la primera vez.
3. **Porque sabía lo que estaba construyendo.**La conexión ágil del Manifiesto

Recuerde los valores:

### "Software de trabajo sobre documentación completa"

Fase 1 llega al software de trabajo

rápido

1. **La fase 3 hace pruebas de la documentación completa**"Respondiendo a cambiar siguiendo un plan"
2. **Las fases 1-2 abarcan el cambio**Cerraduras de fase 3 en el diseño final
3. **"Individuales e interacciones sobre procesos y herramientas"**No dejes que el dogma TDD anule el buen juicio

Colaborar cuando ayuda (Fase 2-3), explorar solo cuando no lo hace (Fase 1)

### "Colaboración de clientes en la negociación de contratos"

La fase 2 se alinea con la especificación

después

1. **comprender el problema**Mejor entregar lo que necesitan que lo que especificaron
2. **¿Por qué esto reduce el churn inútil**El sucio secreto de TDD:
3. **la mayoría de las pruebas escritas antes de la aplicación se reescriben o eliminen.**¿Por qué?

Porque:

## Usted malinterpretó los requisitos

Aún no conocías los casos del borde.*Descubriste un mejor diseño de API*Te diste cuenta de que la función no era necesaria.

Cada prueba que escribas en la Fase 1 es probablemente un esfuerzo desperdiciado.

### Mejor escribir

uno

conjunto de pruebas en la Fase 3, cuando realmente sabes lo que estás construyendo, que escribir-reescribir-reescribir durante la exploración.**La promesa TDD vs. la realidad**TDD promete:

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

"¡Las pruebas impulsan tu diseño!

- ¡Te ayudan a descubrir buenas API!"
- La realidad del TDD:
- "Escribí pruebas para una API que pensé que tenía sentido.
- Luego lo implementé y me di cuenta de que la API era incómoda.

Ahora estoy reescribiendo tanto las pruebas como el código".**Eso no es diseño.**Eso es.

Golpeando.**Mi enfoque:**

Diseño a través de la implementación, luego bloquearlo con pruebas.

1. El resultado final es el mismo código bien probado y bien diseñado.
2. Pero llegué allí con la mitad del churn.
3. Por qué esto todavía ofrece software disciplinado
4. Esto es lo que es este enfoque
5. no:
6. "Codificación de vaqueros"

"Sin pruebas"*"Enviar y rezar"*Para cuando termine con la Fase 3, mi código tiene:

**Cobertura completa de los ensayos**Casos de borde manejados

### Aplicación limpia y legible

Borrar el diseño de API**Documentación (por medio de pruebas)**

Exactamente lo mismo que TDD.

1. **La diferencia es**
   
   - cuando
   - esas pruebas fueron escritas.
   - La disciplina viene de la frontera

2. **La regla es simple:**
   
   ```
   - flake8 (style checking)
   - pylint (code quality)
   - mypy (type checking)
   - black (formatting)
   - radon (complexity analysis)
   ```

3. **Ningún código deja la Fase 2 sin la Fase 3.**Yo no:
   
   ```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
   ```

Código de commit no probado*Abrir PRs sin pruebas*Fusionar a la principal sin que pase IC

- Despliegue sin informes de cobertura
- La disciplina no está en las pruebas de escritura temprano.
- Está dentro.
- no compartir código sin pruebas.
- Las metáforas artesanales

Esta no es una idea nueva.*Es como el trabajo creativo siempre ha funcionado:*

### Sketch → Refinar → Barniz

Los pintores no comienzan con las pinceladas finales.*Ellos:*Sketch**la composición (fase 1)**

Pintura*las capas (Fase 2)*Barniz

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

proteger y presentar (Fase 3)

- El barniz no es lo primero.
- Pero no es opcional.
- Borrador → Editar → Publicar
- Los escritores no editan como se dibujan.

Ellos:*Proyecto*desordenado (Fase 1)

1. Editar**despiadadamente (Fase 2)**Publicar
2. con confianza (Fase 3)**"Escribir borracho, editar sobrio" es un consejo de vida terrible, pero un gran consejo de escritura.**Arcilla → Forma → Vidrio
3. Los potters no se esmaltan antes de dar forma.**Ellos:**Lanzar
4. la arcilla (Fase 1)**Recortar y refinar**la forma (fase 2)**Vidrio y fuego**

**para la durabilidad (Fase 3)**El esmalte es crucial.

### Pero es el último.

Cómo se hace este mapa para el oleoducto DiSE Codegen*Aquí es donde esto se pone interesante:*aplicada

**esta filosofía en el sistema DiSE (Directed Synthetic Evolution).**

- La tubería de códice encarna explícitamente estas tres fases:
- Fase 1 en DISE: La etapa de exploración
- Cuando le pides a DiSE que resuelva un problema, no salta directamente a escribir un código perfecto y probado.
- En su lugar, el

**Generador**

- (codellama o similar) tiene un mandato claro:
- El sistema genera código exploratorio:
- Centrado en el camino feliz
- Manejo de errores mínimos

**No hay optimización prematura**

- Lo suficiente para probar el enfoque*Entonces el*Ejecutador
- Lo dirige.*No con pruebas de unidades formales, sólo con las entradas de la especificación.*¿Si falla?
- No hay problema.*Eso es.*aprender.
- El sistema tiene una escalada adaptativa de 6 etapas:

### Pruebe con un modelo rápido (temperatura baja)

Inténtalo de nuevo con mayor creatividad (temperatura más alta)

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

Escalá a un modelo más poderoso

- Añadir el registro de depuración para entender los fallos
- Dar contexto completo al poderoso modelo
- Utilice el modelo "nivel-dios" como último recurso
- Esto es

*Exactamente.*Fase 1.

### El sistema está explorando el espacio de solución, aprendiendo lo que funciona, fallando rápidamente y adaptándose.

No se han escrito pruebas durante esta fase.*El código es privado para el proceso de generación.*

Fase 2 en diSE: la fase de optimización**Una vez que el código pasa la ejecución básica, DiSE se mueve a**optimización.

1. **Esta es la fase de refinamiento.**El sistema:
2. **Limpia la implementación**Elimina el registro de depuración que se añadió durante fallas
3. **Simplifica código demasiado complejo**Mejora el nombre y la estructura
4. **Ejecuta análisis estático**Optimiza iterativamente

(3 iteraciones por defecto)

Esto es*Exactamente.*

## Fase 2.

El código sigue siendo privado (todavía no está en el registro), pero lo estamos puliendo:**Mejores nombres**

Escribir sugerencias*Estructura más limpia*

Menor complejidad

Mejor rendimiento**La forma ya no es fluida.**

Sabemos lo que estamos construyendo.

1. **Ahora lo hacemos.**Bien.
2. **Fase 3 en DiSE: la fase de pruebas y almacenamiento**Sólo
3. **después**Optimización DiSE genera y ejecuta

pruebas de unidades formales.

- Aquí está la parte crucial: las pruebas se generan a partir de la
- especificación y aplicación perfeccionadas
- , no la exploración inicial.

Los ensayos cubren:*Ejemplos de especificación (corrección)*Casos de borde descubiertos durante la Fase 2

## Manejo de errores que se añadió durante el refinamiento

Características de rendimiento que se midieron*Entonces,*sólo si se aprueban los ensayos

, el código es:

### Almacenado en el

Memoria RAG

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

### (con incrustaciones)

Agregado a la*registro de nodos*:

1. (como un artefacto ejecutable)
2. Se pone a disposición de
3. reutilización

en futuros flujos de trabajo

### Rastreado con

calificaciones de calidad