Arquitectura de software y UML
El software funciona desde hace veinte años, los clientes confían en él, y el único que conoce de verdad el código Delphi se jubila el año que viene. ¿Reescribirlo todo? Eso lleva años y solo aporta valor al final. Hay un camino mejor: pieza a pieza, sin detener la operación.
Por qué ahora, y por qué no todo de una vez
Con Visual Basic 6 la situación es clara. Microsoft ya no da soporte al entorno de desarrollo desde el 8 de abril de 2008. Según Microsoft, el entorno de ejecución funciona también en Windows 11, pero solo recibe soporte en caso de regresiones graves y vulnerabilidades críticas. Microsoft recomienda expresamente sustituir las aplicaciones VB6. Delphi y MFC, en cambio, siguen manteniéndose. Allí la presión llega por otro lado: menos desarrolladores que entienden el código, una interfaz anticuada, falta de pruebas, bibliotecas sin actualizaciones.
Nadie derriba un puente por el que pasa tráfico a diario para construir uno nuevo. Se construye al lado y se trasladan los carriles uno a uno. Martin Fowler da a este patrón el nombre de la higuera estranguladora, que va rodeando poco a poco un árbol: el código nuevo crece alrededor del antiguo hasta que este se puede desconectar. Cada paso entra en funcionamiento y aporta valor de inmediato.
Cinco pasos
- Inventario: registrar módulos, base de datos, interfaces y formularios. ¿Qué partes cambian a menudo y cuáles provocan más errores?
- Registrar el comportamiento: ejecutar el software antiguo con entradas reales y grabar los resultados. Estos «golden master» son la referencia para cada nueva línea.
- Construir un puente: lo antiguo y lo nuevo deben comunicarse mientras ambos sigan vivos.
- Migrar módulo a módulo: empezar por la parte que cambia con más frecuencia o la que más problemas causa. Entregar cada paso.
- Desconectar: solo cuando nada llama ya a la parte antigua, se elimina.
Puentes entre lo antiguo y lo nuevo
- Delphi: el antiguo núcleo de cálculo se hace accesible como DLL con exportaciones
stdcall, y .NET lo llama mediante P/Invoke. Como alternativa, la comunicación se hace a través de COM. - VB6: las partes nuevas se crean en .NET y se ponen a disposición como servidor COM. Con
EnableComHosting, el SDK genera una.comhost.dllque se registra conregsvr32. Dos trampas: VB6 es de 32 bits, pero el envoltorio COM es de 64 bits por defecto. Y .NET ya no genera una biblioteca de tipos. Para el enlace temprano en VB6, escríbala usted mismo en IDL o utilice el enlace tardío conCreateObject. - MFC: C++/CLI une el código nativo y el código .NET en el mismo proceso. Los diálogos nuevos se crean en WPF o WinForms y se incrustan en las ventanas MFC.
Así es el puente Delphi a pequeña escala. El núcleo antiguo:
library Messkern;
// Antiguo núcleo de cálculo, expuesto como DLL con stdcall
function Mittelwert(Werte: PDouble; Anzahl: Integer): Double; stdcall;
var
I: Integer;
Summe: Double;
begin
Summe := 0;
for I := 0 to Anzahl - 1 do
begin
Summe := Summe + Werte^;
Inc(Werte);
end;
if Anzahl > 0 then
Result := Summe / Anzahl
else
Result := 0;
end;
exports
Mittelwert;
begin
end.
Y la llamada desde C#, directamente con la comparación con la nueva implementación:
using System;
using System.Linq;
using System.Runtime.InteropServices;
double[] messreihe = { 10.2, 10.4, 10.1, 10.3 };
double alt = Messkern.Mittelwert(messreihe, messreihe.Length);
double neu = messreihe.Average();
// Golden master: el código nuevo debe devolver lo que devolvía el antiguo
Console.WriteLine(Math.Abs(alt - neu) < 1e-9 ? "gleich" : $"Abweichung: {alt} / {neu}");
internal static class Messkern
{
// Si la DLL es de 32 bits, el proceso .NET también debe ejecutarse como x86
[DllImport("Messkern.dll", CallingConvention = CallingConvention.StdCall)]
internal static extern double Mittelwert(double[] werte, int anzahl);
}
Trampas con los tipos de datos
- Coma flotante: el
Extendedde Delphi ocupa diez bytes en Win32; undoublede .NET, ocho. Por eso, los resultados difieren en las últimas cifras. Compare con tolerancia. - Fecha:
TDateTimede Delphi yDatede VB6 cuentan los días desde el 30/12/1899 como número de coma flotante.DateTime.FromOADatelos convierte. - Moneda:
Currencyes en ambos lenguajes un entero de 64 bits con cuatro decimales fijos. En .NET se convierte endecimal, no endouble. - Textos: un
stringde Delphi nunca debe cruzar el límite de una DLL. UtilicePWideCharoWideString. Las versiones antiguas de Delphi trabajan con textos ANSI, casi siempre en la página de códigos 1252.
De la práctica
Un fabricante de instrumentos de medición utilizaba desde hacía décadas un software Delphi de desarrollo propio. Al principio hubo asesoramiento y planificación: contrapusimos los objetivos y las posibilidades de las nuevas tecnologías, y unos prototipos mostraron cómo podrían ser las soluciones. Después formamos in situ a todo el equipo del cliente. Un equipo de proyecto de diez personas porta el software de forma ágil a C# y WPF, con MariaDB y Entity Framework. El nuevo software ya se utiliza internamente y convence tanto a los técnicos de medición como al departamento de ventas. En una aplicación vertical para obra civil en C++, MFC y ObjectARX, un cálculo de rentabilidad previo mostró a partir de cuándo se amortiza la portabilidad.
Errores típicos
- Todo nuevo, todo de una vez: años sin aportar valor y, al final, falta la mitad.
- Reescribir de memoria en lugar de según el comportamiento medido.
- Corregir sin avisar errores antiguos en los que confían los usuarios o los sistemas posteriores.
- Mezclar 32 y 64 bits. Una DLL de 32 bits en un proceso de 64 bits acaba en una
BadImageFormatException. - Pasar textos a través del límite sin una regla clara. El resultado son bloqueos o caracteres especiales estropeados.
- Reproducir la interfaz píxel a píxel en lugar de mejorar los procesos.
- No implicar al propio equipo. Quien no entiende el código nuevo pronto vuelve a mantener software heredado.
Cómo le ayudamos
- Revisión de modernización: análisis del código y de la arquitectura, arquitectura de destino, cálculo de rentabilidad y un plan por etapas sin interrumpir la operación, para Delphi, VB6, MFC y ObjectARX, como paquete de inicio a precio fijo.
- Portabilidad como proyecto: portamos y modernizamos su software o acompañamos a su equipo en el proceso.
- Formación: su equipo aprende la nueva tecnología, por ejemplo en la formación «C# .NET básico» o en la formación en WPF.
- Su proyecto: Concierte una primera conversación. Más ejemplos en nuestros casos de estudio.
Fuentes: Microsoft, «Support Statement for Visual Basic 6.0 on Windows»; Microsoft Learn, «Exposing .NET Core components to COM»; Martin Fowler, «Strangler Fig Application»; Embarcadero DocWiki, «System.Extended»; casos de estudio «Modernización de un software de instrumentos de medición: de Delphi a C#» y «Modernización de una aplicación vertical de AutoCAD para obra civil», casos de estudio de Cadida.
