La gestión de los estándares de codificación es un componente esencial en nuestra labor como programadores. Facilita la colaboración efectiva en equipo y asegura que el código sea altamente legible para los demás. El dominio de estos estándares nos eleva como programadores más capacitados. Ahora, exploremos aquellos que capturan nuestra atención en este artículo.
Convención de nombres
Para muchos, asignar nombres se percibe como una tarea compleja, y en realidad lo es. Cada lenguaje cuenta con sus propias convenciones de nombres; por ejemplo, las de Java guardan similitudes con las de C#, aunque no son idénticas. La trascendencia de seguir estas convenciones radica en que nos encaminan hacia la creación de un código uniforme. La carencia de estas convenciones conduce a que cada integrante del equipo siga sus preferencias, generando complicaciones en la lectura tanto para los miembros actuales como para los recién llegados.
En el contexto de C#, se distinguen principalmente 3 convenciones que han alcanzado una notable popularidad. No obstante, esto no excluye la posibilidad de que cada equipo cree las suyas. En la mayoría de los casos, la comunidad se adhiere a estas 3 convenciones.
- PascalCase: se utiliza para nombres de archivo, espacios de nombres, clases, métodos y miembros públicos.
- camelCase: utilizada para miembros no públicos o privados.
- UPPER_CASE: se utiliza para nombrar variables constantes o enumeraciones.
Un aspecto que ha generado mucha controversia es el uso del guión bajo () al declarar los miembros privados. Desde mi perspectiva, encuentro que es beneficioso, especialmente cuando se emplea inyección de dependencia. Se presenta con frecuencia la confusión entre la variable que se pasa en el constructor y el miembro al que se asigna. Para solventar esto, incorporó el _ para hacer la distinción. Aunque pueda resultar un tanto molesto incluir unthis., mejora la legibilidad y previene el uso incorrecto de la variable.
public class Product
{
private string _productName;
public void Show(string producttName = null)
{
Console.WriteLine($"mostrar: , { producttName ?? _productName }!");
}
}
Otras formas de conversiones existen en diferentes lenguajes, pero no se integran bien con C#. Muchas de ellas pueden resultar problemáticas. Un ejemplo es la notación húngara. Esta convención está asociada a cómo debemos nombrar las variables. En términos generales, cada variable debe iniciar con una letra que denote su tipo; por ejemplo, una variable que almacene la edad, que podría ser de tipo int, debería llevar el nombre iEdad.
Si bien no está mal, en la actualidad debemos considerar lo siguiente: el compilador transforma todo a código que la máquina comprenda, y realmente no le importa lo que escribimos. Aquí es donde entra un poco de sentido común; en el 99% de los casos, edad era un int y sabemos que no lo necesitamos, sería demasiado. Pero podrían plantear la pregunta ¿y si no puedo distinguirlo? Bueno, en este caso podríamos optar por un nombre largo como saldoTotalEnCuenta. Recordemos que no nos cobran por letra, aunque pueda tardar más en compilar debido a un nombre tan extenso, no ayuda más fácilmente a saber qué tipo tiene esa variable solo por el nombre.
Formatos
Existen algunas normas para el formato en C#. En este caso, a diferencia del ejemplo anterior, son aplicables a varios lenguajes. Estas normas abarcan el formato de saltos de líneas, sangría y espaciado. Actualmente, todos los IDEs de desarrollo cuentan con herramientas para facilitarnos el respeto de estas normas, pero aún así, no está de más conocerlas.
Se genera una gran controversia, aunque parezca increíble, en relación a si se utiliza espacio o tabs para indentar código. No deseo sumergirme en la discusión, sino resaltar la importancia de la cantidad; tanto el tab como la cantidad de espacios deben ser de 4. Esto implica que 1 tab es equivalente a 4 espacios.
Otro estilo, a pesar de la libertad que otorga el lenguaje, establece que al abrir una llave o un bloque de código, debe tener su respectivo cierre. Además, los puntos y coma de cierre de instrucción, después de este, no deben estar seguidos de nada; si deseamos insertar código, debe hacerse en la línea siguiente.
El uso de VAR
La utilización de var resulta especialmente valiosa cuando las variables tienen una duración breve o comparten un mismo ámbito. Esto contribuye a reducir la redundancia y aporta mayor flexibilidad al código. La gran incógnita: ¿Cómo identificamos el tipo cuando estamos usando var? Es bastante sencillo, al posarnos sobre el var, el IDE no revelará el tipo que adoptará, dado que infiere el resultado del método que estamos invocando.
var product = new product(id);
var result = await _someApiproduct.GetAsync(id, cancellationToken);
for(var i = 0; i < max; i++){ // i is implicitly typed}
var product = this.productFactory.GetOrCreate(id);this.someDependency.Submitproduct(product);
Uso de propiedades
Al definir una propiedad, automáticamente se crea una variable de respaldo para almacenar esa propiedad. A menos que necesitemos acceder explícitamente a esa variable, no es necesario declararla; podemos utilizar simplemente la versión automática.
public int Count { get; set; }
Un recurso para optimizar la creación de propiedades es utilizar prop y después presionar la tecla tab; de esta forma, se generará la propiedad y solo será necesario completar el tipo y el nombre.
Declarar Variables
Una costumbre que se solía adoptar en épocas anteriores era la de declarar todas las variables al inicio de la clase. Esto se hacía porque en muchos lenguajes, la inicialización de variables era la primera acción ejecutada, debido a consideraciones de espacio; no obstante, en la actualidad esto ya no resulta necesario. En el presente, esta práctica conlleva un inconveniente: en clases extensas, es incómodo tener que volver al código por alguna razón para revisar las variables. Subimos hasta el inicio y luego debemos retornar al código. Aunque los IDEs en la actualidad permiten agregar marcas o ir a líneas específicas, la mejor práctica es declarar las variables lo más cerca posible de donde serán utilizadas.
Organización de archivos
Es fundamental que todos nuestros archivos estén organizados en carpetas adecuadas o con nombres que guarden relación con su contenido para facilitar la comprensión y la navegación. Las clases, interfaces y enumeraciones deben agruparse en un solo archivo para simplificar el seguimiento y la lectura.
USING cómo destructor
Cuando declaramos una variable, ésta persistirá en la memoria hasta que pierda todas sus referencias y el Garbage Collector realice su tarea. No obstante, una práctica sumamente beneficiosa es utilizar los bloques using para señalar que el objeto ya no está en uso y permitir que el Garbage Collector lo elimine de manera expedita.
Un ejemplo ejemplar de esta situación se da cuando iniciamos una conexión a una base de datos u otro tipo de canal que necesitamos mantener en un estado. Si no cerramos el objeto de conexión, la conexión puede quedar abierta hasta que se elimine el objeto.
using(var connection = new Connection())
using(var stream = connection.OpenStream())
{
// ---
}
Conclusiones
Estos son algunos puntos destacados. Podríamos ahondar más en las técnicas de Clean Code para mejorar nuestra calidad de código. Quizás abordemos esto en futuras publicaciones; espero que hayan disfrutado de esta.