Binary Coffee

驴Por qu茅 tus componentes en Angular deber铆an ser at贸micos?

angular typescript

Comenzar explicando, que este art铆culo es completamente basado en mi experiencia personal a lo largo de los a帽os que llevo en este mundillo de la programaci贸n. Cualquier duda o sugerencia puedes dejarla en los comentarios.

Dicho esto, explicar茅 desde mi punto de vista el por qu茅 para mi, sobre-complicar los componentes puede ser el inicio del desastre en tu proyecto.

A qu茅 me refiero con sobre-complicar un componente

Al decir sobre-complicar un componente, me refiero directamente a la tendencia que tenemos muchos de crear componentes con la idea de ser utilizados y reutilizado en todos los lugares de la aplicaci贸n.

Creo que la mejor manera en que puedo mostrar esto, es mostrando un ejemplo con c贸digo de a lo que me refiero, y as铆 no nos aburrimos (que somos programadores). A continuaci贸n tenemos el componente UserCard que es utilizado en la esquina superior de la p谩gina para mostrar la imagen del usuario:

@Component({
  selector: 'app-user-card',
  templateUrl: './app-user-card.component.html',
  styleUrls: ['./app-user-card.component.scss']
})
export class UserCardComponent {
  @Input() userImageUrl: string;
  constructor() {}
  ...
}

Este componente como se puede apreciar es bien simple y f谩cil de usar y entender por cualquiera que lo necesite usar. Pero qu茅 pasa cuando hay que mostrar el card del usuario en el listado de usuarios, y mostrar m谩s datos. Aqu铆 empiezan a entrar nuevas variables en el componente:

@Component({
  selector: 'app-user-card',
  templateUrl: './app-user-card.component.html',
  styleUrls: ['./app-user-card.component.scss']
})
export class UserCardComponent {
  @Input() userImageUrl: string;
  @Input() userName: string;
  @Input() userLink: string;
  @Input() isInList: boolean;
  constructor() {}
  ...
}

Aqu铆 empieza lo que llamo sobre-complicar el componente, comenzamos a introducir nuevas variables y con los nuevos datos que se necesitan y el conocido indicador que nos refiere si el componente tiene que comportarse como el inicial comportamiento o como el nuevo comportamiento (isInList). Y esto se repite mientras sigan surgiendo lugares donde se necesite dicho componente pero con diferentes variables o sencillamente estilos distintos.

Y este es el comportamiento que creo no deber铆a seguirse, porque desde mi experiencia es el inicio del desastre. Este comportamiento puede f谩cilmente extrapolarse a otros lenguajes y tecnolog铆a, porque es lo mismo que reutilizar la misma funci贸n para diferentes acciones donde cada acci贸n difiere de la anterior por peque帽as cosas pero sigue siendo la misma y por ello por qu茅 duplicar c贸digo si podemos reutilizar el que ya est谩 con m谩s y m谩s y m谩s variable (que nunca terminan).

Y te preguntar谩s: 驴qu茅 pasa con esto?, 驴cual es el problema?. Pues llega el momento en que esto se sale de las manos y el acoplamiento es tan grande, que cuando necesitamos cambiar comportamiento o estilo de dicho componente, clase o funci贸n, estamos en el inminente peligro de romper todos los dem谩s comportamientos. Se llega incluso al punto en que es tan peligroso tocar algo en estos componentes, que se entra en el ciclo infinito de arreglar aqu铆 y romper all谩.

Todo bien, 驴pero c贸mo resuelvo el problema sin repetir c贸digo?

Creo que para explicar la soluci贸n a este problema, empezar茅 resolviendo esto en algo tan simple como una funci贸n y luego veremos como extrapolarlo a un componente visual en Angular. A continuaci贸n tenemos la funci贸n que retorna el listado de usuarios:

listOfUsers() {
  return this.users.filter(user => user.isActive);
}

Como se puede constatar, en el ejemplo anterior obtenemos los usuarios activos del listado. Pero qu茅 ocurre cuando tambi茅n necesitamos en otro lugar los usuarios activos y con el role admin. Pues la tendencia siempre va a lo siguiente:

listOfUsers(isAdmin = false) {
  if (isAdmin) {
    return this.users.filter(user => user.isActive && user.role === 'admin')
  }
  return this.users.filter(user => user.isActive);
}

Y volvemos a lo mismo, cada vez que necesitemos un nuevo par谩metro, continuamos alimentando a la funci贸n con m谩s y m谩s par谩metros, cayendo en el mismo problema que antes mostr茅. Claramente este ejemplo es bien sencillo, pero espero entiendan la idea de lo que quiero mostrar.

驴Pero c贸mo resolver este problema? pues es bien sencillo, y es no sobre-complicar la funci贸n, y dejarla con su comportamiento inicial, y crear una nueva funci贸n que extienda este comportamiento. Ve谩moslo en la pr谩ctica:

listOfUsersWithRoleAdmin() {
  return this.listOfUsers().filter(user => user.role === 'admin');
}

Como se puede ver en el ejemplo anterior, b谩sicamente reutilizamos el c贸digo existente, y no sobre-complicamos la funci贸n. De esta manera, las funciones son lo suficientemente simples, como para no convertirse en un caos total en el futuro.

Y ahora te preguntar谩s, 驴pero c贸mo hago lo mismo con los componentes en Angular?

Angular en la actualidad ha evolucionado lo suficiente como para permitirnos una reutilizaci贸n de todos las partes que conforman un componente, e incluso de los mismos componentes. Es posible, crear componentes que hereden de otros, reutilizando la l贸gica de los mismo y extenderlos, sin caer en sobre-complicar el componente. A continuaci贸n, un ejemplo de c贸mo podr铆amos afrontar el problema inicial del UserCard:

@Component({
  selector: 'app-user-item-card',
  templateUrl: './app-user-item-card.component.html',
  styleUrls: ['./app-user-card-item.component.scss']
})
export class UserCardItemComponent extend UserCardComponent {
  @Input() userName: string;
  @Input() userLink: string;
  constructor() {}
  ...
}

Como se puede apreciar, lo que hice en el ejemplo anterior, fue extender del componente base UserCard, para reutilizar la l贸gica existente y al mismo tiempo adicionar nueva l贸gica a este componente sin sobre-complicarlo. Incluso en los casos en que la vista y los estilos fuesen exactamente los mismo, podr铆amos reutilizarlos del original sin repetir este c贸digo tampoco.

Conclusiones

De esta manera simple, es posible tener siempre componentes at贸micos que no se conviertan en esos monstruo que luego nadie puede editar, porque romper铆as muchas cosas. Recuerda que esta soluci贸n puede ser extendida a otros lenguajes y tecnolog铆as, no es solo para Angular con Typescript.

Tampoco empieces a repetir c贸digo por evitar este problema, porque si malo es sobre-complicar tus componentes, igual de malo y da帽ino, es duplicar c贸digo en tu aplicaci贸n. Claramente tienen diferentes impactos, pero todos repercuten de manera significativa en el proyecto a futuro.

Sin m谩s, recuerda dejar tus comentarios si te fue interesante el art铆culo o si simplemente difieres con mi experiencia y crees que esto deber铆a resolverse de otra manera o para ti no es un problema en lo absoluto.

Happy coding!

Opiniones