Desarrollo Implementación Codificación de Software (... if (a == b) then ...) Universidad de los Andes Demián Gutierrez Enero 2011 ¿Por qué ser buen programador? (Codificador) Pregunta: ¿Cuál es el riesgo menos tomado en consideración en la industria de software? Respuesta: Los programadores incompetentes. Hay estimados que el número de programadores requeridos en los EEUU excede los 200.000, esto es un número enteramente engañoso, ya que no es un problema de cantidad, es un problema de calidad. Un mal programador puede fácilmente crear dos nuevos trabajos al año. Contratar más malos programadores sólo incrementará nuestra aparente necesidad de programadores. Si tuviéramos más buenos programadores y pudiéramos identificarlos más fácilmente, seguramente necesitaríamos en total menos programadores y no más. David Parnas Citado en Julio 21, 2009 de: http://www.codinghorror.com/blog/2009/07/nobody-hates-software-more-than-software-developers.html (traducción libre) Después de 10 años de carrera, he descubierto que la programación en el fondo, es lo menos importante... y sin embargo, por ejemplo... Kent Beck, en relación al XP, entre muchas otras cosas geniales, dice que: 1) hay que abrazar (¿aceptar?) el cambio como algo que forma parte integral del negocio de software (¿de nuestras vidas?) 2) Hay que tener coraje (co!0n3$) para, entre muchas otras cosas, poder hacer refactors, ajustar al vuelo la arquitectura del software si es necesario, etc, etc... y para ésto último... hay que ser buen programador... ¿Por qué ser buen programador? (Codificador) En resumen: ¡Odio el software, odio el código! Y en especial el que desarrollo yo mismo, sobre todo por que sé lo difícil que es lograr que funcione y que funcione bien. Puede sonar extraño, pero es una actitud natural e inclusive saludable para un desarrollador de software. Es una característica común, una marca de iniciación que usted encontrará que la gran mayoría de los programadores comparten. De hecho, creo que se puede diferenciar a un programador competente de uno incompetente en una entrevista con la siguiente pregunta: – ¿Cuál es el peor código que usted ha visto recientemente? – Si la respuesta no es de inmediato y sin titubear la siguiente: – El mío – Entonces usted debería terminar la entrevista inmediatamente y decirle al candidato que lo siente, pero que aún no odia al software lo suficiente, que quizá en unos años si lo sigue intentando. Jeff Atwood Julio 21, 2009 http://www.codinghorror.com/blog/2009/07/nobody-hates-software-more-than-software-developers.html (traducción libre) ¿Tipos de Lenguajes de Programación? Use la herramienta más adecuada para el problema a resolver... Bajo Nivel / Alto Nivel Ruby C Código de Máquina Python Otros... C++ Otros... Ensamblador Hardware Perl Mas Trabajo / Menos Trabajo (Programador) Más Complejidad / Menos Complejidad PHP Cerca del hardware / Lejos del hardware Java Menor Abstracción / Mayor Abstracción Lenguajes de Programación Alto Nivel vs Bajo Nivel Paradigma Imperativo vs Declarativo Programación Imperativa: En la programación imperativa se describe paso a paso un conjunto de instrucciones que deben ejecutarse para variar el estado del programa y hallar la solución, es decir, un algoritmo en el que se describen los pasos necesarios para solucionar el problema Programación Declarativa: En la programación declarativa las sentencias que se utilizan lo que hacen es describir el problema que se quiere solucionar, pero no las instrucciones necesarias para solucionarlo (El sueño de todo programador...) Programación Imperativa o por Procedimientos Los programas imperativos son un conjunto de instrucciones (generalmente secuenciales) que le indican al computador cómo realizar una tarea La implementación de hardware de la mayoría de computadores es imperativa; prácticamente todo el hardware de los computadores está diseñado para ejecutar código de máquina, que es nativo al computador, escrito en una forma imperativa Ejemplo: 01.02.03.04.- A = CalcularA() B = CalcularB() C = (A + B) / 2 Imprimir(C) PHP C/C++ Java Pascal Perl etc... Programación Funcional Los programas escritos en un lenguaje funcional están constituidos únicamente por definiciones de funciones Se verifican ciertas propiedades como la transparencia referencial (el significado de una expresión depende únicamente del significado de sus subexpresiones), y por tanto, la carencia total de efectos laterales No existen asignaciones de variables ni construcciones estructuradas como la secuencia o la iteración (lo que obliga en la práctica a que todas las repeticiones de instrucciones se lleven a cabo por medio de funciones recursivas) Quicksort in Haskell qsort [ ] = [ ] qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ qsort (filter (>= x) xs) Ejemplo tomado de: http://www.haskell.org/haskellwiki/Introduction Programación Funcional Quicksort in C // To sort array a[] of size n: qsort(a,0,n-1) void qsort(int a[], int lo, int hi) { int h, l, p, t; } if (lo < hi) { l = lo; h = hi; p = a[hi]; do { while ((l < h) && (a[l] <= p)) l = l+1; while ((h > l) && (a[h] >= p)) h = h-1; if (l < h) { t = a[l]; a[l] = a[h]; a[h] = t; } } while (l < h); a[hi] = a[l]; a[l] = p; qsort( a, lo, l-1 ); qsort( a, l+1, hi ); } Los programas escritos utilizando el paradigma funcional son mucho más concretos, concisos, y en teoría mucho más fáciles de comprender y desarrollar Programación Funcional Functional programs are often easier to understand. You should be able to understand the program without any previous knowledge of either Haskell or quicksort. The same certainly cannot be said of the C program. It takes quite a while to understand, and even when you do understand it, it is extremely easy to make a small slip and end up with an incorrect program. Quicksort in Haskell qsort [ ] = [ ] qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ qsort (filter (>= x) xs) The first line reads: "When you sort an empty list ([]), the result is another empty list". The second line reads: "To sort a list whose first element is named x and the rest of which is named xs, sort the elements of xs that are less than x, sort the elements of xs that are greater than or equal to x, and concatenate (++) the results, with x sandwiched in the middle." Programación Funcional Algunos tutoriales de haskell http://www.haskell.org/haskellwiki/Tutorials http://book.realworldhaskell.org/ http://learnyouahaskell.com/chapters Otros lenguajes de programación funcionales Haskell Puros: Hibridos: Scala (JavaVM) Toman elementos del paradigma funcional: Miranda LIsp Scheme Ocaml Standar ML ML Erlang Perl Python Ruby etc... Programación Lógica Consiste en el uso de lógica matemática para programar computadores La mayoría de los lenguajes de programación lógica se basan en la teoría lógica de primer orden Se definen una serie de hechos y un conjunto de reglas que relacionan o restringen estos hechos Luego, es posible hacer consultas sobre los hechos y las reglas definidas Se suele utilizar en el desarrollo de sistemas expertos, demostración automática de teoremas y reconocimiento de lenguaje natural Programación Lógica las aves vuelan los pingüinos no vuelan <== regla <== regla "pichurri" es un ave "sandokan" es un perro "alegría" es un ave <== hecho <== hecho <== hecho una mascota vuela si es un ave y no es un pingüino <== regla ¿"pichurri" vuela? ==> Si ¿qué mascotas vuelan? ==> pichurri, alegria Programación Lógica mother_child(trude, sally). father_child(tom, father_child(tom, father_child(mike, sibling(X, Y) sally). erica). tom). :- parent_child(Z, X), parent_child(Z, Y). parent_child(X, Y) :- father_child(X, Y). parent_child(X, Y) :- mother_child(X, Y). ?- sibling(sally, erica). Yes ?- father_child(tom, Child) Child = sally Child = erica Lenguajes de Programación ¿Programación Orientada a Objetos? ¿Programación Orientada a Objetos? La Programación Orientada a Objetos (POO u OOP según sus siglas en inglés) es un paradigma de programación que usa objetos y sus interacciones para diseñar aplicaciones y programas de computadora. Está basado en varias técnicas, incluyendo herencia, modularidad, polimorfismo y encapsulamiento. Su uso se popularizó a principios de la década de 1990. Actualmente son muchos los lenguajes de programación que soportan la orientación a objetos ¿Críticas a la Programación Orientada a Objetos? Esté abierto a nuevos paradigmas de programación... No se vuelva fanático de una herramienta o de un paradigma en particular, pero... Algunas herramientas ofrecen ciertas ventajas sobre otras dependiendo del problema a atacar (y si no me cree, trate de atornillar un tornillo con un martillo) algunos modelos de compilación y ejecución ...entienda como funciona la herramienta que usa... Lenguajes de Programación ¿Modelo de Ejecución? Programa (Código Fuente) Hace el análisis léxico, semántico del código fuente y lo va ejecutando a medida que lo va leyendo Interprete Hardware (CPU, Memoria, etc.) Lenguajes de Programación Modelo de Ejecución Programa (Código Fuente) Esto se ejecuta directamente sobre el computador (sobre el hardware) Compilador El compilador traduce el programa desde el código fuente (el lenguaje en el que se escribe) al código de máquina que es el lenguaje que entiende el hardware Programa (Código de Máquina) Hardware (CPU, Memoria, etc.) Lenguajes de Programación Modelo de Ejecución Programa (Código Fuente) Compilador Programa (Rep. Intermedia) El compilador traduce el programa desde el código fuente (el lenguaje en el que se escribe) a una representación intermedia (o código de máquina virtual) que es el lenguaje que entiende el interprete o máquina virtual El interprete corre sobre un hardware real y ejecuta (interpreta) la representación intermedia del programa (lo que lo hace más rápido que si fuera completamente interpretado Interprete (Máquina Virtual) Hardware (CPU, Memoria, etc.) Lenguajes de Programación Modelo de Ejecución Programa (Código Fuente Lenguaje A) Traductor Luego el lenguaje B puede seguir cualquiera de los modelos de ejecución presentados en las láminas anteriores Programa (Código Fuente Lenguaje B) El traductor toma un programa escrito en un lenguaje A y lo transforma a un lenguaje B Interprete o Compilador (Cualquiera de las estrategias Anteriores) De la importancia de tener buenas herramientas (relacionado con IDEs también) Excusas... para no trabajar (mientras se compila algo) (O de porqué las herramientas y la compilación incremental entre otras cosas son importantes) Cortesía de: xkcd (Google it) depuración Si usted no sabe depurar... ...entonces no sabe programar ¿De donde vienen los términos “bug” o “debug”? El origen del término “bug” (y “debug”) en el mundo de la programación. Esta es una foto de la anotación original en el cuaderno de mantenimiento del computador Harvard Mark II (1947) Fuente: http://en.wikipedia.org/wiki/Software_bug Depuración ¿Cómo Depurar? ¿Cómo depurar? ¿Depurador? ¿Debugger? ¿Salida Estandar? ¿Logs? ¿Hacking? ¿Leer código fuente de terceros? ¿Lectura e interpretación de errores? ¿Excepciones? ¿Es un bug o un feature? ¿Bugtrackers? etc... documentación del Código Fuente "Any fool can write code that a computer can understand. Good programmers write code that humans can understand." Martin Fowler, Refactoring: Improving the Design of Existing Code Código auto-documentado vs documentación del código fuente ¿Qué comentar en el código fuente? Escriba comentarios sólo para código que es difícil de entender Procure no escribir código que sea difícil de entender Si encuentra que tiene que documentar en exceso cierto pasaje de código, entonces es posible que exista una forma de escribir mucho mejor y de forma más legible dicho pasaje No trate de optimizar antes de tiempo (Generalmente lleva a código difícil de entender) No trate de generalizar antes de tiempo (Generalmente lleva a código difícil de entender) ¿Qué comentar en el código fuente? Muchas veces es importante documentar el por qué el código está haciendo algo sobre el “qué” o el “cómo” está haciendo el código El “qué” está haciendo el código debería resultar evidente en el mismo código (Código auto documentado), mientras que el “por qué” lo está haciendo no siempre resulta evidente. Procure documentar por medio de la estructura (arquitectura / patrones / diseño) y las abstracciones utilizadas en el software ¿Código auto-documentado? Every comment in a program is like an apology to the reader. "I'm sorry that my code is so opaque that you can't understand it by looking at it". We just have to accept that we are not perfect but strive to be perfect and go right on apologizing when we need to. In my own personal experience, there are very few "normal" coding situations where you absolutely need comments. Basically everything else is a matter of structuring your system so that a coder can comprehend the structures in use and the choices which drove the system to use those particular structures. Tomado de: http://stackoverflow.com/questions/209015/self-documenting-code Código documentado vs auto-documentado float a, b, c; a=9.81; b=5; c= .5*a*(b^2); const float gravitationalForce = 9.81; float timeInSeconds = 5; float displacement = (1 / 2) * gravitationalForce * (timeInSeconds ^ 2); /* compute displacement with Newton's equation x = Vo*t + 1/2*a*t*t */ const float gravitationalForce = 9.81; float timeInSeconds = 5; float displacement = (1 / 2) * gravitationalForce * (timeInSeconds ^ 2); const float a = 9.81; // gravitational force float b = 5; // time in seconds // multiply the time and gravity together to get displacement. float c = (1/2)*a*(b^2) /** * Gets the value of id. * * @return the vaue of id. */ public int getId() { return id; } /** * Sets the value of id. * * @id the new vaue of id. */ public void setId(int id) { this.id = id; } Evite el exceso de comentarios o los comentarios innecesarios Mejor... public int getId() { return id; } public void setId(int id) { this.id = id; } Documentación... problemas del exceso... Los inconvenientes de comentar más de lo necesario... The Commentator (Un chiste sobre el exceso de documentación) Fuente: http://www.cenqua.com/commentator/ The Commentator (Un chiste sobre el exceso de documentación) Fuente: http://www.cenqua.com/commentator/ Estilos de Codificación Convenciones ¿Buen Código? ¡¡¡Escriba código claro!!! El código ofuscado déjelo para proteger su propiedad intelectual o para el “International Obfuscated C Code Contest” http://en.wikipedia.org/wiki/International_Obfuscated_C_Code_Contest ¿Buen Código? #define _ -F<00||--F-OO--; int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO() { _-_-_-_ _-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ ¿Qué utilidad _-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_ podría tener _-_-_-_-_-_-_-_ ofuscar código? _-_-_-_ } Calcula el valor de PI (bueno... casi...) ¿Buen Código? ¡¡¡Evite el código espagueti!!! Si le gusta la pasta disfrútela en la mesa, no en la pantalla del computador... ¿Buen Código? ¡¡¡Mal síntoma!!! f1 : while (true) { f2 : while (true) { if (true) { // do something here for (int i = 0; i < 10; i++) { if (true) { // do a bit of other thing break f2; // spaghetti??? } // finish whatever you were doing } // this bracket closes what??? // out of the loop (which one?) } else { while (true) { // You don't have a clue, do you? if (true) { for (int j = 0; j < 10; j++) // Damn it, which while is this breaking break; // Spaghetti??? } else { continue f1; // Spaghetti??? } } } // while (true) } // while (true) // resemblance with MS Win code is pure coincidence while (true) { // Ohhh no, we are doomed!!! } } Niveles de indentación ¡¡¡Reduzca en lo posible los niveles de indentación!!! Si le gusta la pasta disfrútela en la mesa, no en la pantalla del computador... ¿Buen Código? if (true) { if (true) { if (true) { if (true) { if (true) { // something } } } else { if (true) { if (true) { // something } } } } else { // something } } ¡¡¡Mal síntoma!!! for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { for (int k = 0; k < 10; k++) { for (int l = 0; l < 10; l++) { for (int m = 0; m < 10; m++) { // something } } } } for (int j = 0; j < 10; j++) { for (int k = 0; k < 10; k++) { for (int l = 0; l < 10; l++) { for (int m = 0; m < 10; m++) { // something } } } } } ¡¡¡Mal síntoma!!! public DataObject getDtaByKey(DataObject getDO) { if (getDO != null) { DataObject curDO = dtaObjectByKey.get(createKey(getDO)); if (curDO != null && curDO != getDO) { throw new IllegalArgumentException( // "curDO != null && curDO != getDO : " + // createKey(getDO)); } } } return curDO; return null; public DataObject getDtaByKey(DataObject getDO) { if (getDO == null) { return null; } GTFO! DataObject curDO = dtaObjectByKey.get(createKey(getDO)); if (curDO != null && curDO != getDO) { throw new IllegalArgumentException( // "curDO != null && curDO != getDO : " + // createKey(getDO)); } } return curDO; public DataObject getDtaByKey(DataObject getDO) { if (getDO == null) { return null; } GTFO! DataObject curDO = dtaObjectByKey.get(createKey(getDO)); if (curDO != null && curDO != getDO) { throw new IllegalArgumentException( // "curDO != null && curDO != getDO : " + // createKey(getDO)); } } return curDO; Menos Indentación protected void clientMouseReleased(MouseEvent evt) { if (draggedPaintable == null) { // GTFO return; } GTFO! if (dx == 0 && dy == 0) { // GTFO return; } MoveCommand moveCommand = new MoveCommand(draggedPaintable, dx, dy); moveCommand.redoCommand(); undoList.add(moveCommand); redoList.clear(); draggedBasePoint = null; draggedPaintable = null; dx = 0; dy = 0; } repaint(); Menos Indentación Niveles de indentación ¡¡¡Aprenda a manejar errores (excepciones) de forma adecuada!!! No deje el manejo de errores / excepciones para el final, se sorprendería lo complejo que puede ser añadir un buen manejo de errores a un código que no fue pensado para soportar esa característica // throws no exception, exceptions are handled inside the method private void doSomeNastyThingThatMightCrash() { try { BufferedReader br = new BufferedReader( new FileReader("somefile.txt")); while (doIt) { String somedata; somedata = br.readLine(); System.err.println(somedata); while (somedata != null) { // etc... } } } } catch (Exception e) { e.printStackTrace(); // ---------------// Handle Exception // ---------------} // does not handle exceptions, exceptions are handled by the caller private void failsafeDoSomeNastyThingThatMightCrash() throws Exception { BufferedReader br = new BufferedReader(new FileReader("somefile.txt")); while (doIt) { String somedata; somedata = br.readLine(); System.err.println(somedata); } } while (somedata != null) { // etc... } // throws no exception, exceptions are handled inside the method private void doSomeNastyThingThatMightCrash() { try { failsafeDoSomeNastyThingThatMightCrash(); } catch (Exception e) { e.printStackTrace(); // ---------------// Handle Exception // ---------------} } Más sobre manejo de excepciones: http://java.sun.com/docs/books/tutorial/essential/exceptions/index.html http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html http://tutorials.jenkov.com/java-exception-handling/index.html Niveles de indentación ¡¡¡Elimine y tenga bajo control los números y los literales “mágicos”!!! Creame... aún no encuentro nada mágico (en el sentido literal) en la programación. Mucha lógica y nada de magia. public class Main extends JFrame { public Main() { setLayout(new BorderLayout()); } } Client client = new Client(); add(client, "Center"); add(initTopPanel(), "North"); setDefaultCloseOperation(3); setSize(640, 480); setVisible(true); float timeInSeconds = 5; float displacement = (1 / 2) * 9.81 * (timeInSeconds ^ 2); ¿Qué números o literales “mágicos” aprecia usted? public class Main extends JFrame { public static final int WIDTH = 640; public static final int HEIGHT = 480; public Main() { setLayout(new BorderLayout()); } } Client client = new Client(); add(client, BorderLayout.CENTER); add(initTopPanel(), BorderLayout.NORTH); setDefaultCloseOperation(EXIT_ON_CLOSE); setSize(WIDTH, HEIGHT); setVisible(true); public staic final float GRAVITY = 9.81; //... other class members, code, etc float timeInSeconds = 5; float displacement = (1 / 2) * GRAVITY * (timeInSeconds ^ 2); Niveles de indentación DRY: Don't Repeat Yourself ¡NO! ¡No se Repita a Usted Mismo! (Evite el Copy/Paste) recuerde que hacer copy/paste NO es reusar código float result // ... float otherResult // ... float andAgain // ... float boring = (1 / 2) * CONST_VAL * (timeX ^ 2) / boom; = (1 / 2) * CONST_VAL * (timeY ^ 2) / blabla; = (1 / 2) * CONST_VAL * (dingdong ^ 2) / enough; = (1 / 2) * CONST_VAL * (threelittle ^ 2) / pigs; byte[] someArray; for (int i = 0; i < someArray.length; i++) { someArray[i] = someByteValue; } // ... byte[] otherArray; for (int i = 0; i < otherArray.length; i++) { otherArray[i] = otherByteValue; } // ... byte[] youGotTheIdeaArray; for (int i = 0; i < youGotTheIdeaArray.length; i++) { youGotTheIdeaArray[i] = youGotTheIdeaByteValue; } public float calcResult(float time, float oops) { return (1 / 2) * CONST_VAL * (time ^ 2) / oops; } // ---------------------------------------float result = calcResult(timeX, boom); // ... float otherResult = calcResult(timeY, blabla); // ... float andAgain = calcResult(dingdong, enough); // ... float boring = calcResult(threelittle, pigs); public void initByteArray(byte[] array, byte initVal) { for (int i = 0; i < array.length; i++) { array[i] = initVal; } } // ---------------------------------------byte[] someArray; initByteArray(someArray, someByteValue); // ... byte[] otherArray; initByteArray(otherArray, otherByteValue); // ... byte[] youGotTheIdeaArray; initByteArray(youGotTheIdeaArray, youGotTheIdeaByteValue); // ---------------------------------------// Not so bad... // ---------------------------------------String sql = "SELECT * FROM foo WHERE name='" + nameVarFromUI + "' AND phone='" + phoneFromUI + "' AND something = '" + stFromUI + "'"; // ---------------------------------------// Better... // ---------------------------------------String sql = "SELECT * FROM foo WHERE name=" + filterQuoteString(nameVarFromUI) + " AND phone=" + filterQuoteString(phoneFromUI) + " AND something = " + filterQuoteString(stFromUI); // ---------------------------------------// Much Better!!! // ---------------------------------------String sql = "SELECT * FROM foo WHERE name = {0} AND phone = {1} AND something = {2}"; sql = MessageFormat.format(sql, nameVarFromUI, phoneFromUI, stFromUI); // Know your language and the best ways to do things! Niveles de indentación Programación a la Defensiva Los demás van a tratar de chocarlo... ¡así que es mejor que usted trate de no chocar! /** * @param x A string used to calculate bla bla... * null values are not allowed. * @param a An integer used to calculate bla bla. * Valid values range between 10 and 100 (inclusive). * @return The “all mighty” calculated float. * Return value must be between 1000 and 2000 (inclusive). */ public float someAlgorithm(String x, int a) { // bla bla run the algorithm // What happens if any of the arguments is wrong? // Crash? Cryptic message? float result = ...; // something } // What happens if calculated result is wrong // The caller crashes? // A bug “who knows were and how far away from this” happens? return result; /** * @param x A string used to calculate bla bla... * null values are not allowed. * @param a An integer used to calculate bla bla. * Valid values range between 10 and 100 (inclusive). * @return The “all mighty” calculated float. * Return value must be between 1000 and 2000 (inclusive). */ public float someAlgorithm(String x, int a) { if (x == null) { throw new IllegalArgumentException( "x null values are not allowed"); // Defensive exception } if (a < 10 && a > 100) { throw new IllegalArgumentException( "a valid values range between 10 and 100 (inclusive)"); // Defensive exception } // bla bla run the algorithm float result = ...; // something if (result < 1000 && result > 2000) { throw new IllegalStateException( "return value must be between 1000 and 2000 (inclusive) " + "oops, you found a bug, result was: " + result); // Defensive exception } return result; } Niveles de indentación Use algún tipo de mecanismo de Logging Imprima cadenas sólo cuando las necesite public synchronized void initFacade(String schedId, String hibeCfg) // throws SchedulerException { System.out.println( "[INFO] Initializing Facade (id/cfg): " + schedId, hibeCfg); if (hibeCfg == null) { System.out.println("[INFO] Initializing Hibernate"); hibeCfg = CledaConnector.getInstance().getDefaultHibernateCfg(); } SchedulerFacade schedulerFacade = schedulerFacadeById.get(schedId); if (schedulerFacade != null) { System.out.println( "[WARN] Facade for the given Id is already initialized: " + schedId); return; } schedulerFacade = new SchedulerFacade(schedId, hibeCfg); schedulerFacadeById.put(schedId, schedulerFacade); schedulerFacade.start(); } System.out.println("[INFO] Facade was correctly initialized"); Tomado y adaptado de CledaScheduler private static final Logger log = Logger.getLogger( // SchedulerFactory.class.getName()); public synchronized void initFacade(String schedId, String hibeCfg) // throws SchedulerException { log.info("Initializing Facade (id/cfg): " + schedId, hibeCfg); if (hibeCfg == null) { log.info("Initializing Hibernate"); hibeCfg = CledaConnector.getInstance().getDefaultHibernateCfg(); } SchedulerFacade schedulerFacade = schedulerFacadeById.get(schedId); if (schedulerFacade != null) { log.warn("Facade for the given Id is already initialized: " + schedId); return; } schedulerFacade = new SchedulerFacade(schedId, hibeCfg); schedulerFacadeById.put(schedId, schedulerFacade); schedulerFacade.start(); } log.info("Facade was correctly initialized"); Tomado y adaptado de CledaScheduler log4j.rootLogger=ERROR, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=[%p] %d{mm:ss.SSS} (%F:%M:%L) %m%n log4j.logger.org.hibernate=ERROR log4j.logger.com.minotauro.cleda.task.core=DEBUG log4j.logger.com.minotauro.cleda.task.test=DEBUG log4j.logger.com.minotauro.cleda.task.core.WaitNotifySupport=INFO Tomado y adaptado de CledaScheduler ¿Buen Código? ¡¡¡Sea coherente y consistente!!! ¿Es mucho pedir? public void doSomething( String xxx, WeirdObject swo, UserData ud); public void doSomethingElse( WeirdObject swo, UserData ud, String xxx, int e); public void moreWorkHere( double extra2, UserData ud, int e, WeirdObject swo, String xxx); public void otherMethod( UserData ud, WeirdObject swo, String xxx); public void grrAgain( WeirdObject swo, String xxx, UserData ud); ¿Qué está mal aquí? public void doSomething( String xxx, WeirdObject swo, UserData ud); public void otherMethod( String xxx, WeirdObject swo, UserData ud); public void grrAgain( String xxx, WeirdObject swo, UserData ud); public void doSomethingElse( String xxx, WeirdObject swo, UserData ud, int e); public void moreWorkHere( String xxx, WeirdObject swo, UserData ud, int e, double x); ¿Mejor? ¿Buen Código? ¡Mantenga sus paquetes, clases y métodos en un tamaño razonable!!! ¿Qué es razonable? ¿Buen Código? La definición de razonable puede variar de contexto en contexto, pero: 1 servidor (de un juego) 1 sola clase 9000 lineas de código ~17 funciones con un promedio de 500 LDC cada función (¡¡¡Eso no es razonable!!!) ¿Buen Código? En lo personal, para Java, creo qué clases con un promedio de 500 LDC y no más de 2000 (En casos muy extremos está bien). Los métodos deberían tener entre 1-30 LDC, aunque algunos programadores quizá pensarían que 30 LDC es demasiado... En cuanto a los paquetes, no se preocupe por la cantidad de clases por paquete, preocúpese más por tener una adecuada estructura de paquetes que refleje la arquitectura del software, mantenga la cohesión y refleje el acoplamiento entre las distintas clases del proyecto http://pmd.sourceforge.net/ PMD scans Java source code and looks for potential problems like: Possible bugs - empty try/catch/finally/switch statements Dead code - unused local variables, parameters and private methods Suboptimal code - wasteful String/StringBuffer usage Overcomplicated expressions - unnecessary if statements, for loops that could be while loops Duplicate code - copied/pasted code means copied/pasted bugs http://checkstyle.sourceforge.net/ Checkstyle can check many aspects of your source code. Historically it's main functionality has been to check code layout issues, but since the internal architecture was changed in version 3, more and more checks for other purposes have been added. Now Checkstyle provides checks that find class design problems, duplicate code, or bug patterns like double checked locking. Analizador de potenciales problemas de código fuente en Java Formato del Código (Esto es importante al momento de usar Control de Versiones y Código Fuente) ¿Por qué? Convenciones de Nombres Convenciones/Reglas de Codificación Lo importante de las convenciones es que TODOs los miembros del equipo de desarrollo las apliquen y que TODOs las apliquen de forma consistente y a lo largo de TOOD el código (¿Es mucho pedir?) Refactoring y sobre codificación: Refucktoring http://freeworld.thc.org/root/phun/unmaintain.html Lenguaje de Programación vs Plataforma ¿Portabilidad? Lenguaje, Plataforma, Programador... ¿Documentación? Del lenguaje y la plataforma La importancia de la documentación... (No sólo del lenguaje sino de la plataforma) Aprenda a usar los distintos tipos de herramientas disponibles para desarrollar software Entornos de Desarrollo Integrados (IDEs) El que diga que puede trabajar sin un IDE no sabe lo que es desarrollar software... (mi humilde opinión) ¿Su IDE soporta su estilo de codificación? ¿Tiene un depurador? ¿Soporta auto-completación? ¿Vi o Emacs vs Eclipse? (LOL!!!) Control de Versiones y Control de Código Fuente Si usted no usa control de código fuente... ...entonces no puede trabajar en equipo (Inclusive me atrevería a decir que tampoco puede trabajar sólo) Recuerde que para usar un sistema de Control de Versiones y Código Fuente no sólo necesita un servidor que provea el servicio adecuado, sino que también necesita un buen cliente CVS, SVN, Hg (Mercurial), Git, Bazaar, Visual Source Safe, entre otros... http://en.wikipedia.org/wiki/Comparison_of_revision_control_software Issue Tracking Bug Tracking http://flyspray.org/ http://www.mantisbt.org/ http://www.atlassian.com/software/jira/ (Propietario) (etc...) Otras Herramientas: Foros, Wikis, Chat (Para trabajar), Herramientas de Planificación y Gestión, Groupware, Gestión de Requerimientos, etc... En general, sobre las herramientas: Use las mejores herramientas que el dinero pueda comprar, o si les gusta el software libre, las mejores herramientas de Software Libre que pueda encontrar Siempre busque y evalúe herramientas nuevas (tanto de tipos que ya conoce como de tipos completamente nuevas), eso le permitirá constantemente descubrir nuevas formas de hacer las cosas, mejores herramientas, etc Tome en cuenta la forma en la que evoluciona la tecnología en el tiempo Comprenda la verdadera razón de ser y el verdadero alcance de la tecnología que está utilizando. Tenga cuidado de los “Buzz-Words” (AJAX, SOA, BPMN, etc) o de las soluciones tecnológicas “apocalípticas” (¿El fin de los tiempos? Esas que proponen la solución a todos los problemas de la humanidad) No estoy diciendo que AJAX, SOA, BPMN sean tecnologías/conceptos “malos”, simplemente estoy diciendo que en principio se “sobre-estimaron” y no se las puso en su correcto lugar (ver gráfico siguiente) Evolución de una tecnología (Visibilidad vs Tiempo) Esto explica muchas cosas en cuanto a los patrones de uso de una tecnología, en especial en el mundo del software (Para FRAMEWORKS y COMPONENTES) Aunque aplica para lenguajes de programación... ¡Evite el Fanatismo! Por más graciosas que puedan pareces las siguientes imágenes en la práctica el fanatismo sólo trae problemas Use las mejores herramientas disponibles, las que estén acordes al contexto y las que su presupuesto pueda pagar ¡Parches! ¿Qué son, cuándo usarlos y cuándo arreglarlos? Gracias ¡Gracias!