[Las cosas que no interesan]
Todo | Music | General | Java

pageicon jueves dic 06, 2007

Peopleware

Después de varios meses de tenerlo en espera pude leer Peopleware, todo un clásico de la administración de proyectos y de la ingeniería de software.

Peopleware es un libro sobre eso, sobre la gente, sobre como el factor humano tiene una incidencia gigante en cualquier proyecto y sobre todo nos cuenta como los gerentes se encargan de ignorar convenientemente toda esta información en pro de sus números, costos y tiempos apretados. Pero es ahí mismo donde radica la fuerza de Peopleware, no es un libro de empleados frustrados contando como nos ignoran, como no somos más que números para nuestras empresas o como hay cosas que importan más que el dinero.

Peopleware es un libro de jefes que le demuestran a los demás jefes que el factor humano si puede ser medido como más les gusta a ellos: en términos de tiempos y de costos. Les demuestra como las condiciones de trabajo, la motivación, la comunicación entre compañeros, la antigüedad de los empleados y todas esas cosas que se suelen ignorar, juegan un papel que hace que un proyecto sea más caro, más barato y al fin, que sea exitoso o no. Por eso es que es un libro que se debe tener en cuenta, por que tiene argumentos aplastantes para hacer que las cosas sean mejor, para hacer que los jefes piensen en serio en mejorar definitivamente las condiciones de trabajo, en disminuir las jornadas de 12 ó 16 horas al día y lo hacen de una forma que hasta el jefe más inhumano se lo plantee, insisto una y otra vez, lo hace con cifras.

Después de esto muchos supondrán que es un libro que deben leer los gerentes o los aspirantes a gerentes, de hecho, es lo que suelen decir las editoriales y reseñas. Pero no, ahí está la otra gran enseñanza de Peopleware, que es un libro que debe ser leído por todos, por que si a nivel individual no enseña como ser mejor persona o mejor programador si que nos enseña la importancia de la motivación, no de darla, sino de saberla recibir; nos enseña lo importante que es mantener nuestro entorno de trabajo en condiciones adecuadas, claro, nuestro jefe nos puede dar los mejores muebles, espacio, etc., pero somos nosotros quienes debemos procurar un silencio que facilite el trabajo creativo.

Finalmente algo que me impactó bastante al ver lo complejo que puede ser para un gerente, es la importancia del trabajo en equipo. Este aspecto, siempre tan descuidado, tiene una influencia definitiva en la calidad del producto que se desarrolla y deja un claro mensaje: hay que saber trabajar y pertenecer a un equipo de trabajo, no solo interactuar técnicamente sino que hay que crear la mística y ese sentimiento de superioridad que caracteriza a los equipos triunfadores.

Es un libro absolutamente recomendado y que seguramente volveré a leer en alguna etapa de mi vida.

No quiero finalizar sin dejar un par de buenos consejos o datos d los aprendidos:

  • Sí, escuchar música mientras se programa tiene un efecto contraproducente, no en la productividad (es la misma) sino en la capacidad para realizar ciertas abstracciones y o descubrir cosas que no son obvias.
  • Me encanta la idea de dejar a un lado la clásica entrevista de trabajo y reemplazarla por una exposición del aspirante donde se puedan medir muchos más aspectos de un futuro empleado o como lo propone el libro, asistir a la contratación de un nuevo compañero de equipo.
  • No todas las personas necesitan lineamientos exactos de trabajo ni listas de actividades a realizar, hay quienes prefieren la libertad para hacer las cosas a su estilo y en esta forma son mucho más productivos, estos son los “Electrones Libres”, a quienes dándoles libertad se les evita ese sentimiento de “la compañía nunca va a utilizar mis buenas ideas”. Puede que no sea tan sencillo, pero ahí está, algo claro para usar cuando seamos gerentes y para exigir (con argumentos) cuando somos empleados. Esto es en otras palabras, definir nuestro trabajo.
  • Cuando trabajamos horas extras no lo hacemos para liberar un producto a tiempo, sino para evitar que nos culpen cuando el trabajo inevitablemente no se tenga a tiempo. (Wow!)
  • El trabajo exageradamente organizado, predecible y controlado puede ser muy efectivo, pero seguramente también muy monótono. La recomendación para darle algo de emoción, innovación y dinámica, es introducir “pequeñas cantidades de desorden” a través de proyectos piloto, entrenamiento, pruebas con nuevas tecnologías, etc. Eso sí, no se recomienda experimentar con más de un aspecto tecnológico a la vez en el mismo proyecto.
pageicon miércoles oct 03, 2007

Las Cosas por Leer

Durante mi entrada a este mundo de la ingeniería de software me he encontrado con cosas increíbles: la forma como se puede concebir un proyecto a un alto nivel, las técnicas para estimar su duración, el cálculo de puntos de función, las metodologías iterativas y la convivencia con el cambio, la asignación de recursos, el modelado del negocio, el análisis, el diseño, las pruebas todas las disciplinas de RUP, etc. Hace 6 meses ni me imaginaba todas las herramientas que existen para administrar un proyecto de desarrollo de software, no es que esté administrando un proyecto ahora, pero si que he tenido que preocuparme por estos aspectos.

Pero son tantos, tan diversos, hay tantas formas de ver un proyecto que resulta abrumadora la cantidad de materias en las que me encuentro ignorante; puedo mirar el proyecto desde el punto de vista de su desarrollo, es decir, las etapas que comprenden el modelado del negocio, la definición de requerimientos, el análisis y diseño, la implementación, las pruebas y el despliegue. Esta es la primera “vista” a la que me acerqué, es la que más conozco o al menos la que se me antoja menos ajena, de todas formas en la universidad se aborda cada uno de estos temas, no con gran profundidad, pero se hace y ya tenía idea de que se trata cada uno. Aún así me he llevado muchas sorpresas: la relevancia que tienen los casos de uso, como a través de ellos se puede conocer el tamaño de un sistema y como a través de ellos se puede hacer un seguimiento a todo el proceso de desarrollo; también he descubierto muchas cosas sobre el diseño, que se trata como todo de un proceso iterativo, que de un diagrama de clases se hace un esbozo inicial y a través de otros diagramas (especialmente el de secuencia) se pude probar ese diseño inicial para entrar en una etapa cíclica de refinamiento. Me he enterado de otras disciplinas sobre las que no tenía mucho conocimiento: las técnicas para modelar el negocio y la preparación de casos de prueba, no solo las he conocido, sino que he aprendido a reconocer su valor en el proceso.

La otra vista desde la que se puede mirar el proyecto es desde la administrativa, es decir, las disciplinas que soportan el proceso y que brindan las técnicas y herramientas para medirlo y controlarlo adecuadamente. Hay técnicas muy interesantes para crear un cronograma iterativo, basado en el proceso y no en el producto, es decir, hay que pensar el proyecto en términos de etapas y disciplinas, no de módulos y submódulos como estamos acostumbrados a hacerlo. El diseñar un cronograma de esta forma es lo que ha permitido estandarizar la forma de administrar proyectos de desarrollo de software, por que podemos comparar los procesos llevados para proyectos similares y empezar a obtener patrones y métricas. Una vez realizada la planificación del proyecto se pueden empezar a definir requerimientos, requerimientos que muy seguramente irán cambiando con el tiempo, a los cuales se les puede hacer seguimiento con casos de uso bien definidos y con las herramientas adecuadas que proporciona la disciplina del entorno (environment); todo esto ya está bien documentando, depurado con el paso del tiempo, con aplicación en miles de proyectos y adaptado a la tecnología de nuestra época.

Todo el interés que me ha generado mi nuevo quehacer me ha traído también una cantidad infinita de recursos: libros, páginas Web completas, artículos en línea, revistas, etc. Es obvio que nunca en mi vida voy a leer todo lo que quiero leer, que por más que me guste hacerlo, debo ser efectivo con las cosas que estudio, es decir, escoger lo mejor, lo más clásico o “lo más” en algún aspecto. No puedo leer cuanto libro consigo o me prestan, no puedo leer todos los artículos de la Web. Por eso hice una selección del material que más me recomendaron o el que más interesante me pareció por el autor o el contenido; es una gran cantidad de material, pero al menos es finita y creo yo, la puedo procesar en unos tres o cuatro meses, ojala tres para finalizar el año con la frente en alto. El material corresponde a las dos vistas de las que he hablado: el proceso de desarrollo y la parte administrativa, todo muy orientado RUP y sus mil formas de hacer lo mismo, pero es que creo que RUP es maravilloso por la claridad y la madurez de las cosas que propone. Claro, también puede llegar a ser un ladrillo.

El hecho de que el material seleccionado haya salido en su gran parte de lo recomendado por RUP, no quiere decir que no se pueda abortar de forma independiente a metodología. Aquí va pues, la tarea que tengo para los próximos tres meses:

Artículos
Entre ellos están todos los recomendados en el curso de “Gerencia de Proyectos” de Mario Zuluaga (http://www.geocities. com/marioztobon/gerenciap.htm), los otros los he encontrado uno a uno.

1. A Software Development Process for Small Projects (http://www.geocities. com/marioztobon/articles/s5096.pdf).
2. When Telepathy Won't Do: Requirements Engineering Key Practices.
3. Listening to the Customer’s Voice.
4. Estimación ISO 9000 (http://www.geocities. com/marioztobon/formatos/Estimacion_ISO_9000.doc).
5. Stop Promising Miracles.
6. Know Your Enemy: Software Risk Management.
7. Running Projects.
8. Configuration Management (http://www.geocities. com/marioztobon/articles/Configuration_Management_Notes.pdf).
9. Improving Quality through Software Inspections.
9. What Is Software Testing? And Why Is It so Hard? (http://www.geocities. com/marioztobon/articles/s1070.pdf).
10. Vee Chart (http://www.geocities. com/marioztobon/articles/Extracto_V_V.pdf).
11. Core Measures (http://www.geocities. com/marioztobon/articles/metricas.pdf).
12. Implementing Software Engineering in a Small Software Group.
13. Looking Back, Looking Ahead.
14. The New Methodology.
15. Continuous Integration.
16. Building a Fort: Lessons in Software Estimation.
17. Function Point Training Manual.
18. Structuring Use Cases with Goals.

Libros
1. Software Project Management in Practice.
2. Getting Things Done.
3. Desarrollo y Gestión de Proyectos Informáticos.
4. Peopleware: Productive Projects and Teams.
5. The Unified Modeling Language User Guide.
6. The Mythical Man-Month.
7. Object-Oriented Analysis and Design with Applications.
8. Head First Design Patterns.
9. The Rational Unified Process: An Introduction.
10. The Rational Unified Process Made Easy.
11. Patterns for Effective Use Cases.
12. Writing Effective Use Cases.
13. Software Requirements.
14. Head First Object-Oriented Analysis and Design.

Otros
1. Memorias de la Informática en Colombia.
2. Ingeniería de Software.
3. La Inteligencia Emocional.
4. The Art of Software Testing.
5. La esperanza no es un método.

Vaya, después de hacer esta lista veo tres cosas:
- Tendré que replantearme lo de 3-4 meses, por que no solo se trata de leer, hay que estudiar y poner en práctica lo aprendido.
- Me hace falta un buen libro sobre diseño de interfaz de usuario.
- ¿Por qué no puedo publicar URLs de geocities?.

Ya veremos como va resultando el camino.

pageicon domingo sep 30, 2007

La Brecha

Ha existido desde siempre una línea que nos separa los ingenieros de nuestros usuarios, una línea construida sobre la diferencia en lenguajes y en la forma de pensar; en el caso del desarrollo de software, nos separa a quienes diseñamos y construimos las aplicaciones de aquellos usuarios que las van a usar o que de una u otra forma se van a ver beneficiados por ellas.

Que exista esta diferencia está bien, la hay en todas las ciencias, artes, deportes, etc. El mundo funciona por que a todos nos gustan cosas diferentes, hay quienes diseñan casas, hay quienes las construyen, otros se especializaron en hacer cemento y los otros en transportarlo, esto no es un problema en sí, es una condición. Sin embargo para que este mismo mundo funcione, debe haber comunicación entre las diferentes especializaciones: quien diseña la casa le debe explicar al que la va a construir para que éste pueda hablar con los que hacen el cemento y hacer el pedido exacto, pero eso no implica que quien hace el cemento, deba ser un experto en el diseño y/o construcción de casas.

Lo que me inquieta y me trae a este punto es que en los ingenieros que tenemos que ver con la informática hemos hecho todo lo posible por aumentar la brecha. Hemos vivido desde hace años con la ilusión de ser y hacer como hackers, de usar un lenguaje ininteligible para los “demás idiotas”; soñamos con cuartos oscuros, llenos de módems, computadores portátiles y un montón de geeks hablando de los temas que “realmente importan” (stuff that matters) y absolutamente aislados de ese mundo donde está el monstruo a vencer, ese monstruo que nos hace la vida más difícil con sus preguntas tontas, con su manejo torpe del teclado, con su odiosa indiferencia cuando le hablamos de Linux, ese monstruo que llamamos “usuario final”.

Los ingenieros (al menos los informáticos) somos unos pedantes, somos capaces de presumir con un pregrado y 10 años de experiencia aún sin conocer un pito sobre UML y programación orientada a objetos, nos encanta sentirnos diferentes con nuestro idioma lleno de tecnicismos, nos encanta hablar rápido para hacer que las cosas parezcan más complejas de lo que son, nos encanta el estrés para demostrar cuan importante es lo que hacemos, nos encanta odiar a nuestros gerentes por que no saben nada de programación. Nos encanta despreciar a nuestros usuarios por que no saben lo que se puede hacer con la tecnología, usamos sobrenombres tan divertidos como “el idiota aquel” para referirnos a ellos, creamos caricaturas y usamos nuestro gran ícono universal para representarlos: el pobre tipo o tipa dándole golpes a un teclado a ver si su aplicación funciona. Y lo peor de todo es que nos sentimos orgullosos de ser así, nos mantenemos aislados de lo no técnico, de lo administrativo, del negocio que estamos modelando.

Una de las características de los que desarrollamos software, es mirar con desprecio hacia las estimaciones. Cuando vemos los tiempos asignados para desarrollar un módulo se dibuja una sonrisa maléfica en nuestra boca para recordarle al gerente lo poco que sabe de desarrollo y cuando nos preguntan el tiempo que nosotros estimamos, siempre explicamos lo difícil sino lo imposible que es estimar, es eso, nos encanta retratar nuestro complejo mundo.

Pero no, el usuario no es tan torpe, el gerente no es tan inepto y nuestro mundo no es tan complejo. Es cierto, somos una ciencia nueva, con mucha incertidumbre, con muchas cosas por descubrir e inventar. Estamos en una situación que nos exige humildad, nos exige mirar con cara de niño curioso hacia otras ciencias, nos exige respetar al usuario que es quien más sabe sobre lo que hacemos, por que es él quien lo usa. Debemos acercarnos a él, preguntarle como se siente lo que hicimos, que hay de bueno, que hay de malo; por que el mundo no se divide entre lo que funciona y lo que no. Hay demasiados factores subjetivos que son clave en el éxito de una aplicación, al usuario no solo debería importarle si funciona o no, el usuario es humano y como tal hay cosas que le gustan por que sí o por que no

Sabemos que no se puede garantizar que una nueva aplicación sea 100% libre de errores, los bugs son el pan de cada día y de hecho la ingeniería de software existe para darle mantenimiento a las aplicaciones con errores. Cuando no podemos dar esta garantía, deberíamos por lo menos procurar una experiencia agradable en el uso de nuestros productos, por que no es justo que aparte de soportar una aplicación con errores, el usuario deba usarla y sentirla como el ingeniero lo ordena, no es justo que se sienta idiota por que las operaciones son como las pensó el ingeniero y no como él cree que deberían ser. Claro, eso tampoco debe llevarnos a implementar cuanta cosa se le ocurra a la gente, pero si debería llevarnos a un acercamiento que facilite el trabajo en equipo, dejar de ver a nuestros usuario únicamente como el receptor de lo que hacemos, debemos convertirlo en una ficha clave en lo que hacemos. Debemos hacer que aprenda UML (que para eso se diseñó), que comprenda como se hace una aplicación, debemos escucharlo, quizá la diferencia entre un botón azul o amarillo sea la clave para la aceptación de una nueva aplicación, en fin, debemos darle al usuario la importancia que se merece, seguramente haciéndolo vamos a encontrar muchas de las respuestas que necesitamos para que los proyectos de desarrollo de software fracasen menos, para tener más claridad en el camino a seguir. Al fin y al cabo, ¿Qué es lo que hace que MAC OS sea tan exitoso?, ¿Por qué sus usuarios lo sienten como una religión?, ¿Por qué aunque Linux sea ahora tan fácil como Windows, los usuarios prefieren este último aunque tengan que pagar mucho más?

pageicon sábado sep 15, 2007

El Software

La Ingeniería de Software siendo una de las áreas que se desprende de las ciencias de la computación, cuenta con un alto nivel de incertidumbre en cuanto a sus metodologías, procesos, disciplinas, etc. Uno de los problemas con los que siempre hemos tenido que lidiar quienes estamos involucrados en el desarrollo de software es tratar de hacerlo un negocio rentable y predecible, por que sabemos que aproximadamente el 70% de este tipo de proyectos fracasan en cuanto a sus costos y tiempos. Esta aterradora cifra nos plantea inmediatamente la pregunta: ¿por qué si es un negocio que genera tantas pérdidas, tiene tantas empresas que siguen empecinadas en invertir en él?

Seguramente la respuesta a esta pregunta no es fácil, seguramente es un negocio que genera tanto pérdidas como ganancias y eso lo hace atractivo. Pero para mí la respuesta es diferente. El software es mucho más que un negocio, es una necesidad real. Jonathan Schwartz's (http://blogs.sun.com/jonathan/) decía hace algunos meses en su Weblog que el software era una industria que estaba jugando un papel similar al que juega el petróleo hoy día: la civilización se está construyendo sobre él. Y esto es cierto, el mundo como lo entendemos hoy no sería posible sin el software, desde hipótesis matemáticas que solo se pudieron demostrar con la aparición del computador, hasta la invención de Internet que ha cambiado nuestra forma de interactuar, trabajar, leer, opinar y hasta jugar y entretenernos.

Estos hechos le dan al software la categoría de IMPRESCINDIBLE, es decir, por más problemas y pérdidas que nos implique su desarrollo tenemos que "lidiar" con él. Para mí esta es la razón por la cual después más proyectos fallidos que exitosos, la industria del software sigue avanzando y las empresas siguen invirtiendo en ella. Seguramente al principio la Ingeniería Civil, mucho antes de llamarse "Ingeniería Civil", tuvo que soportar grandes edificaciones derrumbadas, pequeños sismos que acabaron con ciudades a causa de las malas construcciones y muchos proyectos que tomaban 2 ó 3 veces el tiempo estimado; eso solo se pudo soportar por que es una ciencia imprescindible, por que los seres humanos necesitamos casas para vivir y carreteras para comunicarnos, no importan lo malas que estas sean.

Claro, como esta es una nueva disciplina, nos hemos enfrentado a muchos inconvenientes para llevar a cabo proyectos exitosos. Durante los 90, el modelo de desarrollo de software en cascada fue el paradigma a seguir; había un número de etapas que se ejecutaban una a continuación de la otra, la aplicación se definía en su totalidad y luego se implementaba, igualmente, en su totalidad. Este modelo aunque parece ser que funcionó bien al principio, hizo que nos restregáramos en la cara el dinamismo y la incertidumbre de los negocios que teníamos que implementar, fue descubrir que era poco menos que imposible definir completamente un negocio antes de implementarlo. Esto ocurre bien sea por que los encargados del negocio no lo tienen claro, por que el mercado cambie las reglas del juego, por que esté regido por normas del estado que pueden cambiar en cualquier momento o simplemente por que los clientes no saben exactamente lo que quieren.

Pero los únicos inconvenientes del desarrollo no son por la incertidumbre en el negocio, la tecnología también trae muchos problemas implícitos: enfrentarnos a nuevos lenguajes de programación, frameworks o bases de datos con los que no tenemos experiencia o peor aún, no han sido probados en el dominio del negocio; también siempre hay problemas de integración entre módulos o integración con sistemas heredados (legacy); el rendimiento de las aplicaciones, la infraestructura de la red, la diversidad de sistemas operativos, etc. son factores que silenciosamente pueden llevar al fracaso. La innovación tiene un precio, y es muy alto.

Para mí esta situación es poco menos que aterradora: nunca tenemos claro lo que vamos a implementar y tampoco estamos seguros si va a funcionar.

Ante esta situación angustiante, salieron al rescate las metodologías iterativas. Donde se siguen pasos similares a los del modelo en cascada, pero se hacen una y otra vez sobre los diferentes módulos de la aplicación. Estas iteraciones mitigan inteligentemente el riesgo de lo desconocido, seleccionando en una etapa temprana del proyecto un caso de negocio a implementar y con el cual se hace una prueba de todo el proceso a seguir, la tecnología a implementar y se entrega rápidamente al usuario una "muestra" de lo que va a ser el sistema, aterrizando de esta forma las expectativas y trabajando sobre la base de un producto real. Si la primera iteración complace al cliente y al equipo de desarrollo, se continúa con otra iteración seguramente más grande, pero con la confianza de ambos bandos: hay una idea general y clara de lo que se está haciendo.

Además hay otro factor clave para el éxito de esta metodología: el cambio es algo natural dentro del proceso. Esto quiere decir que un cambio en los requerimientos no va a tener el impacto que tiene cuando se usa una metodología en cascada y es que para eso están diseñadas las iteraciones, para construir nuevos módulos y para refinar los que ya están construidos, por que otro mito que se derrumbó es el de tener módulo perfectos en un solo tirón.

Después de haber estudiado sobre el modelo iterativo, sobre todo RUP, me queda claro que una aplicación nunca está completamente terminada, con el desarrollo de software ocurre lo que le ocurre a cualquier artista con su obra: nunca la termina, siempre habrá algo que no nos gusta y que puede ser mejorado. Esto hace parte de la naturaleza humana.

Hay una gran pregunta que me queda dando vueltas:

¿Qué tan seguro es definir e implementar una arquitectura y tomar decisiones basados en una pequeña parte del problema?
¿Aplica acá la ley de Pareto? ¿El 20% de la funcionalidad me mostrará el 80% de lo que va a ser el proyecto?

Pero a pesar de todas las dudas, estoy encantado con los modelos iterativos. El mundo del software nos ofrece demasiados enigmas que pueden ser descubiertos en su mayoría con una pequeña implementación temprana y hay que olvidarnos de las implementaciones perfectas para empezar a pensar en productos imperfectos que siempre deben ser mejorados.

pageicon miércoles sep 05, 2007

El Arte

Por estos días con todo eso de el cambio y de la ingeniería de software estoy estudiando "Object Oriented Análisis and Design with Applications" de Grady Booch y compañía. Estoy empezando y es casi un viaje cósmico, Booch es de los que sabe lo que dice en cuando al diseño y construcción de software.

Pero lo que más me ha gustado es esta joya, no la traduzco por que sería vulgar:

 "it is maintenance when we correct errors; it is evolution when we respond to changing requirements; it is preservation when we continue to use extraordinary means to keep an ancient and decaying piece of software in operation"
 

pageicon lunes ago 20, 2007

El Cambio

El último año de mi vida ha tenido cambios brutales, la palabra es muy aparatosa, pero es cierto.

La cosa empezó hace un poco más cuando empecé a programar en Cobol para la empresa en que trabajaba. El paso de Java a Cobol no fue muy bien visto, para muchos era un retroceso, significaba devolverse como 15 ó 20 años en tecnología y dejar de pensar en clases, paquetes, objetos, Web, etc, etc.

La verdad es que me estaba hartando de Java, no de la tecnología, sino de lo que había en torno a ella. No parecíamos programadores de un lenguaje, eramos más bien un montón de fanáticos religiosos donde lo mejor de Java es que era Java. Sin muchos argumentos, sin preguntarnos mucho de nada, leyendo siempre javaHispano, TheServerSide, java.net y todas las páginas en las que solo se habla de Java, aprendiendo a defendernos de "Los Otros", los programadores de .NET, pero defendiéndonos sin conocer esa plataforma, defendiéndonos con lo que nos daban las noticias de javaHispano y los objetivos "BenchMarks" de TheServerSide. Era claro para mí que necesitaba un cambio.

Programar en Cobol fue una experiencia bastante loca, dejar de pensar en términos de clases, ver algoritmos con 20 ó 30 mil líneas y empezar a entender las bases de datos jerárquicas era como cambiar de mundo, cambiar de trabajo, eso sí, el negocio era similar, por que fue bien divertido ver como soluciones que en el mundo de los objetos y las arquitecturas multicapas llevaban varias semanas de implementación, en Cobol tomaban apenas unas horas. Claro, lo contrario era mucho más común.

Los meses que duré como programador Cobol fueron rejuvenecedores, me mostraron un mundo que no conocía y sobre todo entendí por que muchas de las cosas son como son ahora, jeje, por ejemplo el impacto que tiene sobre la legibilidad de un programa el poder declarar variables en cualquier punto o el tener que declararlas todas al principio, es mucho más de lo que uno se imagina o por lo menos fue muchísimo más del que yo me imaginaba.

Durante mi "estadía" en Cobol descubrí algunas cosas que hacían falta en el proceso que seguíamos. Una de esas cosas que hacían falta era un IDE que permitiera agilizar el trabajo y detectar algunos problemas que el compilador no detectaba, aunque busqué bastante, no encontré mucho, de hecho nada. Aprovechando que tenía la energía suficiente para trabajar 14 horas al día me puse en la tarea de desarrollarlo. No fue algo maravilloso, pero si que resolvió numerosos problemas, de paso conocí el entorno de NetBeans 5 para aplicaciones Swing y ya entrado en gastos, usé parte del tiempo para estudiar y certificarme como programador Java. No tengo idea como hice para que el tiempo fuera suficiente en ese entonces, solo se que cuando más tareas tenía por hacer, mucho mejor era usando los recursos con que contaba (tiempo, espacio y hasta dinero).

Después a causa de algunos movimientos clave en la empresa pasé al área de investigación y desarrollo, donde apenas duré unos días por que llegó una nueva propuesta de trabajo que tomé, claro, después de meditarlo mucho.

Entré al mundo SAP en un proyecto que se trataba de instalar y personalizar el portal integrándolo con el CRM y la tienda en línea. Algo bien interesante y diferente con respecto a lo que había hecho hasta el momento. Aprendí bastante sobre sistemas integrados, su filosofía, sobre CRMs, tiendas en línea, ABAP y todo lo que pude en los 4 meses que estuve en el proyecto.

Ahora estoy en una nueva ciudad, lejos de mi mundo conocido y entendiendo todas las cosas de las que nunca quise entender por que siempre creí que "lo mio" era ser muy técnico, usar un lenguaje ininteligible para los gerentes, estar encerrado en un garaje con un pc y unos manuales de referencia tipo biblia, tomando café y trabajando hasta la madrugada. Pero no, para eso es la vida, para demostrarle a uno que casi todo lo que creía era mierda, que antes de los 60 no hay criterio para tomar decisiones y que definitivamente la casualidad es la que me guía. No nací para nada, hago lo que haya por hacer y casi todo me gusta. Hago lo que hago por pura casualidad, soy ingeniero de sistemas por que para ser electrónico hubiera tenido que viajar mucho y a mis papás en mis 17, les parecía exagerado eso sabiendo que habían tantas otras cosas por estudiar.

Hoy estoy aprendiendo sobre todo lo que tiene que ver con ingeniería de software, todas las etapas de un proyecto, donde la programación y el desarrollo solo ocupan a lo sumo una tercera parte del ciclo. Ahora lo mío es entender como gestionar un proyecto, ahora lo mío es leer "The Mythical Man-Month" y entender como funcionan los equipos de trabajo, como disminuir el riesgo en un proyecto de desarrollo. Ahora lo mío es sentarme con un usuario y entender como siente, que quiere, ponerme de acuerdo con él y asegurarme de que los dos pensemos lo mismo cuando planteamos una solución. Ahora estoy en un mundo donde la cosa es más un arte que una ciencia exacta, donde no hay soluciones exactas, donde no hay bueno y malo sino lo uno y lo otro. Ahora estoy entendiendo por que UML sí es importante y sobre todo por que los casos de uso en verdad fueron una revolución en su momento, entendiendo que no se trata de los pinches gráficos, que no se trata de hacer bien el muñeco y que los círculos cumplan con un montón de reglas estrictas, donde no importa si tengo que comunicar dos muñecos para entender mejor el funcionamiento del sistema. Donde ahora UML y Java en verdad son herramientas, ya no defiendo las cosas religiosamente, ya no puedo hacerlo.

Eso si me ha gustado de el cambio, que me ha restregado lo equivocado que me mantengo y como es que el mundo no funciona dentro de una cuadrícula.

pageicon lunes jun 25, 2007

SCJP for JSE5 - 9

SOBREESCRITURA Y SOBRECARGA
1.  Sobreescritura de métodos.

La sobreescritura de métodos consiste en la habilidad de definir cierto tipo de comportamiento que es específico para una subclase. Por ejemplo:

class Humano{
    public void caminar(){
       //caminar como un ser humano
    }
    //otros métodos de humanos...
 }

class Pepe extends Humano{
    public void caminar(){
       //caminar de forma particular como Pepe
    }
}

En la implementación anterior la clase Humano define un grupo de métodos que aplicará a todas sus subclases. Pepe por ejemplo, hereda todos los métodos heredables de Humano, pero por alguna razón, define un comportamiento específico para caminar. Quizá por que Pepe sea cojo, tenga un pie más largo que otro o por que camina muy rápido, en fin, de esto se trata la sobreescritura de métodos: las subclases pueden aprovechar todos los métodos que heredan de sus padres y además personalizar el comportamiento que no se acomode a sus necesidades.

No se debe confundir la sobreescritura de métodos con la implementación. Cuando se heredan métodos abstractos de una clase (abstracta por supuesto), estos se implementan no se sobreescriben.

Las reglas para sobreescribir métodos son:

- La lista de argumentos debe ser exactamente igual a la del método sobreescrito. Si esta regla no se cumple, probablemente se obtiene un método sobrecargado.

- El tipo de retorno debe ser el mismo o un subtipo del tipo de retorno declarado en el método sobreescrito en la superclase. Lo de subtipo es nuevo en JSE5, se le llama "Covariant Returns" y se verá más adelante.

- El nivel de acceso no puede ser más restrictivo que el del método sobreescrito.

- Los métodos marcados como private, final o static no pueden ser sobreescritos.

- El método que sobreescribe no puede lanzar 'Checked Exceptions' nuevas o de nivel superior a las declaradas en el método sobreescrito.

- El método que sobreescribe no tiene que declarar excepciones que no vaya a lanzar, no importa las que hayan declaradas en el método original.

OJO: Si un método no puede ser heredado tampoco puede ser sobreescrito.

 
Invocar la versión de la superclase de un método sobreescrito

Sobreescribir un método no quiere decir que el método de la clase de nivel superior ya nunca más puede ser invocado con una instancia de la subclase; la palabra reservada super hace referencia a la instancia de la superclase (sí, al crear la instancia de una subclase, también se crea una de la superclase) y con esta palabra podemos invocar los métodos que han sido sobreescritos en la subclase. Por ejemplo:

class Humano{
    public void caminar(){
       //caminar como un ser humano
    }
 }

class Pepe extends Humano{
    public void caminar(){
       super.caminar(); //invoco la forma de caminar de la clase superior
       //implemento las particularidades del caminado de Pepe
    }
}

El uso de la palabra super para invocar métodos sobreescritos, está restringido para los métodos de instancia que sean accesibles por la subclase (los no private).

2. Sobrecarga de métodos

- La sobrecarga de métodos permite reutilizar el mismo nombre de un método en una clase pero con una lista de argumentos diferente y se puede cambiar el tipo de retorno. Los métodos se pueden sobrecargar en la misma clase o una subclase puede sobrecargar uno o varios métodos de la clase padre. Un ejemplo:

class Humano{
    public void caminar(int kilometros){
       //caminar los metros indicados
    }

    public void caminar(Recorrido rr){
       //seguir el recorrido pasado como parámetro
    }
 }

class Pepe{
    public void caminar(Direccion dir){
       //caminar hacia la dirección indicada
    }
}

Note que en el ejemplo anterior el método caminar() de la clase Pepe no sobreescribe ninguno de Humano sino que lo sobrecarga. Así una instancia de la clase Humano tiene acceso a dos formas del método caminar: una que recibe el número de kilómetros y otra que recibe el recorrido a hacer; mientras una instancia de la clase Pepe tiene acceso a tres formas del método caminar: dos heredadas de Humano y otra sobrecargada en Pepe que recibe una dirección.

Las reglas para sobrecargar métodos son:

- Los métodos sobrecargados tienen que cambiar la lista de argumentos.

- Un método sobrecargado puede cambiar el tipo de retorno.

- Un método sobrecargado puede cambiar el modificador de acceso.

- Un método sobrecargado puede declarar excepciones nuevas o de nivel superior.

Dado el método public Integer calcularPrecioProducto(int valorCompra, double ganancia) throws Exception, algunas versiones sobrecargadas de este método pueden ser:

protected Double calcularPrecioProducto(int valorCompra, double ganancia)
public Integer calcularPrecioProducto(int valorCompra)
public Integer calcularPrecioProducto(double ganancia) throws SQLException

- La decisión de la versión del método que se va a invocar está basada en la lista de argumentos y se hace en tiempo de compilación. Por ejemplo al compilar y ejecutar la clase EjemploSobrecarga:

class Humano{}
class Pepe extends Humano{}
class EjemploSobrecarga{
    void hacerAlgo(Humano hum){
        System.out.println("Procesando un Humano...");
    }

    void hacerAlgo(Pepe pe){
        System.out.println("Procesando Pepe...");
    }

    public static void main(String[] args) {
        Humano pepe = new Pepe();
        new EjemploSobrecarga().hacerAlgo(pepe);
    }
}

La salida será: "Procesando un Humano...".

Aunque la instancia que se pasa como parámetro al método 'hacerAlgo()' es de la clase Pepe, el compilador solo sabe que la variable es una referencia a la clase Humano y por tanto decide invocar la versión que recibe tiene esta clase como argumento. La salida sería diferente si la variable se creará así: 'Pepe pepe = new Pepe();', en este caso el compilador reconoce una referencia a Pepe e invoca el método correspondiente.

Algo que nunca me ha quedado muy claro es que sucede cuando se pasa null como argumento, no se cuál es el criterio para elegir el método. En el ejemplo anterior que sucedería con la línea: 'new EjemploSobrecarga().hacerAlgo(null);'

El Final

Es muy importante reconocer si un método se está sobreescribiendo, sobrecargando o ambos. Hay que reconocer cuando hay errores de compilación o cuando una mala sobreescritura termina en una sobrecarga; esto se debe complementar muy bien con los conceptos de polimorfismo para que dado cualquier código, con la complejidad que sea, podamos predecir la salida.

En SProgramando he publicado un listado de preguntas sobre el tema.

pageicon miércoles jun 20, 2007

Los Recursos

A través de un sitio que hace referencia a este weblog, encontré una buena página con recursos para la certificación. Se trata del Grupo de Usuarios Java del Uruguay que tiene una sección dedicada a la SCJP en donde tienen algunos artículos publicados y otra sección aún más interesante con preguntas y su solución bien explicada.

A mi modo de ver una de las mejores formas de estudiar es ver preguntas y entender bien su solución por que aunque en el examen no importa si se responde por suerte o conocimiento, para efectos educativos (y de la vida en general ;-) es mejor entender como funcionan las cosas por dentro y aprender más que casos concretos, reglas generales. Claro, otra recomendación es hacerlo una vez se acabe de leer la sección correspondiente en el libro guía.

Estos son los enlaces:

- Grupo de Usuarios Java del Uruguay: http://juguy.org/
- Artículos Sobre SCJP: http://juguy.org/content/category/7/75/58/
- Preguntas con Solución detallada: http://juguy.org/content/category/7/76/49/

Más material para el repositorio!.

pageicon miércoles jun 06, 2007

SCJP for JSE5 - 8

1. ENCAPSULACIÓN.
El objetivo de la encapsulación es lograr código que se pueda modificar sin afectar el código de los demás. Esto se logra poniendo en práctica algunas recomendaciones:

  • Proteja los atributos de instancia. (con algún modificador de acceso).
  • Cree métodos públicos para acceder a los atributos, para ello use los estándares JavaBean para los métodos set() y get().

Ejemplo de una clase bien encapsulada:

class Algo{
    private int propiedad;
    public int getPropiedad(){
       return propiedad;
    }
    public void setPropiedad(int valor){
       propiedad = valor;
    }
}

2. HERENCIA, IS-A (ES-UN) Y HAS-A (TIENE-UN).
La herencia es el mecanismo por excelencia de la programación orientada a objetos para reutilizar el código. La herencia permite el diseño de relaciones complejas entre los diferentes componentes de una aplicación y una de las cosas más importantes, el polimorfismo, que permite que cualquier clase sea tratada como uno de sus padres (algunas de las clases de las que hereda).

Dado el código:

class A{
    public void hacerCosas(){
       System.out.println("A está haciendo alguna cosa");
    }
}
class B extends A{ }
class C extends B{ }

Las clases B y C heredan de A. B lo hace directamente y C lo hace a través de B; esto quiere decir que tanto B como C pueden ser tratadas como cualquiera de sus padres, esto es, B puede ser tratada como A y, C puede ser A o B. El siguiente código por ejemplo, es válido y la salida será 4 veces la frase "A está haciendo alguna cosa".

public static void main(String[] args) {
        A clase1 = new A();
        A clase2 = new B();
        A clase3 = new C();
        B clase4 = new C();

        clase1.hacerCosas();
        clase2.hacerCosas();
        clase3.hacerCosas();
        clase4.hacerCosas();
}

Lo mismo ocurre con los parámetros:

public static void unParametroGeneral(A parametro){
        parametro.hacerCosas();
}

public static void main(String[] args) {
        unParametroGeneral(new A());
        unParametroGeneral(new B());
        unParametroGeneral(new C());
}

El problema al tratar las clases como su padre, es que solo se puede acceder a los métodos y atributos de instancia declarados por el mismo padre; para acceder a los métodos y atributos específicos de cada clase, se debe usar una variable de su tipo.

IS-A y HAS-A
La relación IS-A (ES-UN) es una forma de decir "este objeto es de tipo XXX" y se refiere a la herencia entre clases o a la implementación de una interface específica.
Suponiendo que A y B son clases y que Y y Z son interfaces:

  • A IS-A (ES-UN) B si A hereda de B directa o indirectamente.
  • A IS-A X si A implementa X.
  • X IS-A Y si X hereda directa o indirectamente de Y.

La relación HAS-A es mucho más simple y se refiere únicamente al uso que una clase hace de otra. Se dice que A HAS-A (TIENE-UN) B si A tiene un atributo de tipo B. Por ejemplo:

class A{}
class B{
    private A atributo;
}

En este caso la clase B HAS-A A.

3. POLIMORFISMO
El polimorfismo se refiere a la capacidad de un objeto para comportarse de diferentes formas (poli-mórifico), esto en Java está dado por las clases de las que hereda y las interfaces que implementa, ambos, directa o indirectamente.
Un objeto puede ser tratado (lo mencioné anteriormente) como cualquiera de sus padres o las interfaces que implemente, es decir, como cualquiera de las clases o interfaces con las que pase el test IS-A, y claro, solo puede invocar los métodos que estén declarados en la clase que se use como tipo para la variable que apunta al objeto. Los métodos que se ejecutarán serán los de la instancia de la clase que realmente se haya creado.

Todo esto se entiende mejor con un ejemplo.

class Animal{
    public void comer(){
        System.out.println("Comiendo como Animal");
    }
}

class Perro extends Animal{ }

class Labrador extends Perro{
    public void comer(){
        System.out.println("Comiendo como Labrador");
    }

    public void hacerCosasDivertidasDeLabrador(){
        System.out.println("Soy un Perro Labrador haciendo cosas divertidas");
    }
}

En este caso, las instancias de la clase Perro pueden ser tratadas como Animal o Perro y las de Labrador como Animal, Perro y Labrador. Pero claro, si por ejemplo se quiere acceder al método 'hacerCosasDivertidasDeLabrador()' de la clase Labrador debe hacerse a través de una variable de tipo Labrador.
Veamos algo de código:

public static void main(String[] args) {
        Animal an = new Animal();
        Animal pe = new Perro();
        Animal la = new Labrador();

        an.comer();
        pe.comer();
        la.comer();
}

Con el tipo Animal se pueden referenciar las instancias de las tres clases, por que Animal, Perro y Labrador cumplen el test 'IS-A Animal'. Pero los métodos que se acceden corresponden a cada una de las instancias que realmente se crearon. Al ejecutar la clase la salida es:

Comiendo como Animal
Comiendo como Animal
Comiendo como Labrador

Las líneas 'an.comer();' y 'pe.comer()' invocan ambos el mismo método implementado en la clase Animal, por que la clase Perro no tiene ninguno declarado, esto es, lo hace a través de herencia. La línea 'la.comer();' aunque tenga una referencia a través de la clase Animal, invoca el método implementado en la clase Perro por que es la instancia a la que realmente apunta.

Si introdujéramos la siguiente línea 'la.hacerCosasDivertidasDeLabrador()', tendríamos un error de compilación por que aunque la instancia en verdad sea de Labrador, la referencia a través Animal no tiene ni idea sobre la existencia del método. Un buen truco para descifrar este tipo de errores es que los llamados a los métodos se definen en tiempo de compilación, es decir, si el compilador no encuentra una relación directa entre la variable usada (herencia, implementación de una interface) y el método a llamar, lo único que puede hacer es mostrar un error. Pero esto que es clave, lo intentaré explicar mejor en otra entrada. Finalmente, para invocar correctamente el método 'hacerCosasDivertidasDeLabrador()', debemos crear una instancia de la clase Labrador y apuntar a ella (aunque a mucha gente no le gusta usar la palabra apuntador en Java) con una variable de ese mismo tipo, todo este enredo textual en dos líneas de código:

Labrador labra = new Labrador();
labra.hacerCosasDivertidasDeLabrador();

Algo muy importante saber y que debe ser entendido y practicado muy bien es que lo único que se selecciona dinámicamente basado en el objeto actual (en vez de la referencia) son los métodos de instancia. No sucede ni con los métodos estáticos ni con los atributos.

El Final.
De estos temas suelen salir las preguntas más complejas del examen (sin olvidarnos de los hilos) y es clave tenerlos muy claros, por eso es importante resolver un buen número de preguntas que los abarquen.

pageicon martes jun 05, 2007

Y yo que creía que no se podía

NOMBRES DE VARIABLES 

Alguna vez me pregunté si una variable podía tener el mismo nombre de una clase del paquete java.lang o en general, ¿una variable puede tener el mismo nombre de una clase que se esté importando?. A ver:

package whatyoubelievedyoucouldnot;
import javax.swing.JButton;
public class VariableName {
    public static void main(String[] args) {
        String Integer = "Hola Paco";
        System.out.println("Tamanio: " + Integer.length());
        System.out.println("Texto: " + Integer);

        Integer JButton = Integer.length()*2;
        System.out.println("JButton: " + JButton);
    }
}

Si se compila y ejecuta la clase anterior la salida será:

Tamanio: 9
Texto: Hola Paco
JButton: 18

Pues resulta que sí, si se puede usar el nombre de cualquier clase como variable. ¿Pero qué pasa si necesito usar la clase java.lang.Integer?, pues eso, hay que cualificarla completamente:

System.out.println(java.lang.Integer.toHexString(0xCAFE));
String unNumero = "666";
Float Float = java.lang.Float.parseFloat(unNumero);

Aunque el código es como para moler a golpes quien lo haga, según las reglas no hay razón por la que no se puedan usar estos nombres ya que no son palabras reservadas y tienen nombres válidos.

Eso sí, según las buenas prácticas los nombres de variables y atributos deben empezar con letras minusculas, pero esto no es ningún impedimento para que una clase compile.

NOMBRES DE CLASES
¿Y qué hay sobre las clases?, pues lo mismo, como el nombre es válido, puedo hacer lo mismo. Veamos la siguiente obra de arte:

package whatyoubelievedyoucouldnot;
public class Thread {

    @Override
    public String toString(){
        return "Soy un hilo farsante";
    }

    public static void main(String[] args) {
        Thread Thread = new Thread();
        System.out.println(Thread.toString());
    }
}

También asesinaría a quien cometa este tipo de aberración, pero es válida. La salida al ejecutar este programa es "Soy un hilo farsante", por qué el método toString() que se ejecuta es el de la clase 'whatyoubelievedyoucouldnot.Thread'. ¿Qué tal si queremos un hilo de los 'verdaderos'?

package whatyoubelievedyoucouldnot;
public class Thread {

    @Override
    public String toString(){
        return "Soy un hilo farsante";
    }

    public static void main(String[] args) {
        java.lang.Thread Thread = new java.lang.Thread();
        System.out.println(Thread.toString());
    }
}

Igual, se cualifica la clase completamente para diferenciarla de la actual.

Hemos visto verdaderas obras del desastre y la confusión, supongo que si todo el código que hiciéramos fuera así, nadie se atrevería a ser programador. Aunque se ven tantas cosas...

Bien, y ¿qué pasa si hago una clase llamada Thread dentro de un paquete java.lang?, pues ese asunto ya toca con classloaders, el orden en que se cargan las clases, etc. algo para probar en casa y con lo que no me quiero meter.

pageicon lunes may 28, 2007

SCJP for JSE5 - 7

1. Variables locales y modificadores de acceso
Las variables locales son las que se declaran dentro de los métodos y el único modificador que se puede usar con ellas es final, esto incluye los parámetros que recibe un método. Las variables primitivas marcadas como final no pueden ser modificadas y a las variables de referencia marcadas como final, no se les puede asignar un nuevo objeto.

2. Otras consideraciones para el modificador final
- Los métodos marcados como final no pueden ser sobreescritos.
- Los argumentos marcados como final no pueden ser modificados.

public int consultarDatos(final int clave){
    clave = 23; //error de compilación!!
}

Este método no compila por que se está intentando modificar una variable final.

- Las clases final no pueden ser heredadas.

3. Otros modificadores
- abstract: El modificador abstract solo aplica para las clases y los métodos. Un método abstracto es el que ha sido declarado pero no tiene implementación y solo pueden existir dentro de clases abstractas. La primera clase concreta que hereda una clase abstracta, debe implementar todos sus métodos abstractos. Por clase concreta se quiere decir clase no abstracta.

- synchronized: este modificador solo aplica para los métodos. Un método sincronizado solo puede ser ejecutado por un hilo a la vez, esto se verá más adelante cuando se trate el tema de concurrencia.

- native: este modificador solo aplica para los métodos. Un método nativo es implementando normalmente en otro lenguaje para cada plataforma y en la clase solo se declara (como un método abstracto).

- strictfp: aplica para clases y métodos. Una clase o método marcada como strictfp se adhiere al estándar IEEE 754, no es necesario profundizar más (solo si se tiene curiosidad).

- transient: solo aplica para atributos de instancia. Los atributos marcados como transient son ignorados cuando se serializa una clase (tema tratado más adelante).

- volatile: solo aplica para atributos de instancia. Es un modificador utilizado cuando se trabaja con hilos, e indica a la máquina virtual que siempre acceda a una copia de la variable. Esto es complejo y se tratará junto con todo el tema de concurrencia.

4. Combinaciones entre modificadores
Los modificadores (que no son de acceso) que se pueden usar con los métodos son: final, abstract, synchronized y strictfp. Todos estos modificadores se pueden usar conjuntamente, pero no todos con todos. Las combinaciones legales se resumen en la siguiente tabla (una 'X' indica que se pueden combinar, una 'O' indica que no):

  finalabstract
synchronized
strictfp
 final XOX X
 abstract OXO O
 synchronized XOX X
 strictfp X O  X  X

Por ejemplo el modificador synchronized no se puede usar con abstract.

Los modificadores (que no son de acceso) que se pueden usar con atributos de instancia son: final, transient y volatile. Esta es la tabla para combinarlos:

  finaltransientvolatile
 final X X O
 transient X X X
 volatile OX
 X 

5. Métodos con argumentos variables
Los argumentos variables son una de las nuevas características de JSE5.0, e indican que cierto argumento puede recibir un número indeterminado de valores. Solo puede existir un argumento variable para un método y debe ser el último declarado:

void hacerCosas(int otroArgumento, String... valores){}

6. Declaración de constructores
Un constructor válido debe declararse como un método sin tipo de dato de retorno, con el mismo nombre de la clase, puede tener cualquier un modificador de acceso y no puede ser static, final o abstract (ninguno de los tres tiene sentido para un constructor).

public class Perro(){
    //constructores válidos
    Perro(){}
    public Perro(){}
    protected Perro(int valor){}
    //private se suele usar para las clases singleton
    private Perro(String ... args){}
}

7. Declaración de variables
Primitivas
. Pueden ser de 8 tipos: char, boolean, byte, short, int, long, double o float.
Se pueden declarar varias al mismo tiempo e inicializarlas:
int a, b, c, d = 9;
short uno = 1, dos = 2, tres = 3;

Para las versiones anteriores del examen había que conocer los tamaños en bits o bytes de los tipos de datos, para esta versión solo es necesario saber que el orden ascendente de los tipos enteros es: byte, short, int y long; y que float es más pequeño que double.

De Referencia. Se declaran igual que las primitivas pero estas apuntan hacia objetos.
String a = "HOLA", b = null, c = new String("Otro Hola");

8. Variables de instancia
Son las que se declaran afuera de los métodos y existe una por cada instancia de la clase. Pueden modificarse con cualquiera de los cuatro niveles de acceso y usar los siguientes modificadores: final, transient y volatile. No pueden ser ni synchronized, strictfp, native ni static (con esto dejarían de ser variables de instancia).

9. Variables locales
Las variables locales o automáticas, son las que se declaran dentro de los métodos. Solo pueden usar el modificador final, para ellas no aplican los modificadores de acceso. Deben ser inicializadas antes de usarlas:

void hacerAlgoBienBacano(){
    int valor; //variable local
    System.out.println("valor = " + valor); //Error de compilación!!!
}

10. Declaración de arreglos
Se declaran de forma similar a cualquier dato primitivo o de referencia, pero se incluyen brackets a la derecha del tipo de dato o del nombre de la variable para indicar el número de dimensiones del arreglo.
String array[][]; //arreglo de Strings de dos dimensiones
int[] arr1, arr2[]; //arr1 es de una dimensión, pero arr2 es bidimensional

11. Variables y métodos static
El modificador static se usa para crear variables que existirán de forma independiente de cualquier instancia de la clase a la que pertenecen. El modificador static aplica para métodos, variables, clases internas y bloques de inicialización.
El modificador no aplica para constructores, clases, interfaces métodos de clases internas locales, variables de instancia (por que dejarían de ser de instancia) y variables locales.

12. Declaración de enums
Son otra de las nuevas características en JSE5.0. Se crearon para hacer un uso más seguro de las constantes, pues anteriormente se debían declarar como tipos de datos del lenguaje (generalmente primitivos), por lo que las variables podían tener cualquier valor de el dominio del tipo.
Con esta nueva característica es posible restringir el número de valores que puede tener una variable a un grupo de datos predefinido.

enum Animales{PERRO, GATO, MARRANITO, POLLITO};
Animales miMascota;

Con esta simple declaración la variable miMascota solo podrá tener valores que estén declarados detro del enum Animales.

Los enums se comportan de forma muy similar a las clases, es decir, solo pueden usar los modificadores de acceso por defecto (cuando no se digita nada) y public, cuando son públicos el nombre del enum debe ser el mismo del archivo que lo contiene. También pueden declararse dentro de clases (como las clases internas) e interactuar con los modificadores public, private, protected, static y strictfp. No pueden llevar los modificadores transient, volatile, synchronized ni abstract.

Los enums pueden tener constructores, variables de instancia, métodos y 'constant specific class body' (no me atrevo a traducirlo!). Todo se entiende mejor con un ejemplo.

enum TipoPollo {
    //cada tipo de preparación tiene un número de calorias
    CRUDO (10), ASADO (40), COCINADO (20), FRITO (100);

    private int calorias;

    //los valores que se pasan como argumento a la declaración
    //de la variable, son pasados al constructor

    TipoPollo(int calorias){
        this.calorias = calorias;
    }

    public int getCalorias(){
        return this.calorias;
    }

    public String getPresa(){
        return "MUSLO";
    }
}

Dada la anterior lista enumerada, podemos invocarla desde otra clase y ejecutar el siguiente método main():

public static void main(String[] args) {
        TipoPollo unaPresa = TipoPollo.CRUDO;
        System.out.println("El pollo está " + unaPresa.name());
        System.out.println("El número de calorías es: " + unaPresa.getCalorias());
        System.out.println("La presa que venden es: " + unaPresa.getPresa());
}

Ahora supongamos que el pollo frito viene en alas, el resto en muslos; se podría hacer empezar a preguntar por el tipo de presa (if (this.equals(FRITO)) return "ALA"; else return "MUSLO";)) o sobreescribir el método getPresa() del valor FRITO:

enum TipoPollo {
    //cada tipo de preparación tiene un número de calorias
    CRUDO (10), ASADO (40), COCINADO (20),
    FRITO (100){
        @Override
        public String getPresa(){
            return "ALA";
        }
    };


    private int calorias;
    //los valores que se pasan como argumento a la declaración
    //de la variable, son pasados al constructor

    TipoPollo(int calorias){
        this.calorias = calorias;
    }

    public int getCalorias(){
        return this.calorias;
    }

    public String getPresa(){
        return "MUSLO";
    }
}

Así, al ejecutar el método main():

public static void main(String[] args) {
    TipoPollo unaPresa = TipoPollo.FRITO;
    System.out.println("El pollo está " + unaPresa.name());
    System.out.println("El número de calorías es: " + unaPresa.getCalorias());
    System.out.println("La presa que venden es: " + unaPresa.getPresa());
}

La salida sería:

El pollo está FRITO
El número de calorías es: 100
La presa que venden es: ALA

Algunas conclusiones:
- Los constructores de los enums no pueden ser invocados directamente.
- Se puede definir más de un argumento para el constructor (aunque esto no se concluye del código que puse de ejemplo :-]).
- Las constantes pueden sobreescribir los métodos de la lista enumerada.

El Final
Hasta acá el final del primer capítulo del libro guía, es bueno practicar bastante esta primera parte por que es la base para el resto de capítulos, hay muchas preguntas llenas de marañas y procesos complejos cuya respuesta será un simple "compilation fails" y se identificará fácilmente si se tienen claros estos conceptos.
En sprogramando monté un listado de preguntas sobre el capítulo que pueden servir para evaluar el conocimiento sobre el tema, así que a practicar, la url es: http://sprogramando.wikidot.com/scjp-for-jse5-preguntas-grupo1.

Si hay errores en este texto, los anteriores o las preguntas, por favor escribirlo en los comentarios.

Un saludo.

pageicon domingo may 27, 2007

SCJP for JSE5 - 6

Acabo de crear una página donde reúno todos los recursos que voy encontrando con material para la certificación.
Por ahora están los links que he publicado acá mismo y adicionalmente las preguntas que hago sobre cada tema. Pero como la idea es que sea algo más o menos grande y que sirva de verdad, los recursos (links, preguntas, etc) que pongan en los comentarios o envíen a mi correo (alexander.zuluaga[arroba]gmail.com), los iré publicando. Insisto, sobre todo hacen falta preguntas.

La página completa: http://sprogramando.wikidot.com/scjp-for-jse5.

Las preguntas: http://sprogramando.wikidot.com/preguntas-scjp-for-jse5-preguntas.

Pues nada, esperemos a ver como funciona esto.

pageicon sábado may 26, 2007

SCJP for JSE5 - 5

1. DECLARACIÓN DE MÉTODOS Y ATRIBUTOS (MIEMBROS)

Los atributos y métodos de las clases tienen siempre un nivel de acceso aunque éste no sea digitado. Existen cuatro niveles: public, protected, default y private, cada uno de ellos restringiendo o permitiendo el acceso a los miembros de las clases, pero, es muy importante saber que si una clase no puede "ver" a la otra, mucho menos podrá ver sus miembros; esto ocurre en el caso de una clase con modificador de acceso default (cuando no se digita nada) que se intenta acceder desde una clase en un paquete diferente. Por ejemplo:

package uno;
class Servidor{
   //muchos métodos y atributos
}

package dos;
public class Cliente{
   //otro montón de métodos tratando de acceder a Servidor
}

En este caso no importan los modificadores de acceso de los miembros de la clase Servidor, por tener esta el tipo de acceso por defecto (default), la clase Cliente nunca podrá acceder a sus atributos o métodos, a menos claro, que se modifiquen para pertenecer al mismo paquete.

Una clase solo puede invocar los métodos o ver los valores de los atributos de otra, cuando ésta última es pública o se encuentran en el mismo paquete, ahí si empiezan a aplicar los modificadores de acceso de los miembros.

Miembros public
Los miembros marcados como public pueden ser accedidos desde cualquier otra clase a través de una instancia o por herencia.
Ejemplo:

package utilidades;
public class Sumas {
    public int sumar(int num1, int num2){
        return num1 + num2;
    }
}

package operaciones;
import utilidades.Sumas;
//nivel de acceso default
class AlgoRaro {
    public void realizarCalculosCientificos(){
        Sumas s = new Sumas();
        //acceso a través de una instancia

        int resultado = s.sumar(4,4);
        System.out.println("El resultado es: " + resultado);
    }
}

En este ejemplo la clase AlgoRaro puede acceder el método sumar() de la clase Sumas por que aunque están en diferentes paquetes la clase Sumas es pública al igual que el método sumar(), y el acceso se hace a través de una instancia de la clase. Lo contrario no se podría hacer, es decir, la clase Sumas no tiene acceso a ninguno de los métodos o atributos de la clase AlgoRaro por que están en diferente paquete y AlgoRaro tiene acceso por defecto, lo que descarta de una vez cualquier tipo de visibilidad.

Miembros private
Los miembros private solo pueden ser accedidos por la clase a la que pertenecen, de ninguna forma (claro, que las hay las hay: reflection) se pueden invocar desde clases externas.
Ejemplo (modificando el anterior):

package utilidades;
public class Sumas {
   
private