BiblioTech ha crescut, mòdul a mòdul, fins a tenir un domini complet (MaterialBibliotecari, Llibre, Revista, Soci, Prestec, Biblioteca), persistència en quatre formes diferents (text, JSON, SQLite, Entity Framework Core) i cinc interfícies d'usuari diferents. Amb aquest mòdul, el curs fa un pas enrere: en lloc d'afegir funcionalitat nova, toca consolidar i polir tot aquest codi. Aquesta primera lliçó se centra en la base de qualsevol procés de polit: els estàndards de codificació. Un estàndard de codificació no és una qüestió estètica menor —és el que permet que qualsevol persona (inclòs el teu propi "jo" d'aquí a sis mesos) llegeixi codi que no va escriure i l'entengui sense esforç—. Repassaràs i ampliaràs convencions que ja coneixes des del Mòdul 1, i en veuràs algunes de noves que s'apliquen al projecte com a conjunt, no només a una línia solta.

Contingut

  1. Per què importen els estàndards de codificació en un projecte que creix
  2. Convencions de nomenclatura .NET: repàs i ampliació
  3. EditorConfig i analitzadors de codi
  4. Principi de responsabilitat única a nivell de mètode i de classe
  5. Comentaris útils davant de comentaris soroll
  6. Documentació XML (///) a l'API pública de Biblioteca
  7. Nul·labilitat consistent a tot el projecte
  8. Exemple integrat: abans i després d'un fragment de Biblioteca

  1. Per què importen els estàndards de codificació en un projecte que creix

A les primeres lliçons del curs, amb programes de poques línies, qualsevol estil d'escriptura "funcionava": el codi era tan curt que s'entenia igual, es digués x o numeroPagines a una variable. BiblioTech ja no és així: té un domini de diverses classes, diverses formes de persistència i cinc interfícies d'usuari, repartides en un projecte real que, en una empresa, mantindrien diverses persones alhora. En aquest context, un estàndard de codificació consistent deixa de ser una preferència personal i esdevé una necessitat:

Sense estàndard consistent Amb estàndard consistent
Cada classe "es llegeix" diferent; cal reaprendre l'estil a cada fitxer El codi es llegeix de forma uniforme a tot el projecte
Revisar codi d'altri costa més temps (Lliçó 5 d'aquest mòdul) Les revisions se centren en la lògica, no en discutir l'estil
Els errors de nul·labilitat o de noms confusos es colen més fàcilment Molts errors s'eviten només per seguir la convenció
Incorporar algú nou al projecte és lent El codi nou "encaixa" de seguida amb la resta

No es tracta d'imposar un estil per caprici, sinó d'eliminar decisions repetitives —majúscula o minúscula inicial? on va el comentari?— per poder dedicar l'atenció al que de veritat importa: que el codi faci el correcte.

  1. Convencions de nomenclatura .NET: repàs i ampliació

La lliçó de Sintaxi Bàsica i Estructura (Mòdul 1) va introduir les dues convencions centrals de .NET:

Convenció Regla On s'usa
PascalCase Cada paraula comença en majúscula Classes, mètodes, propietats (Biblioteca, RegistrarPrestec, Titol)
camelCase La primera paraula en minúscula Variables locals i paràmetres (titol, idSoci)

A això s'hi afegeixen ara tres convencions addicionals, ja aplicades de passada a BiblioTech però sense anomenar-les formalment fins ara:

  • Prefix I a les interfícies: IPrestable, ICercable (Mòdul 4). El prefix I anticipa, només llegint el nom, que es tracta d'un contracte i no d'una classe concreta —una convenció que veuràs portada més lluny a la Lliçó 3 d'aquest mòdul, amb IRepositoriBiblioteca.
  • Prefix _ als camps privats: _socisPerId (Mòdul 4, a Biblioteca). Distingeix d'un cop d'ull un camp privat d'una propietat pública o d'una variable local, sense necessitat de mirar la seva declaració.
  • Sufix Async als mètodes asíncrons: PrestarLlibreAsync (Mòdul 4), ObtenirMetadadesPerIsbnAsync (Mòdul 5). Avisa qui crida el mètode que ha de fer servir await, sense haver de consultar la signatura completa.
class Biblioteca
{
    private Dictionary<int, Soci> _socisPerId = new Dictionary<int, Soci>(); // _prefix: camp privat

    public List<MaterialBibliotecari> Cataleg { get; } = new List<MaterialBibliotecari>(); // PascalCase: propietat publica

    public async Task PrestarLlibreAsync(Llibre llibre, Soci soci) // sufix Async: metode asincron
    {
        // ...
    }
}

Aquestes tres convencions no són caprichos del propi curs: són les que segueix tota la biblioteca estàndard de .NET i la immensa majoria del codi C# publicat, la qual cosa significa que seguir-les fa que BiblioTech "encaixi" de seguida amb qualsevol altre projecte .NET que algú llegeixi després.

  1. EditorConfig i analitzadors de codi

Recordar una convenció de memòria i aplicar-la a mà a cada línia és propens a errors. Dues eines n'automatitzen bona part:

  • EditorConfig (fitxer .editorconfig a l'arrel del projecte): un fitxer de text que declara regles de format —indentació, ús d'espais davant de tabuladors, salt de línia final, i també convencions de nomenclatura de C#— que editors com Visual Studio o VS Code apliquen automàticament en escriure i donar format al codi.
  • Analitzadors de codi (Roslyn analyzers): eines que examinen el codi a la recerca de problemes —des d'estil fins a errors potencials— i mostren avisos directament a l'editor, abans fins i tot de compilar. .NET inclou un conjunt d'analitzadors activat per defecte a qualsevol projecte modern (dotnet new), i es poden ampliar instal·lant paquets NuGet addicionals (per exemple, Microsoft.CodeAnalysis.NetAnalyzers amb regles més estrictes).
# .editorconfig (fragment il·lustratiu)
root = true

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

Aquesta lliçó no aprofundeix en la sintaxi completa de .editorconfig ni en la configuració d'analitzadors —cada equip sol adoptar un conjunt ja preparat—, però és important saber que existeixen: automatitzen precisament les convencions vistes a l'apartat anterior, de manera que un oblit de nomenclatura es detecta com un avís a l'editor, no en una revisió de codi dies després.

  1. Principi de responsabilitat única a nivell de mètode i de classe

El principi de responsabilitat única (una de les idees centrals dels patrons de disseny, que la lliçó següent retoma amb més detall) diu, de forma senzilla: cada mètode i cada classe hauria de tenir una única raó per canviar. Aplicat al dia a dia, significa que un mètode ha de fer una cosa, i fer-la bé, en comptes de barrejar diverses responsabilitats no relacionades.

// Abans: un metode amb dues responsabilitats barrejades
public void ProcessarPrestec(Llibre llibre, Soci soci)
{
    if (!llibre.Disponible)
    {
        Console.WriteLine("No disponible.");
        return;
    }

    llibre.Prestar();
    Console.WriteLine($"'{llibre.Titol}' prestat a {soci.Nom}."); // responsabilitat de presentacio
    // ... aqui es podria colar tambe logica de desat, de validacio, de notificacio...
}
// Despres: cada metode te una unica responsabilitat
public bool IntentarPrestar(Llibre llibre, Soci soci)
{
    if (!llibre.Disponible)
    {
        return false;
    }

    llibre.Prestar();
    return true;
}

// La decisio de que mostrar per consola (o una altra interficie) viu fora, on correspon
if (biblioteca.IntentarPrestar(llibre1, soci1))
{
    Console.WriteLine($"'{llibre1.Titol}' prestat a {soci1.Nom}.");
}
else
{
    Console.WriteLine("No disponible.");
}

IntentarPrestar ara només decideix si el préstec és possible i actualitza l'estat del llibre; què fer amb aquest resultat (mostrar-ho per consola, per una finestra WPF, o retornar-ho com a JSON des d'un endpoint d'ASP.NET Core) és responsabilitat de qui el crida, no del mètode en si. Aquesta separació és exactament la que ja vas veure, sense anomenar-la així, a les cinc interfícies del Mòdul 7: la mateixa Biblioteca serveix Windows Forms, WPF, ASP.NET Core, Blazor i MAUI precisament perquè la seva lògica no assumeix res sobre com es presenten els seus resultats.

  1. Comentaris útils davant de comentaris soroll

No tots els comentaris aporten valor. Un comentari que repeteix el que el codi ja diu amb claredat és soroll: ocupa espai, i amb el temps pot quedar desactualitzat respecte al codi real, cosa que és pitjor que no tenir cap comentari.

// Soroll: el comentari no diu res que el codi no digui ja
// Incrementa i en 1
i++;

// Suma el preu al total
total += preu;
// Util: explica el "per que", no el "que" (el codi ja ho diu)
// Es revalida la disponibilitat despres del retard simulat, perque podia haver canviat
// mentre s'esperava la resposta del servei de sancions (Modul 4).
if (!llibre.Disponible)
{
    throw new InvalidOperationException($"'{llibre.Titol}' no esta disponible per a prestec.");
}
Tipus de comentari Quan escriure'l?
Explica el "què" fa una línia òbvia Mai: si cal, el nom de la variable o el mètode està mal triat
Explica el "per què" d'una decisió no evident Sí: una regla de negoci, una limitació externa, una raó històrica
Adverteix d'un efecte secundari no obvi Sí: per exemple, que un mètode modifica un objecte rebut per paràmetre
Queda desactualitzat respecte al codi actual Mai: pitjor que no comentar, perquè indueix a error

Regla pràctica: si sents la necessitat de comentar què fa una línia de codi, primer intenta canviar el nom de variables o extreure un mètode amb un nom més descriptiu; reserva el comentari per al que el codi, per si sol, no pot expressar.

  1. Documentació XML (///) a l'API pública de Biblioteca

El Mòdul 1 va introduir breument els comentaris de documentació (///), basats en etiquetes XML, sense fer-los servir encara al model de BiblioTech. Ara que Biblioteca té una API pública consolidada, és el moment de documentar-la:

class Biblioteca
{
    /// <summary>
    /// Intenta registrar el prestec d'un llibre a un soci.
    /// </summary>
    /// <param name="llibre">El llibre que es vol prestar.</param>
    /// <param name="soci">El soci que sollicita el prestec.</param>
    /// <returns>
    /// <c>true</c> si el prestec es va registrar correctament; <c>false</c> si el llibre
    /// no estava disponible.
    /// </returns>
    public bool IntentarPrestar(Llibre llibre, Soci soci)
    {
        if (!llibre.Disponible)
        {
            return false;
        }

        llibre.Prestar();
        return true;
    }
}

<summary> descriu breument què fa el membre; <param> documenta cada paràmetre; <returns> explica el significat del valor retornat. El benefici no és només per a qui llegeix el codi font: qualsevol editor modern (Visual Studio, VS Code amb l'extensió de C#) mostra aquest text automàticament com a ajuda contextual en escriure una crida a IntentarPrestar, igual com passa amb els mètodes de la pròpia biblioteca estàndard de .NET (Console.WriteLine, per exemple, té la seva pròpia documentació XML). Documentar així tota una classe petita seria excessiu; la pràctica habitual és reservar /// per a l'API pública de les classes centrals del projecte —exactament el cas de Biblioteca— i ometre-ho en detalls interns que ja s'expliquen sols pel seu nom.

  1. Nul·labilitat consistent a tot el projecte

La lliçó de Pattern Matching i Característiques Modernes (Mòdul 4) va presentar #nullable enable i va advertir d'un error comú: activar-ho a mitja projecte i no atendre els avisos que genera. Ara que BiblioTech és un projecte complet, aquesta recomanació esdevé una regla d'estàndard de codificació: #nullable enable s'ha d'aplicar de forma consistent a tots els fitxers del projecte, no només als que es van tocar més recentment.

#nullable enable

class Biblioteca
{
    public MaterialBibliotecari? CercarPerTitol(string titol)
    {
        return Cataleg.FirstOrDefault(material => material.Titol == titol);
        // FirstOrDefault pot retornar null; el "?" al tipus de retorn ho fa explicit
    }

    public List<MaterialBibliotecari> Cataleg { get; } = new List<MaterialBibliotecari>();
}
Sense nul·labilitat consistent Amb nul·labilitat consistent
Alguns mètodes avisen que poden retornar null, altres no, sense cap criteri Tot tipus de referència que pot ser null ho declara amb ?, a tot el projecte
El compilador només avisa als fitxers on està activat #nullable enable El compilador avisa de forma uniforme a qualsevol fitxer
Risc de NullReferenceException en fitxers "oblidats" El risc es concentra on de veritat pot passar, marcat amb ?

En un projecte nou, la forma més senzilla d'aconseguir aquesta consistència és activar <Nullable>enable</Nullable> una única vegada al fitxer de projecte (.csproj), que aplica #nullable enable a tots els fitxers .cs automàticament, sense haver de repetir la directiva a cadascun.

  1. Exemple integrat: abans i després d'un fragment de Biblioteca

Unint tot l'anterior, així es veu un fragment de Biblioteca sense cuidar els estàndards vistos en aquesta lliçó, i la seva versió revisada:

// Abans: noms poc clars, responsabilitats barrejades, sense documentacio, sense nul·labilitat
class Biblioteca
{
    public List<MaterialBibliotecari> llista = new List<MaterialBibliotecari>();

    public MaterialBibliotecari Obtenir(string t)
    {
        foreach (var x in llista)
        {
            if (x.Titol == t)
            {
                return x;
            }
        }
        return null;
    }

    public void Proc(string t, Soci s)
    {
        var m = Obtenir(t);
        if (m != null && m.Disponible)
        {
            m.Prestar();
            Console.WriteLine($"'{m.Titol}' prestat a {s.Nom}.");
        }
        else
        {
            Console.WriteLine("No s'ha pogut prestar.");
        }
    }
}
// Despres: noms descriptius, responsabilitats separades, documentat, nul·labilitat explicita
#nullable enable

class Biblioteca
{
    public List<MaterialBibliotecari> Cataleg { get; } = new List<MaterialBibliotecari>();

    /// <summary>
    /// Cerca un material del catalog per el seu titol exacte.
    /// </summary>
    /// <param name="titol">El titol a cercar.</param>
    /// <returns>El material trobat, o <c>null</c> si cap material coincideix.</returns>
    public MaterialBibliotecari? CercarPerTitol(string titol)
    {
        return Cataleg.FirstOrDefault(material => material.Titol == titol);
    }

    /// <summary>
    /// Intenta prestar el material amb el titol indicat.
    /// </summary>
    /// <param name="titol">El titol del material a prestar.</param>
    /// <param name="soci">El soci que sollicita el prestec.</param>
    /// <returns><c>true</c> si el prestec es va registrar; <c>false</c> en cas contrari.</returns>
    public bool IntentarPrestarPerTitol(string titol, Soci soci)
    {
        MaterialBibliotecari? material = CercarPerTitol(titol);

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

        material.Prestar();
        return true;
    }
}

CercarPerTitol i IntentarPrestarPerTitol són ara dos mètodes amb una única responsabilitat cadascun, amb noms que diuen exactament què fan, documentats amb ///, i amb la nul·labilitat de CercarPerTitol explícita a la seva signatura (MaterialBibliotecari?). Cal notar que la decisió de què mostrar per consola ja no viu dins de Biblioteca: queda, com a l'apartat 4, en mans de qui crida el mètode, sigui la consola, un formulari o un endpoint HTTP.

Errors Comuns i Consells

  • Barrejar convencions de nomenclatura dins del mateix projecte: fer servir _camp en una classe i camp a seques en una altra, sense cap criteri, confon més que no tenir cap convenció. Aplica la mateixa regla a tot el projecte.
  • Comentar el "què" en comptes de canviar el nom: si necessites un comentari per explicar què fa una línia senzilla, gairebé sempre és preferible millorar el nom de la variable o extreure un mètode amb un nom descriptiu.
  • Documentar amb /// cada línia del projecte: és un esforç desproporcionat i amb el temps tendeix a desactualitzar-se. Reserva /// per a l'API pública de les classes centrals.
  • Activar #nullable enable només en fitxers nous: deixa el projecte amb un criteri inconsistent. Activa'l a nivell de projecte (.csproj) perquè s'apliqui de forma uniforme.
  • Consell: si tens dubtes sobre com anomenar alguna cosa, pregunta't quin nom faria servir la pròpia biblioteca estàndard de .NET per a un concepte equivalent (List, Dictionary, HttpClient...); gairebé sempre aquesta intuïció coincideix amb la convenció correcta.

Exercicis

  1. Donat el següent mètode de Biblioteca, identifica tres problemes d'estàndard de codificació (nomenclatura, responsabilitat única, nul·labilitat) i reescriu-lo corregint-los:

    public Soci Cercar(int i)
    {
        foreach (var s in Socis)
        {
            if (s.Id == i) return s;
        }
        return null;
    }
    
  2. Afegeix documentació XML (/// amb <summary>, <param> i <returns>) al mètode corregit de l'exercici anterior.

Solucions

Problemes: (a) el paràmetre i i el nom Cercar són poc descriptius; (b) el mètode pot retornar null però la seva signatura no ho reflecteix (Soci en comptes de Soci?); (c) el nom no distingeix "cercar per id" d'altres possibles cerques futures (per nom, per exemple).

public Soci? CercarSociPerId(int idSoci)
{
    return Socis.FirstOrDefault(soci => soci.Id == idSoci);
}
/// <summary>
/// Cerca un soci pel seu identificador.
/// </summary>
/// <param name="idSoci">L'identificador del soci a cercar.</param>
/// <returns>El soci trobat, o <c>null</c> si no existeix cap soci amb aquest identificador.</returns>
public Soci? CercarSociPerId(int idSoci)
{
    return Socis.FirstOrDefault(soci => soci.Id == idSoci);
}

Conclusió

En aquesta lliçó has repassat i ampliat les convencions de nomenclatura de .NET (PascalCase/camelCase, prefixos I/_, sufix Async), conegut EditorConfig i els analitzadors de codi com a eines que automatitzen aquestes convencions, aplicat el principi de responsabilitat única per separar lògica de presentació, distingit comentaris útils de soroll, documentat l'API pública de Biblioteca amb ///, i establert la nul·labilitat consistent com a estàndard de tot el projecte. Amb aquest fragment de Biblioteca ja més net i llegible, la lliçó següent fa un pas més enllà de l'estil: els patrons de disseny, solucions ja provades a problemes de disseny recurrents, que veuràs aplicades directament sobre el propi domini de BiblioTech.

Curs de Programació en C#

Mòdul 1: Introducció al C#

Mòdul 2: Estructures de Control

Mòdul 3: Programació Orientada a Objectes

Mòdul 4: Conceptes Avançats de C#

Mòdul 5: Treballant amb Dades

Mòdul 6: Temes Avançats

Mòdul 7: Construcció d'Aplicacions

Mòdul 8: Bones Pràctiques i Patrons de Disseny

Mòdul 9: Projecte Final

© Copyright 2026. Tots els drets reservats