wandres.dev
DISEÑO DE APIS · las guidelines

Nombrar bien: etiquetas, verbos y el par que muta

La gramática como herramienta de ingeniería: etiquetas de argumento que completan una frase, la distinción entre métodos con efecto y métodos con resultado, y el par de nombres que Swift exige cuando una operación existe en versión mutante y en versión que devuelve un valor nuevo.

⏱ 19 min

Swift es uno de los poquísimos lenguajes cuyo diseño de nombres se apoya explícitamente en categorías gramaticales del inglés: verbos, participios, gerundios, sintagmas preposicionales. Para quien viene de otra tradición esto suena a pedantería, pero cumple una función técnica muy concreta. La gramática es el único sistema de expectativas compartido que existe antes de que tu API exista, y apoyarse en ella permite que un lector deduzca el comportamiento de un método —si muta, si devuelve, si es caro, si tiene efectos— sin haber visto jamás su declaración. Las etiquetas de argumento son la pieza que hace posible ese truco, y también la que más se malinterpreta.

🎯 Al terminar esta lección sabrás
  • Usar etiquetas de argumento para completar frases en vez de para nombrar parámetros.
  • Aplicar la regla de verbo y sustantivo para distinguir efecto de resultado.
  • Construir correctamente el par mutante y no mutante con las formas ed e ing.
  • Justificar cuándo suprimir una etiqueta con el guion bajo y cuándo eso destruye claridad.

La etiqueta pertenece a la frase, no al parámetro

El error de origen consiste en pensar que la etiqueta externa es el nombre del argumento. No lo es: el nombre del argumento es el identificador interno, el que usa el cuerpo de la función. La etiqueta externa es un fragmento de la frase que se leerá en la llamada, y por eso su criterio de calidad no es describir el parámetro, sino encajar gramaticalmente con el nombre del método.

// La etiqueta describe el parametro: rigido y redundante
func mover(distancia: Double, direccion: Direccion)
mover(distancia: 3, direccion: .norte)

// La etiqueta completa la frase: fluido y mas informativo
func mover(_ distancia: Double, hacia direccion: Direccion)
mover(3, hacia: .norte)

De aquí salen dos patrones canónicos. Cuando el método admite una preposición natural, la preposición es la etiqueta y arrastra a todos los argumentos que gobierna: mover(desde: a, hasta: b) mantiene la preposición pegada a la etiqueta porque rige ambos. Cuando el primer argumento forma parte de una frase verbal completa, la etiqueta se suprime y el resto lleva las suyas: vista.añadir(hijo, debajo de: otra).

Hay un caso frontera que conviene tener resuelto de antemano. Si los argumentos son intercambiables entre sí y ninguno domina —los elementos de una suma, los vértices de un triángulo— no hay frase que construir y todas las etiquetas deben suprimirse o ser idénticas, porque inventar etiquetas distintas sugiere una asimetría que no existe.

💡
Prueba del sintagma

Lee la llamada quitando los paréntesis y los dos puntos. Si el resultado suena a sintagma inglés bien formado, las etiquetas están bien elegidas. Si suena a formulario relleno, has nombrado parámetros en lugar de escribir una frase.

Verbos que actúan, sustantivos que devuelven

La segunda regla es la que más comportamiento comunica por unidad de esfuerzo, y se enuncia en una línea: si la operación tiene efecto sobre el receptor, nómbrala con un verbo en imperativo; si devuelve un valor nuevo sin tocar nada, nómbrala con un sintagma nominal.

var lista = [3, 1, 2]

lista.ordenar()                 // verbo: actua sobre lista
let otra = lista.ordenada()     // sustantivo: devuelve una copia

conexion.cerrar()               // verbo: efecto sobre la conexion
let estado = conexion.estado    // sustantivo: solo consulta

La regla se apoya en una intuición lingüística sólida: un imperativo pide una acción y por tanto anuncia consecuencias; un sintagma nominal designa una cosa y por tanto anuncia un resultado. Cuando un método viola la correspondencia —un nombre nominal que además muta, un verbo que solo consulta— el lector construye un modelo mental equivocado y el compilador no puede ayudarle, porque el sistema de tipos no distingue entre efecto pretendido y efecto real.

Los booleanos merecen su propia cláusula. Una propiedad o método que devuelve Bool debe leerse como una aserción sobre el receptor, lo que en la práctica significa empezar por is, has, can o un adjetivo. Y los protocolos siguen otra regla complementaria: los que describen qué es algo se nombran con sustantivos, y los que describen qué puede hacer algo con sufijos de capacidad como able o ible.

flowchart TD
A[Que hace la operacion] --> B{Modifica el receptor}
B -- Si --> C[Verbo en imperativo]
B -- No --> D{Devuelve un booleano}
D -- Si --> E[Asercion con is o has]
D -- No --> F[Sintagma nominal]
C --> G[Existe tambien version no mutante]
G -- Si --> H[Sufijo ed o ing en la copia]
style C fill:#f38ba8,color:#11111b
style F fill:#a6e3a1,color:#11111b
style H fill:#89b4fa,color:#11111b

El par mutante y no mutante

Cuando una misma operación tiene sentido en ambas formas, Swift no te deja elegir nombres arbitrarios: exige un par derivado del verbo, y la regla que gobierna la derivación es gramatical, no ortográfica.

Si el verbo admite participio pasado con sentido de resultado, la versión no mutante lo usa: ordenar y ordenada, invertir e invertida. Si el participio no funciona porque el verbo es en realidad un sustantivo verbalizado —el caso de union, difference, intersection— entonces la versión mutante toma la forma de gerundio o de verbo explícito y la no mutante conserva el sustantivo. En inglés esto produce el par conocido formUnion y union, cuya asimetría desconcierta hasta que se entiende que el sustantivo ya nombraba al resultado y no había participio disponible.

protocol Transformable {
    mutating func normalizar()            // efecto
    func normalizada() -> Self            // resultado
}

extension Transformable {
    func normalizada() -> Self {
        var copia = self
        copia.normalizar()
        return copia
    }
}

Ese patrón tiene una consecuencia de diseño que va más allá del nombre. Al declarar el par en un protocolo y proveer la versión no mutante en una extensión por defecto, obligas a cada conformante a implementar solo la variante mutante, que es la que puede optimizarse in situ, y regalas la otra con coste de una copia. La alternativa simétrica —implementar la no mutante y derivar la mutante por asignación— es correcta pero pierde la oportunidad de mutar sin copiar, y en tipos con almacenamiento grande esa diferencia es medible.

En castellano el par cae con naturalidad porque disponemos de participios con género —ordenar y ordenada, filtrar y filtrada— pero conviene no perder de vista que el par publicado en una biblioteca real se escribirá en inglés, y que ahí la elección entre participio y gerundio no es libre: la decide si el nombre base es verbo o sustantivo, y equivocarse produce nombres que suenan mal a cualquier lector nativo.

Conviene además recordar que la palabra clave mutating solo existe en tipos de valor. En una clase todo método puede modificar el estado sin anunciarlo, lo que significa que en clases el par de nombres ya no lo respalda el compilador y depende enteramente de tu disciplina. Es una razón más, y no menor, para preferir tipos de valor en el diseño de bibliotecas.

Cuando suprimir la etiqueta y cuándo no

El guion bajo es la herramienta más peligrosa del repertorio porque parece un simple ahorro y en realidad borra información en el punto de uso. Las guías admiten su uso en tres situaciones y desaconsejan el resto.

La primera es la de los argumentos que no se distinguen entre sí, ya comentada. La segunda es la de las funciones que forman parte de un dominio con notación establecida, donde la etiqueta rompería la convención: nadie escribe una raíz cuadrada con etiqueta. La tercera, y la más frecuente, es la del argumento que ya está nombrado por el propio método, como el elemento en añadir o el valor en insertar.

// Correcto: el metodo ya dice que se anade un elemento
lista.añadir(elemento)

// Peligroso: dos enteros sin etiqueta y sin simetria
func recortar(_ inicio: Int, _ fin: Int)
recortar(3, 9)     // cual es cual, y estan incluidos

// Reparado
func recortar(desde inicio: Int, hasta fin: Int)

El criterio final vuelve a ser el de la lección anterior: la etiqueta se suprime cuando su presencia no elimina ninguna pregunta, y se conserva cuando su ausencia crea una. Toda supresión que obligue al lector a recordar el orden de los parámetros es una supresión mal hecha, por muy elegante que quede la llamada.

🧩

La etiqueta es sintaxis

Forma parte de la frase de la llamada. No es un nombre de parámetro colocado fuera.

Verbo igual a efecto

Imperativo cuando muta, sintagma nominal cuando devuelve. Romper esa correspondencia engaña sin que el compilador avise.

🔁

El par derivado

Participio cuando el verbo lo admite, gerundio o forma explícita cuando el nombre base ya es un sustantivo.

La gramática como sistema de tipos informal

Hay una manera de mirar estas reglas que las transforma de convención cultural en mecanismo de ingeniería, y consiste en advertir que la gramática está funcionando como un sistema de tipos paralelo al del compilador: uno que no verifica nada, que no puede rechazar un programa, pero que fija expectativas sobre propiedades que el sistema de tipos real de Swift no sabe expresar. La distinción entre imperativo y sintagma nominal codifica presencia o ausencia de efectos, que en Haskell viviría dentro de una mónada y aquí no vive en ninguna parte del tipo; el prefijo is codifica que el valor devuelto es una proposición sobre el receptor y no un dato independiente; el sufijo de capacidad en un protocolo codifica que la conformidad añade poder sin cambiar identidad ontológica. Ninguna de esas tres cosas aparece en la firma, y sin embargo el lector competente las lee con la misma confianza con que lee el tipo de retorno. Esto tiene una implicación epistemológica incómoda: buena parte de lo que creemos saber al leer una API no procede de garantías verificadas sino de convenciones que nadie hace cumplir, y su fiabilidad depende por completo de que la comunidad las respete con disciplina. Cuando alguien publica una biblioteca donde un método con nombre nominal muta, o donde una propiedad con prefijo is dispara una petición de red, no comete un error de estilo: corrompe un canal de información sobre el que otros están razonando, y el daño se propaga porque el lector siguiente ya no puede confiar en la señal ni en el resto del paquete. La lección transferible es que todo sistema formal viene rodeado de una capa de convenciones informales que transportan justo aquello que el formalismo no captura, y que esa capa es tan infraestructura como el compilador aunque nada la valide; el ingeniero maduro se distingue por tratarla con el mismo rigor que trata los tipos, porque entiende que la alternativa no es un sistema más libre sino uno en el que cada lectura exige verificar la implementación, es decir, uno donde la abstracción ha dejado de existir.

📝
Lo esencial

Las etiquetas construyen la frase de la llamada y por eso su criterio es gramatical, no descriptivo. El imperativo anuncia efecto y el sintagma nominal anuncia resultado; los booleanos se leen como aserciones. El par mutante y no mutante se deriva con participio o con gerundio según lo que admita el verbo base, y conviene declararlo en un protocolo dejando la copia como implementación por defecto. Suprimir una etiqueta solo es legítimo cuando su ausencia no genera ninguna pregunta.

⚔️ Reescribe una API por su gramática
  1. Localiza en tu código cinco métodos y clasifícalos en mutantes y no mutantes según lo que realmente hacen, no según su nombre.
  2. Corrige los que violen la correspondencia entre verbo y efecto, y anota cuántos eran.
  3. Escoge una operación que tenga sentido en ambas formas y publica el par completo derivándolo por la regla del participio.
  4. Declara ese par en un protocolo con la versión no mutante como extensión por defecto y mide el coste de la copia.
  5. Busca un guion bajo en tu API pública y demuestra, con una llamada real, si elimina o crea preguntas al lector.