La GUI es una parte notoriamente dificil de hacer bien, lo cual se evidencia, entre otras cosas, por la imposibilidad de hacer una GUI multiplataforma realmente buena (solo se puede hasta cierto punto).
El problema que experimentan con Delphi es similar en todos lados: Delphi hereda los problemas del API de windows, de la OOP de entonces. Hacer GUI en web es jodido porque se heredan los problemas de html/css/js. Y así por el estilo. Abstraer esos problemas ayuda en unas cosas, pero tiene el lio de que hay que re-implementar varias otras, por lo que es una propuesta difícil.
Este tema me toca porque llevo dandole vueltas a hacer un lenguaje/herramienta y la parte de la GUI es algo que le llevo cavilando un rato, y nada de lo que hay me convence del todo (no es que no haya una solución: es que implica rehacer los controles!)
Hay formas de hacerlo mejor? Si. Pero requiere ayuda de los lenguajes/herramientas porque como dice:
Cita:
|
Empezado por Casimiro
Pero eso toma tiempo, y si tienes a alguien esperando para entregarlo, es imposible "perder" tanto tiempo y al final lo dejas que funcione, aunque no cumpla correctamente la POO.
|
Si las herramientas, APIs, etc no colaboran el esfuerzo empieza a "cansar" hasta el purista mas dedicado.
Cita:
Empezado por AgustinOrtu
Existirá alguna manera (o es viable que Embarcadero implemente) la posibilidad de ocultar estos detalles de implementación?
La primera solucion que vino a mi cabeza son interfaces; pero no estoy conforme con eso, ya que es facilmente hackeable ("solucionable"): en vez de usar la interface uso la clase! en un periquete! al demonio con la POO!
|
Hay varias cosas que son parte
fundamental del problema. La OOP? Es uno de ellos!.
Especificamente, la *herencia*.
Mal #1: Herencia
Como dice Agustin, el lio es que la herencia arrastra un montón de cosas y hay que esforzarse por "ocultarlas". Ironicamente, se supone que la OO promueve el encapsulamiento, pero la herencia no ayuda en ese sentido.
Peor aun, la mayoría de los toolkits gráficos se basan en armar arboles como TControl -> TEdit -> TEditPassword
| TEditNumber -> TEditMoney, etc.
La falla sistematica de esto se evidencia en que cuando se adquiere una libreria (como decir, devexpress, o se usa firemonkey) hay QUE REHACER TODOS LOS CONTROLES. La OO, tal como se hizo popular cuando Delphi nació, ha fallado en su cometido en esta area especifica.
Ahora, OO es un paradigma que combina al dedillo con la GUI, asi que esto es un lio de como se ha usado de forma general...
Mal #2: Coordinacion
El segundo y mas grande problema es de coordinación. Por ejemplo, necesito deshabilitar el boton "Login" si los campos "Password1/2" no cumple con mis N-validaciones.
Aun este escenario "sencillo" muestra que hacer la coordinación es difícil (tipicamente: Requiere regar código en varios lados, hacer callbacks, y rastrear la lógica cuando se hace depuración). Cuando uno entonces intenta hacer una pantalla mas compleja, se nota mucho la carga que el manejo de estado implica ("código spaguetti!").
Mal #3: Estado + Tiempo
El siguiente gran lio es el manejo del estado y como este muta en el tiempo. Quienes hacen apps webs se dan cuenta lo simple -relativamente- que es hacer código de formularios, y eso es porque la web es "sin-estado" por defecto (opera en batch). Esto es facil porque una vez que tengo los datos del formulario, se con exactitud, que esos son los datos y no tengo que coordinarme con nadie mas diferente, si acaso, de la BD, que como esta es transaccional, todo me sale limpio.
EL problema es que el código OO
tiende a tener decenas/cientos/miles de estados internos
destructivos, y coordinar y estar pendiente de eso se vuelve complicado y difícil de manejar. Combinado con manejar la BD, archivos, eventos del sistema, etc todo se confabula para hacer la vida difícil.
Cuando se tiene código "
Sin-estado", estructuras
"inmutables" y funciones
"idempotentes y sin efectos secundarios" es supremamente mas facil.
Eso es lo que los proponentes de los lenguajes funcionales llevan rato diciendo. Sin embargo, la GUI es
nativamente "con-estado y mutable" así que no se puede ir al extremo en este asunto - que es por lo que les ha fallado el mensaje-.
Ademas, es critico que lo que toca la GUI sea rapido, y ahi
manejar estado es vital.
----------
RAD no es incompatible con hacer código mas limpio. Sin uno se fija, armar la parte visual de las apps en Delphi es fantastico (mucho mas que en Visual Studio, Xcode... y de ahi en adelante todo es un asco). Es lo que pasa en el *código* lo que complica la cosa.
---------
Como se ve manejo de GUI mejor? Bueno, si han visto el sistema Modelo-Vista-Controlador y similares, entonces no es muy lejos. La Web tiene un modelo casi ideal, lastima que usa DOM, CSS y Javascript! - que lo complica mucho-.
Asi es como seria (usando como ejemplo, una pantalla login):
1- EL modelo es simple:
Código PHP:
//LoginModel es facil de testear, e independiente de plataforma, diseño,
//toolkit y demás!
class LoginModel:
Email=EmailString
Pass1=PassString
Pass2=PassString
//EmailString y PassString son strings que han pasado validaciones y con
//certeza no están vacíos
constructor Login.create(email:EmalString, pass1, pass2:PassString)
function Login.TryLogin():Boolean
//Hacer el login
//Esto valida las cadenas
function isValidEmail(value:string):Boolean
function isValidPassword(value:string):Boolean
Ahora, esto es solo una idea de modelo. Puede ser aun mas simple (como un hashtable) y no usarse e ir directo al controlador.
-------
Para la parte de GUI, la idea es usar composición en vez de herencia. Ahora el problema es que Delphi, VS usa herencia por todos lados.
Porque composición? Porque en una GUI se reusa un monton de cosas. Por ejemplo, bordes, fondos, captura de eventos de teclado, etc. En vez de tener una arbol profundo de clases, seria ideal poder elejir que usar, como:
Código PHP:
//Supongamos que intento hacer un control de chart de barra
//No heredo nada, excepto declaro soy un control, pero si hago composicion
class ChartBar:UIControl
//Esto es privado!
Bar: Rectangle array
KeyListen: KeyboardListener
MouseListen: MouseListener
function create()
this.parent = parent
this.view.dimensiones = ...
this.view.Add(Bar)
this.KeyListen.ListenFor(this.view)
this.MouseListen.ListenFor(this.view)
//Metodos de negocio!
function draw(values:Integer Array)
for value in values
this.Bar[i].draw(width=10, height=value)
Para coordinar, tengo 2 lios: Como coordino valores con controles, y como coordino el thread de la GUI con el de negocios (para no bloquear la GUI).
Para el primer caso, el modelo reactivo (
http://reactivex.io/) y los controles reactivo (
https://facebook.github.io/react/) son una gran mejora.
Para el segundo, es el mismo lio que el manejo multi-hilo, el modelo de Actor, pero en especial, el de CSP es todo un avance (
https://swannodette.github.io/2013/0...ial-processes/).
-----
Con respecto a que se puede hacer en Delphi? Todo esto (ya el lenguaje es mas que avanzado)
1- La parte de hacer los formularios se puede dejar tal cual
2- Hacer el modelo es trivial en Delphi
3- Hacer el coordinador es la parte compleja, porque Delphi, que yo sepa, no tiene una solucion inmediata.
4- Hacer la parte de multi-hilos es muy viable. Delphi ya tiene muchas mejoras. Implementar CSP estoy viendo como es pero parece ser muy simple...