Algunas cosas que solemos decir los programadores

Algunas cosas que solemos decir en nuestra profesión:

  • «Funcionaba en mi computadora. Ven conmigo y velo por ti mismo si no me crees»
  • ¿Quién te dio el usuario admin?  ¿Eres administrador?
  • «No es un error, es sólo otra de sus funciones»
  • «Eso es raro…»
  • «Nunca había hecho eso antes…»


  • «Ayer funcionaba»
  • «¡¿Cómo es posible?!»
  • «Revisaste la conexión de red, configuración?» (Especialmente si la aplicación se vuelve muuuy lenta)
  • «¿Metiste datos erróneos y falló?»
  • «Hay algo extraño en tus datos»
  • «¡No he tocado el código en semanas!»
  • «Has de tener una versión equivocada de librerías»
  • «Debe haber sido una coincidencia desafortunada, así que no molestes»
  • «¡No puedo hacer pruebas unitarias de todo!»
  • «No fue error mio, debe ser algo en la librería Open Source que estamos usando»
  • «Esto funciona, aunque no he escrito ninguna prueba unitaria»
  • «Alguien debe haber movido mi código»
  • «¿Ya revisaste si no tienes virus en tu computadora?»
  • «Bueno a pesar de que no funciona, ¿Como se siente con la aplicación?»
  • «No puedes usar esta versión en este sistema operativo»
  • «¿Qué es lo que quieres hacer metiendo esos datos?»
  • «¿Dónde estabas cuando la aplicación se cayó?»
  • «Estoy seguro de que eso lo arregla»
  • «¿Ya reinició el servidor?»
  • «¿Que versión de JRE/JDK/JVM tienen instalada?»

Tomado del artículo original de javacodegeeks.com

Integración JavaServer Faces 2.0, Spring 3 y Hibernate 3 con MySQL en Netbeans 7.0 y Maven

Un video donde mostramos como integrar JavaServer Faces 2.0 con Spring 3 y Hibernate 3 de forma esquemática.  La intención es tan solo de dar una idea de como están estructuradas las carpetas, clases y archivos de configuración, así como dependencias de librerías.  En este ejemplo nos conectamos a una base de datos MySQL y desplegamos una lista de usuarios. El script de la tabla utilizada viene comentado en la clase UsuariosObj.  El proyecto es creado en Netbeans 7, con Maven lo que lo hace portable entre diferentes IDEs.

Todos los archivos de configuración y clases están en un archivo para su descarga y no es necesario poner atención al detalle del código escrito durante el video.  Las librerías se descargarán en cuanto se construya el proyecto desde Netbeans.

El código se puede descargar de: IntegracionJSF2Spring3Hibernate3.zip

Quince Principios Que Un Ingeniero De Software Debe Seguir

Una lista de quince principios que un Ingeniero de Software quizá debería seguir.

  • Mantén en mente los fundamentos.  Si olvidas los conceptos básicos de los lenguajes de programación estás perdiendo tu conocimiento más fundamental.  Lo cual no es buena idea.
  • Asume siempre el peor escenario.  Si tuviste una educación formal en ciencias de la computación, quizá aprendiste algo acerca de la notación “big-O” que te dice el costo de un algoritmo, si es lineal o cuadrático por ejemplo. Saber cuando un algoritmo no tiene manera de ejecutarse rápidamente es importante.



  • Prueba tu código. Asegúrate de probar tu código.  Dependiendo del método que uses, puedes manejar pruebas en varios niveles.  Pero siempre debes crear tantas pruebas como puedas.
  • No emplees nuevas tecnologías sólo porque son nuevas, úsalas para resolver problemas. Como tecnólogos, tendemos a usar las herramientas más nuevas con la esperanza de arreglar las cosas mágicamente.  Que sea útil es la clave, aunque no sea lo máximo.
  • Leer, y mucho. Si no lees acerca de la industria tarde o temprano quedarás fuera de ella.
  • Prueba nuevas técnicas y tecnologías.  Esto no se contrapone con lo dicho anteriormente. Es necesario probar cosas nuevas para determinar si puede ser útil.  Probar cosas nuevas ayuda a aprender y a mantenerte al tanto de la industria.  Prueba sin poner en riesgo un proyecto crítico.
  • Si falla aprenderás algo.  Si tu código falla al menos aprenderás porque no funciona y refinarás la solución.  En algunos casos, se puede considerar a la falla como un pequeño éxito.
  • Cambia el software.  Algunas veces se necesita simplemente terminar el trabajo, pero se debe estar consiente de la deuda técnica que se adquiere. Si simplemente se entrega software sin remover la deuda técnica de forma continua, a la larga el proyecto será una verdadera pesadilla cuando demasiados errores se hayan acumulado.
  • Hacerlo de la “forma correcta”. Muchos desarrolladores tienen la idea de una «forma correcta» de diseño y desarrollar aplicaciones, pero esto puede no ser lo ideal para el proyecto o puede estar sobrado. Esto parece una contradicción con el punto anterior, pero lo ideal es conservar un balance.
  • Deja el código mejor de lo que lo encontraste. En vez de predicar los beneficios de la refactorización, piensa si quieres mantener una pila de código que se vuelve cada vez peor. Si se limpia un poco cada vez que se modifica entonces no será tan difícil después.
  • Ten en cuenta siempre la concurrencia. Si estas construyendo una aplicación web, y no nos referimos a algo de la escala de Facebook, cosas raras pueden ocurrir con la carga excesiva.  Siempre que se tenga una aplicación con una concurrencia de usuarios mayor a 100 pueden ocurrir cosas raras cuando se lee y se escribe sobre algunos recursos, como en las instancias de HashMaps y esto es solo alguna de las cosas de las que te debes preocupar.
  • La cantidad de almacenamiento puede ser libre, pero la transferencia apesta.  Quizá piensas que escribir todo en disco es una forma excelente de persistir datos. Generalmente lo es, pero si usas el almacenamiento en disco para guardar recursos temporales sin depurar, tu aplicación podría volverse lenta muy rápidamente.  El almacenamiento debería limitarse a aquellos datos que necesiten persistir por largos periodos de tiempo, o cuando los datos no pueden residir en memoria.
  • La memoria no puede llegar tan lejos como se piensa.  Para comenzar, muchos tienen sus aplicaciones y sus bases de datos en el mismo servidor. Esto es perfectamente aceptable hasta que ambos requieran de mucha RAM.  Por ejemplo típicamente se tiene una aplicación con Tomcat a 528MB, no obstante una vez que se tiene que lidiar con el almacenamiento persistente (RDBMS, NoSQL, etc) frecuentemente se puede pasar hasta los 8GB y las cosas pueden ponerse difíciles. Obviamente, esto depende mucho de los usuarios que acceden al sistema y de cuantos datos almacenan.
  • El almacenamiento en cache lo arregla todo hasta que tira al servidor. Si se buscan mecanismos para liberar de consultas excesivas a la base de datos, se termina usando una especie de cache.  El problema es que el cache puede terminar usando mucha más memoria que la que se usa de forma típica, especialmente cuando se tiene que lidiar con datos que dependen del numero de usuarios que acceden. Lo peor de usar un cache es que se puede llegar al punto en que se genere un error OutOfMemory, por mencionar el caso de java.  En este punto, el servidor caerá o dejará de responder y el cache no será de ninguna utilidad y se habrá convertido en parte
    del problema.
  • Piensa como un consultor.  Con los empleados algunas empresas tienden a cambiar las cosas.  Los plazos se pueden mover, el alcance puede aumentar y el desarrollador tiene que encontrar la manera de cumplir con estas nuevas restricciones.  Es necesario que se deje en claro que los plazos no pueden moverse debido a que el trabajo necesario para hacer las cosas no cambia o que el alcance no puede aumentar sin hacer lo mismo con el número de recursos disponibles.  Los consultores tienden a administrar los proyectos de forma diferente que los empleados y está en estos últimos cambiar esa regla.

Buenas prácticas para el uso de Bases de Datos

Un buen diseño de base de datos facilita el mantenimiento, protege la información y ayuda a que las consultas funcionen bien. Estas recomendaciones sirven como guía: conviene adaptarlas al motor de base de datos, a la aplicación y a las necesidades del proyecto.

Nombres y estructura

1. Usa nombres claros y consistentes

Elige una convención y aplícala a tablas y columnas. Los nombres en singular son una opción habitual: Estudiante en vez de Estudiantes. Usa nombres descriptivos, como FechaInscripcion en lugar de Fecha.

Ejemplo: Estudiante, Curso e Inscripcion, con columnas como FechaInscripcion y EstadoInscripcion.

2. Evita espacios y caracteres difíciles de manejar

Los espacios pueden obligar a escribir los nombres entre comillas o delimitadores, según el motor de base de datos.

Ejemplo: usa FechaNacimiento en vez de Fecha de nacimiento. También puedes usar fecha_nacimiento si esa es la convención elegida.

3. Evita prefijos redundantes

El nombre de un objeto debe describir su propósito. No hace falta indicar que es una tabla si ya se sabe por el contexto.

Ejemplo: usa Escuela en vez de TblEscuela o EscuelaTabla.

4. Define identificadores y relaciones de forma deliberada

Las claves primarias permiten identificar registros y relacionarlos. No todas tienen que ser enteros: elige el tipo que mejor represente el dominio y considera si necesitas una clave natural, una clave generada o ambas.

Ejemplo: EstudianteId puede ser un entero generado por la base de datos. Para un país, un código como MX podría ser una clave natural adecuada.

Tipos de datos y seguridad

5. Guarda las contraseñas como hashes seguros

Nunca guardes contraseñas como texto legible ni como valores que se puedan descifrar. La aplicación debe verificarlas mediante una función de hash diseñada para contraseñas, como Argon2id, bcrypt o scrypt.

Ejemplo: almacena el resultado del hash y sus parámetros. Al iniciar sesión, verifica la contraseña ingresada contra ese valor.

6. Elige tipos de datos adecuados para las claves y los índices

Los tipos compactos y compatibles con las relaciones pueden ayudar al rendimiento, pero el tipo de columna debe corresponder a los datos y las consultas reales. Una columna de texto puede ser una clave o un índice válido cuando el dominio lo justifica.

Ejemplo: usa un entero para EstudianteId. Para un código postal, conserva el texto si puede incluir ceros iniciales o letras.

7. Usa tipos booleanos para valores de verdadero o falso

Usa el tipo booleano que ofrezca el motor de base de datos. En algunos motores se representa internamente como BIT; en otros, como un tipo distinto. El nombre de la columna puede indicar claramente que contiene una condición.

Ejemplo: usa EsActivo o IsActive, con un valor verdadero o falso.

8. Protege el acceso a la base de datos con autenticación y permisos mínimos

Cada aplicación o servicio debe usar una cuenta propia con solo los permisos necesarios. Reserva las cuentas administrativas para tareas administrativas.

Ejemplo: la cuenta de la aplicación puede leer y modificar las tablas que necesita, pero no crear usuarios ni cambiar la configuración del servidor.

Consultas y acceso a los datos

9. Selecciona solo las columnas que necesitas

Evita SELECT * en las consultas de la aplicación. Solicitar campos innecesarios puede aumentar el tráfico y complicar los cambios en el esquema.

Ejemplo: usa SELECT EstudianteId, Nombre FROM Estudiante si la pantalla solo muestra el identificador y el nombre.

10. Evalúa el uso de un ORM según la complejidad del proyecto

Un ORM puede simplificar el acceso a los datos y el mantenimiento. Aun así, conviene revisar las consultas que genera y configurar correctamente las relaciones y la carga de datos.

Ejemplo: usa carga anticipada cuando necesites consultar los cursos de varios estudiantes. Evita cargar colecciones que la pantalla no utiliza. Para consultas especializadas, puede ser más conveniente escribir SQL directamente.

11. Diseña índices a partir de las consultas reales

Los índices pueden acelerar búsquedas, ordenamientos y uniones, pero también ocupan espacio y pueden hacer más lentas las escrituras. Usa planes de ejecución y herramientas de análisis para decidir cuáles crear.

Ejemplo: si las consultas filtran con frecuencia por Correo, evalúa crear un índice sobre esa columna. Si buscan por EscuelaId y ordenan por FechaInscripcion, analiza un índice compuesto para ese patrón.

12. Elige el tipo de índice según el motor y la consulta

No existe una regla universal según la consulta sea por rango o puntual. Influyen el motor, la distribución de los datos y el orden de las columnas indexadas.

Ejemplo: revisa el plan de ejecución para comprobar si un índice sobre FechaInscripcion ayuda a consultar las inscripciones de un periodo.

Integridad, disponibilidad y documentación

13. Haz cumplir la integridad de los datos en la base de datos

Usa claves primarias y foráneas, restricciones CHECK, valores NOT NULL y reglas de unicidad cuando correspondan. La aplicación también puede validar los datos, pero la base de datos debe proteger las reglas fundamentales.

Ejemplo: una clave foránea de Inscripcion.EstudianteId a Estudiante.EstudianteId evita referencias a estudiantes inexistentes.

14. Documenta el esquema y las decisiones importantes

Mantén diagramas entidad-relación, definiciones de tablas, convenciones y notas sobre procedimientos, disparadores y scripts. Actualiza la documentación cuando cambie el diseño.

Ejemplo: documenta por qué EstadoInscripcion tiene ciertos valores válidos y qué proceso actualiza ese campo.

15. Planifica los respaldos y la recuperación ante fallos

Define la frecuencia de las copias, cuánto tiempo se conservarán y cuánto tiempo de interrupción o pérdida de datos es aceptable. Prueba periódicamente la restauración: una copia que no se puede recuperar no es suficiente.

Ejemplo: una aplicación crítica puede requerir respaldos automáticos, replicación y conmutación por error, además de pruebas de recuperación.

16. Separa los componentes cuando la arquitectura y la carga lo justifiquen

Mantener el servidor de base de datos y el servidor web en máquinas distintas puede mejorar el aislamiento, la seguridad y la gestión de recursos. En sistemas pequeños o administrados en la nube, otras arquitecturas pueden ser más adecuadas.

Ejemplo: una aplicación de alto tráfico puede alojar la base de datos en una instancia privada, accesible solo desde los servicios autorizados.

17. Mantén los datos binarios grandes fuera de las consultas habituales

Las imágenes y otros archivos grandes pueden almacenarse en un sistema de archivos o en un servicio de almacenamiento de objetos, guardando en la base de datos solo una referencia. Si deben residir en la base, considera colocarlos en una tabla separada para evitar cargarlos en consultas frecuentes.

Ejemplo: guarda FotoPerfilUrl en Estudiante y almacena el archivo en un servicio de almacenamiento.

Decisiones de diseño

18. Normaliza los datos para reducir duplicación y errores

La normalización ayuda a mantener la coherencia. Si una consulta importante requiere muchas uniones y el rendimiento lo justifica, considera una desnormalización controlada, documentada y mantenida correctamente.

Ejemplo: conserva los datos de Escuela en una tabla propia. Si un informe muy usado necesita datos resumidos, puedes crear una copia que se actualice mediante un proceso definido.

19. Invierte tiempo en el diseño y valida las decisiones

Identifica las entidades, relaciones, reglas y consultas principales antes de construir el esquema. Revisa el diseño con ejemplos de datos y escenarios de cambio.

Ejemplo: antes de crear Inscripcion, define si un estudiante puede inscribirse varias veces en el mismo curso y qué regla debe impedir duplicados

Anti Patrones Java – Manejo de XML

Una mala práctica en el manejo de documentos XML es no hacer uso de parsers o analizadores. El siguiente código muestra un escenario común:

int inicio = xml.indexOf("<nombre>");
int fin = xml.indexOf("</nombre>");
String nombre = xml.substring(inicio, fin);

El método anterior que en apariencia funciona, tiene los siguientes inconvenientes:

  • Puede haber mas de un nodo «name» en el documento.
  • El contenido de «name» puede no estar hecho de caracteres de datos solamente.
  • Puede haber caracteres escapados en los datos.
  • Si los datos contenidos en el nodo son CDATA puede no devolver el resultado esperado.
  • El documento XML puede tener namespaces.

En general un documento XML es mucho mas complejo que es un String de java, por el tipo de operaciones que están implícitas en la lectura. Para leer de forma correcta el contenido de un documento XML existen analizadores como Xerces que ademas son muy ligeros. El equivalente en JDOM es el siguiente:

SAXBuilder builder = new SAXBuilder(false);
Document doc = doc = builder.build(new StringReader(xml));
String nombre = doc.getRootElement().getChild("nombre").getText();

Otra mala práctica en el manejo de XML que es muy común es en la construcción del documento, haciendo algo como esto:

String nombre = ...
String atributo = ...
String xml = "<root>"
            +"<nombre atr=\""+ atributo +"\">"
            + nombre
            +"</nombre>"
            +"</root>";

Cuando lo correcto es hacer más bien lo siguiente:

Element root = new Element("root");
root.setAttribute("atr", atributo);
root.setText(nombre);
Document doc = new Documet();
doc.setRootElement(root);
XmlOutputter out = new XmlOutputter(Format.getPrettyFormat());
String xml = out.outputString(root);

Olvidándonos de escapar caracteres y con la sentencia

XmlOutputter out = new XmlOutputter(Format.getPrettyFormat())

Le damos el formato visual adecuado a nuestro documento.  También podremos agregar namespaces a nuestros nodos sin ningún problema. JDom es sin duda una magnifica opción para manejar documentos XML.

JDom es sin duda una magnifica opción para manejar documentos XML.

Java y Chuck Norris

Unos cuantos hechos acerca de Chuck Norris, que quizá te convenga saber para tu examen de certificación SCJP.

  • Chuck Norris puede crear clases que son ambas cosas: abstract y final.
  • Chuck Norris no despliega aplicaciones, las mete a patadas en el servidor.
  • Chuck Norris puede usar cualquier clase en java.util.* para matarte y sin leer los javadocs. 
  • Chuck Norris puede golpear tan duro a tu aplicación web que la convierte en una aplicación swing con iconos en forma de cráneos humanos. 
  • Chuck Norris contó el mismo para llegar al valor Float.POSITIVE_INFINITY y demostrar que es correcto, dos veces. 
  • synchronized no protege de Chuck Norris, si él lo necesita lo toma. 
  • Chuck Norris no usa javac, el escribe sus aplicaciones directamente en código binario. 
  • El código java de Chuck Norris nunca necesita optimizarse. 
  • Su código es tan rápido que rompe la velocidad de la luz y durante las pruebas mata a 37 personas en los laboratorios de Sun. 
  • El código de Chuck Norris nunca tiene un error. ¡Nunca! 
  • Cuando alguien intenta usar un método deprecated de Chuck Norris, reciben automáticamente una patada voladora en tiempo de compilación. 
  • El paquete java.lang, originalmente contenía la clase Chuck Norris, pero fue retirada luego de una revisión de diseño y una patada voladora propinada a Bill Joy, el diseñador a cargo. 
  • Chuck Norris no escribe código. El simplemente se sienta frente al monitor y lo mira hasta que obtiene lo que quiere. 
  • El código corre mejor cuando Chuck Norris lo mira. 
  • Si tú obtienes una ChuckNorrisException probablemente morirás. 
  • Los objetos de Chuck Norris puede lanzar patadas voladoras a cualquier objeto privado de otro paquete. 
  • Los niveles de visibilidad son public, default, protected, private y “protectedbyChuckNorris”, ¡No intentes acceder a campos con el último modificador! 
  • Chuck Norris puede dividir por cero. 
  • El Garbage Collector solo pasa sobre el código de Chuck Norris cuando hay cuerpos que recolectar. 
  • Chuck Norris implementa “Indestructible”. Todas las demás criaturas implementan “Killable” 
  • Chuck Norris puede hacer herencia múltiple en java. 
  • El código de Chuck Norris usa generics desde la versión 1.3 de java. 
  • Cuando se ejecuta una clase de Chuck Norris, el CPU la corre al doble de velocidad. 
  • Chuck Norris y Java
  • El código de Chuck Norris no puede ser decompilado, no te molestes en tratar.
🙂

Anti-Patrones Java – Concatenación de cadenas

Veamos el siguiente ejemplo.

String s = "";

for (Persona p : personas) {
s += ", " + p.getNombre();
}
s = s.substring(2); //Quita la primera coma

Este código muestra un ejemplo claro de una mala práctica que puede afectar el rendimiento óptimo de una aplicación, su tiempo de ejecución es de orden aproximado O(personas.length²). La concatenación repetitiva de cadenas en ciclos causa exceso de basura y copiado de arreglos. Además es necesario remover la última coma, lo cual es evidentemente un parte fea del código.

La siguiente sería una mejor práctica:

StringBuilder sb = new StringBuilder(personas.size() * 16); // Con una estimacion inicial del tamaño del buffer

for (Persona p : personas) {
if (sb.length() > 0) sb.append(", ");
sb.append(p.getNombre);
}

Que incluye además una estimación inicial del tamaño del buffer.

Invocar al recolector de basura

Java y otros lenguajes tienen un mecanismo de liberación de memoria llamado Garbage Collector, el cual permite reutilizar la memoria durante la ejecución de un programa. Se puede llamar al recolector de basura utilizando System.gc() o Runtime.getRuntime.gc(). Aunque hacer esto no se considera buena práctica ya que tiene repercusiones importantes en el rendimiento de una aplicación. La mejor práctica es no tener que llamar a estos métodos haciendo un buen diseño y uso de los recursos.

La descripción en la documentación para estos métodos es la siguiente:


System.gc()

Hace correr al recolector de basura.

Al llamar al método gc se sugiere a la máquina virtual realice un esfuerzo de reciclaje de objetos no utilizados con el fin de hacer que la memoria que estos objetos ocupan esté disponible para su uso rápido. Cuando se devuelve el control de la llamada al método, la maquina virtual de java ha hecho su mejor esfuerzo para recuperar el espacio de los objetos desechados.

La llamada System.gc() es efectivamente equivalente a la llamada Runtime.getRuntime.gc()


Runtime.getRuntime.gc()


Hace correr al recolector de basura. Al llamar a este método se sugiere a la maquina virtual realice su mayor es fuerzo de reciclaje de objetos no utilizados con el fin de hacer que la memoria que estos objetos ocupan esté disponible para su uso rápido. Cuando se devuelve el control de la llamada a al método, la máquina virtual ha hecho su mejor esfuerzo para recuperar el espacio de los objetos desechados.

La maquina virtual lleva a cabo este proceso de reciclaje de forma automática cuando es necesario, en un hilo separado, incluso si el método gc no se invoca explícitamente.

El método System.gc() es el medio convencional y conveniente de la invocación de este proceso. En algunas ocasiones esta invocación no tendrá mayor efecto, ya que la liberación de recursos nunca está garantizada.