← Ruby EspañolChapter 13 of 13

Mejores Practicas

## Objetivos de Aprendizaje - Escribir codigo Ruby idiomatico - Seguir las convenciones de la guia de estilo de Ruby - Usar las fortalezas de Ruby efectivamente - Evitar errores comunes ## Guia de Estilo de Ruby ### Convenciones de Nombres ```ruby # Variables y metodos: snake_case primer_nombre = "Alicia" def calcular_total end # Clases y modulos: CamelCase class CuentaUsuario end module ProcesamientoPagos end # Constantes: SCREAMING_SNAKE_CASE MAXIMO_REINTENTOS = 3 TIEMPO_POR_DEFECTO = 30 # Booleanos: terminar con ? o is_ valido? = true esta_activo = true tiene_hijos = false # Metodos bang: terminar con ! def ordenar! @datos.ordenar! end # Metodos peligrosos: terminar con ! def eliminar! @registro.destruir end ``` ### Indentacion y Espaciado ```ruby # Usar 2 espacios para indentacion (no tabs) def nombre_metodo if condicion hacer_algo end end # Espacios alrededor de operadores total = a + b resultado = x * y / z # Sin espacios alrededor de parentesis en definiciones de metodos def saludar(nombre) "Hola, #{nombre}" end # Espacio despues de comas array = [1, 2, 3] hash = { nombre: "Alicia", edad: 30 } ``` ### Longitud de Linea ```ruby # Mantener lineas bajo 120 caracteres # Si es necesario, romper con continuacion nombre_metodo_largo(arg1, arg2, arg3, arg4, arg5) # O usar barra invertida resultado_largo = algun_metodo(arg1) + otro_metodo(arg2) ``` ## Ruby Idiomatico ### Preferir Metodos de Enumerable ```ruby # Mal for n in numeros puts n end # Bien numeros.each { |n| puts n } # Mal resultado = [] numeros.each { |n| resultado << n * 2 } # Bien resultado = numeros.map { |n| n * 2 } # Mal encontrado = nil items.each { |item| encontrado = item if item.valido? } # Bien encontrado = items.find { |item| item.valido? } ``` ### Usar Symbol to Proc ```ruby # Forma larga nombres.map { |nombre| nombre.upcase } # Idiomatico nombres.map(&:upcase) ``` ### Usar ||= Con Mesura ```ruby # Puede causar problemas con valores falsy valor = false valor ||= predeterminado # valor se convierte en predeterminado (incorrecto!) # Enfoque mas seguro valor = predeterminado if valor.nil? # O valor = valor ? valor : predeterminado # O (Ruby 2.3+) valor &&= valor # Solo asigna si es truthy ``` ### Asignacion Paralela ```ruby # Intercambiar variables idiomatically a, b = b, a # Evitar cuando no es necesario x = 1 y = 2 z = x + y # Solo usar lineas separadas ``` ### Condicionales ```ruby # Ternario para casos simples estado = aprobado ? "Exito" : "Fallo" # Clausulas de guardia def procesar(datos) return unless datos.valido? # ... logica principal end # Modificador de una linea puts "debug" if modo_depuracion ``` ## Errores Comunes ### Mutando Constantes ```ruby # Mal DATOS = [1, 2, 3] DATOS << 4 # Modifica el original! # Bien - freeze DATOS = [1, 2, 3].freeze # O clonar cuando sea necesario modificado = DATOS.dup << 4 ``` ### Shadowing de Variables ```ruby # Esto sombrea 'nombre' externo accidentalmente nombre = "Alicia" [1, 2, 3].each do |nombre| # Ahora nombre es 1, 2, 3 en cada iteracion end puts nombre # "Alicia" - aun funciona pero confuso ``` ### Optimizacion Prematura ```ruby # No sacrificar legibilidad por micro-optimizaciones # Mal resultado = mapa { |e| e.to_s } * "" # Bien y claro resultado = mapa(&:to_s).join ``` ### Monkey Patching ```ruby # Arriesgado - puede romper otro codigo class String def es_email? self =~ /@/ end end # Mas seguro - usar refinements module ExtensionesString refine String do def es_email? self =~ /@/ end end end ``` ## Organizacion del Codigo ### Responsabilidad Unica ```ruby # Mal - hace multiples cosas def procesar_usuario(usuario) validar(usuario) guardar(usuario) enviar_email(usuario) registrar(usuario) end # Bien - separar responsabilidades def registrar_usuario(usuario) validar(usuario) guardar(usuario) end def saludar_usuario(usuario) enviar_email(usuario) registrar(usuario) end ``` ### Longitud de Metodos ```ruby # Mal - metodo hace demasiado def importar_y_procesar_datos # 100 lineas de codigo end # Bien - separar en metodos mas pequenos def importar_datos end def procesar_datos end ``` ### Longitud de Clases ```ruby # Mal - Dios object class GestorUsuario def crear_usuario end def eliminar_usuario end def autenticar end def enviar_email end def generar_informe end # 50 mas metodos... end # Bien - Responsabilidad Unica class ServicioUsuario def crear_usuario end end class ServicioAutenticacion def autenticar end end class ServicioNotificacion def enviar_email end end ``` ## Documentacion ### Comentarios ```ruby # Buen comentario - explica POR QUE, no QUE # Logica de reintento necesaria porque la API externa puede ser inestable MAXIMO_REINTENTOS = 3 # Mal comentario - redundante # Incrementar contador por 1 contador += 1 ``` ### RDoc/YARD ```ruby # @param nombre [String] el nombre del usuario # @param edad [Integer] la edad del usuario # @return [Usuario] el usuario creado # @raise [ArgumentError] si el nombre esta vacio def crear_usuario(nombre:, edad:) end ``` ## Consejos de Rendimiento ### Evaluacion Perezosa ```ruby # Mal - crea array completo datos = (1..1_000_000).map { |n| calculo_pesado(n) }.select { |n| n.valido? } # Bien - procesa uno a la vez datos = (1..1_000_000).lazy.map { |n| calculo_pesado(n) }.select { |n| n.valido? }.first(100) ``` ### Construccion de Cadenas ```ruby # Mal - crea cadenas intermedias html = "" partes.each { |parte| html += parte } # Bien html = partes.join ``` ### Usar metodos bang cuando sea apropiado ```ruby # Cuando no necesitas el original lista.ordenar! # Mas eficiente que lista = lista.ordenar ``` ## Mejores Practicas de Pruebas ```ruby # Probar comportamiento, no implementacion # Mal expect(usuario.instance_variable_get(:@nombre)).to eq("Alicia") # Bien expect(usuario.nombre).to eq("Alicia") # Usar nombres de pruebas descriptivos # Mal it "test1" do end # Bien it "retorna el nombre completo del usuario cuando primero y ultimo estan presentes" do end # Una asercion por prueba (generalmente) # Pero las aserciones compuestas estan bien expect(usuario).to have_attributes(nombre: "Alicia", edad: 30, valido: true) ``` ## Mejores Practicas de Seguridad ### Validacion de Entrada ```ruby # Siempre validar entrada def procesar_pedido(id_pedido) raise ArgumentError, "ID de pedido invalido" unless id_pedido.is_a?(Integer) end # Sanitizar antes de SQL (usar consultas parametrizadas) # Usuario.where("nombre = ?", params[:nombre]) # Con ActiveRecord ``` ### Evitar eval ```ruby # Peligroso - nunca usar con entrada del usuario eval(entrada_usuario) # Alternativas mas seguras # Para codigo: analizar con Ripper # Para datos: usar JSON/YAML ``` ## Resumen - Seguir convenciones de nomenclatura de Ruby: snake_case, CamelCase, SCREAMING_SNAKE_CASE - Usar metodos de Enumerable sobre bucles manuales - Preferir `map`, `select`, `find` sobre `each` con condicionales - Usar clausulas de guardia para retornos anticipados - Mantener metodos cortos y enfocados - Escribir pruebas para comportamiento, no implementacion - Usar metodos bang cuando se intended mutacion - Evitar monkey patching sin refinements - Documentar POR QUE, no QUE - Mantener lineas bajo 120 caracteres

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →