[APORTE] Buenas prácticas y convenciones en Java - Parte uno - Convenciones

Iniciado por 3n31ch, 27 Enero 2015, 20:15 PM

0 Miembros y 2 Visitantes están viendo este tema.

3n31ch

BUENAS PRÁCTICAS Y CONVENCIONES EN JAVA - PARTE UNO - CONVENCIONES




Introducción

El presente documento es la primera parte de lo que esperamos junto Gus Garsaky sea una guía para todos aquellos desarrolladores en java. Espero que les sea de utilidad y poder ayudar a todos los desarrolladores en java que aun no esten familiarizados con el concepto de buenas prácticas y convenciones.

Es importante destacar que quizás exceptuando esta primera parte, el resto del documento puede ser de utilidad para desarrolladores sin importar el lenguaje de programación utilizado.

Sin nada mas que agregar, empecemos con la parte uno, Convenciones.




CONVENCIONES




Es importante señalar que las convenciones presentadas acá están basadas en el documento Java Code Conventions publicado por Sun Mycrosystems el año 1997: http://www.oracle.com/technetwork/java/codeconventions-150003.pdf




Indice

1.  Por qué convenciones de código.
2.  Nombres de archivos.
3.  Organización de archivos.
4.  Indentación.
5.  Comentarios.
6.  Declaraciones.
7.  Sentencias.
8.  Espacios en blanco.
A.  Convenciones de capitalización.
9.  Convenciones de nombres.
10. Hábitos de programación.




1. Por qué convenciones de código

Las convenciones de código son importantes para los programadores por múltiples razones entre ellas, las mas destacadas:


  • El 80% del tiempo de vida y costo de un software esta en la manteniente de un proyecto
  • Casi ningún software es mantenido de por vida por su autor original
  • Las convenciones de código mejoran la legibilidad del software, lo cual permite a los ingenieros comprender el código rápidamente.
  • Un software es como cualquier otro producto, y por esta misma razón debes procurar que como cualquier otro producto, este cumpla con los estándares de calidad adecuados.




2. Nombres de archivos

2.1 Extensiones de los archivos

Los archivos en java utilizan las siguientes exenciones:

Tipo de archivoExtensión
Código fuente Java.java
Bytecode de Java.class

2.2 Nombres de archivos comunes

Los nombres de archivos mas utilizados son:

Tipo de archivoUtilidad
GNUmakefileEl nombre preferido para archivos "make".
READMEEl nombre preferido para archivos que resumen los contenidos de un directorio den particular.




3. Organización de archivos

Un archivo consta de secciones que deben ser separadas por lineas en blanco y comentarios opcionales que identifiquen cada sección.

Archivos con mas de 2000 lineas son engorrosos y deben ser evitados.

3.1 Archivos fuente de Java

Cada archivo de fuente de Java contiene un sola clase o interfaces publica. cuando una clase o interfaces privada esta asociada con una clase publica, se puede poner el mismo archivo que la clase publica. La clase publica debe ser la primera clase o interfaces en el archivo.

Código (java) [Seleccionar]
public class MyClass {
   private class MyPrivateClass {
   
   }


Los archivos fuente de Java tienen el siguiente orden:


  • Comentarios de inicio.
  • Sentencias package e import.
  • Declaraciones de clases e interfaces.

3.1.1 Comentarios de inicio

Todo código fuente debe tener comentarios de inicio que señale el nombre de la clase, versión, una aviso de copyright , y también una breve descripción del propósito de la clase en el programa.

Código (java) [Seleccionar]
/*
* ClassName
*
* Version Alpha 0.0.12
*
* Copyright notice
*
* This class is...
*
*/


3.1.2 Sentencias de package e import

La primera linea no-comentario de un archivo de fuente en java es la sentencia de package, posterior a esto, las sentencias de import.

Código (java) [Seleccionar]
package components

import javax.swing.JFrame;
import javax.swing.JPanel;


3.1.3 Declaración de clases e interfaces

La siguiente table describe las partes de la declaración de una clase o interface, en el orden que debe aparecer.


Parte de la declaración de una clase o interfaceNotas
Comentario de documentación de la clase o interface (/**...*/)Ver la sección 5.2 para mas información
Sentencias class o interface
Comentario de implementación de la clase o interface si fuera necesario (/*...*/)Este comentario debe tener toda información necesaria para la clase o interface que no fuera apropiada para estar en los comentarios de documentación
Variables de clase (static)Primero las variables de clase public, luego protected, después las de nivel de package y por ultimo private.
Variables de instanciaPrimero las variables de clase public, luego protected, después las de nivel de package y por ultimo private
Constructores
MétodosEstos métodos se deben agrupar por funcionalidad más que por visión o accesibilidad.




4. Indentación

Se deben utilizar cuatro espacios por cada unidad de indentado. La construcción exacta del indentado (espacios vs. tabulaciones) no se especifica. Los tabuladores deben ser exactamente cada 8 espacios (no cuatro).

4.1 Longitud de línea

Evitar mas de 80 caracteres por linea, ya que no son bien manejados por muchas terminales y herramientas.

Nota: Ejemplos de uso en documentación deben ser mas breves - generalmente no mas de 70 caracteres.

4.2 Ajustes de líneas

Cuando una expresión no quepa en una sola linea, debe ser cortada de acuerdo a los siguientes principios:

  • Cortar antes de una coma.
  • Cortar después de un operador.
  • Preferir cortes de alto nivel (más hacia la derecha de la expresión) que de bajo nivel (más a la izquierda que la expresión.)
  • Alinear la nueva linea con la primera expresión del nivel anterior.
  • Si las reglas anteriores llevan a un código confuso o a código que se aplastan contra el margen derecho, indente con 8 espacios en su lugar.

Ejemplos de cortes de llamadas métodos:

Código (java) [Seleccionar]
myFunction(longExpression1, longExpression2, longExpression3,
longExpression4, longExpression5);

myVariable = myFunction1(longExpression1,
myFunction2(longExpression2,
  longExpression3 ));


Ejemplos de cortes de operaciones aritméticas. Se prefiere el primero, ya que el salto de linea ocurre fuera de la expresión que encierra el paréntesis:

Código (java) [Seleccionar]
LongName1 = LongName2 * (longName3 + longName4 - longName5)
+ 4 * longName6;

LongName2 = LongName1 * (longName3 + longName4
- longName5) + 4 * longName6;



Ejemplos de indentación de declaraciones de métodos. El primer ejemplo es el caso convencional. El segundo se desplazaría la segunda y tercera linea muy a la derecha si se utiliza la sangría convencional, por lo que en vez de eso se utilizaron los 8 espacios de indentación:

Código (java) [Seleccionar]
public void myMethod1(int arg1, Object arg2, String arg3,
 Object arg4) {
/*...*/
}

private static void myMethodWithAVeryLongName (int arg1,
Object arg2, String arg3, int arg4, int arg5,
Object arg6) {
/*...*/
}


El ajuste de linea para sentencias if por lo general usa la regla de 8 espacios, ya que el convencional (4 espacios) dificulta la lectura del cuerpo. Por ejemplo:

Código (java) [Seleccionar]
//No usar esta indentacion
if ((condition1 && condition2)
   || (condition3 && condition4)
   ||!(condition5 && condition6)) { // Malos cortes
   doSomethingAboutIt(); // Hace esta linea facil de olvidar
}

//Usar esta indentacion en su lugar
if ((condition1 && condition2)
|| (condition3 && condition4)
||!(condition5 && condition6)) {
doSomethingAboutIt();
}

//O usar esta
if ((condition1 && condition2) || (condition3 && condition4)
||!(condition5 && condition6)) {
doSomethingAboutIt();
}


Aquí tres aceptables formas de expresiones ternarias:

Código (java) [Seleccionar]
bool1 = (myVeryLongBooleanExpression) ? bool2 : bool3;

bool2 = (myVeryLongBooleanExpression) ? bool1
 : bool3;

bool3 = (myVeryLongBooleanExpression)
? bool2
: bool1;





5. Comentarios

Los programas en java tienen dos tipos de comentarios: comentarios de implementacion y comentarios de documentación. los comentarios de implementacion son los que se encuentran en C++, los cuales son los delimitados por /*...*/, y //. Los comentarios de documentación (conocidos como "doc comments") están solo en java, y son delimitados por /**....*/. los comentarios de documentación pueden ser extraídos de archivos html utilizando las herramientas de javadoc.

Los comentarios de implementación son para comentar código o para comentar una implementación en particular. los comentarios de documentado son para describir las especificaciones de el código, desde una perspectiva de implementación libre. Para ser leído por desarrolladores quienes no necesariamente tienen el código fuente en cuestión.

Los comentarios podrían ser usados para obtener descripciones del código y proveer una información adicional que no es fácilmente deducible con el propio código. Los comentarios deben contener solo información que es relevante para el lector y el entendimiento del programa. Por ejemplo, la información sobre el paquete correspondiente en que se construye o el directorio en el que se encuentra el archivo no debe ser parte de  un comentario.

Decisiones no triviales o no obvias del diseño son apropiadas, pero se debe evitar la duplicación de la información que este presente y clara en el código.

Nota: la frecuencia de los comentarios a veces refleja la mala calidad del código. Cuando usted se siente obligado a insertar un comentario, considere volver a escribir el código para hacerlo mas claro.

Los comentarios no deben encerrarse en grandes cajas dibujadas con asteriscos u otros caracteres.
Los comentarios nunca deben incluir caracteres espaciales.

5.1 Formato de comentarios de implementación:

Los programas pueden tener cuatro estilos de implementación de comentarios: bloque, una linea, remolque y de fin de linea.

5.1.1 Comentarios de bloque:

Los comentarios de bloque son usados para la descripción de archivos, métodos, estructuras de datos y algoritmos. Deben ser usados al principio de cada archivo y antes de cada método. También pueden ser usados en otros lugares como por ejemplo dentro de métodos. Los comentarios de bloques dentro de funciones o métodos deben tener una sangría al mismo nivel que el código a describir.

Un código de bloque debe ser precedido por una linea en blanco para apartarlo del resto del código.

Los comentarios de bloque tienen un asterisco "*" antes de cada linea.

Código (java) [Seleccionar]
/*
* Here is a block comment.
*/


Los comentarios de bloques pueden empezar con /*-, que es reconocido por el guion como un comentario de bloque que no debe ser reformado

Código (java) [Seleccionar]
/*
* Here is a block comment with some very special
* formatting that I want indent(1) to ignore.
*
*     one
*          two
*               three
*/


Nota: Si no utilizas un indentado no debes utilizar /*-

5.1.2. Comentarios de una sola linea

Comentarios cortos pueden ser incluidos en una sola linea indentados de tal manera que se encuentre al mismo nivel del código que describen. Si un comentario no puede ser escrito en una sola linea, se debe utilizar un comentario de bloque. Un comentario de una sola linea debe ser precedido por una linea en blanco.

Código (java) [Seleccionar]
if (condition) {
/* Handle the condition. */
...
}


5.1.3. Comentarios de remolque

Comentarios muy cortos pueden aparecer en la misma linea del código que describen, pero debe ser indentado de tal manera de que este se encuentre lejos del código. Si existe mas de un comentario con estas características, todos deben ser indentados al mismo nivel.

Código (java) [Seleccionar]
if (a == 2) {
return TRUE; /* special case */
} else {
return isprime(a); /* works only for odd a */
}


5.1.4. Comentarios de fin de linea

El delimitador de comentarios // puede convertir en comentario una linea. Puede comentar una linea completa o solo parte de ella. No debe ser usado consecutivamente en múltiples lineas para textos extensos; sin embargo, se puede usar consecutivamente para comentar secciones de código.

Código (java) [Seleccionar]
if (foo > 1) {
// Do a double-flip.
...
}
else
return false; // Explain why here.

//if (bar > 1) {
//
// // Do a triple-flip.
// ...
//}
//else
// return false;


5.2 Comentarios de documentado

Los comentarios de documentado describen clases, interfaces, constructores, métodos y archivos. Cada comentario de documentado es creado dentro de los delimitadores /**...*/.

Código (java) [Seleccionar]
/**
* @param  name the component name
* @return    the component
*/


Java asocia los comentarios de documentado a la siguiente declaración posicionada posterior el comentario de documentado, por esta razón estos comentarios no deben ser ingresados dentro de los métodos o secciones que se intentan describir.

Nota: Los comentarios de documentado serán vistos mas afondo en otra parte independiente de este documento, por el momento para mas información: http://www.oracle.com/technetwork/articles/java/index-137868.html




6. Declaraciones

6.1. Numero de declaraciones por línea

Se recomienda una declaración por línea, ya que facilita la adición de comentarios. Por esta razón se prefiere:

Código (java) [Seleccionar]
int level; // indentation level
int size;  // size of table


Antes que:

Código (java) [Seleccionar]
int level, size;

No poner diferentes tipos en la misma linea. Ejemplo:

Código (java) [Seleccionar]
int foo, fooarray[];

Nota: Los ejemplos anteriores usaban un espacio entre el tipo y el nombre identificador. Otra alternativa aceptable es usar tabulaciones:

Código (java) [Seleccionar]
int level;
int size;


6.2. Ubicación

Localizar las declaraciones solo al inicio de los bloques (Los bloques son aquellos delimitados por {}). No esperar a declarar variables antes de su primer uso; esto puede llegar a ser confuso para el programador, y probablemente pueda omitir una declaración.

Código (java) [Seleccionar]
public void MyMethod() {
int int1; // beginning of method block
if (condition) {
int int2; // beginning of "if" block
/*...*/
}
}


La única excepción a esta regla es en caso de los ciclos for, ya que en Java se pueden declarar dentro del ciclo for

Código (java) [Seleccionar]
for (int i = 0; i < maxLoops; i++) {
/*...*/
}


Evitar declarar variables que tengan el mismo nombre que algún atributo de la clase que la contiene.

Código (java) [Seleccionar]
private int count;

public int counter(){
int count = 0;
/*...*/
}


6.3. Inicialización

Intentar inicializar las variables locales en el mismo momento en que son declaradas. A menos que no pueda ser inicializada porque su valor depende de cálculos realizados por el programa posterior a su declaración.

6.4. Declaración de clases e interfaces

Cuando programa en java clases e interfaces, debe seguir el siguiente formato de reglas:

  • No deben haber espacios entre el nombre de un método y el paréntesis que delimita su lista de parámetros.
  • Abrir llaves de apertura aparecen al final de la misma linea de la declaración de la sentencia.
  • La llave de cierre empieza en una nueva linea posterior a la ultima instrucción del bloque, y al mismo nivel de indentación que la sentencia de declaración del bloque. En caso de no existir ninguna instrucción dentro del bloque, la llave de cierre se coloca inmediatamente después a la de apertura.
  • Los métodos se separar con una linea en blanco.

Código (java) [Seleccionar]
class Sample extends Object {

private int ivar1;
private int ivar2;

Sample(int i, int j) {
ivar1 = i;
ivar2 = j;
}
int emptyMethod() {}
/*...*/
}





7. Sentencias

7.1. Sentencias simples

Cada linea debe tener solo una sentencia. El siguiente ejemplo es incorrecto.

Código (java) [Seleccionar]
var1++; var2--;

7.2 Composición de sentencias

Las sentencias compuestas son sentencias que contienen listas de sentencias encerradas entre llaves.

Las sentencias encerradas deben tener una indentación mas que su nivel superior

Las llaves de inicio deben estar al final de la linea que comienza la sentencia compuesta; la llave de cierre debe empezar en una nueva linea y ser indentada al mismo nivel que el principio de la sentencia compuesta.

Las llaves se usan en todas las sentencias, sin importar su simplicidad. Esto hace mas fácil añadir nuevas sentencias.

7.3. Sentencias return

Una sentencia que retorna un valor no debe usar paréntesis, amenos que hagan que el valor de retorno sea mas evidente de alguna manera.

7.4. Sentencias if, if-else, if-else-if-ese

Las sentencias if-else deben seguir el siguiente formato:

Código (java) [Seleccionar]
if (condition) {
/* statement */
}

if (condition) {
/* statement */
} else {
/* statement */
}

if (condition) {
/* statement */
} else if (condition){
/* statement */
} else {
/* statement */
}


Nota: La sentencia if siempre debe usar llaves. con el fin de evitar errores.

7.5. Sentencias for

Una sentencia for debe seguir el siguiente formato:

Código (java) [Seleccionar]
for(initialization; condition; update) {
/* statements */
}


Una sentencia for bacía debe seguir el siguiente formato:

Código (java) [Seleccionar]
for(initialization; condition; update);

Si se utiliza una coma en la inicialización, condición, o actualización se debe evitar usar mas de tres variables. Si aun así, es necesario, es recomendado separar la sentencia, declarando las variables antes del bucle o actualizando en el bucle

7.6. Sentencias while

Una sentencia while debe seguir el siguiente formato:

Código (java) [Seleccionar]
while (condition) {
/* Statement */
}


Una sentencia while bacía debe seguir el siguiente formato

Código (java) [Seleccionar]
while (condition);

7.7. Sentencia do-while

Una sentencia do-while debe seguir el siguiente formato:

Código (java) [Seleccionar]
do {
/* statement */
} while (condition);


7.8. Sentencia switch

Una sentencia switch debe seguir el siguiente formato:

Código (java) [Seleccionar]
switch (condition) {
case 0:
/* statement */
break;
case 2:
/* statement */
break;
default:
/* statement */
break;
}


Siempre que un caso se propague (no incluya sentencia break), añadir un comentario donde la sentencia break se encontraría normalmente.

Cada sentencia switch debe incluir un caso por defecto. El break del caso por defecto es redundante, pero evita que se propague por error si se añade otro caso.

7.9. Sentencia try-catch

Una sentencia try-catch debe seguir el siguiente formato:

Código (java) [Seleccionar]
try {
/* statement */
} catch (Exception e) {
/* statement */
}





8. Espacios en blanco

8.1. Líneas en blanco

Las lineas en blanco nos permite separar secciones de código que están lógicamente relacionadas.

Se debe usar siempre dos lineas en blanco para las siguientes circunstancias:

  • Entre las secciones de un archivo fuente
  • Entre las definiciones de clases e interfaces.

Se debe usar siempre un linea en blanco en las siguientes circunstancias:

  • Entre métodos
  • Entre las variables locales de un método y su primera sentencia
  • Antes de un comentario de bloque o de un comentario de linea
  • Entre las secciones logísticas de un método para facilitar la comprensión

8.2. Espacios en blanco

Los espacios en blanco son usados en las siguientes circunstancias:
  • Las palabras claves del lenguaje seguidas por un paréntesis deben ser separados por un espacio en blanco
    Nota: no se debe usar un espacio en blanco entre el nombre de  un método y su paréntesis de apertura. Esto ayuda a distinguir palabras claves de llamadas de métodos.
  • Debe haber un espacio en blanco después de una coma en listas de argumentos.
  • Todo los operadores binarios excepto . se deben separar de sus operandos por un espacio en blanco. Los espacios en blanco no deben separar los operadores de incremento (++) y decremento (--) de sus operandos.
  • Los casting deben ir seguidos de un espacio en blanco.




A. Convenciones de capitalización

Nota: Esta sección ha sido a agregada con el propósito de facilitar la comprensión de la sección 9. Convenciones de nombres

Muchas de las convenciones de nombre tienen como objetivo la correcta "Capitalización" a la hora de declarar los nombres de  paquetes, clases, métodos, variables, constantes... Al utilizar la palabra "Capitalización" se intenta referir a la utilización de mayúsculas y minúsculas a la hora de crear un nombre identificador para los elementos anteriormente mencionados.

Existen distintos tipos de Capitalización y en este caso 4(3+1):

A.1. Pascal case:

Se refiere a utilizar mayúsculas en la inicial de cada palabra y el resto de las letras tendrán que ser minúsculas sin excepción alguna.

Código (java) [Seleccionar]
public class MyClass {

}


A.2. Camel case:

Se refiere a utilizar mayúsculas en la inicial de cada palabra con excepción de la primera letra de la primera palabra y el resto de las letras tendrán que se minúsculas.

Código (java) [Seleccionar]
public Color getColor() {
return color;
}


A.3. Upper case:

Se refiere a utilizar mayúsculas en todo el conjunto.

Código (java) [Seleccionar]
final int MYCONSTANT = 2;

A.4. Lower case:

Se refiere a utilizar minúsculas en todo el conjunto.

Código (java) [Seleccionar]
package mypackage;

Nota: Este ultimo fue agregado para efectos de este documento en especifico.




9. Convenciones de nombres

Las convenciones de nombres hacen a los programas mas fáciles de leer. También dan información acerca de un elemento solo con leer su nombre lo que resulta muy útil a la hora de entender el código.













ElementoConvenciónEjemplo
PaquetesEl prefijo del nombre de los paquetes debe respetar la convención "Lower case" y debe ser uno de los nombres de dominio de alto nivel (com, edu, gov, net...).
Los subsecuentes componentes del nombre del paquete vari'an de acuerdo a las convenciones de nombres internas de cada organización.
Código (java) [Seleccionar]
package com.sun.eng;
package com.apple.quicktime.v2;
Clases e interfacesLos nombres de las clases e interfaces deben ser sustantivos y respetar la convención "Pascal case".
Evitar usar abreviaturas a no ser que la abreviatura sea mas conocida como URL o HTML
Código (java) [Seleccionar]
public class ImageSprite{}
public interface RasterDelegate {}
MétodosEl nombre de los métodos deben ser vervos y respetar la convención "Camel case"
Código (java) [Seleccionar]
public void drawImage() {}
public void fillPolygon() {}
VariablesEl nombre de todas las variables debe respetar la convención "Camel case". Los nombres de variables no deben empezar con guion bajo o el signo dolar.
Los nombres de variables deben ser cortos pero significativos, se deben evitar nombres de un solo carácter, excepto para variables de índices temporales.
Nombres comunes para variables temporales son i, j, k, m, y n para enteros; c, d, y e para caracteres.
Código (java) [Seleccionar]
int i;
char c;
String gameTitle;
ConstantesEl nombre de todas las constantes debe respetar la convención "Upper case". En caso de existir mas de una palabra, estas serán separadas por un guion bajo.
Código (java) [Seleccionar]
final float PI = 3.14;
final float WINDOW_SCALE = 2;




10. Hábitos de programación

10.1. Acceso a variables de instancia y de clase:

Por principios de encapsulación ninguna variable de instancia o clase a de ser publica sin una buena razón. Para acceder a variables de instancia o clase se utilizan los denominados métodos set o get.

10.2. Acceder a variables y métodos de clase

Evitar usar un objeto para acceder a una variable o método de clase. Usar el nombre de la clase en su lugar.

Código (java) [Seleccionar]
MyClass.classMethod(); // Correcto
myObject.classMethod(); // Incorrecto


10.3. Constantes

Las constantes numéricas no se deben  codificar directamente, excepto se trata de un bucle for.

10.4. Asignacion de variables

Evitar asignar el mismo valor a variables en la misma sentencia.

Código (java) [Seleccionar]
var1 = var2 = 5; // Evitar

10.5. Hábitos varios

10.5.1. Paréntesis

Es muy recomendado usar paréntesis en expresiones que implican distintos operadores aun cuando no sea necesario. Esto facilita la comprensión del código.

10.5.2. Valores de retorno

Es apropiado hacer que la estructura del programa se ajuste a su intención. Por Ejemplo:

Código (java) [Seleccionar]
if (booleanExpression) {
   return true;
} else {
return false;
}


En lugar de hacer:

Código (java) [Seleccionar]
return booleanExpression;

10.5.3. Expresión ternaria

Si una expresión incluye un operador binario antes del signo ? en el operador ternario , se debe
colocar entre paréntesis. Ejemplo:

Código (java) [Seleccionar]
(myVar >= 0) ? 20 : -20;

10.5.4 Comentarios especiales

Usar XXX en un comentario para indicar que algo tiene algún error pero funciona. Usar FIXME
para indicar que algo tiene algún error y no funciona.




Muchas gracias por leer, y espero que les sea de ayuda.

3n31ch

Disculpen la demora, pero entre traducir y transcribir para que se vea bonito en el foro me demore un año  :xD

vangodp


3n31ch


MNicolas

De verdad admiro a la gente que se dedica a ayudar desinteresadamente a los demás!

;-)

Usuario Invitado

En éstos días publicaré los patrones de diseño más usados y sus ventajas y desventajas.

Salu2.
"La vida es muy peligrosa. No por las personas que hacen el mal, si no por las que se sientan a ver lo que pasa." Albert Einstein

3n31ch


hossman92

muy buen aporte gracias me esta sirviendo mucho par dejar bonito mi codigo  :D :D

BlackZeroX

falta mucho por ejemplo de losDTO, VO, declaración de las interfaces y manejo de capas, servicios, pools, contenedores de persistencia (como meta-container), uff pero esta genial aun asi :)

Dulces Lunas!¡.
The Dark Shadow is my passion.