Skip to content

Latest commit

 

History

History
1283 lines (1004 loc) · 32.9 KB

README_esES.md

File metadata and controls

1283 lines (1004 loc) · 32.9 KB

Tabla de Contenidos

Preludio

Arquitectura líquida. Es como el jazz — improvisáis, trabajáis juntos, tocáis los unos con los otros, haces algo, hacen algo.

—Frank Gehry

El estilo importa. Aunque Elixir tiene mucho estilo, como ocurre con todos los lenguajes, puede estropearse. No estropees el estilo.

Esta es la guía de estilo de la comunidad para el lenguaje de programación Elixir. Por favor, siéntete libre de abrir pull requests y sugerencias, y ¡forma parte de la vibrante comunidad de Elixir!

Si estás buscando otros proyectos en los que contribuir, por favor ve al sitio web de Hex package manager.

  • Usa dos espacios por nivel de indentación. No utilices tabulaciones. [enlace]

    # no recomendado - cuatro espacios
    def some_function do
        do_something
    end
    
    # recomendado
    def some_function do
      do_something
    end
  • Usa los finales de línea de Unix (Los usuarios de *BSD/Solaris/Linux/OSX ya están cubiertos por defecto, pero los usuarios de Windows tendrán que prestar especial atención). [enlace]

  • Si usas Git puede que quieras utilizar la siguiente configuración para protegerte de que se te cuelen los finales de línea en Windows: [enlace]

    git config --global core.autocrlf true
  • Usa espacios alrededor de operadores, después de comas, dos puntos y de punto y coma. No coloques espacios alrededor de parejas como llaves, paréntesis, etc. Los espacios en blanco puede que sean (en la mayoría de casos) irrelevantes para Elixir en tiempo de ejecución, pero su uso apropiado es clave para escribir código fácilmente legible. [enlace]

    sum = 1 + 2
    {a, b} = {2, 3}
    [first | rest] = [1, 2, 3]
    Enum.map(["one", <<"two">>, "three"], fn num -> IO.puts num end)
  • No utilices espacios después de operadores que no sean una palabra y que sólo reciben un argumento; o alrededor del operador de rango. [enlace]

    0 - 1 == -1
    ^pinned = some_func()
    5 in 1..10
  • Utiliza líneas en blanco entre defs para separar las funciones en párrafos lógicos. [enlace]

    def some_function(some_data) do
      altered_data = Module.function(data)
    end
    
    def some_function do
      result
    end
    
    def some_other_function do
      another_result
    end
    
    def a_longer_function do
      one
      two
    
      three
      four
    end
  • ...pero no dejes líneas en blanco cuando tengas defs de una sola línea cuyos argumentos representen pattern matching. [enlace]

    def some_function(nil), do: {:err, "No Value"}
    def some_function([]), do: :ok
    def some_function([first | rest]) do
      some_function(rest)
    end
  • Si utilizas la sintaxis do: con funciones y la línea que constituye el cuerpo de la función es demasiado larga, pon el do: en una nueva línea con un nivel de indentación más que la línea anterior. [enlace]

    def some_function(args),
      do: Enum.map(args, fn(arg) -> arg <> " is on a very long line!" end)

    Si tienes varias funciones con el mismo nombre y en alguno de los casos la línea que constituye el cuerpo de la función es demasiado larga, pon el do: en una nueva línea para cada función:

    # no recomendado
    def some_function([]), do: :empty
    def some_function(_),
      do: :very_long_line_here
    
    # recomendado
    def some_function([]),
      do: :empty
    def some_function(_),
      do: :very_long_line_here
  • Si tienes más de un defs multilínea, no utilices defs de una sola línea. [enlace]

    def some_function(nil) do
      {:err, "No Value"}
    end
    
    def some_function([]) do
      :ok
    end
    
    def some_function([first | rest]) do
      some_function(rest)
    end
    
    def some_function([first | rest], opts) do
      some_function(rest, opts)
    end
  • Usa el operador pipe (|>) para encadenar funciones una tras otra. [enlace]

    # no recomendado
    String.strip(String.downcase(some_string))
    
    # recomendado
    some_string |> String.downcase |> String.strip
    
    # Los pipelines multilínea no se indentan a mayores
    some_string
    |> String.downcase
    |> String.strip
    
    # Los pipelines multilínea que estén en el lado derecho de un pattern match
    # deben ser indentados en una nueva línea
    sanitized_string =
      some_string
      |> String.downcase
      |> String.strip

    Aunque este sea el método recomendado, ten en cuenta que al copiar y pegar pipelines multilínea en IEx podría causar un error de sintaxis, ya que IEx evaluará la primera línea sin darse cuenta de que la siguiente línea tiene otro pipeline.

  • Evita utilizar el operador pipe una única vez. [enlace]

    # no recomendado
    some_string |> String.downcase
    
    # recomendado
    String.downcase(some_string)
  • Utiliza variables simples (bare variables) como comienzo de una cadena de funciones. [enlace]

    # ¡NUNCA HAGAS ESTO!
    # Realmente se interpretará como String.strip("nope" |> String.downcase).
    String.strip "nope" |> String.downcase
    
    # no recomendado
    String.strip(some_string) |> String.downcase |> String.codepoints
    
    # recomendado
    some_string |> String.strip |> String.downcase |> String.codepoints
  • Al definir una lista que ocupa varias líneas, inicia la lista en una nueva línea, e indenta los elementos para mantenerlos alineados. [enlace]

    # no recomendado - sin indentación
    list = [:first_item, :second_item, :next_item,
    :last_item]
    
    # mejor, pero no recomendado - con indentación
    list = [:first_item, :second_item, :next_item,
            :last_item]
    
    # recomendado - la lista comienza en su propia línea
    # bueno para listas cortas y compactas
    list =
      [:first_item, :second_item, :next_item,
       :last_item]
    
    # también recomendado - cuando cada elemento está en su propia línea
    # bueno para listas largas, listas con elementos largos, o listas con comentarios
    list = [
      :first_item,
      :second_item,
      :next_item,
      # comentario
      :many_items,
      :last_item
    ]
  • Evita los espacios y tabulaciones al final de línea (trailing whitespace). [enlace]

  • Termina cada fichero con una nueva línea. [enlace]

Sintaxis

  • Usa paréntesis cuando def tenga argumentos, y omítelos cuando no. [enlace]

    # no recomendado
    def some_function arg1, arg2 do
      # body omitted
    end
    
    def some_function() do
      # body omitted
    end
    
    # recomendado
    def some_function(arg1, arg2) do
      # body omitted
    end
    
    def some_function do
      # body omitted
    end
  • Añade una línea en blanco tras una "asignación" multilínea como una pista visual de que ha terminado. [enlace]

    # no recomendado
    some_string =
      "Hello"
      |> String.downcase
      |> String.strip
    another_string <> some_string
    
    # recomendado
    some_string =
      "Hello"
      |> String.downcase
      |> String.strip
    
    another_string <> some_string
    # tampoco recomendado
    something =
      if x == 2 do
        "Hi"
      else
        "Bye"
      end
    something |> String.downcase
    
    # recomendado
    something =
      if x == 2 do
        "Hi"
      else
        "Bye"
      end
    
    something |> String.downcase
  • Nunca utilices do: para if/unless multilínea. [enlace]

    # no recomendado
    if some_condition, do:
      # a line of code
      # another line of code
      # note no end in this block
    
    # recomendado
    if some_condition do
      # some
      # lines
      # of code
    end
  • Utiliza do: para sentencias if/unless de una sola línea. [enlace]

    # recomendado
    if some_condition, do: # some_stuff
    
  • Nunca utilices unless con else. Reescríbelo poniendo el caso positivo primero. [enlace]

    # no recomendado
    unless success? do
      IO.puts 'failure'
    else
      IO.puts 'success'
    end
    
    # recomendado
    if success? do
      IO.puts 'success'
    else
      IO.puts 'failure'
    end
  • Utiliza true como la última condición de cond cuando necesites una cláusula por defecto. [enlace]

    # no recomendado
    cond do
      1 + 2 == 5 ->
        "Nope"
      1 + 3 == 5 ->
        "Uh, uh"
      :else ->
        "OK"
    end
    
    # recomendado
    cond do
      1 + 2 == 5 ->
        "Nope"
      1 + 3 == 5 ->
        "Uh, uh"
      true ->
        "OK"
    end
  • Nunca dejes un espacio entre el nombre de la función y el paréntesis de apertura. [enlace]

    # no recomendado
    f (3 + 2) + 1
    
    # recomendado
    f(3 + 2) + 1
  • Utiliza paréntesis en las llamadas a funciones, sobretodo dentro de un pipeline. [enlace]

    # no recomendado
    f 3
    
    # recomendado
    f(3)
    
    # no recomendado y además se interpreta como rem(2, (3 |> g)), que no es lo que quieres.
    2 |> rem 3 |> g
    
    # recomendado
    2 |> rem(3) |> g
  • Omite los paréntesis en las llamadas a macros en las que se pasa un bloque do. [enlace]

    # no recomendado
    quote(do
      foo
    end)
    
    # recomendado
    quote do
      foo
    end
  • Opcionalmente omite los paréntesis en llamadas a funciones (fuera de un pipeline) cuando el último argumento es una función. [enlace]

    # recomendado
    Enum.reduce(1..10, 0, fn x, acc ->
      x + acc
    end)
    
    # también recomendado
    Enum.reduce 1..10, 0, fn x, acc ->
      x + acc
    end
  • Usa paréntesis para llamadas a funciones con aridad cero, de tal forma que puedan ser distinguidas de las variables. A partir de Elixir 1.4, el compilador te avisará de los lugares en los que exista ambigüedad. [enlace]

    defp do_stuff, do: ...
    
    # no recomendado
    def my_func do
      do_stuff # ¿es una variable o una llamada a una función?
    end
    
    # recomendado
    def my_func do
      do_stuff() # esto es claramente una llamada a una función
    end
  • Utiliza siempre la sintaxis especial para listas de keywords. [enlace]

    # no recomendado
    some_value = [{:a, "baz"}, {:b, "qux"}]
    
    # recomendado
    some_value = [a: "baz", b: "qux"]
  • Omite los corchetes de las listas de keywords siempre que sean opcionales. [enlace]

    # no recomendado
    some_function(foo, bar, [a: "baz", b: "qux"])
    
    # recomendado
    some_function(foo, bar, a: "baz", b: "qux")
  • Indenta y alinea las cláusulas with sucesivas. Pon el argumento do: en una nueva línea, indentada normalmente. [enlace]

    with {:ok, foo} <- fetch(opts, :foo),
         {:ok, bar} <- fetch(opts, :bar),
      do: {:ok, foo, bar}
  • Si la expresión with tiene un bloque do con más de una línea, o tiene una opción else, utiliza la sintaxis multilínea. [enlace]

    with {:ok, foo} <- fetch(opts, :foo),
         {:ok, bar} <- fetch(opts, :bar) do
      {:ok, foo, bar}
    else
      :error ->
        {:error, :bad_arg}
    end

Nombrado

  • Usa snake_case para atoms, funciones y variables. [enlace]

    # no recomendado
    :"some atom"
    :SomeAtom
    :someAtom
    
    someVar = 5
    
    def someFunction do
      ...
    end
    
    def SomeFunction do
      ...
    end
    
    # recomendado
    :some_atom
    
    some_var = 5
    
    def some_function do
      ...
    end
  • Usa CamelCase para módulos (mantén los acrónimos como HTTP, RFC, XML en mayúsculas). [enlace]

    # no recomendado
    defmodule Somemodule do
      ...
    end
    
    defmodule Some_Module do
      ...
    end
    
    defmodule SomeXml do
      ...
    end
    
    # recomendado
    defmodule SomeModule do
      ...
    end
    
    defmodule SomeXML do
      ...
    end
  • Los nombres de macros predicado (funciones generadas en tiempo de compilación que devuelven un valor booleano) que pueden ser utilizadas dentro de guards deberían prefijarse con is_. Para una lista de las expresiones permitidas, échale un vistazo a la documentación de Guard. [enlace]

    defmacro is_cool(var) do
      quote do: unquote(var) == "cool"
    end
  • Los nombres de las funciones predicado que no pueden ser usadas dentro de guards deberían de terminar en signo de interrogación (?) en lugar de tener un prefijo is_ (o similar). [enlace]

    def cool?(var) do
      # Complex check if var is cool not possible in a pure function.
    end
  • Las funciones privadas que compartan el mismo nombre con alguna función pública deben empezar con do_. [enlace]

    def sum(list), do: do_sum(list, 0)
    
    # private functions
    defp do_sum([], total), do: total
    defp do_sum([head | tail], total), do: do_sum(tail, head + total)

Comentarios

  • Escribe código expresivo e intenta transmitir la intención de tu programa a través de flujos de control, estructura y nombrado. [enlace]

  • Utiliza un espacio entre el carácter introductorio del comentario # y el resto del texto del comentario. [enlace]

    String.first(some_string) #no recomendado
    String.first(some_string) # recomendado
  • Los comentarios que sean más largos de una palabra se escribirán capitalizados, y las frases utilizarán signos de puntuación. Usa un espacio tras cada punto. [enlace]

    # no recomendado
    # a estos comentarios en minúsculas les falta los signos de puntuación
    
    # recomendado
    # Ejemplo de capitalización
    # Usa signos de puntuación para frases completas.
  • Las anotaciones se escriben normalmente en la línea inmediatamente superior al código que anotan. [enlace]

  • La palabra clave para la anotación estará completamente en mayúsculas, seguida de dos puntos y un espacio, a continuación se añade la nota que describe el problema. [enlace]

    # TODO: Deprecate in v1.5.
    def some_function(arg), do: {:ok, arg}
  • En casos en los que el problema sea tan obvio que cualquier tipo de documentación resultará redundante, puedes poner las anotaciones al final de la línea sin ningún tipo de nota. Este uso debería de ser la excepción y no la norma. [enlace]

    start_task()
    Process.sleep(5000) # FIXME
  • Utiliza TODO para anotar código que falte o funcionalidades que deberán ser añadidas posteriormente. [enlace]

  • Utiliza FIXME para denotar código que debe ser arreglado. [enlace]

  • Utiliza OPTIMIZE para denotar código lento o ineficiente que pudiese llegar a causar problemas de rendimiento. [enlace]

  • Utiliza HACK para denotar "code smells" en los que se hayan empleado prácticas de programación cuestionables y que deban ser refactorizados. [enlace]

  • Utiliza REVIEW para denotar cualquier cosa que deba ser revisada para confirmar que funciona como se espera. Por ejemplo: REVIEW: Are we sure this is how the client does X currently? [enlace]

  • Utiliza claves de anotación propias si lo consideras oportuno, pero asegúrate de documentarlas en el fichero README de tu proyecto o similar. [enlace]

  • Utiliza un fichero por módulo a no ser que el módulo sea utilizado únicamente de manera interna por otro módulo (como en el caso de un test). [enlace]

  • Utiliza snake_case para el nombre del fichero y CamelCase para el nombre del módulo. [enlace]

    # el fichero se llama some_module.ex
    
    defmodule SomeModule do
    end
  • Representa cada nivel de anidación dentro del módulo como un directorio. [enlace]

    # el fichero se llama parser/core/xml_parser.ex
    
    defmodule Parser.Core.XMLParser do
    end
  • No dejes una línea en blanco tras defmodule. [enlace]

  • Deja una línea en blanco después de cada bloque de código a nivel de módulo. [enlace]

  • Lista los atributos y directivas del módulo en el siguiente orden: [enlace]

    1. @moduledoc
    2. @behaviour
    3. use
    4. import
    5. alias
    6. require
    7. defstruct
    8. @type
    9. @module_attribute
    10. @callback
    11. @macrocallback
    12. @optional_callbacks

    Añade una línea en blanco entre cada grupo, y ordena alfabéticamente los términos (como nombres de módulo). Aquí tienes un ejemplo general de cómo deberías ordenar el código en tus módulos:

    defmodule MyModule do
      @moduledoc """
      An example module
      """
    
      @behaviour MyBehaviour
    
      use GenServer
    
      import Something
      import SomethingElse
    
      alias My.Long.Module.Name
      alias My.Other.Module.Example
    
      require Integer
    
      defstruct name: nil, params: []
    
      @type params :: [{binary, binary}]
    
      @module_attribute :foo
      @other_attribute 100
    
      @callback some_function(term) :: :ok | {:error, term}
    
      @macrocallback macro_name(term) :: Macro.t
    
      @optional_callbacks macro_name: 1
    
      ...
    end
  • Usa la pseudo variable __MODULE__ cuando un módulo se refiera a sí mismo. Esto evitará que tengas que actualizar cualquier referencia cuando el nombre del módulo cambie. [enlace]

    defmodule SomeProject.SomeModule do
      defstruct [:name]
    
      def name(%__MODULE__{name: name}), do: name
    end
  • Si prefieres utilizar otro nombre para esta referencia, define un alias. [enlace]

    defmodule SomeProject.SomeModule do
      alias __MODULE__, as: SomeModule
    
      defstruct [:name]
    
      def name(%SomeModule{name: name}), do: name
    end
  • Evita repeticiones en los nombres de módulos y espacios de nombrado. Mejorará la legibilidad global y elimina alias ambiguos. [enlace]

    # no recomendado
    defmodule Todo.Todo do
      ...
    end
    
    # recomendado
    defmodule Todo.Item do
      ...
    end

Documentación

La documentación en Elixir (ya sea cuando es leída en iex mediante h o cuando es generada con ExDoc) utiliza los atributos de módulo @moduledoc y @doc.

  • Incluye siempre un atributo @moduledoc en la línea inmediatamente posterior a defmodule de tu módulo. [enlace]

    # no recomendado
    
    defmodule SomeModule do
    
      @moduledoc """
      About the module
      """
      ...
    end
    
    defmodule AnotherModule do
      use SomeModule
      @moduledoc """
      About the module
      """
      ...
    end
    
    # recomendado
    
    defmodule SomeModule do
      @moduledoc """
      About the module
      """
      ...
    end
  • Utiliza @moduledoc false si no pretendes documentar un módulo. [enlace]

    defmodule SomeModule do
      @moduledoc false
      ...
    end
  • Separa el código tras @moduledoc con una línea en blanco. [enlace]

    # no recomendado
    
    defmodule SomeModule do
      @moduledoc """
      About the module
      """
      use AnotherModule
    end
    
    # recomendado
    defmodule SomeModule do
      @moduledoc """
      About the module
      """
    
      use AnotherModule
    end
  • Usa heredocs con markdown para la documentación. [enlace]

    # no recomendado
    
    defmodule SomeModule do
      @moduledoc "About the module"
    end
    
    defmodule SomeModule do
      @moduledoc """
      About the module
    
      Examples:
      iex> SomeModule.some_function
      :result
      """
    end
    
    # recomendado
    defmodule SomeModule do
      @moduledoc """
      About the module
    
      ## Examples
    
          iex> SomeModule.some_function
          :result
      """
    end

Typespecs

Typespecs es una notación para declarar tipos y especificaciones, ya sea para documentación o para la herramienta de análisis estático Dialyzer.

Los tipos propios deben de ser definidos en la parte superior del módulo junto con las demás directivas (ver Módulos).

  • Sitúa las definiciones @typedoc y @type juntas, y separa cada par con una línea en blanco. [enlace]

    defmodule SomeModule do
      @moduledoc false
    
      @typedoc "The name"
      @type name :: atom
    
      @typedoc "The result"
      @type result :: {:ok, term} | {:error, term}
    
      ...
    end
  • Si la unión de tipos es demasiado larga para caber en una sola línea, añade una nueva línea e indenta con espacios para mantener los tipos alineados. [enlace]

    # no recomendado - sin indentación
    @type long_union_type :: some_type | another_type | some_other_type |
    a_final_type
    
    # recomendado
    @type long_union_type :: some_type | another_type | some_other_type |
                             a_final_type
    
    # también recomendado - un tipo por línea
    @type long_union_type :: some_type |
                             another_type |
                             some_other_type |
                             a_final_type
  • Nombra al tipo principal para un módulo t, por ejemplo: la especificación de tipo para una struct. [enlace]

    defstruct name: nil, params: []
    
    @type t :: %__MODULE__{
      name: String.t | nil,
      params: Keyword.t
    }
  • Sitúa las especificaciones justo antes de la definición de la función, sin separarlas con una línea en blanco. [enlace]

    @spec some_function(term) :: result
    def some_function(some_data) do
      {:ok, some_data}
    end

Structs

  • Usa una lista de atoms para los campos de la struct que tengan valor nil, seguida del resto de claves. [enlace]

    # no recomendado
    defstruct name: nil, params: nil, active: true
    
    # recomendado
    defstruct [:name, :params, active: true]
  • Omite los corchetes cuando el argumento de defstruct sea una lista de keywords. [enlace]

    # no recomendado
    defstruct [params: [], active: true]
    
    # recomendado
    defstruct params: [], active: true
    
    # obligatorio - los corchetes no son opcionales cuando la lista tenga al menos un atom
    defstruct [:name, params: [], active: true]
  • Indenta las líneas adicionales en la definición de una struct, manteniendo las primeras claves alineadas. [enlace]

    defstruct foo: "test", bar: true, baz: false,
              qux: false, quux: 1

Excepciones

  • Haz que los nombres de las excepciones terminen en Error. [enlace]

    # no recomendado
    defmodule BadHTTPCode do
      defexception [:message]
    end
    
    defmodule BadHTTPCodeException do
      defexception [:message]
    end
    
    # recomendado
    defmodule BadHTTPCodeError do
      defexception [:message]
    end
  • Utiliza mensajes de error en minúsculas cuando lances excepciones. No utilices puntuación al final. [enlace]

    # no recomendado
    raise ArgumentError, "This is not valid."
    
    # recomendado
    raise ArgumentError, "this is not valid"

Colecciones

Por el momento no se han añadido recomendaciones para las colecciones.

Strings

  • Haz match de strings utilizando la concatenación de string en lugar de patrones binarios: [enlace]

    # no recomendado
    <<"my"::utf8, _rest>> = "my string"
    
    # recomendado
    "my" <> _rest = "my string"

Expresiones Regulares

Por el momento no se han añadido recomendaciones para expresiones regulares.

  • Evita la metaprogramación cuando no sea necesaria. [enlace]

Testing

  • Cuando escribas aserciones con ExUnit, se consistente con el orden de los valores esperados y actuales que estás probando. Es preferible poner el valor esperado a la derecha, a no ser que la aserción sea un pattern match. [Enlace]

    # recomendado - resultado esperado a la derecha
    assert actual_function(1) == true
    assert actual_function(2) == false
    
    # no recomendado - orden inconsistente
    assert actual_function(1) == true
    assert false == actual_function(2)
    
    # obligatorio - la aserción es un pattern match
    assert {:ok, expected} = actual_function(3)
  • Aleksei Magusev's Elixir Style Guide — Una guía que surge del estilo de programación utilizado en las librerías del core de Elixir. Desarrollada por Aleksei Magusev y Andrea Leopardi, miembros del equipo principal de Elixir. Aunque el proyecto Elixir no se adhiere a ninguna guía de estilo específica, esta es la guía más cercana a sus convenciones.

  • Credo's Elixir Style Guide — Guía de Estilo para el lenguaje Elixir, implementada para la herramienta de análisis estático de código Credo.

Herramientas

Dirígete a Awesome Elixir para encontrar librerías y herramientas que puedan ayudarte con el análisis de código y corrección estilo.

Contribuir

Es nuestra esperanza que esto se convierta en un lugar central en el que la comunidad discuta las mejores prácticas en Elixir. Estás invitado a abrir tickets y a enviar pull requests con mejoras. ¡Gracias por tu ayuda por adelantado!

Revisa la guía para contribuir y el código de conducta (ambos en inglés) para más información.

Corre la voz

Una guía de estilo de la comunidad no tiene sentido sin el soporte de la comunidad. Por favor tuitea, ponle star, y haz que otros programadores de Elixir conozcan esta guía de forma que puedan contribuir.

Derechos

Licencia

Creative Commons License Este trabajo está hecho bajo licencia Creative Commons Attribution 3.0 Unported License

La estructura de esta guía, partes del código de ejemplo, y muchos otros puntos iniciales de este documento fueron tomados de la Ruby community style guide. Muchas cosas ya eran directamente aplicables a Elixir, lo que nos permitió sacar antes este documento y empezar más rápido.

Aquí está la lista de gente que ha contribuido amablemente a este proyecto.