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