h1

Un DBA en nuestro proyecto

07/13/2009

Wizdoc [Icon By Buuf]  Tips & Tricks.

¿Respaldos? ¿Qué respaldos?

— Mike Gunderloy, Ten of the Biggest Mistakes Developers Make With Databases (Diez de los más grandes errores cometidos por desarrolladores con las bases de datos). Developer.com, June 6 2009.

En estos primeros días del nuevo año fiscal (FY09-FY10) tenemos que ponernos al corriente con los cursos de capacitación obligatoria – esos del estilo "Preparación ante gripe aviar" o "Salvaguardando la información de la compañía" – y debido a que la gran mayoría de éstos contiene mucha información y son bastante tediosos, de vez en cuando me doy un respiro.

Webeando en la red me encontré con el sitio The Daily WTF: Curious Perversions in Information Technology, donde publican algunas de esas joyas de programación y soporte técnico que nos hacen implorar que alguien nos libere de nuestra miseria. Por ejemplo, en "Muerte por un Delete" (Death by Delete), "Rick" nos cuenta cómo una empresa de artículos para mascotas (denominada con el alias MegaPetCo) contaba con una base de datos de varios Gigabytes, concentrando casi toda su información… en una sola tabla. Un día a un pobre infeliz, compañero de Rick, se le ocurrió realizar optimizaciones sobre dicha tabla y mediante un delete mal verificado, borró todos los registros, que por cierto nunca habían sido respaldados. Al final, MegaPetCo no pudo recuperarse ante este evento y tuvo que declararse en bancarrota. ¡Tómala barbón!

Pues bien, entre varios artículos encontré uno que me llamó mucho la atención. Con el título "Todo el dolor, sin la ganancia" (All Pain, No Gain), "Steve" describe cómo en la empresa en la que trabajaba imponían estrictas políticas de seguridad con respecto a las bases de datos, supuestamente previniendo ataques informáticos como la Inyección de SQL, por lo que las aplicaciones debían llamar a Stored Procedures (SP) en vez de ejecutar directamente las consultas sobre la base de datos. Entonces, el autor incluye el siguiente SP:

Create Procedure [dbo].[Authenticate]
  @StartDate datetime,
  @EndDate datetime,
  @UserID numeric(18,0),
  @Password char(50),
  @DatabaseName char(50)

  AS

Declare @strSQL char(2000)

Set @strSQL =
  ”Select count(c.ID) as Count, sum(sc.Total) as Users”
  + ” from Users sc ”
  + ” inner join UserRelationship pr on pr.PartyIDChild = sc.OrganizationID ”
  + ” inner join Batch b on b.BatchID = sc.BatchID ”
  + ” inner join ” + ltrim(rtrim(@DatabaseName)) + ”.dbo.Users c on sc.UserID= c.ID ”
  + ” where b.SentDate between ”””
    + ltrim(rtrim(@StartDate)) + ””””
    + ” and ””” + ltrim(rtrim(@EndDate)) + ””””
  + ” and c.UserID = ” + ltrim(rtrim(str(@UserID)))
  + "and c.Password = " + ltrim(rtrim(str(@Password)))

Exec (@strSQL)

Comentando que "…ellos habían pasado por el doloroso proceso de usar SPs, sin obtener ninguna de sus ventajas", dejando como un ejercicio para el lector encontrar por qué. Después asevera que "…lo más increíble es que al señalar esto al desarrollador senior que diseñó el SP, aquél no entendió cuál era el problema, por lo que la administración no me dejó siquiera hablar al respecto. Afortunadamente, ya no trabajo ahí."

Honestamente yo tampoco tenía idea de qué se trataba el problema, pues siendo Javero, se me dificulta saber incluso para qué base de datos es este script. Así que mediante un clavado en los foros de discusión y una pequeña asesoría de mi señora – quien tiene responsabilidades como DBA – me iluminaron un poco al respecto:

• Por principio, el script está sobrecomillado y ni siquiera compila, pero es un SP específico de Microsoft SQL Server.

• En segunda, el SP le tupe duro al desempeño de la base de datos porque cada vez que se ejecuta, vuelve a construir todo el query, perdiendo las bondades de un stored procedure – llámese compilar las instrucciones contenidas en él y guardarlas en memoria. Pero eso sí, complica el mantenimiento de la base de datos al ser un "query dinámico".

• Por otro lado, dependiendo de la versión de SQL Server empleada, la línea "and c.Password = " es una trampa mortal, porque no detiene un ataque de Inyección de SQL: ¿Que pasaría si lo ejecutamos con password = ‘UNION DELETE FROM USERS’?

• Finalmente, este SP utiliza entre sus parámetros el nombre del esquema de base de datos que se quiere explotar (@DatabaseName char(50)). De esta forma, al SP se le está dando la posibilidad de acceder y modificar tablas de un esquema para el que este usuario normalmente no debería tener permisos.

Mi propio WTF

Después de ver todos los detalles que un simple script de base de datos puede contener, me di cuenta para mi horror que dejé por ahí un muertito. Explico la situación:

En otra vida, participé como líder técnico en un proyecto con el objetivo de construir un pequeño portal de créditos hipotecarios. Dicho portal incluía gestión de documentos, algunos flujos de trabajo y la generación de varios reportes de acuerdo a la información almacenada en la base de datos. Por ejemplo, uno de los reportes desplegaba "el valor catastral promedio de las viviendas localizadas en un municipio dado".

Gracias al uso de una metodología ágil de desarrollo, el proyecto iba muy bien: la interfaz y flujos de trabajo eran constantemente verificados por los usuarios y cada tres o cuatro semanas liberábamos una versión prácticamente sin bugs. El único detalle con el proyecto es que jamás nos asignaron un DBA formal y muchas de sus funciones eran llevadas a cabo por los miembros del equipo de desarrollo. Para este momento, muchos ya se habrán imaginado que asignarle a un desarrollador (Javero, Dotnetero o lo que fuere) las tareas de modificar un esquema de bases de datos es como regalarle una caja de cerillos a un niño de 8 años: tarde o temprano ocurrirá una tragedia.

Al final del proyecto, realizamos las pruebas mínimamente requeridas y se quedaron dos recursos dando los toques finales al sistema. Para aquél entonces yo ya había salido de la empresa, aunque seguía contactando a la mayoría de los miembros del equipo.

En fin, poco después de mi partida, el sistema salió a producción… y a los pocos meses de su liberación empezaron a darse algunos problemas: adicionalmente a "detalles" como "funcionalidad que no se había implementado" y un par de casos de "pérdida de código fuente", la mayoría de incidencias consistía en una progresiva disminución del desempeño de la aplicación. El más grave era un reporte Web que cruzaba varias tablas y podía tardarse hasta 30 minutos en generarse.

Esto provocó la queja de los usuarios y se envió a un par de analistas para determinar la raíz el problema. Ellos detectaron dos causas:

• Las tablas de la base de datos no tenían integridad referencial.

• Las tablas no tenían índices.

Sin embargo muchos de los SPs – principalmente los de reportes – tenían la estructura del ejemplo mostrado más arriba. Así que directa o indirectamente, el batidillo fue mi responsabilidad. Claro que para nuestra honra, no cometimos errores más graves como dejar todos los campos como nulables, o almacenar BLOBs y dejarlos como llaves primarias. Sin embargo esto no sirve de mucho consuelo, pues aunque después del diagnóstico se realizaron algunos cambios y se montó el sistema en un servidor más grande, nunca se alcanzó el objetivo de desempeño y el sistema fue relegado al olvido. Como nota adicional, por razones contractuales el cliente había requerido a nuestra empresa una fianza de más de un millón de pesos (unos US$100,000 de aquél entonces) que al final se quedó. En última instancia, el cliente decidió terminar la relación con la empresa a la que llegué a pertenecer. Oops.

Un micro-postmortem

Mi antiguo empleador jamás realizó un postmortem del proyecto y estoy casi seguro que se quedó con la espinita de "…nche Eduardo, me costaste un melón." Bueno, aquí presento a manera de resumen, lo que he aprendido desde aquél entonces:

Casi todos los sistemas alguna vez construidos no son más que interfaces de una o varias bases de datos. Consecuentemente, la parte más crítica de una aplicación es su base de datos y si ésta no ha sido diseñada e implementada correctamente, todo lo que se construya a su alrededor – sin importar lo sofisticado, novedoso o eficiente que sea – es completamente inútil.

Por lo tanto, si queremos que un proyecto de desarrollo sea concluido exitosamente, debemos tener como parte integral de nuestro equipo un DBA de tiempo completo; nunca de los nuncas debemos darle a los desarrolladores la opción de modificar el esquema de la base de datos.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: