DANIEL FERNANDO HENAO GUTIERREZ
David Elias Gatica Morales
Wilder Rojas
El principio KISS en C# te ayuda a escribir código simple, legible y libre de sobreingeniería. Si estás aprendiendo buenas prácticas de programación, esta guía te muestra cómo identificar nested ifs, reemplazar bucles for con LINQ y aplicar lambda expressions para reducir líneas innecesarias.
¿Qué significa el principio KISS en programación?
KISS son las siglas de Keep It Simple, Stupid, aunque también lo encuentras como Keep It Short and Simple para evitar el tono brusco de la palabra original. La idea central es que tu código resuelva el problema con la menor cantidad de elementos posibles, sin fragmentar ni complicar lo que puede resolverse de forma directa [0:30].
¿Qué es la sobreingeniería? Es cuando diseñas una aplicación demasiado grande o compleja para resolver algo simple. La frase que lo resume bien: nunca uses una bazuca para matar una mosca.
Separar responsabilidades es buena práctica, pero llevarla al extremo te lleva al efecto contrario. La clave está en ajustar la solución a la complejidad real del problema: cuando algo es sencillo, aplica algo sencillo.
¿Cómo identificar un nested if y por qué deberías evitarlo?
Un nested if ocurre cuando colocas un if dentro de otro if para validar condiciones que perfectamente podrían ir juntas. Es uno de los errores más comunes que rompen el principio KISS [2:00].
En el proyecto de C# de la clase, había exactamente ese caso: dos validaciones encadenadas que solo verificaban una condición adicional. La solución fue mover ambas condiciones al mismo if, eliminando un bloque completo y dejando el código más limpio.
if externo y otro if interno con una sola comprobación.if que combina ambas condiciones.Este cambio no afecta el comportamiento, pero sí mejora drásticamente la mantenibilidad. Y aquí viene lo interesante: cuando alguien más lea tu código, entenderá la intención sin tener que rastrear bloques anidados.
¿Cómo reemplazar un for loop con LINQ y foreach en C#?
Los bucles for y foreach son útiles para recorrer colecciones, pero .NET tiene una librería llamada LINQ que extiende las colecciones con métodos para transformar y manipular datos de forma más expresiva [3:30].
En la clase se reemplazó un for que imprimía cada tarea de una lista por un TaskList.ForEach con una lambda expression, equivalente a una arrow function en JavaScript. Así se eliminó la necesidad de acceder a la lista por índice con TaskList[i].
¿Qué es una lambda expression? Es una función anónima y corta que se escribe en línea. En C# se usa con la sintaxis
p => acción, dondeprepresenta cada elemento de la colección.
¿Cómo enumerar tareas con un contador dentro del foreach?
Al pasar de for a foreach, pierdes el índice automático. Para recuperarlo, creas una variable, por ejemplo indexTask, y la incrementas dentro de la lambda.
Aquí entra un detalle clave: la diferencia entre post-incremento y pre-incremento.
indexTask en cero y usas post-incremento (indexTask++), la primera tarea se imprime como cero.++indexTask) o inicializar la variable en uno y mantener el post-incremento.El resultado final es una sola línea que recorre la lista, imprime cada tarea y la numera correctamente. Lo que antes ocupaba varios bloques quedó reducido a una expresión clara.
¿Cómo verificar que el código sigue funcionando tras aplicar KISS?
Después de cada refactor, valida siempre que nada se rompió. En el proyecto se usaron dos comandos básicos de la CLI de .NET [6:40]:
dotnet build para confirmar que el código compila sin errores.dotnet run para ejecutar la aplicación y probar el flujo.Cuando la salida muestra 1. task one, sabes que el cambio fue exitoso y que aplicaste KISS sin alterar el comportamiento.
¿Cuándo no debo simplificar el código? Cuando el problema realmente es complejo. KISS no significa evitar abstracciones necesarias, sino no inventarlas cuando no aportan valor.
La práctica que te recomiendo: revisa tu propio repositorio y busca nested ifs, bucles que podrían usar LINQ o variables que podrías eliminar. Comparte en los comentarios qué refactor hiciste y cómo quedó tu código después.
DANIEL FERNANDO HENAO GUTIERREZ
David Elias Gatica Morales
Wilder Rojas
Silvia Corrales
Angel Javier Sanchez Tenjo
Daniel Alberto Vera Angulo
Miguel Angel Reyes Moreno
Juan Ezequiel Molina Riddell
David Elias Gatica Morales
José David Gómez Brenes
Sandra Valentina Rodríguez Cortés
wilking trinidad
Jordi Yair Calva García
Alexis Dorado Muñoz
Jonathan Alejandro Gómez reyes
JUAN ESTEBAN MORENO NORIEGA
Carlos Alberto Irias Torres
JUAN SILVA
Leandro Cosme Tomassini
Jaime Betancur
Jaime Betancur
Jose Carlos Vega Moron
Jose Carlos Vega Moron
Mathías Cabrera
Mathías Cabrera
Luis Alvarez
**KISS **
Jajajaj menos explicit
el termino Keep It Simple Stupid lo he encontrado en un libro llamado padre rico padre pobre de robert kyosaki
KISS
KISS: es un acrónimo de Keep It Simple Stupid o Keep It Short and Simple y a rasgos generales se puede traducir como Mantenlo simple!.
Este principio establece que la mayoría de sistemas funcionan mejor si se mantienen simples o sencillos a diferencia de aquellos que se hacen complejos de manera innecesaria. Es decir, que desde el incio del proyecto la sencillez tiene que ser una meta en el desarrollo y que la complejidad innecesaria debe ser eliminada cada vez que sea detectada. Muchas veces esta complejidad ocurre cuando se diseñan grandes soluciones para objetivos simples.
Tratemos de utilizar la mejor solución dependiendo de la complejidad de lo que estemos trabajando. Cuando algo es muy complejo o muy grande, es recomendable buscar soluciones más complejas o avanzadas que se ajusten, pero si algo es más simple, pequeño o sencillo, lo ideal es darle una solución acorde a sus características.
Es bueno tener presente que:
Si ya no comprendes tu propio código después de un breve período de tiempo, las campanas de alarma deberían sonar. Porque cuanto más complicado es o se presenta, más difícil es para todos los involucrados trabajar con él.
Algunos ejemplos de complejidad innecesaria son:
Utilizar en el ForEach para recorrer el TaskList; se esta usando una variable de nombre p; pero esto se podria mejorar su nombramiento como task
public static void ShowTaskList() { var indexTask = 1; Console.WriteLine("----------------------------------------"); TaskList.ForEach(task => Console.WriteLine((indexTask++) + ". " + task )); Console.WriteLine("----------------------------------------"); }
Igual lo pense, debería aplicarlo el profe XD
Me ganaste el comentario por 4 meses jajaja
No estoy completamente de acuerdo con la refactorización del for. Aún así me parece mucho mejor que como estaba.
La razón es que no me da buena espina el código imperativo como el operador ++ o la función WriteLine dentro de una función anonima que es usada dentro de otra función. Esto porque rompe con el esquema de las funciones puras.
Sin embargo creo es una especie de code smell personal, no tiene que ser necesariamente siempre así, siempre hay que juzgar por la situación.
Yo con tal de evitar mezclar funcional e imperativo llegué a esto:
foreach (var (task, i) in taskList.WithIndex()) { Console.WriteLine($"{i + 1}. {task}"); }
Y claro, primero es más largo, y segundo tuve que poner más abajo otro pedazo de código que encontré en internet para definir WithIndex, por lo que no necesariamente mi solución es mejor pero quería compartir esto por si a alguien le parece interesante y encuentra más del tema.
Sé yo pensé lo mismo, pero ahora que dependerá del proyecto, en este caso no se esta pensando en establecer funciones puras o evitar side effects solo en hacer una lista y reducir 7 lineas a una linea, aunque tambien es un buen code smell.
Esa frase es poética
"No debemos usar una bazuka para matar una mosca" que excelente.
Eliminé los Console.WriteLine por un forEach
List<string> MenuOptionsList=new List<string>{"----------------------------------------","Ingrese la opción a realizar:","1. Nueva tarea","2. Remover tarea","3. Tareas pendientes","4. Salir"}; MenuOptionsList.ForEach(menuOption=>Console.WriteLine(menuOption));
yo al empezar la clase: "vamos, dilo, dilooo"
Tasks.ForEach((task) => { Console.WriteLine($"{Tasks.IndexOf(task) + 1} . {task}"); });
Aparentemente se ve mejor, pero lastimosamente se llama en cada iteración, lo cual tiene una complejidad de tiempo O(n) para cada llamada. Esto puede hacer que el código sea significativamente más lento para listas grandes, ya que cada búsqueda del índice recorre la lista hasta encontrar el elemento.
todo esta perfecto en el curso, pero creo que fue una mala idea no haberlo hecho en visual studio, por que las personas que llegan a este curso normalmente estan usando IDE para programar, la mayoria que podemos pagar la plataforma tenemos una computadora que sin problema corre visual studio exagero de mas profe, pero pues ya que a darle
Recordar que no siempre es viable cambiar el for a foreach, puesto que al hacer este cambio, perdemos la información del indice (en el video nos muestran cómo recuperarla, pero justamente eso es lo que hace el for). Recomiendo tener en cuenta en qué momentos usar el uno o el otro, porque en el caso de desarrollar un videojuego en Unity, y necesitar listar el ranking de jugadores, es mucho menos engorroso usar el for. Linq permite tener un performance más optimo a la hora de ejecutar el código cuando las listas son inmensamente grandes; por ende es otro factor clave que nos puede poner en duda si elegir el uno o el otro, pero siempre tener en cuenta que cada proyecto puede tener unas características específicas de reescalabilidad y que por esta razon pueda diferir mucho cuál sea la mejor opción.
Algunas consideraciones sobre Linq que nos pueden ayudar en un futuro:
https://medium.com/swlh/is-using-linq-in-c-bad-for-performance-318a1e71a732
private static void ShowMenuOptions() { TaskList.ForEach(p => Console.WriteLine(p.IndexOf(p) + 1 + ". " + p)); Console.WriteLine("----------------------------------------"); }
Principio KISS: Mantenlo simple
¿Qué es?
KISS es un principio de diseño que busca priorizar la simplicidad en el desarrollo de software. Se basa en la idea de que un sistema o código es más efectivo si se mantiene simple y fácil de entender.
¿Por qué es importante?
La complejidad innecesaria puede generar problemas como:
¿Cómo aplicar el principio KISS?
Ejemplos de aplicación en C#:
como comentario , cuando creas un lambda el P es el nombre de la variable, si somos consistentes con los estandares de variables para que sea legible seria mejor dejarlo asi :TaskList.ForEach(task => Console.WriteLine($"{(++indexTask)}.{task}"));
Este principio puedes aplicarlo , cuando te sientes muy orgulloso del codigo, query que hiciste porque es muy complejo y funciono, ahi te debes preguntar si este principio si lo tuviste en cuenta
Para poder reforzar aun mas el principio de buenas practicas de NOMBRAMIENTO, podemos mejorar la variable p que se usa en el ForEach
TaskList.ForEach(Task => Console.WriteLine(IndexTask++) + ". " } Task)
Otra mejora que pude hacer es en la asignación de la posición de la lista:
if (indexToRemove > -1 && ListOfTask.Count > 0)
{
ListOfTask.RemoveAt(indexToRemove);
Console.WriteLine("Tarea " + ListOfTask[indexToRemove] + " eliminada");
}
Hi everyone!
I share a fragment of the code where I also apply the principle:
//Before applying the principle string taskNumberToDelete = Console.ReadLine(); int indexToRemove = Convert.ToInt32(taskNumberToDelete) - 1; //After int indexToRemove = Convert.ToInt32(Console.ReadLine()) - 1; ```pply the principle:
Hi everyone!
I share a fragment of the code where I also apply the principle:
Before applying the principle
string taskNumberToDelete = Console.ReadLine(); int indexToRemove = Convert.ToInt32(Console.ReadLine()) - 1; ```After ```js int indexToRemove = Convert.ToInt32(Console.ReadLine()) - 1; ```I also share my repository where you will find the summary of this course: Thanks! Never stop learning!💚
Es bueno aprender desde cero
using System; using System.Collections.Generic; namespace ToDo { internal class Program { private static List<string> taskList { get; set; } public static List<string> GetTaskList() { return taskList; } public static void SetTaskList(List<string> value) { taskList = value; } // Función para mostrar la lista de tareas public static void ShowTaskList() { Console.WriteLine("----------------------------------------"); //Mejorar en una linea de codigo para compilar un codigo var taskIndex = 1; GetTaskList().ForEach(task => Console.WriteLine(taskIndex++ + ". " + task)); Console.WriteLine("----------------------------------------"); } static void Main(string[] args) { SetTaskList(new List<string>()); int menuSelected = 0; do { menuSelected = ShowMainMenu(); if ((Menu)menuSelected == Menu.add) { ShowMenuAdd(); } else if ((Menu)menuSelected == Menu.remove) { ShowMenuRemove(); } else if ((Menu)menuSelected == Menu.List) { ShowTaskList(); // Llamada al método ShowTaskList en lugar de ShowMenuTaskList } } while ((Menu)menuSelected != Menu.Exit); } public static int ShowMainMenu() { List<string> MenuOptionsList = new List<string> { "----------------------------------------", "Ingrese la opción a realizar:", "1. Nueva tarea", "2. Remover tarea", "3. Tareas pendientes", "4. Salir", "----------------------------------------" }; MenuOptionsList.ForEach(menuOption => Console.WriteLine(menuOption)); string taskIndex = Console.ReadLine(); Console.WriteLine("----------------------------------------"); return Convert.ToInt32(taskIndex); } public static void ShowMenuRemove() { try { Console.WriteLine("Ingrese el número de la tarea a remover: "); //Llamo a la funcion de la lista ShowTaskList(); string taskIndex = Console.ReadLine(); // Remove one position int indexToRemove = Convert.ToInt32(taskIndex) - 1; if (indexToRemove > -1 && GetTaskList().Count > 0) { string taskToRemove = GetTaskList() [indexToRemove]; GetTaskList().RemoveAt(indexToRemove); Console.WriteLine("Tarea " + taskToRemove + " eliminada"); } } catch (Exception) { } } public static void ShowMenuAdd() { try { Console.WriteLine("Ingrese el nombre de la tarea: "); string task = Console.ReadLine(); GetTaskList().Add(task); Console.WriteLine("----------------------------------------", "Tarea registrada"); } catch (Exception) { } } public static void ShowMenuTaskList() { if (GetTaskList() == null || GetTaskList().Count == 0) { Console.WriteLine("No hay tareas por realizar"); } else { ShowTaskList(); } } } public enum Menu { add = 1, remove = 2, List = 3, Exit = 4 } }