Por Steven Feuerstein, adaptado y traducido al español por José Preda
Priorizar y aplicar mejores prácticas de PL/SQL para pulir aplicaciones nuevas o antiguas.
No es difícil llegar a una lista de qué hacer y no hacer para los desarrolladores. Esta lista puede convertirse en lugar de facilitadora en una completamente abrumadora, sin embargo, porque puede ser:
(a) difícil de recordar todas las mejores prácticas,
(b) un desafío ponerlas en práctica y
(c) misterioso determinar si los desarrolladores en un equipo realmente cumplen o no con las mejores prácticas.
El reto para cualquier organización de desarrollo es realizar un seguimiento de las mejores prácticas y aplicarlas.
Este artículo explora formas para aplicar una lista de prioridades de las mejores prácticas, desde un punto de vista práctico y, a continuación, muestra algunas técnicas de análisis automatizado de código para el cumplimiento de una amplia gama de prácticas recomendadas.
Mejores Prácticas acopladas.
Con la mayor frecuencia posible, toma tus mejores prácticas y aplícalas en trozos de código reutilizables, como por ejemplo un paquete de manejo de errores genérico. A continuación, sólo tienes que formar y convencer a los desarrolladores para que utilicen esos componentes, y ellos automáticamente estarán siguiendo las mejores prácticas.
Ten en cuenta el código en la LISTA 1. Esta es una lógica bastante típica para manejo de errores: estoy mostrando exactamente cómo estoy realizando mi trabajo, incluso escribir información en una tabla de base de datos. Un gran problema con este código es que mi INSERT en la tabla de log se convierte en una parte de mi transacción de negocios. Hago rollback de la transacción y pierdo mi registro. Yo realmente debería aprovechar las ventajas de las transacciones autónomas!
LISTA 1: Típica lógica para manejo de errores
EXCEPTION
WHEN NO_DATA_FOUND
THEN
v_msg := 'No company for id ' TO_CHAR (v_id);
v_err := SQLCODE;
v_prog := 'fixdebt';
INSERT INTO errlog VALUES
(v_err, v_msg, v_prog, SYSDATE, USER);
WHEN OTHERS
THEN
v_err := SQLCODE;
v_msg := SQLERRM;
v_prog := 'fixdebt';
INSERT INTO errlog VALUES
(v_err, v_msg, v_prog, SYSDATE, USER);
RAISE;
En lugar de corregir cada una de estas secciones, debería construir un paquete de manejo de errores y, a continuación, aplicarlo en cada sección. La LISTA 2 ofrece la especificación de un ejemplo sencillo para este tipo de paquete. La LISTA 3 muestra la aplicación de este paquete a mi sección de excepción.
LISTA 2: Especificación de paquete para manejo de errores
CREATE OR REPLACE PACKAGE errpkg
IS
PROCEDURE raise (
err_in IN INTEGER := SQLCODE
, msg_in IN VARCHAR2 := NULL
);
PROCEDURE record_and_stop (
err_in IN INTEGER := SQLCODE
, msg_in IN VARCHAR2 := NULL
);
PROCEDURE record_and_continue (
err_in IN INTEGER := SQLCODE
, msg_in IN VARCHAR2 := NULL
);
FUNCTION errtext (err_in IN INTEGER := SQLCODE)
RETURN VARCHAR2;
END errpkg;
LISTA 3: Aplicando el errpkg al código de mi aplicación
EXCEPTION
WHEN NO_DATA_FOUND
THEN
errpkg.record_and_continue (SQLCODE,
' No company for id ' TO_CHAR (v_id));
WHEN OTHERS
THEN
errpkg.record_and_stop;
END;
Al confiar en el estándar errpkg, ya no tienes que pensar acerca de cómo escribir información en el log ni tienes que tomar ninguna acción para propagar la excepción fuera del bloque de inclusión. El errpkg hace todo esto por ti, conforme a las normas definidas para la aplicación. Se utiliza mucho menos tiempo para escribir tu sección de excepción, y el código sigue las mejores prácticas definidas en tu equipo sin tener que pensar sobre que son las famosas “mejores prácticas”.
Por supuesto, no todos los aspectos del desarrollo de aplicaciones pueden ser capturados en paquetes genéricos y reutilizables. Todavía tienes que escribir un montón de código personalizado, y todavía necesitas prestar atención a las mejores prácticas para estas líneas de PL/SQL. Debido a que es difícil mantener un seguimiento de todas las mejores prácticas, debes inevitablemente priorizarlas.
Priorizar prácticas para aplicaciones nuevas
No todas las mejores prácticas son iguales. Algunos tienen un enorme impacto sobre la estructura general, legibilidad y mantenibilidad del código. Otros abordan aspectos relativamente menores de la calidad del código.
En lugar de intentar memorizar todas las mejores prácticas o intentar presionar a los desarrolladores a seguir todas ellas, comienza con una lista de prioridades de las mejores prácticas. Identifica cuales son las más importantes a seguir y cómo a seguirlas. A continuación, crea listas de comprobaciones cortas y sencillas que los desarrolladores puedan colocar en o cerca de sus equipos para recordarlos de forma fácil y frecuente.
Ofrezco algunas sugerencias para la lista de ítems priorizados para la comprobación de mejores prácticas en dos escenarios: desarrollo de aplicaciones nuevas y el mantenimiento de las aplicaciones existentes o heredadas.
Al crear una nueva aplicación, usted tiene la oportunidad de hacerlo bien. El énfasis principal de las mejores prácticas debe estar en la estructura general de código y la legibilidad, con una parte de recordatorios sobre mejoras criticas de performance. No tengo la intención de profundizar en todos estos temas de la lista de comprobación de mejores prácticas en gran detalle. En el libro Oracle PL/SQL Best Practices se han cubierto algunos de ellos. Éstas son algunas de mis sugerencias para los elementos de la lista de comprobación de mejores prácticas para nuevas aplicaciones:
NO ESCRIBIR SQL. En lugar de escribir un SELECT INTO cuando necesite algunos datos, llame a una función que obtenga los datos y contenga toda la lógica de manejo de errores y optimización oculta en su interior. Aún mejor, utiliza una comprensiva “encapsulación integral en paquetes de datos” que controlen la mayor parte de tus necesidades de SQL.
Oracle Designer genera paquetes de tabla API (TAPI). También puedes generar estos paquetes con PL/Generator, una utilidad de Quest Software.
Una lista de recordatorios con mejores prácticas SQL específicas puede ofrecer estos elementos:
ESCRIBIR PEQUEÑOS TROZOS DE CODIGO. Recomiendo encarecidamente que restrinja la longitud de su sección ejecutable a 50 o 60 líneas de código. Será mucho más fácil de leer y mantener este código con el tiempo. La mejor manera de seguir esta práctica en el nuevo código es emplear el diseño de arriba-abajo y confiar en módulos locales o anidados. El artículo “OverloadCheck” en OTN (otn.oracle.com/pub/articles) explica esta técnica en detalle.
Una lista con avisos específicos sobre fragmentos de código puede ofrecer estos elementos:
· Escribir no más de 50 líneas de código de BEGIN a END.
· Crear procedimientos y funciones locales para ocultar lógica.
· Ocultar todas las fórmulas y reglas de negocio detrás de una interfaz de función.
ESCRIBIR PRUEBAS UNITARIAS PRIMERO. Antes de empezar a escribir código, debes diseñar las pruebas que determinarán si el código está o no trabajando. Si esperas hasta después de que hayas escrito tu programa, subconscientemente escribirás pruebas sólo para las condiciones y lógica que sabes (o esperas) funcione correctamente. Al escribir las pruebas en primer lugar, te concentras en el diseño general de tu código base y en la interfaz con programas individuales.
Por supuesto, escribir código de prueba es un tema enorme y un desafío en sí mismo, pero recomiendo que tomes ventaja de Ounit y utPLSQL: software de pruebas unitarias automatizadas gratuitas para los desarrolladores de PL/SQL, disponibles en http://www.ounit.com/. El autor principal de este artículo ha formado parte como diseñador y desarrollador para ambas herramientas.
Tenga en cuenta estos elementos de prueba para su lista de comprobación:
· Escribir casos de prueba antes de escribir ningún código.
· Escribir un caso de prueba para verificar un error.
· Escribir un caso de prueba para validar una mejora exitosa.
· Implementar los casos de prueba utilizando un framework automatizado (Ounit y utPLSQL o tu propia utilidad interna).
Priorizando prácticas para Mantenimiento
Muchos desarrolladores PL/SQL gastan una buena parte de su tiempo manteniendo aplicaciones existentes. Esto es a menudo un trabajo desafiante y frustrante, porque mucho código está mal escrito, es difícil de comprender y en gran medida no fueron probados. Casi todas las aplicaciones tienen un programa "agujero negro": un fragmento terriblemente grande y no estructurado de código que todo el mundo tiene miedo de tocar. Si realiza un cambio en la línea de 255, se podrían introducir 25 errores en el programa. No hay forma conocer realmente el impacto de los cambios en el código, porque ninguna prueba de regresión está en su lugar.
Cuando te enfrentas con la aplicación de las mejores prácticas para una aplicación existente, aplica los cambios de forma iterativa e incremental. Es difícil para un administrador de desarrollo aceptar de forma proactiva el cambio en una aplicación existente y ejecutándose en producción sólo porque se puede escribir mejor.
Sin embargo, desearas aplicar las mejores prácticas claves cada vez que abras el programa de agujero negro, sólo de forma limitada. Aquí están algunas sugerencias para una lista de comprobación de mejores prácticas para aplicar cambios de esta forma:
· Escribir una prueba de regresión. Esto puede ser un ejercicio doloroso, pero simplemente debe realizarse si deseas tener alguna esperanza de mantener un fragmento de código con cierta confianza. Antes de empezar a mantener un programa existente, sentarse y pensar a través de tantas condiciones como puedas que puedan probar para verificar que el programa funciona. Implementar esas condiciones en un paquete de prueba, ejecutar ese código y confirmar que el programa funciona. A continuación, al realizar los cambios, puedes volver a ejecutar esta prueba y confirmar que no has introducido ningún error. Una vez más, Ounit y utPLSQL pueden ofrecer asistencia en este ámbito.
· Crear módulos locales que oculten un área identificable de funcionalidad. La sección ejecutable del programa podría ser de 1.000 líneas de largo. Comienza por la parte superior de la sección ejecutable y lee hacia abajo a través del código. Cuando puedas identificar las líneas 20 o 30 o 100 que, por ejemplo, validan datos e inicializan parámetros, saca todas esas líneas de código de la sección ejecutable y reemplázalas con una sola línea de código:
initializar_datos, y, a continuación, mueve todas esas líneas a la sección de declaración con este contexto de procedimiento local:
PROCEDURE initializar_datos IS
...tódo el codigo...
END initializar_datos;
Con el tiempo, la ilegible sección ejecutable se volverá más pequeña y accesible.
Desde una perspectiva de rendimiento, buscar áreas para aplicar FORALL y BULK COLLECT, que ofrecen mejoras en los rendimientos espectaculares en prácticamente todas las circunstancias. Encuentre todas las instrucciones DML en el programa. Si aparecen dentro de cualquier tipo de bucle (cursor o de otro modo), extraiga toda la lógica DML, reemplazándola con una llamada a un procedimiento; transfiera esa lógica a la sección de declaración como un módulo local; y, a continuación, y seguidamente mejórelo para utilizar procesamiento masivo.
Validando el cumplimiento
Compras los libros; escribes las listas de comprobación, evangelizas sobre las mejores prácticas. Y luego todos los desarrolladores de tu equipo escriben su código. Es muy improbable que todos (o alguno?) recuerde y siga incluso, las recomendaciones priorizadas.
Por lo tanto, debes tomar una decisión: hacer estas mejores prácticas totalmente opcionales (que significa que se omitirán en gran medida) o realizar un esfuerzo para asegurar que la gente cumpla con ellas.
Sugiero que encuentres formas de comprobar el código que los desarrolladores de tu equipo escriben (o que tú mismo escribes, porque incluso con las mejores intenciones, estarás presionado para hacer todo de la forma correcta!). Los dos mejores métodos de validación de cumplimiento son la revisión de código y el análisis de código.
Ojo con el código! Ninguna pieza de código debe pasarse a QA o ejecutarse en un entorno de producción hasta que ha sido examinado por otro desarrollador (que no sea el autor del código). La revisión de código puede tomar muchas formas, que van desde Extreme Programing de a pares a un simple sistema de compañeros.
Con la programación de apares, ningún programador escribe el código solo. En su lugar, dos personas se sientan juntas frente a cada estación de trabajo, y cada línea de código es examinada y evaluada por ambos. Esto es, obviamente, un punto extremo, y aunque ofrece un enorme valor, pocos equipos de desarrollo siguen esta estrategia.
Algunas organizaciones tienen un proceso formal de revisión de código en el que todos los desarrolladores presentan su código en una reunión a otros desarrolladores para recibir comentarios. Otros confían en un enfoque menos formal: los programadores Senior simplemente se pasean por el entorno, parando para fijarse y ofrecer asesoramiento sobre el código de otro programador.
Analizar Código con SQL. Por supuesto, cuando estás trabajando en el desarrollo de una aplicación de gran tamaño, tendrás decenas de miles de líneas de código. Simplemente puede resultar impráctico revisar cada línea de código. En este escenario, el análisis de código automatizado se convierte en importante. Afortunadamente, el idioma PL/SQL es accesible para este tipo de análisis.
Cuando se compila un programa, Oracle analiza el código y almacena gran cantidad de información acerca de ese programa en una variedad de vistas del diccionario de datos.
La TABLA 1 ofrece una lista parcial de estas vistas. Debido a que estos metadatos sobre el código se almacenan en vistas, puede utilizar SQL para escribir consultas contra las vistas para analizar el código y obtener retroalimentación sobre el cumplimiento de mejores prácticas.
TABLA 1: Vistas del diccionario de datos que contienen información sobre un programa
USER_SOURCE :Inluye las líneas de código fuente para todos los programas que usted posee
ALL_ARGUMENTS: Incluye información acerca de los parámetros a los procedimientos y funciones que se puede llamar a
ALL_PROCEDURES : Contiene la lista de procedimientos y funciones que se puede ejecutar
ALL_DEPENDENCIES : Es uno de varios puntos de vista que le ofrecen información acerca de las dependencias entre los objetos de base de datos.
Vamos a comenzar con un ejemplo sencillo. El tipo de dato CHAR permite declarar cadenas de longitud fija; casi todo nuestro trabajo se basa en VARCHAR2, datos de cadena de longitud variable. Variables basadas en CHAR pueden introducir errores en el código, dando falsos negativos en comparaciones entre cadenas, por ejemplo.
Me gustaría encontrar todas las instancias de declaraciones de un CHAR en mi código. La siguiente sentencia muestra el código que encontrará todas tales apariciones (y tal vez más):
SELECT NAME, line, text
FROM user_source
WHERE INSTR (UPPER(text), ' CHAR') > 0
OR INSTR (UPPER(text), ' CHAR(') > 0
OR INSTR (UPPER(text), ' CHAR (') > 0;
Consultas independientes como la de este ejemplo demuestran la esencia de la técnica, pero su uso no es la mejor manera de implementar esta funcionalidad. Un enfoque mucho mejor es poner las diversas consultas en un conjunto de procedimientos empaquetados que fácilmente pueden invocar los desarrolladores.
El paquete valstd es un ejemplo de paquete de validación de las normas. Tiene la siguiente especificación:
CREATE OR REPLACE PACKAGE valstd
AUTHID CURRENT_USER
IS
PROCEDURE progwith (str IN VARCHAR2);
PROCEDURE exception_handling;
PROCEDURE encap_compliance;
END valstd;
El paquete valstd ofrece los siguientes programas:
progwith: Muestra todos los programas con una cadena especificada.
exception_handling: Valida un conjunto de normas relacionado al control de excepciones (basado en progwith ).
encap_compliance: Identifica programas que violan la mejor práctica de encapsulación de datos, es decir “Nunca referenciar a una tabla directamente; en su lugar, llamar a procedimientos y funciones para ejecutar el SQL”
Echemos un vistazo a la implementación de algunas partes de valstd.
El procedimiento progwith es una extensión de la consulta “Mostrar CHAR”. El LISTADO 4 ofrece la implementación de este procedimiento. En las líneas de 3 a 11, creo una colección (matriz asociativa) de registros para albergar la información que consulto desde USER_SOURCE . En las líneas de 13 a 19, aprovecho el BULK COLLECT en la base de datos Oracle9i para obtener todas las filas coincidentes en mi colección con una única consulta. Esta sintaxis concisa también es increíblemente eficiente.
LISTA 4: La implementación de progwith
1 PROCEDURE progwith (str IN VARCHAR2)
2 IS
3 TYPE info_rt IS RECORD (
4 NAME user_source.NAME%TYPE
5 , text user_source.text%TYPE
6 );
7
8 TYPE info_aat IS TABLE OF info_rt
9 INDEX BY PLS_INTEGER;
10
11 info_aa info_aat;
12 BEGIN
13 SELECT NAME '-' line
14 , text
15 BULK COLLECT INTO info_aa
16 FROM user_source
17 WHERE UPPER (text) LIKE '%' UPPER (str) '%'
18 AND NAME != 'VALSTD'
19 AND NAME != 'ERRNUMS';
20
21 disp_header ('Verificando la presencia de '' str ''');
22
23 FOR indx IN info_aa.FIRST .. info_aa.LAST
24 LOOP
25 DBMS_OUTPUT.PUT_LINE (
26 info_aa (indx).NAME, info_aa (indx).text);
27 END LOOP;
28 END progwith;
Una vez que he obtenido mis datos, puedo mostrarlo. En la línea 21, llamo a un procedimiento local denominado disp_header para mostrar la información del encabezado (y ocultar los detalles). Por último, en las líneas de 23 a 26, muestro los resultados de la búsqueda.
El procedimiento encap_compliance que se muestra en el LISTADO 5 es una estructura similar, pero tiene una consulta diferente en su núcleo. Encontrarás que en las líneas 18 a 29 mediante una consulta contra ALL_DEPENDENCIES identifico todos los objetos de código de PL/SQL que hacen referencia directa a una tabla o vista. Si la directiva en tu organización es llamar a procedimientos y funciones predefinidos (y, con suerte, generados) que ocultan las instrucciones SQL, esta consulta expone todos los programas que violan la directriz y omiten la API de tabla.
LISTA 5: La implementación de encap_compliance
1 PROCEDURE encap_compliance
2 IS
3 SUBTYPE qualified_name_t IS VARCHAR2 (200);
4
5 TYPE refby_rt IS RECORD (
6 NAME qualified_name_t
7 , referenced_by qualified_name_t
8 );
9
10 TYPE refby_aat IS TABLE OF refby_rt
11 INDEX BY PLS_INTEGER;
12
13 refby_aa refby_aat;
14 BEGIN
15 SELECT owner '.' NAME refs_table
16 , referenced_owner '.' referenced_name
17 table_referenced
18 BULK COLLECT INTO refby_aa
19 FROM all_dependencies
20 WHERE owner = USER
21 AND TYPE IN
22 ('PACKAGE'
23 , 'PACKAGE BODY'
24 , 'PROCEDURE'
25 , 'FUNCTION'
26 )
27 AND referenced_type IN ('TABLE', 'VIEW')
28 AND referenced_owner NOT IN ('SYS', 'SYSTEM')
29 ORDER BY owner, NAME, referenced_owner, referenced_name;
30
31 disp_header ('Programas que referencias tablas o vistas');
32
33 FOR indx IN refby_aa.FIRST .. refby_aa.LAST
34 LOOP
35 DBMS_OUTPUT.PUT_LINE (refby_aa (indx).NAME
36 , refby_aa (indx).referenced_by
37 );
38 END LOOP;
39* END encap_compliance;
Silbidos y Campanas. Una vez que ha creado su paquete de validación de estándares, puede agregarle silbidos y campanas, como aquí se indica:
Escribe un archivo HTML y, a continuación, publicar los resultados en la intranet o envía la información como un correo electrónico (utilizando el nuevo paquete UTL_MAIL de Oracle 10g) al desarrollador responsable del determinado programa.
Ejecuta los programas de validación por la noche en un puesto de trabajo programado con DBMS_JOB o, en el mundo de Oracle 10g, el nuevo paquete y marco DBMS_SCHEDULER. Cada mañana cuando un desarrollador se registre y compruebe su correo electrónico, verá un informe sobre cualquier violación de las normas y puede, a continuación, eficientemente desplazarse por la lista de violaciones y corregirlos.
Tomando las mejores prácticas en serio
Todos queremos escribir un código mejor, más eficiente y fácilmente mantenible. El desafío es averiguar cómo hacer esto sin dejar de cumplir nuestros plazos (y encontrar tiempo para pasar con nuestras familias).
Desarrolla listas de prioridades sobre técnicas de mejores prácticas, que todos deben seguir. A continuación, refuerza esas listas con componentes estándar que automáticamente se ajusten a las mejores prácticas, mientras se reduce el volumen y la complejidad del código que los desarrolladores tienen que escribir. Revisa el código para reforzar las mejores prácticas, comparte conocimientos y mejorar el código base. Por último, construye y ejecutar las utilidades de análisis que barrerán miles de líneas de código para identificar violaciones a las mejores prácticas.
Esta potente combinación de procesos, código reutilizable y análisis automatizado puede transformar las mejores prácticas de un sueño a una realidad práctica.
Sobre el autor:
Steven Feuerstein ( steven@stevenfeuerstein.com ) es un experto en el lenguaje Oracle PL/SQL. Es el autor y coautor de nueve libros sobre PL/SQL, incluyendo Oracle PL/SQL Programming and Oracle PL/SQL Best Practices (todos de O'Reilly & Associates), es un consultor senior en tecnología para Quest Software, y ha desarrollado software desde 1980.
El texto original en ingles de este post lo puedes encontrar en http://www.oracle.com/technology/oramag/oracle/04-mar/o24tech_plsql.html
Priorizar y aplicar mejores prácticas de PL/SQL para pulir aplicaciones nuevas o antiguas.
No es difícil llegar a una lista de qué hacer y no hacer para los desarrolladores. Esta lista puede convertirse en lugar de facilitadora en una completamente abrumadora, sin embargo, porque puede ser:
(a) difícil de recordar todas las mejores prácticas,
(b) un desafío ponerlas en práctica y
(c) misterioso determinar si los desarrolladores en un equipo realmente cumplen o no con las mejores prácticas.
El reto para cualquier organización de desarrollo es realizar un seguimiento de las mejores prácticas y aplicarlas.
Este artículo explora formas para aplicar una lista de prioridades de las mejores prácticas, desde un punto de vista práctico y, a continuación, muestra algunas técnicas de análisis automatizado de código para el cumplimiento de una amplia gama de prácticas recomendadas.
Mejores Prácticas acopladas.
Con la mayor frecuencia posible, toma tus mejores prácticas y aplícalas en trozos de código reutilizables, como por ejemplo un paquete de manejo de errores genérico. A continuación, sólo tienes que formar y convencer a los desarrolladores para que utilicen esos componentes, y ellos automáticamente estarán siguiendo las mejores prácticas.
Ten en cuenta el código en la LISTA 1. Esta es una lógica bastante típica para manejo de errores: estoy mostrando exactamente cómo estoy realizando mi trabajo, incluso escribir información en una tabla de base de datos. Un gran problema con este código es que mi INSERT en la tabla de log se convierte en una parte de mi transacción de negocios. Hago rollback de la transacción y pierdo mi registro. Yo realmente debería aprovechar las ventajas de las transacciones autónomas!
LISTA 1: Típica lógica para manejo de errores
EXCEPTION
WHEN NO_DATA_FOUND
THEN
v_msg := 'No company for id ' TO_CHAR (v_id);
v_err := SQLCODE;
v_prog := 'fixdebt';
INSERT INTO errlog VALUES
(v_err, v_msg, v_prog, SYSDATE, USER);
WHEN OTHERS
THEN
v_err := SQLCODE;
v_msg := SQLERRM;
v_prog := 'fixdebt';
INSERT INTO errlog VALUES
(v_err, v_msg, v_prog, SYSDATE, USER);
RAISE;
En lugar de corregir cada una de estas secciones, debería construir un paquete de manejo de errores y, a continuación, aplicarlo en cada sección. La LISTA 2 ofrece la especificación de un ejemplo sencillo para este tipo de paquete. La LISTA 3 muestra la aplicación de este paquete a mi sección de excepción.
LISTA 2: Especificación de paquete para manejo de errores
CREATE OR REPLACE PACKAGE errpkg
IS
PROCEDURE raise (
err_in IN INTEGER := SQLCODE
, msg_in IN VARCHAR2 := NULL
);
PROCEDURE record_and_stop (
err_in IN INTEGER := SQLCODE
, msg_in IN VARCHAR2 := NULL
);
PROCEDURE record_and_continue (
err_in IN INTEGER := SQLCODE
, msg_in IN VARCHAR2 := NULL
);
FUNCTION errtext (err_in IN INTEGER := SQLCODE)
RETURN VARCHAR2;
END errpkg;
LISTA 3: Aplicando el errpkg al código de mi aplicación
EXCEPTION
WHEN NO_DATA_FOUND
THEN
errpkg.record_and_continue (SQLCODE,
' No company for id ' TO_CHAR (v_id));
WHEN OTHERS
THEN
errpkg.record_and_stop;
END;
Al confiar en el estándar errpkg, ya no tienes que pensar acerca de cómo escribir información en el log ni tienes que tomar ninguna acción para propagar la excepción fuera del bloque de inclusión. El errpkg hace todo esto por ti, conforme a las normas definidas para la aplicación. Se utiliza mucho menos tiempo para escribir tu sección de excepción, y el código sigue las mejores prácticas definidas en tu equipo sin tener que pensar sobre que son las famosas “mejores prácticas”.
Por supuesto, no todos los aspectos del desarrollo de aplicaciones pueden ser capturados en paquetes genéricos y reutilizables. Todavía tienes que escribir un montón de código personalizado, y todavía necesitas prestar atención a las mejores prácticas para estas líneas de PL/SQL. Debido a que es difícil mantener un seguimiento de todas las mejores prácticas, debes inevitablemente priorizarlas.
Priorizar prácticas para aplicaciones nuevas
No todas las mejores prácticas son iguales. Algunos tienen un enorme impacto sobre la estructura general, legibilidad y mantenibilidad del código. Otros abordan aspectos relativamente menores de la calidad del código.
En lugar de intentar memorizar todas las mejores prácticas o intentar presionar a los desarrolladores a seguir todas ellas, comienza con una lista de prioridades de las mejores prácticas. Identifica cuales son las más importantes a seguir y cómo a seguirlas. A continuación, crea listas de comprobaciones cortas y sencillas que los desarrolladores puedan colocar en o cerca de sus equipos para recordarlos de forma fácil y frecuente.
Ofrezco algunas sugerencias para la lista de ítems priorizados para la comprobación de mejores prácticas en dos escenarios: desarrollo de aplicaciones nuevas y el mantenimiento de las aplicaciones existentes o heredadas.
Al crear una nueva aplicación, usted tiene la oportunidad de hacerlo bien. El énfasis principal de las mejores prácticas debe estar en la estructura general de código y la legibilidad, con una parte de recordatorios sobre mejoras criticas de performance. No tengo la intención de profundizar en todos estos temas de la lista de comprobación de mejores prácticas en gran detalle. En el libro Oracle PL/SQL Best Practices se han cubierto algunos de ellos. Éstas son algunas de mis sugerencias para los elementos de la lista de comprobación de mejores prácticas para nuevas aplicaciones:
NO ESCRIBIR SQL. En lugar de escribir un SELECT INTO cuando necesite algunos datos, llame a una función que obtenga los datos y contenga toda la lógica de manejo de errores y optimización oculta en su interior. Aún mejor, utiliza una comprensiva “encapsulación integral en paquetes de datos” que controlen la mayor parte de tus necesidades de SQL.
Oracle Designer genera paquetes de tabla API (TAPI). También puedes generar estos paquetes con PL/Generator, una utilidad de Quest Software.
Una lista de recordatorios con mejores prácticas SQL específicas puede ofrecer estos elementos:
ESCRIBIR PEQUEÑOS TROZOS DE CODIGO. Recomiendo encarecidamente que restrinja la longitud de su sección ejecutable a 50 o 60 líneas de código. Será mucho más fácil de leer y mantener este código con el tiempo. La mejor manera de seguir esta práctica en el nuevo código es emplear el diseño de arriba-abajo y confiar en módulos locales o anidados. El artículo “OverloadCheck” en OTN (otn.oracle.com/pub/articles) explica esta técnica en detalle.
Una lista con avisos específicos sobre fragmentos de código puede ofrecer estos elementos:
· Escribir no más de 50 líneas de código de BEGIN a END.
· Crear procedimientos y funciones locales para ocultar lógica.
· Ocultar todas las fórmulas y reglas de negocio detrás de una interfaz de función.
ESCRIBIR PRUEBAS UNITARIAS PRIMERO. Antes de empezar a escribir código, debes diseñar las pruebas que determinarán si el código está o no trabajando. Si esperas hasta después de que hayas escrito tu programa, subconscientemente escribirás pruebas sólo para las condiciones y lógica que sabes (o esperas) funcione correctamente. Al escribir las pruebas en primer lugar, te concentras en el diseño general de tu código base y en la interfaz con programas individuales.
Por supuesto, escribir código de prueba es un tema enorme y un desafío en sí mismo, pero recomiendo que tomes ventaja de Ounit y utPLSQL: software de pruebas unitarias automatizadas gratuitas para los desarrolladores de PL/SQL, disponibles en http://www.ounit.com/. El autor principal de este artículo ha formado parte como diseñador y desarrollador para ambas herramientas.
Tenga en cuenta estos elementos de prueba para su lista de comprobación:
· Escribir casos de prueba antes de escribir ningún código.
· Escribir un caso de prueba para verificar un error.
· Escribir un caso de prueba para validar una mejora exitosa.
· Implementar los casos de prueba utilizando un framework automatizado (Ounit y utPLSQL o tu propia utilidad interna).
Priorizando prácticas para Mantenimiento
Muchos desarrolladores PL/SQL gastan una buena parte de su tiempo manteniendo aplicaciones existentes. Esto es a menudo un trabajo desafiante y frustrante, porque mucho código está mal escrito, es difícil de comprender y en gran medida no fueron probados. Casi todas las aplicaciones tienen un programa "agujero negro": un fragmento terriblemente grande y no estructurado de código que todo el mundo tiene miedo de tocar. Si realiza un cambio en la línea de 255, se podrían introducir 25 errores en el programa. No hay forma conocer realmente el impacto de los cambios en el código, porque ninguna prueba de regresión está en su lugar.
Cuando te enfrentas con la aplicación de las mejores prácticas para una aplicación existente, aplica los cambios de forma iterativa e incremental. Es difícil para un administrador de desarrollo aceptar de forma proactiva el cambio en una aplicación existente y ejecutándose en producción sólo porque se puede escribir mejor.
Sin embargo, desearas aplicar las mejores prácticas claves cada vez que abras el programa de agujero negro, sólo de forma limitada. Aquí están algunas sugerencias para una lista de comprobación de mejores prácticas para aplicar cambios de esta forma:
· Escribir una prueba de regresión. Esto puede ser un ejercicio doloroso, pero simplemente debe realizarse si deseas tener alguna esperanza de mantener un fragmento de código con cierta confianza. Antes de empezar a mantener un programa existente, sentarse y pensar a través de tantas condiciones como puedas que puedan probar para verificar que el programa funciona. Implementar esas condiciones en un paquete de prueba, ejecutar ese código y confirmar que el programa funciona. A continuación, al realizar los cambios, puedes volver a ejecutar esta prueba y confirmar que no has introducido ningún error. Una vez más, Ounit y utPLSQL pueden ofrecer asistencia en este ámbito.
· Crear módulos locales que oculten un área identificable de funcionalidad. La sección ejecutable del programa podría ser de 1.000 líneas de largo. Comienza por la parte superior de la sección ejecutable y lee hacia abajo a través del código. Cuando puedas identificar las líneas 20 o 30 o 100 que, por ejemplo, validan datos e inicializan parámetros, saca todas esas líneas de código de la sección ejecutable y reemplázalas con una sola línea de código:
initializar_datos, y, a continuación, mueve todas esas líneas a la sección de declaración con este contexto de procedimiento local:
PROCEDURE initializar_datos IS
...tódo el codigo...
END initializar_datos;
Con el tiempo, la ilegible sección ejecutable se volverá más pequeña y accesible.
Desde una perspectiva de rendimiento, buscar áreas para aplicar FORALL y BULK COLLECT, que ofrecen mejoras en los rendimientos espectaculares en prácticamente todas las circunstancias. Encuentre todas las instrucciones DML en el programa. Si aparecen dentro de cualquier tipo de bucle (cursor o de otro modo), extraiga toda la lógica DML, reemplazándola con una llamada a un procedimiento; transfiera esa lógica a la sección de declaración como un módulo local; y, a continuación, y seguidamente mejórelo para utilizar procesamiento masivo.
Validando el cumplimiento
Compras los libros; escribes las listas de comprobación, evangelizas sobre las mejores prácticas. Y luego todos los desarrolladores de tu equipo escriben su código. Es muy improbable que todos (o alguno?) recuerde y siga incluso, las recomendaciones priorizadas.
Por lo tanto, debes tomar una decisión: hacer estas mejores prácticas totalmente opcionales (que significa que se omitirán en gran medida) o realizar un esfuerzo para asegurar que la gente cumpla con ellas.
Sugiero que encuentres formas de comprobar el código que los desarrolladores de tu equipo escriben (o que tú mismo escribes, porque incluso con las mejores intenciones, estarás presionado para hacer todo de la forma correcta!). Los dos mejores métodos de validación de cumplimiento son la revisión de código y el análisis de código.
Ojo con el código! Ninguna pieza de código debe pasarse a QA o ejecutarse en un entorno de producción hasta que ha sido examinado por otro desarrollador (que no sea el autor del código). La revisión de código puede tomar muchas formas, que van desde Extreme Programing de a pares a un simple sistema de compañeros.
Con la programación de apares, ningún programador escribe el código solo. En su lugar, dos personas se sientan juntas frente a cada estación de trabajo, y cada línea de código es examinada y evaluada por ambos. Esto es, obviamente, un punto extremo, y aunque ofrece un enorme valor, pocos equipos de desarrollo siguen esta estrategia.
Algunas organizaciones tienen un proceso formal de revisión de código en el que todos los desarrolladores presentan su código en una reunión a otros desarrolladores para recibir comentarios. Otros confían en un enfoque menos formal: los programadores Senior simplemente se pasean por el entorno, parando para fijarse y ofrecer asesoramiento sobre el código de otro programador.
Analizar Código con SQL. Por supuesto, cuando estás trabajando en el desarrollo de una aplicación de gran tamaño, tendrás decenas de miles de líneas de código. Simplemente puede resultar impráctico revisar cada línea de código. En este escenario, el análisis de código automatizado se convierte en importante. Afortunadamente, el idioma PL/SQL es accesible para este tipo de análisis.
Cuando se compila un programa, Oracle analiza el código y almacena gran cantidad de información acerca de ese programa en una variedad de vistas del diccionario de datos.
La TABLA 1 ofrece una lista parcial de estas vistas. Debido a que estos metadatos sobre el código se almacenan en vistas, puede utilizar SQL para escribir consultas contra las vistas para analizar el código y obtener retroalimentación sobre el cumplimiento de mejores prácticas.
TABLA 1: Vistas del diccionario de datos que contienen información sobre un programa
USER_SOURCE :Inluye las líneas de código fuente para todos los programas que usted posee
ALL_ARGUMENTS: Incluye información acerca de los parámetros a los procedimientos y funciones que se puede llamar a
ALL_PROCEDURES : Contiene la lista de procedimientos y funciones que se puede ejecutar
ALL_DEPENDENCIES : Es uno de varios puntos de vista que le ofrecen información acerca de las dependencias entre los objetos de base de datos.
Vamos a comenzar con un ejemplo sencillo. El tipo de dato CHAR permite declarar cadenas de longitud fija; casi todo nuestro trabajo se basa en VARCHAR2, datos de cadena de longitud variable. Variables basadas en CHAR pueden introducir errores en el código, dando falsos negativos en comparaciones entre cadenas, por ejemplo.
Me gustaría encontrar todas las instancias de declaraciones de un CHAR en mi código. La siguiente sentencia muestra el código que encontrará todas tales apariciones (y tal vez más):
SELECT NAME, line, text
FROM user_source
WHERE INSTR (UPPER(text), ' CHAR') > 0
OR INSTR (UPPER(text), ' CHAR(') > 0
OR INSTR (UPPER(text), ' CHAR (') > 0;
Consultas independientes como la de este ejemplo demuestran la esencia de la técnica, pero su uso no es la mejor manera de implementar esta funcionalidad. Un enfoque mucho mejor es poner las diversas consultas en un conjunto de procedimientos empaquetados que fácilmente pueden invocar los desarrolladores.
El paquete valstd es un ejemplo de paquete de validación de las normas. Tiene la siguiente especificación:
CREATE OR REPLACE PACKAGE valstd
AUTHID CURRENT_USER
IS
PROCEDURE progwith (str IN VARCHAR2);
PROCEDURE exception_handling;
PROCEDURE encap_compliance;
END valstd;
El paquete valstd ofrece los siguientes programas:
progwith: Muestra todos los programas con una cadena especificada.
exception_handling: Valida un conjunto de normas relacionado al control de excepciones (basado en progwith ).
encap_compliance: Identifica programas que violan la mejor práctica de encapsulación de datos, es decir “Nunca referenciar a una tabla directamente; en su lugar, llamar a procedimientos y funciones para ejecutar el SQL”
Echemos un vistazo a la implementación de algunas partes de valstd.
El procedimiento progwith es una extensión de la consulta “Mostrar CHAR”. El LISTADO 4 ofrece la implementación de este procedimiento. En las líneas de 3 a 11, creo una colección (matriz asociativa) de registros para albergar la información que consulto desde USER_SOURCE . En las líneas de 13 a 19, aprovecho el BULK COLLECT en la base de datos Oracle9i para obtener todas las filas coincidentes en mi colección con una única consulta. Esta sintaxis concisa también es increíblemente eficiente.
LISTA 4: La implementación de progwith
1 PROCEDURE progwith (str IN VARCHAR2)
2 IS
3 TYPE info_rt IS RECORD (
4 NAME user_source.NAME%TYPE
5 , text user_source.text%TYPE
6 );
7
8 TYPE info_aat IS TABLE OF info_rt
9 INDEX BY PLS_INTEGER;
10
11 info_aa info_aat;
12 BEGIN
13 SELECT NAME '-' line
14 , text
15 BULK COLLECT INTO info_aa
16 FROM user_source
17 WHERE UPPER (text) LIKE '%' UPPER (str) '%'
18 AND NAME != 'VALSTD'
19 AND NAME != 'ERRNUMS';
20
21 disp_header ('Verificando la presencia de '' str ''');
22
23 FOR indx IN info_aa.FIRST .. info_aa.LAST
24 LOOP
25 DBMS_OUTPUT.PUT_LINE (
26 info_aa (indx).NAME, info_aa (indx).text);
27 END LOOP;
28 END progwith;
Una vez que he obtenido mis datos, puedo mostrarlo. En la línea 21, llamo a un procedimiento local denominado disp_header para mostrar la información del encabezado (y ocultar los detalles). Por último, en las líneas de 23 a 26, muestro los resultados de la búsqueda.
El procedimiento encap_compliance que se muestra en el LISTADO 5 es una estructura similar, pero tiene una consulta diferente en su núcleo. Encontrarás que en las líneas 18 a 29 mediante una consulta contra ALL_DEPENDENCIES identifico todos los objetos de código de PL/SQL que hacen referencia directa a una tabla o vista. Si la directiva en tu organización es llamar a procedimientos y funciones predefinidos (y, con suerte, generados) que ocultan las instrucciones SQL, esta consulta expone todos los programas que violan la directriz y omiten la API de tabla.
LISTA 5: La implementación de encap_compliance
1 PROCEDURE encap_compliance
2 IS
3 SUBTYPE qualified_name_t IS VARCHAR2 (200);
4
5 TYPE refby_rt IS RECORD (
6 NAME qualified_name_t
7 , referenced_by qualified_name_t
8 );
9
10 TYPE refby_aat IS TABLE OF refby_rt
11 INDEX BY PLS_INTEGER;
12
13 refby_aa refby_aat;
14 BEGIN
15 SELECT owner '.' NAME refs_table
16 , referenced_owner '.' referenced_name
17 table_referenced
18 BULK COLLECT INTO refby_aa
19 FROM all_dependencies
20 WHERE owner = USER
21 AND TYPE IN
22 ('PACKAGE'
23 , 'PACKAGE BODY'
24 , 'PROCEDURE'
25 , 'FUNCTION'
26 )
27 AND referenced_type IN ('TABLE', 'VIEW')
28 AND referenced_owner NOT IN ('SYS', 'SYSTEM')
29 ORDER BY owner, NAME, referenced_owner, referenced_name;
30
31 disp_header ('Programas que referencias tablas o vistas');
32
33 FOR indx IN refby_aa.FIRST .. refby_aa.LAST
34 LOOP
35 DBMS_OUTPUT.PUT_LINE (refby_aa (indx).NAME
36 , refby_aa (indx).referenced_by
37 );
38 END LOOP;
39* END encap_compliance;
Silbidos y Campanas. Una vez que ha creado su paquete de validación de estándares, puede agregarle silbidos y campanas, como aquí se indica:
Escribe un archivo HTML y, a continuación, publicar los resultados en la intranet o envía la información como un correo electrónico (utilizando el nuevo paquete UTL_MAIL de Oracle 10g) al desarrollador responsable del determinado programa.
Ejecuta los programas de validación por la noche en un puesto de trabajo programado con DBMS_JOB o, en el mundo de Oracle 10g, el nuevo paquete y marco DBMS_SCHEDULER. Cada mañana cuando un desarrollador se registre y compruebe su correo electrónico, verá un informe sobre cualquier violación de las normas y puede, a continuación, eficientemente desplazarse por la lista de violaciones y corregirlos.
Tomando las mejores prácticas en serio
Todos queremos escribir un código mejor, más eficiente y fácilmente mantenible. El desafío es averiguar cómo hacer esto sin dejar de cumplir nuestros plazos (y encontrar tiempo para pasar con nuestras familias).
Desarrolla listas de prioridades sobre técnicas de mejores prácticas, que todos deben seguir. A continuación, refuerza esas listas con componentes estándar que automáticamente se ajusten a las mejores prácticas, mientras se reduce el volumen y la complejidad del código que los desarrolladores tienen que escribir. Revisa el código para reforzar las mejores prácticas, comparte conocimientos y mejorar el código base. Por último, construye y ejecutar las utilidades de análisis que barrerán miles de líneas de código para identificar violaciones a las mejores prácticas.
Esta potente combinación de procesos, código reutilizable y análisis automatizado puede transformar las mejores prácticas de un sueño a una realidad práctica.
Sobre el autor:
Steven Feuerstein ( steven@stevenfeuerstein.com ) es un experto en el lenguaje Oracle PL/SQL. Es el autor y coautor de nueve libros sobre PL/SQL, incluyendo Oracle PL/SQL Programming and Oracle PL/SQL Best Practices (todos de O'Reilly & Associates), es un consultor senior en tecnología para Quest Software, y ha desarrollado software desde 1980.
El texto original en ingles de este post lo puedes encontrar en http://www.oracle.com/technology/oramag/oracle/04-mar/o24tech_plsql.html
Excelente, toca ir implementando poco a poco
ResponderEliminar