# namespaces, require, tests, project structure y domain modeling

Esta semana vamos a pasar de “escribir funciones” a **organizar un proyecto real**. La meta es entender cómo se reparte el código en namespaces, cómo se conectan con `require`, cómo se ordenan `src` y `test`, y cómo se modela un dominio con funciones puras.

La idea no es memorizar una receta. Es entender por qué esta estructura hace el proyecto más fácil de leer, probar y mantener.

## **1) Namespaces: la manera de ordenar el código**

Un namespace (`ns`) es una forma de agrupar funciones relacionadas. En Clojure, normalmente cada archivo tiene un namespace, y ese namespace debe coincidir con la ruta del archivo.

```java
;; src/clojure_saveme/week3/domain.clj
(ns clojure-saveme.week3.domain)
```

Piensa en esto así:

*   el archivo dice **dónde vive** el código
    
*   el namespace dice **cómo lo llamas**
    
*   juntos te ayudan a no mezclar responsabilidades
    

Regla práctica:

*   `src/clojure_saveme/week3/domain.clj`
    
*   `clojure-saveme.week3.domain`
    

La carpeta usa `_` y el namespace usa `-` porque así se traduce la ruta al nombre lógico del módulo.

## **2)** `require`**: conectar módulos entre sí**

Cuando un namespace necesita usar funciones de otro, lo trae con `:require`.

```java
;; src/clojure_saveme/week3/core.clj
(ns clojure-saveme.week3.core  
  (:require [clojure-saveme.week3.domain :as domain]))

(defn checkout  
  [raw-order min-total discount-percentage]
  (let [order (domain/build-order raw-order)]
    (if (domain/eligible-for-discount? order min-total)
      (domain/mark-paid (domain/apply-discount order discount-percentage))
      (domain/mark-paid order))))
```

![](http://localhost:63342/markdownPreview/1534365378//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles align="center")

Qué está pasando aquí:

1.  `core` no reescribe la lógica del negocio
    
2.  `core` llama a `domain`
    
3.  `:as domain` evita repetir el nombre completo cada vez
    

Eso mismo se ve en los tests: un namespace de pruebas también hace `require` del código que quiere verificar.

## **3) Estructura del proyecto: separar por responsabilidad**

Cuando el proyecto crece, ya no conviene poner todo en un solo archivo. La idea es separar por intención:

```java
src/clojure_saveme/
  week3/
    domain.clj
    core.clj
test/clojure_saveme/
  week3/
    domain_test.clj
    core_test.clj
```

![](http://localhost:63342/markdownPreview/1534365378//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles align="center")

Interpretación simple:

*   `domain.clj` = reglas y modelado
    
*   `core.clj` = orquestación del caso de uso
    
*   `*_test.clj` = pruebas del namespace correspondiente
    

Así encuentras rápido qué hace cada pieza y dónde cambiarla.

## **4) Tests: probar comportamiento, no duplicar lógica**

Un test importa el namespace que quiere probar igual que cualquier otro archivo.

```java
(nsclojure-saveme.week3.domain-test  
  (:require [clojure.test :refer :all]
            [clojure-saveme.week3.domain :as domain]))
(deftest order-total-test  
  (is (=300 (domain/order-total {:items [{:price 100 {:price 200}]})))
  (is (=0 (domain/order-total {:items []}))))
```

La clave es esta: el test no “recalcula” el resultado por otro camino. Solo verifica que la función haga lo esperado.

Cuando pruebas `core`, pruebas el flujo completo:

```java
(deftest checkout-test  (testing "applies discount when order qualifies"    
   (let [result (core/checkout {:id 2 :customer "Luis" :items [{:price 500}]} 300 10)]
      (is (= :paid (:status result)))
      (is (= [{:price 450}] (:items result))))))
```

![](http://localhost:63342/markdownPreview/1534365378//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles align="center")

`testing` sirve para dar contexto cuando un mismo test cubre varios escenarios.

## **5) Funciones puras: la base para probar fácil**

Una función pura:

*   devuelve siempre lo mismo para la misma entrada
    
*   no depende de cosas externas como archivos, base de datos o impresión en consola
    

```java
(defn order-total  
  [order]
  (reduce +0 (map :price (:items order))))
```

![](http://localhost:63342/markdownPreview/1534365378//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles align="center")

Esto es ideal para tests porque solo necesitas entrada y salida.

Contraejemplo:

```java
(defn order-total-impuro!  
  [order]
  (println "calculando total...")
  (reduce +0 (map :price (:items order))))
```

![](http://localhost:63342/markdownPreview/1534365378//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles align="center")

Ese `println` mete un efecto secundario y complica la prueba.

## **6) Domain modeling: tres tipos de funciones**

Para modelar bien un dominio, ayuda separar el código en tres grupos.

### **1\. Constructores / normalización**

Toman datos crudos y devuelven una forma consistente.

```java
(defn build-order  
  [{:keys [id customer items]}]
  {:id id
   :customer customer
   :items items
   :status:pending})
```

![](http://localhost:63342/markdownPreview/1534365378//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles align="center")

### **2\. Reglas de negocio**

Preguntan algo sobre el dominio.

```java
(defn eligible-for-discount?  
  [ordermin-total]
  (>= (order-total order) min-total))
```

![](http://localhost:63342/markdownPreview/1534365378//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles align="center")

### **3\. Transformaciones**

Devuelven una nueva versión del dato sin mutarlo.

```java
(defn apply-discount  
  [order percentage]
  (update order :items          
          (fn [items]
            (map #(update % :price * (-1 (/ percentage 100))) items))))
(defn mark-paid  
  [order]
  (assoc order :status :paid))
```

![](http://localhost:63342/markdownPreview/1534365378//Users/josediaz/Projects/JoeDayz/ClojureSaveme/articles align="center")

Separar así hace que el código sea más claro: si cambia una regla, no tienes que tocar todo el flujo.

## **7)** `core.clj`**: orquestar, no inventar reglas**

`core.clj` funciona como el coordinador del caso de uso. Su trabajo es combinar piezas, no concentrar toda la lógica.

```java
(defn checkout  
  [raw-order min-total discount-percentage]
  (let [order (domain/build-order raw-order)]
    (if (domain/eligible-for-discount? order min-total)
      (domain/mark-paid (domain/apply-discount order discount-percentage))
      (domain/mark-paid order))))
```

Piensa en esto como un flujo:

1.  recibo datos crudos
    
2.  los normalizo
    
3.  consulto una regla
    
4.  aplico transformaciones
    
5.  devuelvo el resultado final
    

## **8) Qué código vive esta semana**

*   src/clojure\_saveme/week3/domain.clj — dominio y funciones puras
    
*   src/clojure\_saveme/week3/core.clj — orquestación y casos de uso
    
*   test/clojure\_saveme/week3/domain\_test.clj — pruebas del dominio
    
*   test/clojure\_saveme/week3/core\_test.clj — pruebas de orquestación
    

## **9) Cómo correr las pruebas**

```bash
clojure -M:test -m cognitect.test-runner
```

## **10) Ejercicios para practicar**

### **Básico**

*   crea un namespace `clojure-saveme.week3.reports` y haz `require` de `domain`
    
*   escribe una función pura `product-discount` que reciba un producto y un porcentaje
    

### **Intermedio**

*   agrega una regla `overdue?` para pedidos y su test
    
*   separa `checkout` en dos funciones: una que decide si aplica descuento y otra que aplica la transformación
    

### **Avanzado**

*   crea `clojure-saveme.week3.reports` que dependa de `core` y `domain`
    
*   escribe una función que resuma pedidos: total general, cantidad pagada, cantidad pendiente
    
*   agrega tests con lista vacía como caso borde
    

## **11) Meta de la semana**

Al terminar, deberías poder explicar:

*   por qué la ruta del archivo determina el namespace
    
*   cómo se usa `:require` con `:as`
    
*   cómo ordenar `src` y `test` cuando el proyecto crece
    
*   por qué las funciones puras son más fáciles de probar
    
*   cómo separar dominio y orquestación
    

Si entiendes eso, ya estás pensando como alguien que puede trabajar en un backend Clojure real: módulos claros, reglas bien separadas y tests que acompañan al código.

Enjoy!

Joe
