- Notifications
You must be signed in to change notification settings - Fork1
jeko2000/clojure-style-guide
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Los models a seguir son importantes.
-- Oficial Alex J. Murphy / RoboCop
Esta guía de estilo para Clojure recomienda mejores practicas con elfin de que programadores de Clojure puedan desarrollar código quepueda ser mantenido por otros programadores del lenguaje. Una guía deestilo que refleja correctamente usos reales del lenguaje será usada.Mientras que una guía que trate de imponer un estilo rechazado poraquellos individuos a quién la guía trata de ayudar, está destinada aque nunca se use sin importar que tan buena sea.
Esta guía está separada en varias secciones de reglas relacionadas. Heintentado proveer razones fundamentales tras las reglas aquíexpuestas. Si es el caso de que la razón es omitida, es porque la heconsiderado evidente.
Cabe decir que estas reglas no salen de la nada. Las reglas son, en sugran mayoría basadas en mi extensiva carrera como ingeniero desoftware profesional, comentarios y sugerencias de miembros de lacomunidad de Clojure, y varios prestigiosos recursos de programaciónde Clojure tales como"Clojure Programming"y"The Joy of Clojure".
La guía es todavía un trabajo en progreso ya que algunas secciones aúnfaltan y otras están incompletas. Existen también unas reglas que sebeneficiarían de mejores ejemplos. A su debido tiempo, estos y otrosproblemas serán solucionados mas por ahora, vale la pena tenerlos enmente.
Ten en cuenta que la comunidad de desarrollo de Clojure tambiénmantiene una lista deestándares de código para librerías.
Tú tienes la opción de generar un archivo PDF o una copia HTML de estaguía usandoPandoc.
Traducciones de esta guía están disponibles en los siguientes idiomas:
- Diseño y organización de códigofuente
- Sintaxis
- Nombramiento
- Colecciones
- Mutación
- Strings o cuerdas
- Excepciones
- Macros
- Comentarios
- Existencial
- Herramientas
- Pruebas
- Organización de librerías
Casi todos están convencido que todos los estilos, salvo el suyo, esfeo e ilegible. Elimina "salvo el suyo" y probablemente estén en locorrecto...
-- Jerry Coffin (acerca de indentación/sangría)
Para indentación/sangría usaespacios y notabuladores.[link]
Usa 2 espacios de sangría en loscuerpos de formas con argumentos. Esto incluye todos las formas
def
,formas especiales y macros que incluyen enlaces locales comoloop
,let
,when
,cond
,as->
,cond->
,case
,with-*
, etc.[link];; bueno(when algo (algo-mas))(with-out-str (println"Hola") (println"mundo!"));; malo - cuatro espacios(when algo (algo-mas));; malo - un solo espacio(with-out-str (println"Hola") (println"mundo!"))
Alinea verticalmenteargumentos de funciones o macros que abarcan múltiples líneas.[link]
;; bueno(filter even? (range110));; malo(filter even? (range110))
Usa un solo espacio de sangría paraargumentos de funciones o macros cuando no aparezcan en la mismalínea que el nombre de la función.[link]
;; bueno(filter even? (range110))(or uno dos tres);; malo - sangría de dos espacios(filter even? (range110))(or uno dos tres)
Alinea verticalmenteenlaces
let
y palabras clave "keywords", en mapas.[link];; bueno(let [cosa1"algo" cosa2"algo más"] {:cosa1 cosa1:cosa2 cosa2});; malo(let [cosa1"algo" cosa2"algo más"] {:cosa1 cosa1:cosa2 cosa2})
La linea entre elnombre de una función y su vector de argumentos es opcional y puedeser excluida cuando no conlleve documentación.[link]
;; bueno(defnfoo [x] (bar x));; bueno(defnfoo [x] (bar x));; malo(defnfoo [x] (bar x))
Incluye el
dispatch-val
o valor de envío de un multimétodo en la misma lineaque el nombre de la función.[link];; bueno(defmethodfoo:bar [x] (baz x))(defmethodfoo:bar [x] (baz x));; malo(defmethodfoo:bar [x] (baz x))(defmethodfoo:bar [x] (baz x))
Al agregar documentación, enespecial a una función con la forma del ejemplo anterior, asegúrateque la documentación aparezca inmediatamente después del vector deargumentos. De otra forma, éste no será parte de ladocumentación.[link]
;; bueno(defnfoo"cadena de documentación" [x] (bar x));; malo(defnfoo [x]"cadena de documentación" (bar x))
La línea entre el vector de argumentode una función y su cuerpo es opcional si el cuerpo es pequeño.[link]
;; bueno(defnfoo [x] (bar x));; bueno para una función pequeña(defnfoo [x] (bar x));; bueno para funciones de varias aridades(defnfoo ([x] (bar x)) ([x y] (if (predicate? x) (bar x) (baz x))));; malo(defnfoo [x] (if (predicate? x) (bar x) (baz x)))
Agrega sangría para cadaaridad de una función. De igual forma, alinea verticalmente sus argumentos.[link]
;; bueno(defnfoo"Yo tengo dos aridades." ([x] (foo x1)) ([x y] (+ x y)));; malo - sangría innecesaria(defnfoo"I have two arities." ([x] (foo x1)) ([x y] (+ x y)))
Ordena las aridades de unafunción de mínimo a máximo número de argumentos. Lo que ocurrefrecuentemente en funciones con distintas aridades es que existe unnúmero K de argumentos los cuales completamente especifican elcomportamiento de la función. Para el caso de aridades N < K, lafunción es parcialmente aplicada y para aridades N > K, la funciónprovee un fold sobre la versión con K aridades sobre varargs, oargumentos variables.[link]
;; bueno - fácilmente encontramos la aridad que necesitamos(defnfoo"Yo tengo dos aridades." ([x] (foo x1)) ([x y] (+ x y)));; regular - todas las aridades están basadas en la función con aridad 2(defnfoo"Yo tengo dos aridades." ([x y] (+ x y)) ([x] (foo x1)) ([x y z & mas] (reduce foo (foo x (foo y z)) mas)));; malo - en desorden(defnfoo ([x]1) ([x y z] (foo x (foo y z))) ([x y] (+ x y)) ([w x y z & mas] (reduce foo (foo w (foo x (foo y z))) mas)))
Agrega sangría en cada líneade documentación si ésta abarca más de una sola línea[link]
;; bueno(defnfoo"Hola. Esto es una documentación que abarca varias líneas." [] (bar));; malo(defnfoo"Hola. Esto es una documentaciónque abarca varias líneas." [] (bar))
Usa las terminaciones de línea de estilo Unix.(Usuarios de BDS, Solaris, Gnu Linux, y OSX ya las usan por defecto.Usuarios de Windows tendrán que ser más cuidadosos.)[link]
- Si estas usando Git, es posible que quieras agregar el siguientecambio de configuración para ayudar a prevenir que terminacionesde línea de estilo Windows se introduzcan al proyecto:
bash$ git config --global core.autocrlf true
Si existe texto inmediatamente antes o después de una sección entreparéntesis
(...)
, corchetes[...]
o llaves{...}
, agrega unespacio antes de la apertura y después de la clausura del mismo.[link];; bueno(foo (bar baz) quux);; malo(foo(bar baz)quux)(foo ( bar baz ) quux)
No agregues comas
,
entreelementos de una secuencia literal.[link];; bueno[123](123);; malo[1,2,3](1,2,3)
Considera mejorar lalegibilidad de mapas literales a través del uso prudente de comas ylíneas.[link]
;; bueno{:nombre"Bruce Wayne":identidad-secreta"Batman"};; bueno y discutiblemente más legible{:nombre"Bruce Wayne":identidad-secreta"Batman"};; bueno y discutiblemente más compacto{:nombre"Bruce Wayne",:identidad-secreta"Batman"}
Agrega todos los paréntesisque cierran una expresión en una sola línea.[link]
;; bueno(when algo (algo-mas));; malo. Los paréntesis están en distintas líneas(when algo (algo-mas))
Usa líneas vacíasentre formas de nivel superior.[link]
;; bueno(defx...)(defnfoo...);; malo(defx...)(defnfoo...)
Una excepción de esta regla es durante el agrupamiento dedefiniciones relacionadas tipo
def
.;; bueno(defmin-filas10)(defmax-filas20)(defmin-columnas15)(defmax-columnas30)
No agregues líneasvacías en medio de la definición de una función o un macro. Unaexcepción a esta regla es cuando se desea indicar grupos deconstrucciones en pares como aquellas encontradas en
let
ycond
.[link]Donde sea factible, evita tenerlíneas con más de 80 caracteres.[link]
Evita tener espacio en blanco alfinal.[link]
Usa un archivo por cada espaciode nombre o namespace.[link]
Comienza cada namespacecon una forma comprensiva de tipo
ns
. Si es necesario, ésta debeestar compuesta de líneas pararefer
,require
, eimport
, en eseorden.[link](nsejemplos.ns (:refer-clojure:exclude [next replace remove]) (:require [clojure.string:as s:refer [blank?]] [clojure.set:as set] [clojure.java.shell:as sh]) (:import java.util.Date java.text.SimpleDateFormat [java.util.concurrent Executors LinkedBlockingQueue]))
En la forma
ns
, debespreferir el uso de:require :as
en lugar de:require :refer
enlugar de:require :refer :all
. También debes preferir:require
sobre:use
, ya que la forma:use
es considerada obsoleta.[link];; bueno(nsejemplos.ns (:require [clojure.zip:as zip]));; bueno(nsejemplos.ns (:require [clojure.zip:refer [lefts rights]]));; aceptable según lo garantizado(nsejemplos.ns (:require [clojure.zip:refer:all]));; malo(nsejemplos.ns (:use clojure.zip))
Evita el uso de namespacesde un solo segmento.[link]
;; bueno(nsejemplos.ns);; malo(nsejemplos)
Evita el uso denamespaces demasiado largos, es decir, con más de 5 segmentos.[link]
Evita funciones con más de 10líneas de código. Idealmente, la mayoría de tus funciones deben detener menos de 5 líneas de código.[link]
Evita tener listas deargumentos que requieren más de 3 o 4 argumentos en orden.[link]
Evita el uso de referencias directaso adelantadas ya que son muy raramente necesarias.[link]
Evita el uso de funciones como
require
yrefer
que alteran tu namespace. Estas funciones soncompletamente innecesarias fuera de un ambiente REPL.[link]Usa la forma
declare
para referenciasdirectas o adelantas cuando éstas sean necesarias.[link]Debes preferir funciones de ordensuperior como
map
en lugar deloop/recur
.[link]Debes preferir pre y postcondiciones sobre pruebas o tests dentro del cuerpo de una función.[link]
;; bueno(defnfoo [x] {:pre [(pos? x)]} (bar x));; malo(defnfoo [x] (if (pos? x) (bar x) (throw (IllegalArgumentException."x must be a positive number!")))
No definas vars dentro de tusfunciones.[link]
;; muy malo(defnfoo [] (defx5)...)
No ocultes los nombres de
clojure.core
con nuevas definiciones o enlaces locales.[link];; malo - necesitamos clojure.core/map para referirnos a la funcion(defnfoo [map]...)
Usa
alter-var-root
en lugar dedef
paracambiar el valor de una var.[link];; bueno(defcosa1); valor de cosa es ahora 1; algunos cambios a cosa(alter-var-root #'cosa (constantlynil)); valor de cosa es ahora nil;; malo(defcosa1); algunos cambios a cosa(defcosanil); valor de cosa es ahora nil
Usa la forma
seq
como condición determinación para probar que una secuencia está vacía.[link];; bueno(defnimprimir-seq [s] (when (seq s) (prn (first s)) (recur (rest s))));; malo(defnimprimir-seq [s] (when-not (empty? s) (prn (first s)) (recur (rest s))))
Usa
vec
en lugar deinto
cuando senecesite convertir una secuencia a un vector.[link];; bueno(vec alguna-seq);; malo(into [] alguna-seq)
Usa la forma
when
enlugar de(if ... (do ...)
.[link];; bueno(when predicado (foo) (bar));; malo(if predicado (do (foo) (bar)))
Usa
if-let
en lugar delet
+if
.[link];; bueno(if-let [resultado (foo x)] (algo-con resultado) (algo-mas));; malo(let [resultado (foo x)] (if resultado (algo-con resultado) (algo-mas)))
Usa
when-let
en lugar delet
+when
.[link];; bueno(when-let [resulatado (foo x)] (haz-algo-con resulatado) (haz-algo-mas-con resulatado));; malo(let [resulatado (foo x)] (when resulatado (haz-algo-con resulatado) (haz-algo-mas-con resulatado)))
Usa
if-not
en lugar de(if (not ...) ...)
.[link];; bueno(if-not predicado (foo));; malo(if (not predicado) (foo))
Usa
when-not
en lugar de(when (not ...) ...)
.[link];; bueno(when-not pred (foo) (bar));; malo(when (not pred) (foo) (bar))
Usa
when-not
en lugar de(if-not ... (do ...)
.[link];; bueno(when-not predicado (foo) (bar));; malo(if-not predicado (do (foo) (bar)))
Usa
not=
en lugar de(not (= ...))
.[link];; bueno(not= foo bar);; malo(not (= foo bar))
Usa
printf
en lugar de(print (format ...))
.[link];; bueno(printf"Hola, %s!\n" nombre);; ok(println (format"Hola, %s!" nombre))
Al hacer comparaciones,recuerda que la funciones en Clojure como
<
,>
, etc. aceptan unnumero variable de argumentos.[link];; bueno(<5 x10);; malo(and (> x5) (< x10))
Debes preferir
%
en lugar de%1
en funciones literales con solo un argumento.[link];; bueno#(Math/round %);; malo#(Math/round %1)
Debes preferir
%1
en lugarde%
en funciones literales con más de un argumento.[link];; bueno#(Math/pow %1 %2);; malo#(Math/pow % %2)
No envuelvas funciones enotras funciones anónimas cuando no sea necesario.[link]
;; bueno(filter even? (range110));; malo(filter #(even? %) (range110))
No uses funcionesliterales si el cuerpo de la función consiste en más de una forma.[link]
;; bueno(fn [x] (println x) (* x2));; malo ya que necesitas usa la forma `do`#(do (println %) (* %2))
Debes preferir el uso de
complement
enlugar de una función anónima.[link];; bueno(filter (complement predicado?) coll);; malo(filter #(not (predicado? %)) coll)
Esta regla debe de ser ignorada si el complemento de un predicadoexiste como otra función como es el caso con
even?
yodd?
Aplica el uso de
comp
cuando su uso produzcacódigo más simple[link];; Asumiendo `(:require [clojure.string :as str])`...;; bueno(map #(str/capitalize (str/trim %)) ["tope"" prueba"]);; mejor(map (comp str/capitalize str/trim) ["tope"" prueba"])
Aplica el uso de
partial
cuando su usoproduzca código más simple[link];; bueno(map #(+5 %) (range110));; discutiblemente mejor(map (partial +5) (range110))
Debes preferir el uso de threadingmacros como
->
o->>
en vez de tener muchas expresiones una dentrode la otra.[link];; bueno(-> [123] reverse (conj4) prn);; no tan bueno(prn (conj (reverse [123])4));; bueno(->> (range110) (filter even?) (map (partial *2)));; no tan bueno(map (partial *2) (filter even? (range110)))
Usa
:else
como la últimaexpresión de prueba encond
.[link];; bueno(cond (neg? n)"negativo" (pos? n)"positivo":else"cero");; malo(cond (neg? n)"negativo" (pos? n)"positivo"true"cero")
Debes preferir el uso de
condp
en lugar decond
cuando el predicado y la expresión no cambian.[link];; bueno(cond (= x10):diez (= x20):veinte (= x30):treinta:else:desconocido);; much better(condp = x10:diez20:veinte30:treinta:desconocido)
Debes preferir
case
en lugar decond
ocondp
cuando las expresiones de prueba son contantes durante el tiempo decompilación.[link];; bueno(cond (= x10):diez (= x20):veinte (= x30):treinta:else:dunno);; mejor(condp = x10:diez20:veinte30:treinta:dunno);; lo mejor(case x10:diez20:veinte30:treinta:dunno)
Usa formas cortas en
cond
y formasrelacionadas. Cuando esto no sea posible, trata de proveer pistasvisuales indicando los grupos que son pares a través de comentarios olíneas vacías.[link];; bueno(cond (prueba1) (accion1) (prueba2) (accion2):else (accion-por-defecto));; más o menos(cond;; prueba caso 1 (prueba1) (funcion-larga-que-require-una-nueva-linea (subforma-complicada (-> 'que-ocupa multiples-lineas)));; prueba caso 2 (prueba2) (otra-funcion-larga (con-otra-subforma (-> 'que-ocupa multiples-lineas))):else (el-caso-de-accion-por-defecto (que-tambien-abarca 'multiples lineas)))
Usa un conjunto o
set
como predicadocuando sea apropiado[link];; bueno(remove #{1} [012345]);; malo(remove #(= %1) [012345]);; bueno(count (filter #{\a \e \i \o \u}"un elefante se balanceaba"));; malo(count (filter #(or (= % \a) (= % \e) (= % \i) (= % \o) (= % \u))"un elefante se balanceaba"))
Usa
(inc x)
y(dec x)
en lugar de(+ x 1)
y(- x 1)
.[link]Usa
(pos? x)
,(neg? x)
y(zero? x)
enlugar de(> x 0)
,(< x 0)
y(= x 0)
.[link]Usa
list*
en lugarde una lista en línea de invocaciones decons
.[link];; bueno(list*123 [45]);; malo(cons1 (cons2 (cons3 [45])))
Usa formas de interoperación conJava que han sido endulzadas sintácticamente[link]
;;; Creación de objetos;; bueno(java.util.ArrayList.100);; malo(new java.util.ArrayList100);;; Invocación de método estático;; bueno(Math/pow210);; malo(. Math pow210);;; invocación de método de instancia;; bueno(.substring"hola"13);; malo(."hola" substring13);;; acceso a campo o valor estático;; buenoInteger/MAX_VALUE;; malo(. Integer MAX_VALUE);;; acceso de campo o valor de instancia;; bueno(.algunCampo algun-objeto);; malo(. algun-objeto algunCampo)
Usa unaanotación compacta para metadatos para quienes sus valores han de serbooleanos.[link]
;; bueno(def ^:privatea5);; malo(def ^{:privatetrue}a5)
Denota secciones privadas de tu código comotal.[link]
;; bueno(defn-funcion-privada []...)(def ^:privatevar-privada...);; malo(defnfuncion-privada []...); no es privada en lo absoluto(defn ^:privatefuncion-privada []...); demasiado verboso(defvar-privada...); no es privada en lo absoluto
Para acceder una var privada, porejemplo, durante tus pruebas, usa la forma
@# algun.ns/var
[link]Ten cuidado con respecto aexactamente que se le adjuntan metadatos.[link]
;; se le adjuntan metadatos a la var referenciada por `a`(def ^:privatea {})(meta a);=> nil(meta #'a);=> {:private true};; se le adjuntan metadatos al valor vacío del hash-map(defa ^:private {})(meta a);=> {:private true}(meta #'a);=> nil
Las únicas dificultades reales en la programación son la invalidaciónde caché y el nombrar las cosas.
-- Phil Karlton
Al nombrar tus namespaces, usa lassiguientes dos esquemas:[link]organizacion
proyecto.modulo
organizacion.proyecto.modulo
Usa el nombramiento estilo
lisp
consegmentos compuestos de namespaces como por ejemplodiego.project-euler
)[link]Usa el nombramiento estilo
lisp
paranombres de funciones y variables.[link];; bueno(defalguna-var...)(defnalguna-funcion...);; malo(defalgunaVar...)(defnalgunafuncion...)(defalguna_funcion...)
Usael nombramiento estilo
CamelCase
para protocolos, records, y tipos yasegúrate de mantener en mayúscula siglas como HTTP, RFC, XML.[link]Al nombrar métodos quefuncionan como predicados, es decir, aquellos que retornan un valorbooleano de true o false, deben de terminar con un signo deinterrogación.[link]
;; bueno(defnpalindromo?...);; malo(defnpalindromo-p...); Estilo de Common Lisp(defnes-palindromo...); Estilo de Java
Los nombres defunciones o macros que no son seguras bajo transacciones STM deben determinar con un signo de admiración.[link]
Usa
->
al nombrar funciones deconversion.[link];; bueno(defnf->c...);; no tan bueno(defnf-a-c...)
Agrégaleasteriscos al principio y al final de los nombres devariables dinámicas.[link]
;; bueno(def ^:dynamic *a*10);; malo(def ^:dynamica10)
Recuerda que no es necesario usarninguna anotación especial para denotar constantes. Esto es debido aque se asume que todo es constante a menos que se especifique locontrario.[link]
Usa un guión bajo
_
para denotar argumentos o variables de deconstrucción cuyo valor no esusado por el resto del cuerpo.[link];; bueno(let [[a b _ c] [1234]] (println a b c))(dotimes [_3] (println"Hello!"));; malo(let [[a b c d] [1234]] (println a b d))(dotimes [i3] (println"Hola!"))
Sigue el ejemplo del namespace
clojure.core
usando nombres comopred
ycoll
.- en funciones, usa
f
,g
,h
- para representar argumentosn
- para representar una cantidadindex
,i
- para representar un índice numeralx
,y
- para númerosxs
- para secuenciasm
- para mapass
- para stringsre
- para expresiones regulares o regexcoll
- para coleccionespred
- para predicados& more
- para representar argumentos variadosxf
- para una xforma o un transducer
- en macros, usa
expr
- para expresionesbody
- para el cuerpo del macrobinding
- para el vector de enlace en el macro
- en funciones, usa
Es mejor tener 100 funciones que operan una sola estructura de datosque tener 10 funciones que operan en 10 estructuras de datos
--Alan J. Perlis
A menos de que su estructura sea necesaria,evita usar listas para uso genérico.[link]
Debes preferir el uso dekeywords como claves o keys.[link]
;; bueno{:nombre"Daniel":edad30};; malo{"nombre""Daniel""edad"30}
Debes preferir el uso del sintaxisliteral para colecciones en vez de sus respectivos constructores. Sinembargo, al definir conjuntos o sets, solo usa el sintaxis literal silos valores son constantes al momento de compilación.[link]
;; bueno[123]#{123}(hash-set (func1) (func2)); Valores determinados en compilación;; malo(vector123)(hash-set123)#{(func1) (func2)}; Lanzará una excepción si (func1) = (func2)
En lo posible, evita tener que acceder miembros de una colecciónusando su índice.[link]
Debes preferir el usode keywords como funciones al acceder valores de mapas.[link]
(defm {:nombre"Daniel":edad30});; bueno(:nombre m);; más verboso de lo necesario(get m:nombre);; malo - suceptible a un NullPointerException(m:nombre)
Utiliza el hecho de que la mayoría decolecciones actúan como funciones de sus miembros.[link]
;; bueno(filter #{\a \e \o \i \u}"esto es una prueba");; malo - demasiado feo para ser compartido
Utiliza el hecho de que keywords puedenactuar como funciones de una colección[link]
((juxt:a:b) {:a"ala":b"bala"})
Evita hacer tus colecciones"transient", a menos que se trate de pociones de tu código que necesitanmuy alto rendimiento.[link]
Evita el uso de colecciones de Java.[link]
Evita el uso de arrays de Java,excepto en escenarios de interoperabilidad o código de altorendimiento que trata con tipos de Java primitivos.[link]
Considera envolver todas tus usos de input/output, o I/O con el macroio!
para evitar malas sorpresas si accidentalmente llamas ese tipo decódigo en una transacción. Esto es debido a que las transaccionespueden ser llamadas varias veces y, por ende, el código que contienendebe ser puro (sin efectos externos).[link]
Evita el uso de
ref-set
en loposible.[link](defr (ref0));; bueno(dosync (alter r +5));; malo(dosync (ref-set r5))
Intenta de mantener al mínimo el tamaño de tus transacciones, esdecir, la cantidad de trabajo encapsulada en ellas.[link]
Evitatener transacciones largas y cortas interactuando con un mismo Ref.[link]
Usa
send
solamente para accioneslimitadas por la CPU y que no bloquean hilos o threads, en especialel de I/O.[link]Usa
send'off
para acciones quepueden, de alguna forma, bloquear un thread.[link]
Evita actualizarátomos dentro de transacciones STM.[link]
En lo posible, debespreferir el uso de
swap!
en lugar dereset!
.[link](defa (atom0));; bueno(swap! a +5);; no tan bueno(reset! a5)
Debes preferir el uso de funciones de manipulaciones provenientes de
clojure.string
en lugar de interoperar con Java o escribir tuspropias versiones.[link];; bueno(clojure.string/upper-case"daniel");; malo(.toUpperCase"daniel")
Si es necesario lanzaruna excepción, asegúrate de usar tipos de excepciones ya existentes.Por ejemplo,
java.lang.IllegalArgumentException
,java.lang.UnsupportedOperationException
,java.lang.IllegalStateException
,java.io.IOException
[link]Debes preferir el usode
with-open
en lugar definally
.[link]
No escribas un macro si una función es suficiente.[link]
Construyeun ejemplo de uso para un macro antes de escribir el macro en sí.[link]
En lo posible, divide macroscomplicados en funciones pequeñas.[link]
Un macro debe proveer
azúcar sintáctico
, es decir, debe simplificar el formaciónsintáctica de la expresión. El núcleo del macro deben de serfunciones simples ya que esto incrementa su capacidad de compilación.[link]Debes preferir formas con sintaxis citado en lugar de laconstrucción manual de listas.[link]
Buen código es su mejor propia documentación. Al prepararte paraagregar un comentario, debes preguntarte, "¿Cómo puedo mejorar micódigo de tal forma que este comentario no sea necesario?" Mejora tucódigo primero y después documéntalo para hacerlo aun más claro.
-- Steve McConnell
Haz que tu código sea tanauto-documentado como sea posible.[link]
Escribecomentarios de encabezadura con al menos 4 puntos y comas.[link]
Escribe comentarios principales con 3 puntos y comas.[link]
Escribe comentarios acerca de un fragmento de código con dos puntos ycomas. Además, asegúrate de escribir el comentario antes del fragmentoque al que hace referencia y alinéalo a él.[link]
Escribe comentarios marginales con un punto y coma.[link]
Asegúrate de siempre tener al menos un espacio entre un punto y coma yel texto que lo prosigue.[link]
;;;; Título;;; Esta sección de código tiene estas importantes implicaciones:;;; 1. Foo.;;; 2. Bar.;;; 3. Baz.(defnfuncion [argumento];; Si zob, entonces veeblefitz. (quux zot mumble; Zibblefrotz. frotz))
Comentarios compuestos de más de una palabra deben empezar conmayúscula y usar puntuación. También separa oraciones con unun espacio.[link]
Evita el uso de comentarios innecesarios.[link]
;; malo(inc contador); Incrementa el valor del contador por uno
Mantén vigentes tus comentarios. Uncomentario desactualizado es peor que no tener un comentario.[link]
Debes preferir el uso demacro lector
#_
en lugar de un comentario regular al comentar unaforma en su totalidad.[link];; bueno(+ foo #_(bar x) delta);; malo(+ foo;; (bar x) delta)
Buen código es como un buen chiste... no necesita explicación.
-- Russ Olsen
- Evita escribir comentarios paradocumentar código malo. Mejora tu código con el fin de hacer que seauto documente. ("Hacer, o no hacer. No hay intentar." --Yoda)[link]
Anotaciones debe de ser escritas en lalínea inmediatamente antes del código al que referencia.[link]
La anotación debe estar compuestapor el keyword de anotacion seguido por dos puntos y un espacio,después por una nota describiendo el problema.[link]
Si la descripción de un problemarequiere el uso de múltiples líneas, todas las líneas deben seguirla misma indentación o sangría de la primera línea.[link]
Marca tu anotación confecha e iniciales para que su relevancia sea fácilmente verificada.[link]
(defnalguna-funcion [];; FIXME: Esto ha causado problemas ocasionalmente en v1.2.3.;; Es posible que sea relacionado con la actualizacion;; de BarUtilidad (xz 13-1-31) (baz))
En casos donde el problema estan evidente que cualquier tipo de documentación es redundante,anotaciones sin notas pueden ser hechas después del código al que sehace referencia. Recuerda que este uso debe ser la excepción y no laregla.[link]
(defnbar [] (sleep100)); OPTIMIZE
Usa
TODO
para marcar funcionalidad que debeser agregada después.[link]Usa
FIXME
para marcar código fallido que debeser arreglado.[link]Usa
OPTIMIZE
para marcar código lento oineficiente que puede causar problemas de rendimiento[link]Usa
HACK
para anotar usos cuestionables de laspracticas usadas que deben ser corregidas.[link]Usa
REVIEW
para marcar código que debe serrevisado para confirmar que esta trabajando correctamente. Porejemplo:REVIEW: ¿Estamos segurlos que el cliente untiliza X en este momento?
[link]Usa otros keywords de anotacioncuando sea apropriado y asegúrate de documentarlos en el
README
oarchivo equivalente de tu proyecto.[link]
Escribe código de forma funcionalusando mutación solo cuando tenga sentido.[link]
Sé consistente con el uso de esta guía.[link]
Usa el sentido común.[link]
Aquí presentamos algunas herramientas creadas por la comunidad deClojure que pueden ayudarte en tu camino para escribir Clojure idiomático.
Slamhound es unaherramienta que automáticamente genera declaraciones de
ns
para tucódigo existente.kibit es un analizador estático decódigo para Clojure que usa[core.logic](https://github.com/clojure/core.logic para encontrarpatrones de código para los cuales pueden existir formas, funciones, omacros más idiomáticos.
Guarda tus pruebas en undirectorio separado. Normalmente, bajo
test/tuproyecto/
en lugardesrc/tuproyecto/
. Tu herramienta de construcción esresponsable de hacer que estos archivos estén disponibles donde seannecesarios. La mayoría de modelos hacen esto automáticamente.[link]Nombre tu ns
tuproyecto.algo-test
, un archivo que usualmente es nombradotest/tuproyecto/algo_test.clj
(o.cljc
,cljs
).[link]Al usar
clojure.test, define tus prubeas con
deftesty nombrales
algo-test`. Por ejemplo;; bueno(deftestalgo-test...);; malo(deftestalgo-tests...)(deftesttest-algo...)(deftestalgo...)
[link]
Si estas publicando librerías con elfin de que sean usadas por otros, asegúrate de seguir laCentralRepositoryguidelinespara escoger tu
groupId
andartifactId
. Esto ayuda prevenirconflictos de nombre y facilita cualquier tipo de uso. Un buenejemplo es el deComponent.[link]Evita incluir dependencias innecesarias. Por ejemplo, es preferiblecopiarle una función de 3 líneas a tu proyecto en lugar de unadependencia que conlleva cientos de vars que no piensas usar.[link]
Separa la funcionalidadcentral de tu librería y sus puntos de integración en distintosartefactos. De esta forma, usuarios pueden consumir tu librería sintener que estar atados a preferencias de herramientas externas. Porejemplo,Componentprovee functionalidad central, yreloaded proveeintegración con Leiningen.[link]
Nada escrito en esta guía está escrito en piedra. Mi deseo es trabajarjunto con todos aquellos interesados en el estilo de código Clojurecon el fin de poder construir un recurso que sea beneficioso para lacomunidad entera de Clojure.
No tengas miedo de abrir tickets o hacer pull requests con mejorías.De antemano, muchas gracias por tu ayuda!
Es posible contribuir a la guía de estilo financialmente a través degittip.
Este trabajo está licenciado bajo la licenciaCreative Commons Attribution 3.0 Unported License
Una guía de estilo escrita por la comunidad es de poco uso si la mismacomunidad no sabe de su existencia. Por ende, comparte la guía con tusamigos y colegas. Cada comentario, sugerencia u opinión hace que estaguía sea solo un tanto mejor. Y queremos tener la mejor guía posible, cierto?
Salud,Bozhidar
About
Una guía de estilo para Clojure escrita por la comunidad
Resources
Uh oh!
There was an error while loading.Please reload this page.