BiblioTech ha crecido, módulo a módulo, hasta tener un dominio completo (MaterialBibliotecario, Libro, Revista, Socio, Prestamo, Biblioteca), persistencia en cuatro formas distintas (texto, JSON, SQLite, Entity Framework Core) y cinco interfaces de usuario diferentes. Con este módulo, el curso da un paso atrás: en vez de añadir funcionalidad nueva, toca consolidar y pulir todo ese código. Esta primera lección se centra en la base de cualquier proceso de pulido: los estándares de codificación. Un estándar de codificación no es una cuestión estética menor —es lo que permite que cualquier persona (incluido tu propio "yo" dentro de seis meses) lea código que no escribió y lo entienda sin esfuerzo. Repasarás y ampliarás convenciones que ya conoces desde el Módulo 1, y verás algunas nuevas que se aplican al proyecto como conjunto, no solo a una línea suelta.

Contenido

  1. Por qué importan los estándares de codificación en un proyecto que crece
  2. Convenciones de nomenclatura .NET: repaso y ampliación
  3. EditorConfig y analizadores de código
  4. Principio de responsabilidad única a nivel de método y de clase
  5. Comentarios útiles frente a comentarios ruido
  6. Documentación XML (///) en la API pública de Biblioteca
  7. Nulabilidad consistente en todo el proyecto
  8. Ejemplo integrado: antes y después de un fragmento de Biblioteca

  1. Por qué importan los estándares de codificación en un proyecto que crece

En las primeras lecciones del curso, con programas de pocas líneas, cualquier estilo de escritura "funcionaba": el código era tan corto que se entendía igual, se llamara x o numeroPaginas a una variable. BiblioTech ya no es así: tiene un dominio de varias clases, varias formas de persistencia y cinco interfaces de usuario, repartidas en un proyecto real que, en una empresa, mantendrían varias personas a la vez. En ese contexto, un estándar de codificación consistente deja de ser una preferencia personal y se convierte en una necesidad:

Sin estándar consistente Con estándar consistente
Cada clase "se lee" distinto; hay que reaprender el estilo en cada fichero El código se lee de forma uniforme en todo el proyecto
Revisar código ajeno cuesta más tiempo (Lección 5 de este módulo) Las revisiones se centran en la lógica, no en discutir el estilo
Los errores de nulabilidad o de nombres confusos se cuelan más fácilmente Muchos errores se evitan solo por seguir la convención
Incorporar a alguien nuevo al proyecto es lento El código nuevo "encaja" de inmediato con el resto

No se trata de imponer un estilo por capricho, sino de eliminar decisiones repetitivas —¿mayúscula o minúscula inicial? ¿dónde va el comentario?— para poder dedicar la atención a lo que de verdad importa: que el código haga lo correcto.

  1. Convenciones de nomenclatura .NET: repaso y ampliación

La lección de Sintaxis Básica y Estructura (Módulo 1) introdujo las dos convenciones centrales de .NET:

Convención Regla Dónde se usa
PascalCase Cada palabra empieza en mayúscula Clases, métodos, propiedades (Biblioteca, RegistrarPrestamo, Titulo)
camelCase La primera palabra en minúscula Variables locales y parámetros (titulo, idSocio)

A eso se añaden ahora tres convenciones adicionales, ya aplicadas de pasada en BiblioTech pero sin nombrarlas formalmente hasta ahora:

  • Prefijo I en interfaces: IPrestable, IBuscable (Módulo 4). El prefijo I anticipa, con solo leer el nombre, que se trata de un contrato y no de una clase concreta —una convención que verás llevada más lejos en la Lección 3 de este módulo, con IRepositorioBiblioteca.
  • Prefijo _ en campos privados: _sociosPorId (Módulo 4, en Biblioteca). Distingue de un vistazo un campo privado de una propiedad pública o de una variable local, sin necesitar mirar su declaración.
  • Sufijo Async en métodos asíncronos: PrestarLibroAsync (Módulo 4), ObtenerMetadatosPorIsbnAsync (Módulo 5). Avisa a quien llama al método que debe usar await, sin tener que consultar la firma completa.
class Biblioteca
{
    private Dictionary<int, Socio> _sociosPorId = new Dictionary<int, Socio>(); // _prefijo: campo privado

    public List<MaterialBibliotecario> Catalogo { get; } = new List<MaterialBibliotecario>(); // PascalCase: propiedad publica

    public async Task PrestarLibroAsync(Libro libro, Socio socio) // sufijo Async: metodo asincrono
    {
        // ...
    }
}

Estas tres convenciones no son caprichos del propio curso: son las que sigue toda la biblioteca estándar de .NET y la inmensa mayoría del código C# publicado, lo que significa que seguirlas hace que BiblioTech "encaje" de inmediato con cualquier otro proyecto .NET que alguien lea después.

  1. EditorConfig y analizadores de código

Recordar una convención de memoria y aplicarla a mano en cada línea es propenso a errores. Dos herramientas automatizan buena parte de ese trabajo:

  • EditorConfig (fichero .editorconfig en la raíz del proyecto): un fichero de texto que declara reglas de formato —indentación, uso de espacios frente a tabuladores, salto de línea final, y también convenciones de nomenclatura de C#— que editores como Visual Studio o VS Code aplican automáticamente al escribir y al dar formato al código.
  • Analizadores de código (Roslyn analyzers): herramientas que examinan el código en busca de problemas —desde estilo hasta errores potenciales— y muestran avisos directamente en el editor, antes incluso de compilar. .NET incluye un conjunto de analizadores activado por defecto en cualquier proyecto moderno (dotnet new), y pueden ampliarse instalando paquetes NuGet adicionales (por ejemplo, Microsoft.CodeAnalysis.NetAnalyzers con reglas más estrictas).
# .editorconfig (fragmento ilustrativo)
root = true

[*.cs]
indent_style = space
indent_size = 4
dotnet_naming_rule.interfaces_should_be_prefixed_with_i.severity = warning

Esta lección no profundiza en la sintaxis completa de .editorconfig ni en la configuración de analizadores —cada equipo suele adoptar un conjunto ya preparado—, pero es importante saber que existen: automatizan justamente las convenciones vistas en el apartado anterior, de modo que un olvido de nomenclatura se detecta como un aviso en el editor, no en una revisión de código días después.

  1. Principio de responsabilidad única a nivel de método y de clase

El principio de responsabilidad única (una de las ideas centrales de los patrones de diseño, que la próxima lección retoma con más detalle) dice, de forma simple: cada método y cada clase debería tener una única razón para cambiar. Aplicado al día a día, significa que un método debe hacer una cosa, y hacerla bien, en vez de mezclar varias responsabilidades no relacionadas.

// Antes: un metodo con dos responsabilidades mezcladas
public void ProcesarPrestamo(Libro libro, Socio socio)
{
    if (!libro.Disponible)
    {
        Console.WriteLine("No disponible.");
        return;
    }

    libro.Prestar();
    Console.WriteLine($"'{libro.Titulo}' prestado a {socio.Nombre}."); // responsabilidad de presentacion
    // ... aqui se podria colar tambien logica de guardado, de validacion, de notificacion...
}
// Despues: cada metodo tiene una unica responsabilidad
public bool IntentarPrestar(Libro libro, Socio socio)
{
    if (!libro.Disponible)
    {
        return false;
    }

    libro.Prestar();
    return true;
}

// La decision de que mostrar por consola (u otra interfaz) vive fuera, donde corresponde
if (biblioteca.IntentarPrestar(libro1, socio1))
{
    Console.WriteLine($"'{libro1.Titulo}' prestado a {socio1.Nombre}.");
}
else
{
    Console.WriteLine("No disponible.");
}

IntentarPrestar ahora solo decide si el préstamo es posible y actualiza el estado del libro; qué hacer con ese resultado (mostrarlo por consola, por una ventana WPF, o devolverlo como JSON desde un endpoint de ASP.NET Core) es responsabilidad de quien lo llama, no del método en sí. Esta separación es exactamente la que ya viste, sin nombrarla así, en las cinco interfaces del Módulo 7: la misma Biblioteca sirve a Windows Forms, WPF, ASP.NET Core, Blazor y MAUI precisamente porque su lógica no asume nada sobre cómo se presentan sus resultados.

  1. Comentarios útiles frente a comentarios ruido

No todos los comentarios aportan valor. Un comentario que repite lo que el código ya dice con claridad es ruido: ocupa espacio, y con el tiempo puede quedar desactualizado respecto al código real, lo que es peor que no tener comentario alguno.

// Ruido: el comentario no dice nada que el codigo no diga ya
// Incrementa i en 1
i++;

// Suma el precio al total
total += precio;
// Util: explica el "por que", no el "que" (el codigo ya lo dice)
// Se revalida la disponibilidad tras el retardo simulado, porque pudo cambiar
// mientras se esperaba la respuesta del servicio de sanciones (Modulo 4).
if (!libro.Disponible)
{
    throw new InvalidOperationException($"'{libro.Titulo}' no esta disponible para prestamo.");
}
Tipo de comentario ¿Cuándo escribirlo?
Explica el "qué" hace una línea obvia Nunca: si hace falta, el nombre de la variable o el método está mal elegido
Explica el "por qué" de una decisión no evidente Sí: una regla de negocio, una limitación externa, una razón histórica
Advierte de un efecto secundario no obvio Sí: por ejemplo, que un método modifica un objeto recibido por parámetro
Queda desactualizado respecto al código actual Nunca: peor que no comentar, porque induce a error

Regla práctica: si sientes la necesidad de comentar qué hace una línea de código, primero intenta renombrar variables o extraer un método con un nombre más descriptivo; reserva el comentario para lo que el código, por sí solo, no puede expresar.

  1. Documentación XML (///) en la API pública de Biblioteca

El Módulo 1 introdujo brevemente los comentarios de documentación (///), basados en etiquetas XML, sin usarlos todavía en el modelo de BiblioTech. Ahora que Biblioteca tiene una API pública consolidada, es el momento de documentarla:

class Biblioteca
{
    /// <summary>
    /// Intenta registrar el prestamo de un libro a un socio.
    /// </summary>
    /// <param name="libro">El libro que se quiere prestar.</param>
    /// <param name="socio">El socio que solicita el prestamo.</param>
    /// <returns>
    /// <c>true</c> si el prestamo se registro correctamente; <c>false</c> si el libro
    /// no estaba disponible.
    /// </returns>
    public bool IntentarPrestar(Libro libro, Socio socio)
    {
        if (!libro.Disponible)
        {
            return false;
        }

        libro.Prestar();
        return true;
    }
}

<summary> describe brevemente qué hace el miembro; <param> documenta cada parámetro; <returns> explica el significado del valor devuelto. El beneficio no es solo para quien lee el código fuente: cualquier editor moderno (Visual Studio, VS Code con la extensión de C#) muestra este texto automáticamente como ayuda contextual al escribir una llamada a IntentarPrestar, igual que ocurre con los métodos de la propia biblioteca estándar de .NET (Console.WriteLine, por ejemplo, tiene su propia documentación XML). Documentar así toda una clase pequeña sería excesivo; la práctica habitual es reservar /// para la API pública de las clases centrales del proyecto —exactamente el caso de Biblioteca— y omitirlo en detalles internos que ya se explican solos por su nombre.

  1. Nulabilidad consistente en todo el proyecto

La lección de Pattern Matching y Características Modernas (Módulo 4) presentó #nullable enable y advirtió de un error común: activarlo a mitad de proyecto y no atender a los avisos que genera. Ahora que BiblioTech es un proyecto completo, esa recomendación se convierte en una regla de estándar de codificación: #nullable enable debe aplicarse de forma consistente en todos los ficheros del proyecto, no solo en los que se tocaron más recientemente.

#nullable enable

class Biblioteca
{
    public MaterialBibliotecario? BuscarPorTitulo(string titulo)
    {
        return Catalogo.FirstOrDefault(material => material.Titulo == titulo);
        // FirstOrDefault puede devolver null; el "?" en el tipo de retorno lo hace explicito
    }

    public List<MaterialBibliotecario> Catalogo { get; } = new List<MaterialBibliotecario>();
}
Sin nulabilidad consistente Con nulabilidad consistente
Algunos métodos avisan de que pueden devolver null, otros no, sin ningún criterio Todo tipo de referencia que puede ser null lo declara con ?, en todo el proyecto
El compilador solo avisa en los ficheros donde está activado #nullable enable El compilador avisa de forma uniforme en cualquier fichero
Riesgo de NullReferenceException en ficheros "olvidados" El riesgo se concentra donde de verdad puede ocurrir, marcado con ?

En un proyecto nuevo, la forma más simple de lograr esta consistencia es activar <Nullable>enable</Nullable> una única vez en el fichero de proyecto (.csproj), que aplica #nullable enable a todos los ficheros .cs automáticamente, sin tener que repetir la directiva en cada uno de ellos.

  1. Ejemplo integrado: antes y después de un fragmento de Biblioteca

Uniendo todo lo anterior, así se ve un fragmento de Biblioteca sin cuidar los estándares vistos en esta lección, y su versión revisada:

// Antes: nombres poco claros, responsabilidades mezcladas, sin documentacion, sin nulabilidad
class Biblioteca
{
    public List<MaterialBibliotecario> lista = new List<MaterialBibliotecario>();

    public MaterialBibliotecario Get(string t)
    {
        foreach (var x in lista)
        {
            if (x.Titulo == t)
            {
                return x;
            }
        }
        return null;
    }

    public void Proc(string t, Socio s)
    {
        var m = Get(t);
        if (m != null && m.Disponible)
        {
            m.Prestar();
            Console.WriteLine($"'{m.Titulo}' prestado a {s.Nombre}.");
        }
        else
        {
            Console.WriteLine("No se pudo prestar.");
        }
    }
}
// Despues: nombres descriptivos, responsabilidades separadas, documentado, nulabilidad explicita
#nullable enable

class Biblioteca
{
    public List<MaterialBibliotecario> Catalogo { get; } = new List<MaterialBibliotecario>();

    /// <summary>
    /// Busca un material del catalogo por su titulo exacto.
    /// </summary>
    /// <param name="titulo">El titulo a buscar.</param>
    /// <returns>El material encontrado, o <c>null</c> si ningun material coincide.</returns>
    public MaterialBibliotecario? BuscarPorTitulo(string titulo)
    {
        return Catalogo.FirstOrDefault(material => material.Titulo == titulo);
    }

    /// <summary>
    /// Intenta prestar el material con el titulo indicado.
    /// </summary>
    /// <param name="titulo">El titulo del material a prestar.</param>
    /// <param name="socio">El socio que solicita el prestamo.</param>
    /// <returns><c>true</c> si el prestamo se registro; <c>false</c> en caso contrario.</returns>
    public bool IntentarPrestarPorTitulo(string titulo, Socio socio)
    {
        MaterialBibliotecario? material = BuscarPorTitulo(titulo);

        if (material is null || !material.Disponible)
        {
            return false;
        }

        material.Prestar();
        return true;
    }
}

BuscarPorTitulo y IntentarPrestarPorTitulo son ahora dos métodos con una única responsabilidad cada uno, con nombres que dicen exactamente qué hacen, documentados con ///, y con la nulabilidad de BuscarPorTitulo explícita en su firma (MaterialBibliotecario?). Nótese que la decisión de qué mostrar por consola ya no vive dentro de Biblioteca: queda, como en el apartado 4, en manos de quien llama al método, sea la consola, un formulario o un endpoint HTTP.

Errores Comunes y Consejos

  • Mezclar convenciones de nomenclatura dentro del mismo proyecto: usar _campo en una clase y campo a secas en otra, sin ningún criterio, confunde más que no tener convención alguna. Aplica la misma regla en todo el proyecto.
  • Comentar el "qué" en vez de renombrar: si necesitas un comentario para explicar qué hace una línea sencilla, casi siempre es preferible mejorar el nombre de la variable o extraer un método con un nombre descriptivo.
  • Documentar con /// cada línea del proyecto: es un esfuerzo desproporcionado y con el tiempo tiende a desactualizarse. Reserva /// para la API pública de las clases centrales.
  • Activar #nullable enable solo en ficheros nuevos: deja al proyecto con un criterio inconsistente. Actívalo a nivel de proyecto (.csproj) para que se aplique de forma uniforme.
  • Consejo: si tienes duda sobre cómo nombrar algo, pregúntate qué nombre usaría la propia biblioteca estándar de .NET para un concepto equivalente (List, Dictionary, HttpClient...); casi siempre esa intuición coincide con la convención correcta.

Ejercicios

  1. Dado el siguiente método de Biblioteca, identifica tres problemas de estándar de codificación (nomenclatura, responsabilidad única, nulabilidad) y reescríbelo corrigiéndolos:

    public Socio Buscar(int i)
    {
        foreach (var s in Socios)
        {
            if (s.Id == i) return s;
        }
        return null;
    }
    
  2. Añade documentación XML (/// con <summary>, <param> y <returns>) al método corregido del ejercicio anterior.

Soluciones

Problemas: (a) el parámetro i y el nombre Buscar son poco descriptivos; (b) el método puede devolver null pero su firma no lo refleja (Socio en vez de Socio?); (c) el nombre no distingue "buscar por id" de otras posibles búsquedas futuras (por nombre, por ejemplo).

public Socio? BuscarSocioPorId(int idSocio)
{
    return Socios.FirstOrDefault(socio => socio.Id == idSocio);
}
/// <summary>
/// Busca un socio por su identificador.
/// </summary>
/// <param name="idSocio">El identificador del socio a buscar.</param>
/// <returns>El socio encontrado, o <c>null</c> si no existe ningun socio con ese identificador.</returns>
public Socio? BuscarSocioPorId(int idSocio)
{
    return Socios.FirstOrDefault(socio => socio.Id == idSocio);
}

Conclusión

En esta lección has repasado y ampliado las convenciones de nomenclatura de .NET (PascalCase/camelCase, prefijos I/_, sufijo Async), conocido EditorConfig y los analizadores de código como herramientas que automatizan esas convenciones, aplicado el principio de responsabilidad única para separar lógica de presentación, distinguido comentarios útiles de ruido, documentado la API pública de Biblioteca con ///, y establecido la nulabilidad consistente como estándar de todo el proyecto. Con este fragmento de Biblioteca ya más limpio y legible, la siguiente lección da un paso más allá del estilo: los patrones de diseño, soluciones ya probadas a problemas de diseño recurrentes, que verás aplicadas directamente sobre el propio dominio de BiblioTech.

Curso de Programación en C#

Módulo 1: Introducción a C#

Módulo 2: Estructuras de Control

Módulo 3: Programación Orientada a Objetos

Módulo 4: Conceptos Avanzados de C#

Módulo 5: Trabajando con Datos

Módulo 6: Temas Avanzados

Módulo 7: Construcción de Aplicaciones

Módulo 8: Mejores Prácticas y Patrones de Diseño

Módulo 9: Proyecto Final

© Copyright 2026. Todos los derechos reservados