Apuntes: "Principios de Diseño Orientado a Objetos"

Volviendo a mis inicios, retomaremos el camino de los artículos que buscan reforzar determinados conocimientos o conceptos que en otras arquitecturas o lenguajes son tan comunes pero que muchas veces son desconocidos en el mundo PHP.

Teniendo en cuenta que PHP5 es una realidad que nos permite pasar a desarrollos más elaborados, con una Orientación a Objetos más robusta, es fundamental saber que existen "principios de diseño" que nos marcan el rumbo.

Aquí mis apuntes sobre estos temas (que en un futuro espero extenderme en detalle):

Principios de Diseño Orientado a Objetos
  1. SRP - Single Responsibility Principle (Principio de Responsabilidad Única)
  2. OCP - Open/Closed Principle (Principio Abierto / Cerrado)
  3. LSP - Liskov Substitution Principle (Principio de Sustitución de Liskov)
  4. DIP - Dependency Inversion Principle (Principio de Inversión de Dependencias)
  5. ISP - Interface Segregation Principle (Principio de Segregación de Interfaces)
Algunos apuntes encontrados en Wikipedia (inglés)
http://en.wikipedia.org/wiki/Single_responsibility_principle
http://en.wikipedia.org/wiki/Open/closed_principle
http://en.wikipedia.org/wiki/Liskov_substitution_principle

1. SRP - Single Responsibility Principle (Principio de Responsabilidad Única)


Enunciado formal: "Una clase debería tener solo una razón para cambiar"

2. OCP - Open/Closed Principle (Principio Abierto / Cerrado)


Enunciado formal: "Entidades de Software (clases, módulos, funciones, etc) deberían ser abiertas para la extensión y cerradas para la modificación"

3. LSP - Liskov Substitution Principle (Principio de Sustitución de Liskov)


Enunciado formal: "Subtipos deben ser sustituibles por sus clases bases"

4. DIP - Dependency Inversion Principle (Principio de Inversión de Dependencias)


Enunciado formal: "los clientes tienden a ser propietarios de las interfaces y aquellos que ofrecen los servicios las implementan"

5. ISP - Interface Segregation Principle (Principio de Segregación de Interfaces)

Enunciado formal: "Clientes no deberían depender de métodos que no utilizan"

Taller: concluida la segunda etapa - Proyecto "Clases Bases"

Cuando empezamos este "taller piloto" claramente no sabía cómo iba resultar ni todos los problemas que iban a surgir... aunque siempre supe por donde debía transitar y que sería evidente que cambiaría constantemente para ir ajustándome a los acontecimientos.

Esta segunda etapa estuvo concentrada en el trabajo en equipo, con teamleaders a cargo de pequeños grupos de desarrolladores y con un especial aditamento: la falta de experiencia en gestión de los líderes como a su vez en desarrollo POO de los dirigidos, y para peor, todos "a distancia".

El proceso fue lento y existieron muchos problemas que tuvimos que ir solucionando, pero finalmente llegamos al cometido: afirmar conocimientos a los novatos sobre los temas de programación orientada a objetos usando PHP5.

Todos sacamos -directa o indirectamente- conclusiones y adquirimos experiencia en muchos temas: trabajo a distancia, educación a distancia, gestión a distancia, colaboración, versionado, comunicación, herramientas colaborativas, etc.

Como "producto" de ese proceso tenemos un proyecto libre llamado "Clases Bases", que obviamente están invitados a probarlo, estudiarlo, preguntar, criticar y hasta continuar desarrollando.

Próximamente comentaré la tercer y última etapa del taller (serán los últimos 3 meses del mismo): desarrollar un proyecto libre todos los equipos juntos y usando Zend Framework.


¡Felicitaciones a todos! ¡Excelente trabajo!

A estar atentos de las novedades ;-)

Por fin: campañas para migrar definitivamente a PHP5

Hace un tiempo ya que critico nuestra propia actitud pasiva cuando argumentamos que no usamos PHP5 porque en la mayoría de los servidores de hosting solo tienen instalado PHP4.

Hay que entender que siempre "somos parte del problema o parte de la solución", por consiguiente, si quieres que la situación cambie, no consumas sus productos, quéjate, solicita cambios, nuevas características, has proselitismo, crea una "causa"... como sucedió ahora.

"Debemos pasar de los dichos a los hechos

De la misma forma, creo que nos hace falta tener más
"sentimiento de comunidad", como sucede habitualmente -hasta de forma exagerada- en el mundo GNU/Linux. No es posible que nos sigamos quejando que los proveedores de hosting siguen usando PHP4. Deberíamos hacer campañas para promover la migración a las nuevas versiones de PHP, pero fundamentalmente, incorporar en nuestros desarrollos las características avanzadas del lenguaje, e invitar a usarlo como si fuera una arquitectura, actualizar a nuestro equipo de desarrolladores, visitar empresas, universidades, etc."

Artículo escrito en Nov / 2006 - "debemos profesionalizarnos"


No me canso de hablar del tema, de lo importante que es migrar a la versión 5 del lenguaje, pero fundamentalmente "migrar" la mentalidad de los programadores clásicos de PHP hacia niveles similares de madurez que cuentan los desarrolladores en arquitecturas como Java o .Net (no sirve si cambiamos de lenguaje pero seguimos programando igual, seguir rechazando la programación orientada a objetos... ya ni se discute que sirve).

Hace pocos días parece que el mundo se puso de acuerdo y han surgido dos noticias muy importantes. Primero, la creación de un movimiento que empuja la migración definitiva hacia PHP5 (exponiendo todas sus ventajas, buscando el apoyo de empresas, colocando una fecha límite, etc) y segundo, la noticia oficial de que PHP4 dejará de ser desarrollado (este será el último año).

Contundente la frase final del anuncio: "Por favor, dedica lo que queda del año para hacer que tus aplicaciones puedan funcionar sobre PHP5"

Claro, si PHP5 hace varios años que está disponible como una versión estable y ahora se anuncia que en el correr del fin de este año -principios del próximo- estaría disponible la primer versión 6 (PHP6)... ¿como puede ser que todavía se maneje la excusa de usar PHP4 porque "es más estable, seguro y probado"?


Espero que cuando solo exista PHP5 y PHP6 empiece a usarse, la comunidad no cometa el mismo error con el cambio a PHP7.

Debemos madurar, lo único constante es el cambio (y hay que asumir riesgos).



PD: hace pocas semanas también fue lanzado Zend Framework 1.0. Me pregunto, tú, desarrollador profesional de PHP... lo empezaste a probar? Donde quieres estar hoy? y mañana?

Capturando el pizarrón de mi clase


Hace mucho tiempo tengo la costumbre de sacar fotos con mi celular como forma rápida de documentar lo que se puede escribir en un pizarrón durante una discusión de diseño, tanto en el trabajo como en el dictado de un curso.

Para mis cursos

En mi caso particular sigo la premisa de "para improvisar hay que estar antes muy preparado", por lo cual cada clase me lleva muchas horas de trabajo pero que luego "en vivo" suelo ir adaptándola rápidamente a como van reaccionando mis interlocutores. No es la primera vez que de camino a la universidad voy -en el mismo ómnibus- haciendo correcciones con un lápiz a los ejercicios que ya tenía preparados, pues se me ocurrió que cambiando o hasta quitando determinados detalles podía simplificar aún más el entendimiento de los conceptos.

El problema luego es que siempre trato de seguir relacionando los temas y los ejercicios unos con otros, y necesito una forma rápida de documentar estos cambios de último momento (se me complica dictar una clase, hacer cambios en el aire, para luego registrarlo a mano).

Si fuera el caso de una empresa lo ideal es que luego de una reunión escribir un acta (para registrar lo sucedido y hasta donde se llegó) y agregar todas estas fotos.

En este caso les muestro como ejemplo lo que hicimos en la clase pasada de mi curso de PHP5

Nota: los dibujos no están muy prolijos pues la idea es ser progresivo con los ejemplos, ir borrando y agregando nuevos detalles, o haciendo comentarios al margen sobre temas que necesitan ser reforzados en el momento (aunque de ahora en más voy a poner un poco más de cuidado así las fotos salen mejor ;-) ) :


Aquí, continuando con la primera foto que explica el concepto de un diseño básico de 3 capas, explico cómo sería la codificación a partir de un módulo listado_clientes.php que hiciera uso de cada capa del sistema, empezando por la "presentación". El módulo invocaría a la clase HTML del paquete "presentación", que a su vez invoca a la clase Mensaje del paquete "dominio", para luego invocar a la clase BaseDeDatos del paquete "persistencia" (para más información buscar en este mismo blog por "diseño 3 capas").

Aquí definimos una estrategia del tipo "divide y vencerás" para enfrentar la larga lista de requerimientos del trabajo obligatorio de desarrollo que deben culminar para aprobar el curso de actualización profesional. No sé si se dan cuenta, pero deben desarrollar un primer prototipo con la funcionalidad base de Twitter, más toda otra serie de requisitos (patrones de diseño, 3 capas, Ajax, plantear mejoras al sistema original, etc).

Tratando de mostrar el proceso completo del desarrollo de un sistema orientado a objetos usando UML, se parte de un diagrama de Casos de Uso (ya borrado del pizarrón), un Diagrama de Paquetes, Diagrama de Clases y el -en mi opinión- más importante para todo desarrollador profesional: el Diagrama de Secuencia.

Y aquí, como "la cereza de la torta", me voy abruptamente al borde del abismo de la improvisación y ya engancho con la introducción al tema de "Principios de Diseño de la Orientación a Objetos" de la mano del más revelador de todos: "Principio Abierto / Cerrado (Open/Closed)".

La memoria trabaja mejor con imágenes

Creo que estas fotos son muy útiles para nuestro uso profesional. La memoria trabaja en base a imágenes y asociaciones, y a veces uno no recuerda tan fácilmente a partir de nuestras propias transcripciones escritas de lo que ve (siempre te pierdes algo), pero a mi me pasa que una sola imagen puede hacerme recordar exactamente todo lo que se habló en ese momento.

Pruébalo en tu próxima reunión que hagan uso de un pizarrón, y luego súbelo al Wiki de la intranet de tu organización para documentar y compartir la experiencia ;-)

TallerPHP: Se inició el primer contacto con los líderes de los equipos

Sepan disculpar mi demora con el avance del taller, pero se han suscitado muchos compromisos juntos que me han dejado poco tiempo libre.

Pero bueno, más real no puede ser el taller, ¿cuando han visto un Gerente que no esté ocupado y que sobrecargue a sus "Team Leaders"? ;-)

Como habrán visto en la planilla, cada líder tendrá 2 misiones: desarrollar un sistema particular y desarrollar un sistema en conjunto con los demás equipos.

Por consiguiente, empezaremos con el proyecto común para iniciar el trabajo en equipo, definir la comunicación entre nosotros y posteriormente la asignación de tareas de cada uno de sus recursos (desarrolladores).

"Clases Base"

La idea es desarrollar una estructura base de clases como cuentan en el lenguaje Java: clase Array, String, Integer, etc. Cada líder irá tomando un conjunto de clases y asignará a sus recursos una para desarrollar. Puede ser una clase entera, o compartir con ellos el desarrollo parcial de cada parte (un método cada uno).

Donde tomaremos las clases es en www.gotapi.com, sección J2SE 1.5 (especificación del lenguaje Java) y navegando en el arbol (izquierda): java.lang

De ahí (documentación de la API) sacaremos la estructura base de cada clase. Antes de iniciar cualquier desarrollo debemos estar coordinados entre los líderes y su gerente de proyectos.

Está demás decir que los desarrolladores de cada equipo vayan "calentando los motores", pues en poco días recibirán el llamado para unirse a las filas.

Los escucho: ¿preguntas, dudas, crisis? ;-)

Taller: Ya se encuentran armados los equipos de desarrollo



Espartanos, desayunad bien. ¡Porque esta noche cenaremos en el infierno!

Mil disculpas a todo el mundo, pero la verdad que me he envuelto en muchos compromisos que me han quitado tiempo para dedicarme a terminar de definir el taller. Por suerte, luego de analizarlo varios días tengo ya pronto los equipos de desarrollo con cada uno de sus integrantes.

Están creados los foros en Google Groups, existe uno privado exclusivo para los líderes (donde impartiré las órdenes y las sugerencias para gestionar sus equipos) y luego uno para cada equipo así pueden trabajar con su líder.

Se encuentra una planilla pública donde se puede visualizar la lista de grupos e integrantes y los sistemas que se deberán desarrollar.

En las próximas horas me estoy comunicando con cada líder para empezar a trabajar en los requerimientos de los sistemas.

¡Bienvenidos, seguimos con la segunda parte del Taller Piloto de PHP5!

Solución Semana 4: "Sistema Modular" (V de V)

El punto V de los requerimientos de la Semana 4 decía:

Seguridad: el sistema actual confía de los datos que recibe, lo cual puede convertirse en un problema de seguridad a través de un ataque del tipo "sql injection". Proponer una solución a este problema.

En el propio manual oficial de PHP hay un capítulo exclusivo sobre Seguridad (IV) y dentro existe una sección sobre Bases de Datos y una sub-sección que dice concretamente Inyección de SQL:

La Inyección Directa de Comandos SQL es una técnica en la cual un atacante crea o altera comandos SQL existentes para exponer datos escondidos, o sobrescribir datos críticos, o incluso ejecutar comandos del sistema peligrosos en la máquina en donde se encuentra la base de datos. Esto se consigue cuando la aplicación toma información de entrada del usuario y la combina con parámetros estáticos para construir una consulta SQL. Los siguientes ejemplos, desafortunadamente, están basados en historias reales.

Esta parte la vivimos la comienzo de la puesta en producción del sistema de registro de usuarios para este taller piloto de PHP5, donde uno o más saboteadores intentaron borrar la base de datos usando este tipo de ataque.

Veamos qué podemos hacer para reforzar la seguridad

La esencia es evitar completamente que los datos lleguen en bruto desde la url o de un formulario hacia la base de datos, verificando cada dato y asegurando que la construcción final del SQL no sea alterada para modificar el funcionamiento normal de nuestro sistema.

La lista a continuación no es extensa, solo intenta ser una introducción al tema:

  1. Verificar los tipos de datos que se reciben: controlar cada uno de los parámetros según el tipo de dato que se espera. Si es un campo numérico del formulario se deberá verificar que sus datos sean así, numéricos, evitando que agreguen una cadena de texto (String) con código SQL maligno.
  2. "Escapear" caracteres riesgosos: comilla simple ('), comilla doble ("), barra invertida (\) y NULL (el byte NULL). Hay que tener en cuenta que si los datos son grabados en la base de datos con "caracteres escapeados" (addslashes), hay que hacer el proceso inverso para presentarlos en pantalla (quitando las "\" con stripslashes).
  3. Agregar procesos que verifiquen sentencias SQL: otra forma de reforzar es verificar que cada cadena de texto que debamos ejecutar en la base no contenga determinadas palabras que no estamos usando para una determinada operación. Por ejemplo, si deseamos obtener datos sin modificar la base (SELECT) no deberíamos permitir que se ejecutaran comandos como "INSERT", "DELETE" y "UPDATE" (ni ningún otro que permita saber información interna ni de las estructuras de las tablas), y/o directamente prohibir que se puedan agregar "AND", "OR" o un ";" (lo que permite agregar a continuación otra sentencia SQL).
Estimo que la mejor forma de tener controlado este proceso es separar los datos por un lado, la generación de las consultas SQL por otro, y evitar tener un proceso genérico donde todo pase por el mismo lugar.

Algunos ejemplos

Nota: si la imagen no se visualiza claramente, presionar sobre ella para ampliarla.


Validar el tipo de valor que recibo por parámetros: para luego pasarlo al armado de la consulta.

En este caso esperamos que los valores posibles son Null o un Integer, si es el primero hacemos un "SELECT * FROM usuarios" y si es el segundo esperamos que sea un número de usuario. Verificamos que no sea nulo, y luego nos aseguramos que sea un valor numérico.

Crear un método "quote" en la clase BaseDeDatos:
el término quote se usa en muchos frameworks a la hora de crear un proceso que "escapee" (si alguien conoce castellanización que avise) las variables que se usan en una sentencia SQL.

En este caso verificamos la existencia de funciones que ya realizan automáticamente el "escaping", de lo contrario lo hacemos manualmente. De la misma forma existe una función de PHP específica para la base MySQL, lo cual nos ataría a futuro si queremos cambiar de base de datos.

Separar los datos de la consulta sql:
para poder procesar fácilmente cada dato.


En este caso tomamos nuestro método ejecutarSQL, que solo recibía una sentencia sql, y que ahora recibe por un lado el esqueleto de la sentencia y por otro los valores a ser insertados en la construcción de la sentencia final. Su funcionamiento es similar al de cualquier sistema de templates.


Aquí pasamos por referencia (&) la sentencia original para modificarla, sustituyendo nosotros cada uno de los valores en los lugares que corresponde insertar y ejecutando la "sanitización" de cada valor con el método "quote".


Nuevamente la definición del método "quote".

Este es un ejemplo de cómo funcionaría en una situación donde queremos solo obtener datos de la base de datos, definiendo primero un array de datos asociando la clave PAR01 (parámetro 1) y el valor recibido por la url. Luego, se armar el template SQL y colocando el PAR01 donde debería ir para que el proceso de armado sustituya de forma segura por el valor correspondiente luego de "desinfectarlo".

Este es otro caso, el más complejo, donde hay alteración de la base de datos y existe más de un parámetro. La lógica es simple, y como afirmé más arriba, es lo mismo que utilizar un sistema de templates o plantillas, defines una marca o variable que será sustituida por el valor que tu asignes, manteniendo el resto sin alterar.

Validación con Javascript


Finalmente, no quiero olvidarme comentar el tema de las validaciones desde el propio cliente con Javascript (lo vi comentado en una de las soluciones entregadas por algunos participantes del taller). La solución de este lado del proceso puede considerarse un complemento, pero no la solución más segura. Estimo que cualquier usuario que quiera hacer un ataque de este tipo lo primero que probará si encuentra controles del lado del cliente es deshabilitar el Javascript en el navegador. Sirve como complemento, pero no es la mejor opción ni la más segura.

La recomendación final

El tema de la seguridad es una tarea muy especializada, no sirve agregar un par de métodos con algunas funciones, habría que auditar constantemente todo el código nuevo que se agrega al sistema. Para este caso particular, el SQL Injection, como afecta exclusivamente a la persistencia de datos en un motor de base de datos, lo mejor es tener una "capa de abstracción" de terceros que tenga bien resuelta toda esta problemática. Por ejemplo, podemos usar MDB2 del framework Pear o directamente PDO que incorpora el propio PHP5.1 en adelante.

Documentación relacionada
Ya se encuentra la planilla actualizada, como así también el repositorio con los fuentes y como siempre, en los comentarios de esta entrada se pueden sacar las dudas sobre este tema :-)

PD: en las próximas horas se estarán haciendo los anuncios con los equipos de desarrollo armados. En primera instancia estarán involucrados los participantes que sobrevivieron todo el proceso del taller (¡Felicitaciones! ;-)) y posteriormente iré analizando la incorporación de más colaboradores en base a la evolución de las primeras pruebas y teniendo en cuenta la lista de registrados al taller.

¡POR FIN, CERRAMOS LA SEMANA 4!

Inciamos hoy el curso presencial de Desarrollo de Sistemas Web con PHP5 (Universidad ORT)

Nota: sigue estando el nombre antiguo de "Programación de Páginas Web con PHP", debería ser Desarrollo de Sistemas Web con PHP5

Menú del día:
  • Acreditación del Docente
  • Presentación del curso
  • Encuesta a los alumnos
  • Introducción a la Web 2.0
  • Conceptos sobre el entorno Web
¡No te lo pierdas, 4 meses intensivos! ;-)

Solución Semana 4: "Sistema Modular" (IV de V)

El requerimiento número 4 correspondiente a la Semana 4 de Taller decía:

Mejorar la búsqueda: corregir la búsqueda por nombre y descripción para que pueda obtener más de una coincidencia (actualmente solo trae una).

En esta situación se podían discutir dos alternativas.
El sistema originalmente iniciaba el formulario de consultas y procedía a ejecutar posteriormente el módulo "mostrar_usuario". Conceptualmente este módulo sirve para eso, para mostrar un usuario, lo cual nos podía llevar a modificarlo para que permitiera mostrar más de uno, ya que el requerimiento así lo especifica.

La segunda alternativa era sustituir la invocación del módulo actual por el "listado_usuarios", ya que la implementación existente tiene todas las características solicitadas: poder mostrar más de un usuario pero agregando ahora parámetros de filtros de búsqueda. De esta forma, una vez generada la lista de usuarios encontrados se podría seleccionar el correspondiente para visualizar la ficha completa del mismo.

En este caso lo ideal sería esta última opción.

Los fuentes afectados fueron:
  • index.php
  • dominio/DominioFachada.class.php
  • persistencia/PersistenciaFachada.class.php
  • persentacion/ListadoUsuarios.class.php
  • persentacion/PresentaciónFachada.class.php
Y los templates afectados fueron:
  • contenido_consultar_usuario.tpl.html
  • contenido_listado_usuarios.tpl.html
Fundamentalmente se agregó que el listado de usuarios pudiera recibir por parámetros filtros de búsqueda ($request), lo que luego de cruzar todas las capas correspondientes se termina recreando consultas SQL que permiten incorporar estas condiciones.

PersistenciaFachada.class.php

public function traerUsuarios( $request = null ){
require_once(
FWK . DIRECTORY_SEPARATOR . "SentenciaSQL.class.php");
$SentenciaSQL = new SentenciaSQL();

// Consulta base
$SentenciaSQL->addSelect("*");
$SentenciaSQL->addFrom("usuarios");

if( (
$request['id'] != "" ) ){
$SentenciaSQL->addWhere("id = ".$request['id']);
}
if( (
$request['nombre'] != "" ) ){
$SentenciaSQL->addWhere(" nombre LIKE '%".$request['nombre']."%'");
}
if( (
$request['descripcion'] != "" ) ){
$SentenciaSQL->addWhere(" descripcion LIKE '%".$request['descripcion']."%'");
}
return
self::ejecutarSQL( $SentenciaSQL->generar() );
}

Aquí lo único que hace es armar la consulta en base a si viene cargado o no cada parámetro que corresponde con las condiciones de filtro de la consulta SQL.

Ya se encuentra la planilla actualizada, como así también el repositorio con los fuentes y como siempre, en los comentarios de esta entrada se pueden sacar las dudas sobre este tema :-)

Entradas populares