Principios Solid
Principios Solid
La deuda técnica es el costo del trabajo adicional causado por la elección de la solución más
rápida en lugar de la más efectiva. Si bien, en ocasiones, la deuda técnica vale la pena, es
importante que tu equipo comprenda las ventajas y las desventajas de las decisiones apresuradas
y cómo gestionar el re trabajo de una manera eficiente.
• imprudente
◦ cuando el desarrollador sabe que tiene el error pero no tiene tiempo de resolverlo y
solo copia ay pega.
• Inadvertida
◦ generada por desconocimiento de la deuda o falta de conocimientos sobre el tema
• prudente
◦ cuando sabemos que la deuda existe y no se esta trabajando sobre ello
Nota:
La mala calidad en el software siempre la acaba pagando o asumiendo alguien.
Ya sea el cliente, el proveedor con recurso o el propio desarrollador dedicando tiempo a re
factorizar o malgastando tiempo programado sobre un sistema frágil.
CLEAN CODE
Se considera que el código es limpio (en inglés, clean code) cuando es fácil de leer y entender. Si
resuelve los problemas sin agregar complejidad innecesaria, permitiendo que el mantenimiento o
las adaptaciones, por algún cambio de requerimiento, sean tareas más sencillas, entonces
estamos hablando de “clean code” Para crear código limpio hay que conocer y poner en práctica
un conjunto de principios o técnicas de desarrollo que nos ayudarán a evitar los code smells, es
decir, esos síntomas de un programa que te dan el indicio de que existe un problema más
profundo.
• Nombrar tus variables con un nombre que tenga significado y que sepamos para que es y
que valores contiene
• Nombrar las clases dependiendo que es lo que va ser y para que va ser usada
Pagina: 1
• Nombrar funciones con valores entendibles para que sepamos para que funciona y que es
lo que va hacer dicha función.
function printJob() {
throw new Error('Function not implemented.');
}
Pagina: 2
} else {
result = 4000;
}
}
}
return result;
}
function workingSteps() {
if( isFirstStepWorking === true ) {
if( isSecondStepWorking === true ) {
if( isThirdStepWorking === true ) {
if( isFourthStepWorking === true ) {
return 'Working properly!';
}
else {
return 'Fourth step broken.';
}
}
else {
return 'Third step broken.';
}
}
else {
return 'Second step broken.';
}
Pagina: 3
}
else {
return 'First step broken.';
}
}
console.log({ workingSteps: workingSteps() }); // Cambiar los valores de la línea 31 y esperar los resultados
})();
function workingSteps() {
if(!isFirstStepWorking) return 'First step broken.';
if(!isSecondStepWorking) return 'Second step broken.';
if(!isThirdStepWorking) return 'Third step broken.';
if(!isFourthStepWorking) return 'Fourth step broken.';
return 'Working properly!';
}
//getFruitsByColor
console.log({redFruits: getFruitsByColor('red')}); // ['manzana', 'fresa']
console.log({yellowFruits: getFruitsByColor('yellow')}); // ['piña', 'banana']
console.log({purpleFruits: getFruitsByColor('purple')}); // ['moras', 'uvas']
// console.log({ pinkFruits: getFruitsByColor('pink') }); // Error: the color must be: red, yellow, purple
// workingSteps
console.log({workingSteps: workingSteps()});
})();
Pagina: 4
PRINCIPIOS DE DRY (Don’t Repeat Yourself)
class Product {
constructor(public name: string, public price: number = 0, public size: Size = '') {
}
isProductReady(): boolean {
for (const key in this) {
switch (typeof this[key]) {
case 'string':
if (this[key].length <= 0) throw new Error(`${key} is empty`);
break;
case 'number':
if (this[key] <= 0) throw new Error(`${key} is zero`);
break;
default:
throw new Error(`${key} is invalid`);
}
}
return true;
}
toString() {
// NO DRY
if (this.name.length <= 0) throw new Error('Name is empty');
if (this.price <= 0) throw new Error('price is zero');
if (this.size.length <= 0) throw new Error('size is empty');
return `Product name: ${this.name} ${this.price} ${this.size}`;
}
toStringDRY() {
// DRY
if (!this.isProductReady()) return;
return `Product name: ${this.name} ${this.price} ${this.size}`;
}
}
(() => {
const bluePant: Product = new Product('Blue Large Pant', 100, 'large');
console.log(bluePant.toString());
console.log(bluePant.toStringDRY());
})();
Pagina: 5
Al igual que lo visto en la sección de clean code para las clases se aplican las mismas reglas. y
debemos tomar en cuenta que las clases deber ser especificar para cada servicio o función que
va realizar.
El principio de responsabilidad única o SRP (siglas del inglés, Single Responsibility Principle) en
ingeniería de software establece que cada módulo o clase debe tener responsabilidad sobre una
sola parte de la funcionalidad proporcionada por el software y esta responsabilidad debe estar
encapsulada en su totalidad por la clase. Todos sus servicios deben estar estrechamente
alineados con esa responsabilidad. Este principio está incluido en el acrónimo SOLID. Robert C.
Martín.
(() => {
class Person {
constructor(
public name: string,
public gender: Gender,
public birthdate: Date
){}
}
constructor(
public email: string,
public role: string,
name: string,
gender: Gender,
birthdate: Date,
){
super( name, gender, birthdate );
this.lastAccess = new Date();
}
checkCredentials() {
return true;
}
}
Pagina: 6
'/usr/home',
'/home',
'[email protected]',
'Admin',
'Fernando',
'M',
new Date('1985-10-21')
);
})();
interface PersonProps {
birthdate : Date;
gender : Gender;
name : string;
}
class Person {
public birthdate: Date;
public gender : Gender;
public name : string;
interface UserProps {
email : string;
role : string;
}
class User {
constructor({
email,
role,
}: UserProps ) {
this.lastAccess = new Date();
this.email = email;
this.role = role;
}
checkCredentials() {
return true;
}
}
interface SettingsProps {
lastOpenFolder : string;
Pagina: 7
workingDirectory : string;
}
class Settings {
constructor({
lastOpenFolder,
workingDirectory,
}: SettingsProps ) {
this.lastOpenFolder = lastOpenFolder;
this.workingDirectory = workingDirectory;
}
}
interface UserSettingsProps {
birthdate : Date;
email : string;
gender : Gender;
lastOpenFolder : string;
name : string;
role : string;
workingDirectory : string;
}
class UserSettings {
constructor({
name, gender, birthdate,
email, role,
lastOpenFolder, workingDirectory,
}: UserSettingsProps ){
})();
Donde en el ejemplo anterior se deja responsabilidad para cada una de las clases quitando la
herencia que existía ya que la herencia es muy complicada de manejar en una responsabilidad
única para cada clase
Pagina: 8
Seguro que la mayoría de vosotros habéis escuchado alguna vez la palabra SOLID, la Santísima
Trinidad de la programación orientada a objetos y es que bajo esta palabra se esconden sus 5
principios básicos: Single responsability, Open-closed, Liskov substitution, Interface segregation
and Dependency inversion.
Pero, si no somos SOLID… ¿qué estamos haciendo? Probablemente estés escribiendo código
SINGLENTON
Uno de los primeros patrones que aprendemos por su facilidad de entender e implementar e
intenta resolver básicamente dos problemas (adiós Principio de responsabilidad única):
• Garantizar que una clase tenga una única instancia, por ejemplo, para controlar el
acceso a un recurso compartido como una base de datos
• Proporcionar un acceso seguro a estados globales (variables globales) La misma
instancia viajará por todo el código y todos los clientes la compartirán. Incluso la
mayoría de ellos no serán conscientes de que están rehusando la misma instancia
que ha sido utilizada por otros. Parece una fiesta pero definitivamente esto no mola:
• Proporciona estados globales dentro de la aplicación lo que infiere en dificultar para
probar (testing) nuestro código
• No permite inyección de dependencias
• Aplicaciones con estados globales son aplicaciones que esconden sus
dependencias
• Nuestros clientes quedan acoplados a los Singleton
• Incumple la S de SOLID. Se preocupa de solucionar dos problemas: cómo se
instancia una clase (ocultando su constructor haciéndolo privado) y cómo se
comporta su propio ciclo de vida
El acoplamiento fuerte es una generalización del patrón Singleton. Básicamente consiste en qué
grado tus clientes conocen detalles de las clases que consumen. Entre más detalles conozcan
(alto acoplamiento) más difícil será realizar cambios en tu código. También aumentará la
probabilidad de romper y mantener tus aplicaciones. Imagina que queremos conocer si hoy es el
1<?php
2
3class Usuario
Pagina: 9
{
4 public int $dia_cumpleaños;
5 public int $mes_cumpleaños;
6
7 public function __construct(...): void
8
{
9
// TO-DO
10
11 }
12 }
13
14 class Cliente
15 {
16 public function felicitar(Usuario $usuario): void
17 {
18 $today = getdate();
19
20 if (
21 $today['mday'] === $usuario->dia_cumpleaños &&
22 $today['mon'] === $usuario->mes_cumpleaños
23 ){
24 // mandar email
25
}
26
27 }
}
Tenemos una clase Usuario que almacena la fecha de nacimiento del usuario como dos atributos
de clase de tipo entero: un atributo para el día y otro para el mes. Además, por otro lado, hemos
implementado una clase que mandará un e-mail de felicitación al usuario el día de su cumpleaños.
Para esto miraremos si los atributos de la clase Usuario coinciden con el día y el mes de la fecha
usuario. Y nuestra clase Cliente deja de funcionar, se ha roto. ¿Por qué? Porque Cliente está
funcionar. Está violando el principio Tell, Don’t Ask: desde getters y setters hasta clases
anémicas.
UNTESTABILITY
Como hemos visto usar el patrón Singleton y tener código fuertemente acoplado reduce
Pagina: 10
premisa fundamental: ¡nuestro código debe ser fácil de probar! ¿Sabes la tranquilidad que da
PREMATURE OPTIMIZATION
Seamos sinceros, la mayoría de las optimizaciones que hacemos los desarrolladores no sirven
para nada. Punto. Miento, sí, para una única cosa muy diferente a su propósito: dificultar la
legibilidad de nuestro código. Las técnicas de optimización son mucho más complejas que
sustituir un loop de 20 ítems que usa Active Record por una query hecha a pelo.
• No lo hagas
• No lo hagas todavía
INDESCRIPTIVE NAMING
Este parece obvio, ¿quién iba a tirarse piedras sobre su mismo tejado? Pues lo hacemos todos y
todos los días. Sobretodo evita las abreviaturas. ¿A qué debemos esta manía? Las abreviaturas
no aportan ninguna ventaja y muchas veces tiramos de ellas como solución a problemas de
indentación de código (¿sabes por qué deberías seguir una guía de estilo de código?)
Además, son peligrosas. Un ejemplo muy típico. Tmp y temp ¿esto qué significa? ¿temporal?
¿temperatura? No des por hecho que todo el mundo va utilizar tmp para temporal y temp para
temperatura.
DUPLICATION
Aunque ojo, no en el 100% de los casos es así: si haces DDD (Domain Drive Diseng) podrías ser
bueno tener objetos repetidos en contextos diferentes; y a veces es mejor un poco de código
Pagina: 11