El estándar de codificación es una herramienta que debe acompañar a cada programador que se involucre en la construcción de este software. El estándar de codificación funciona como una guía durante la escritura y estructuración del código, estableciendo pautas, reglas y principios que se deben seguir para mantener la consistencia en todo el código fuente.
Es importante acoplarse al estándar en todo momento para generar efectos positivos en la comunicación y colaboración entre los desarrolladores, logrando un código más limpio, fácil de leer y comprensible. Además, en un estándar de codificación no solo se especifican pautas para dar estilo al código, si no que se hace énfasis en las buenas prácticas que se deben seguir para mantener la robustez del software.
Este estándar contiene las siguientes secciones:
- Reglas de nombrado: establece las pautas para el nombramiento de variables, constantes, métodos, clases, propiedades (una característica especial del lenguaje utilizado C#) y espacios de nombre (namespaces).
- Estilo: esta sección se enfoca en la estructura visual del código como la indentación, uso de comentarios y la distribución de elementos en las estructuras de control.
- Manejo de excepciones: aquí se abarcan las reglas que se deben seguir para implementar buenas prácticas en la captura de excepciones y cuales deben ser registradas en la bitácora de errores de la aplicación.
- Prácticas seguras de construcción: en este apartado se encuentran las estrategias que se deben seguir en determinadas áreas del código para mantener la robustez del software.
Éste estandar servirá como guia para la escritura homogenea, legible y segura del código en el proyecto de tecnologías para la construcción de software, el cual estará escrito en C# y apegandose mayormente al estandar establecido por microsoft.
El proyecto seguirá el paradigma de orientación a objetos y estará escrito en inglés.
El proyecto se trata de un juego multijugador en linea ...
- Utilice nombres descriptivos para variables, constantes, métodos, clases, propiedades y espacios de nombre (namespaces).
- Utilice la notación PascalCase para los nombres de propiedades, métodos, clases, proyectos y namespaces. Esta consiste en comenzar cada palabra en mayúsculas, sin espacios ni guiones.
- Utilice la notación camelCase para los parámetros de métodos y las variables. Esta consiste en comenzar la primera palabra con minúscula y las siguiente con mayúscula, sin espacios ni guiones.
- Las variables internas y privadas deberán tener el prefijo "_" y se usará readonly siempre que sea posible.
- Los nombres de las interfaces deben llevar el prefijo "I".
- Las clases serializadas por el servicio deben contener el sufijo "DC", haciendo alusión a "Data contract".
- Las clases que se encarguen de la persistencia de datos deben contener el sufijo "DB".
- Para las clases que contengan las pruebas unitarias de una clase en especifico deben nombrarse con el nombre de la clase que prueban seguido del sufijo "Test".
- Los métodos de pruebas unitarias deben tener un nombre descriptivo alusivo a la prueba seguido del sufijo "Test".
Ejemplo general:
namespace GameApplication.Accounts
{
public enum AccountType
{
Basic,
Premium
}
public interface IAccount
{
int AccountId { get; }
AccountType Type { get; }
void GrowLevel();
}
public class BasicAccount : IAccount
{
private int _accountId;
public BasicAccount(int accountId)
{
//code
}
public int AccountId => _accountId;
public AccountType Type => AccountType.Basic;
public void GrowLevel()
{
//Code
}
}
}Así no:
namespace application
{
public enum types
{
Basic,
Premium
}
public interface Account
{
int id { get; }
types type { get; }
void growLevel();
}
public class BasicAccount : Account
{
private int ID;
public BasicAccount(int id)
{
//code
}
public int id => ID;
public types type => types.Basic;
public void growLevel()
{
//Code
}
}
}Constantes:
-
Utilizar la notación de UPPER_SNAKE_CASE para el nombramiento de constantes.
Ejemplo:
const double PI = 3.1416;
Así no:
const double pi = 3.1416;
Consejos:
- Evite el uso de abreviaturas o acrónimos en los nombres, a excepción de las abreviaturas ampliamente conocidas y aceptadas.
- Prefiere la claridad a la brevedad.
- Evite usar nombres de una sola letra, excepto para contadores de bucle simples.
- Utilizar 4 espacios para la indentación, no tabulación.
- Se usará estilo de llaves Allman, es decir, las llaves que abren y cierran bloques de código, deben ocupar una sola línea, y empezar a escribir código en la siguiente línea.
- Evitar usar this, a menos que sea absolutamente necesario.
- Espacios entre operadores binarios.
Ejemplo
private Foo()
{
if (Bar == null)
{
DoThing();
}
while (true)
{
Do();
}
}Así no:
private Foo() {
if (Bar==null) {
DoThing();
}
else {
DoTheOtherThing();
}
}Comentarios
Solo se utilizarán comentarios de linea, y se escribirán sobre la linea o lineas de codigo del que se habla, al mismo nivel de indentación, y con un espacio despues de los diagonales.
Procurar utilizarlos solamente cuando sea necesario explicar la razón por la que se codificó de una manera específica en alguna parte o con finalidades de documentación para la API de la aplicación
- Comentarios de documentación: Todas las clases, structs, enum, funciones, propiedades y campos públicos deben describirse en cuanto a su propósito y uso. Esta regla garantiza que la documentación se genere y difunda correctamente para todas las clases, métodos y propiedades.
- Marcas de codigo incompleto: Se utilizarán comentarios "todo" (por hacer) en ubicaciones del codigo que se terminarán despues.
Ejemplo:
// <summary>
// The Controller definition defines ...
// </summary>
public class Controller
{
/// <summary>
/// The ID assigned to the Controller
/// </summary>
public int id;
}Así no:
// The Controller class
public class Controller
{
public int id; // The ID assigned to the Controller
}- Debe haber un espacio entre la declaración de la estructura de control y el paréntesis.
- Las llaves son necesarias, incluso si solo contendrán una linea.
Ejemplo
if (bar == null)
{
//code
}
while (true)
{
//code
}Así no:
if(Bar == null)
{
//code
}
while (true)
{
//code
}- Las excepciones se manejarán con bloques try-catch, y se usará using cuando sea posible y más legible que un bloque try-catch.
- No se usará en bloques try-catch el tipo de excepción más alto (Exception), sino errores especificos.
- Se usarán filtros de excepciones en vez de bloques if cuando sean necesarios.
- Las excepciones atrapadas por bloques catch se nombrarán "error".
Librería: log4net.
La bitácora debe manejarse prioritariamente en la clase que implemente los contratos (ServiceImplementation) en el servidor, ya que es la primera capa de comunicación directa con el servidor.
Las siguientes listas muestran una guía para identificar en qué nivel registrar cada elemento en la bitácora.
FATAL: errores que afectan al sistema completamente. Generalmente conexiones fallidas a la base de datos o archivos no encontrados en el sistema.
- EntityException
- FileNotFoundException
WARNING: situaciones anormales que pueden indicar futuros problemas. Por ejemplo, información que no es actualizada debido a un error de conexión en la base de datos, o correos no enviados.
- SmtpCommandException
INFO: eventos significativos en la ejecución del sistema. Pueden ir desde registrar el inicio de sesión de un jugador, intentos fallidos de inicio de sesión, canales de comunicación cerrados inesperadamente, entre otros.
Para manejar los diferentes resultados o flujos que puede generar la ejecución de un método en la parte del servidor, estos devolverán un código de acuerdo al resultado obtenido.
Todos los códigos manejados se encuntran en el archivo ==ErrorCodes.md==
- Utilizar una cuenta solo con los permisos esenciales para acceder a la base de datos. Con el fin de reducir el daño potencial en caso de un compromiso de la cuenta, debido a un atacante externo o por un error de programación.
- Las credenciales de la cuenta de acceso a la base de datos no deben estar situada dentro del código. Ya que el código de este proyecto es público y cualquier persona puede utilizarlas para acceder a la base de datos.
- Liberar los recursos después de utilzarlos. Liberar los recursos (como conexiones a bases de datos, Flujos a archivos, etc.) evita consumo innecesario de memoria. Si no se liberan, pueden agotarse los recursos del sistema y llevar a errores durante la ejecución de la aplicación.
- Validación de parámetros de entrada en una función. Para asegurarse que los datos se encuentren como se esperan y garantizar el correcto funcionamiento de la función.
- Ningún método debe devolver null como valor de retorno. Devolver null puede llevar a NullPointerExceptions. Considere devolver un valor por defecto, una excepción o un objeto opcional para indicar la ausencia de un valor.
- Validación de las entradas de datos del usuario por medio de campos. Para asegurarse que el usuario introduzca datos válidos para la aplicación y evitar errores en el procesamiento y consistencia de estos.
- Respetar el principio de encapsulación. Utilice siempre campos privados y propiedades públicas si se necesita acceder al campo desde fuera de la clase o struct. Asegúrese de ubicar en el mismo lugar el campo privado y la propiedad pública.
- Limitar la cantidad de información crítica al usuario. No mostrar el error especifico al usuario para evitar revelar información sensible sobre la aplicación, en su lugar, notificarle con un mensaje breve y descriptivo de lo que sucedió.
- Encriptación de contraseñas que se registran en la base de datos.
- No registrar información sensible o confidencial en las bitácoras de error. Esto se hace con el fin de mantener segura la información de los usuarios en cualquier situación que se vulnere el sistema de bitácoras. En su lugar se pueden utilizar identificadores o palabras clave.