Escribir un código bonito, bien diseñado y con buena apariencia no es tan difícil como parece. Requiere un poco de esfuerzo conocer las reglas principales y simplemente usarlas en tu código. Y no tiene que ser como todo a la vez, sino que a medida que te sientas cómodo con una cosa intenta pensar en otra, y así sucesivamente.
Construir código sólido, no estúpido
Empecemos por introducir las reglas más elementales que se denominan SOLID. Es un término que describe una colección de principios de diseño para un buen código que inventó Robert C. Martin y cómo va:
S significa Principio de Responsabilidad Única
Establece que una clase debe tener una y sólo una razón para cambiar. En otras palabras, una clase debe tener un solo trabajo que hacer, por lo que debemos evitar escribir clases grandes con muchas responsabilidades. Si nuestra clase tiene que hacer muchas cosas entonces cada una de ellas debe ser delegada en otras separadas.
clase Notificación
def inicializar(parámetros)
@parámetros = parámetros
end
def llamada
EmailSender.new(mensaje).call
end
privado
def mensaje
# alguna implementación
end
fin
O significa Principio Abierto/Cerrado
Establece que usted debe ser capaz de extender el comportamiento de una clase, sin modificarla. En otras palabras, debe ser fácil extender una clase sin hacer ninguna modificación en ella. Podemos conseguirlo, por ejemplo, utilizando el patrón de estrategia o decoradores.
clase Notificación
def initialize(parámetros, remitente)
@parámetros = parámetros
@remitente = remitente
end
def llamada
sender.call mensaje
end
privado
def mensaje
# alguna implementación
end
fin
clase EmailSender
def call(mensaje)
# alguna implementación
end
fin
clase SmsSender
def call(mensaje)
# alguna implementación
end
fin
Con este diseño, es posible añadir nuevos remitentes sin cambiar ningún código.
L significa Principio de Sustitución de Liskov
Establece que las clases derivadas deben ser sustituibles por sus clases base. En otras palabras, el uso de clases que proceden del mismo ancestro debe ser fácil de sustituir por otra descendiente.
clase Logger {
info (mensaje) {
console.info(this._prefixFor('info') + mensaje)
}
error (mensaje, err) {
console.error(this._prefixFor('error') + mensaje)
if (err) {
console.error(err)
}
}
_prefijoPara (tipo) {
// alguna implementación
}
}
class ScepticLogger extends Registrador {
info (mensaje) {
super.info(mensaje)
console.info(this._prefixFor('info')) + 'Y eso es todo lo que tenía que decir.')
}
error (mensaje, err) {
super.error(mensaje, err)
console.error(this._prefixFor('error')) + '¡Gran cosa!')
}
}
Podemos sustituir fácilmente el nombre de la clase, porque ambas tienen exactamente la misma interfaz de uso.
Me refiero al principio de segregación de interfaces
Afirma que se deben crear interfaces de grano fino específicas para cada cliente. ¿Qué es una interfaz? Es una forma proporcionada de uso de alguna parte del código. Así que una violación de esta regla podría ser, por ejemplo, una clase con demasiados métodos, así como un método con demasiadas opciones de argumento. Un buen ejemplo para visualizar este principio es un patrón de repositorio, no sólo porque a menudo ponemos un montón de métodos en una sola clase, sino también esos métodos están expuestos a un riesgo de aceptar demasiados argumentos.
# no es el mejor ejemplo esta vez
clase NotificationRepository
def encontrar_todos_por_id(ids:, info:)
notificaciones = Notification.where(id: ids)
info ? notificaciones.where(tipo: :info) : notificaciones
end
end
# y una mejor
clase NotificationRepository
def encontrar_todos_por_id(ids:)
Notification.where(id: ids)
end
def encontrar_todos_los_id(ids:)
find_all_by_ids(ids).where(type: :info)
end
end
D significa Principio de Inversión de Dependencia
Establece que se debe depender de abstracciones, no de concreciones. En otras palabras, una clase que utiliza otra no debe depender de sus detalles de implementación, todo lo que importa es la interfaz de usuario.
clase Notificación
def initialize(parámetros, remitente)
@parámetros = parámetros
@remitente = remitente
end
def llamada
sender.call mensaje
end
privado
def mensaje
# alguna implementación
end
fin
Todo lo que necesitamos saber sobre el objeto sender es que expone el método `call` que espera el mensaje como argumento.
No es el mejor código
También es muy importante conocer las cosas que deben evitarse estrictamente al escribir código, así que aquí va otra colección con principios ESTÚPIDOS que hacen que el código no sea mantenible, difícil de probar y reutilizar.
S significa Singleton
Los Singletons se consideran a menudo como anti-patrones y generalmente deben evitarse. Pero el principal problema de este patrón es que es una especie de excusa para las variables/métodos globales y podría ser rápidamente sobreutilizado por los desarrolladores.
T significa Acoplamiento Estanco
Se conserva cuando un cambio en un módulo requiere también cambios en otras partes de la aplicación.
U significa Intestabilidad
Si su código es bueno, escribir pruebas debería parecer divertido, no una pesadilla.
P significa Optimización Prematura
La palabra prematuro es la clave aquí, si no lo necesitas ahora entonces es una pérdida de tiempo. Es mejor centrarse en un código bueno y limpio que en algunas micro-optimizaciones - que generalmente provocan un código más complejo.
Me refiero a Nombres Indescriptivos
Es lo más difícil a la hora de escribir buen código, pero recuerda que no es sólo para el resto de tu equipo sino también para el futuro tú, así que trátalo bien 🙂 Es mejor escribir un nombre largo para un método pero que lo diga todo, que uno corto y enigmático.
D significa Duplicación
La razón principal de la duplicación en el código es seguir el principio de acoplamiento estrecho. Si tu código está fuertemente acoplado, simplemente no puedes reutilizarlo y aparece código duplicado, así que sigue DRY y no te repitas.
No es realmente importante en este momento
También me gustaría mencionar dos cosas muy importantes que a menudo se omiten. Deberías haber oído hablar de la primera - es YAGNI que significa: no lo vas a necesitar. De vez en cuando observo este problema mientras hago revisión de código o incluso escribiendo mi propio código, pero deberíamos cambiar nuestra forma de pensar sobre la implementación de una característica. Deberíamos escribir exactamente el código que necesitamos en este momento, ni más ni menos. Debemos tener en cuenta que todo cambia muy rápidamente (especialmente los requisitos de la aplicación) así que no tiene sentido pensar que algo algún día será útil. No pierdas el tiempo.
No lo entiendo.
Y la última cosa, no muy obvia supongo, y puede ser bastante controvertida para algunos, es un código descriptivo. No me refiero sólo a usar los nombres correctos para las clases, variables o métodos. Es muy, muy bueno cuando todo el código es legible a primera vista. ¿Cuál es el propósito de un código muy corto cuando es tan enigmático como puede ser, y nadie sabe lo que hace, excepto la persona que lo escribió? En mi opinión, es mejor escribir algunos caracteresdeclaraciones de estadootra cosa más de una palabra y luego ayer sentarse y preguntarse: espera cuál es el resultado, cómo sucedió, y así sucesivamente.
const params = [
{
películas: [
{ título: 'The Shawshank Redemption' },
{ título: 'One Flew Over the Cuckoo's Nest' }
]
},
{
películas: [
{ título: 'Salvar al soldado Ryan' },
{ title: 'Pulp Fiction' },
{ título: 'The Shawshank Redemption' },
]
}
]
// primera proposición
function uniqueTitlesDePelícula (params) {
const títulos = params
.map(param => param.películas)
.reduce((prev, nex) => prev.concat(next))
.map(película => película.título)
return [...nuevo conjunto(títulos)]
}
// segunda proposición
function uniqueTitlesDePelicula (params) {
const títulos = {}
params.forEach(param => {
param.movies.forEach(movie => titles[movie.title] = true)
})
return Object.keys(títulos)
}
En resumen
Como puedes ver, hay muchas reglas que recordar, pero como mencioné al principio, escribir un buen código es cuestión de tiempo. Si empiezas a pensar en una mejora de tus hábitos de codificación entonces verás que otra buena regla seguirá, porque todas las cosas buenas surgen de sí mismas al igual que las malas.
Más información:
¿Qué es Ruby on Jets y cómo crear una aplicación con él?
Vuelendar. Un nuevo proyecto de Codest basado en Vue.js
Informe semanal de Codest sobre los mejores artículos tecnológicos. Creación de software para 50 millones de sockets simultáneos (10)