Ir al contenido


Foto

Buenas prácticas de programación


  • Por favor identifícate para responder
12 respuestas en este tema

#1 cram

cram

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 832 mensajes
  • LocationMisiones, Argentina

Escrito 03 julio 2014 - 07:41

Hace precisamente un día, me llaman por un problemilla (un bug) en un sistema que hice.
Normalmente les pido a los clientes que vean todo el sistema en búsqueda de errores, por al menos una semana en forma exhaustiva  :D nadie lo hace, pues todo está bien  ^o| Todos sabemos, que no existen programas perfectos.
La cosa, es que no me costó ver donde estaba el error y  lo pude solucionar. Todo gracias a las anotaciones, aclaraciones, etc.
Dado que el sistema tomó los datos de uno anterior y convirtió la estructura (DataPump, que buena herramienta) de un sistema con base en Paradox, las relaciones quedaron bien, pero cuando el cliente tuvo que crear nuevos elemento se encontró con el bug. Mucho tiempo después.

Me gustó leer esto sobre buenas costumbres de codificación:  :ap:
http://jachguate.wor...pegar/#more-707

Recientemente, contesté una encuesta de poliburro, donde comento el porque de mi preferencia para trabajar solo antes que con lineamientos y códigos de terceros como ocurre en el caso de la modalidad "freelance".
Y es eso: Delphi, Pascal en sí crea buenas costumbres de programación (es un todo en uno).  (y)

  • 0

#2 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 03 julio 2014 - 08:00

Joel Spolky, ex Microsoft, tiene un blog con un largo y extenso temario sobre prácticas, recomendaciones, tips, etc a la hora de sentarse a hacer software.

Hay artículos que han sido traducidos al español, aunque la mayoría están en inglés.

No tienen desperdicio.
Para mi la meta-lección es aprender por uno mismo a desarrollar un sistema que permita llevar el orden en casa. Si la casa está en orden las cosas se harán en orden.

Saludos,
  • 0

#3 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 539 mensajes
  • LocationCali, Colombia

Escrito 03 julio 2014 - 08:45

Es claro que Delphi incita a utilizar buenas prácticas de programación, ya que algunos hagan caso omiso a esto es otra cosa.

Siempre  cuando doy clases de programación en Delphi, tengo tres máximas, hablando de buenas prácticas de programación.

1.  Si un procedimiento ocupa más de 60 lineas de código, revisalo, lo más probable es que esté mal planteado el problema.

2.  Las bases de datos tienen como fundamento las matemáticas, y Delphi se alinea perfectamente a ese modelo matemático, así que si requieres de procedimientos para consultar una base de datos,  ¡TE FALLARON LAS MATEMATICAS!.  la cosa está mal hecha.

3. Si para hacer algo, tienes que hacer muchos trucos de desarrollo, el problema no está bien planteado, empieza otra vez.

un corolario para los diseñadores de bases de datos:  SIEMPRE LLEGA AL MENOS A LA TERCERA FORMA NORMAL,  desnormaliza cuanto tengas argumentos sólidos para hacerlo. (esto lo digo porque la programación en web con lenguajes de script, requieren desnormalizaciones o trucos que no se deben utilizar en aplicaciones Delphi).

Saludos.
  • 0

#4 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 03 julio 2014 - 09:00

2.  Las bases de datos tienen como fundamento las matemáticas, y Delphi se alinea perfectamente a ese modelo matemático, así que si requieres de procedimientos para consultar una base de datos,  ¡TE FALLARON LAS MATEMATICAS!.  la cosa está mal hecha.

¡Podrías ampliar este punto. Más en concreto lo de "así que si requieres de procedimientos para consultar una base de datos".

Si un procedimiento ocupa más de 60 lineas de código, revisalo, lo más probable es que esté mal planteado el problema.

Quisiera hacerte una aclaración un tanto semántica. En lugar de decir que está mal planteado sugeriría algo menos violento. Como por ejemplo:
Si para una funcionalidad te estás exediendo de líneas, piensa dos veces, y vuelve a leer tu objetivo. Mejor divide y vencerás.

Decir que está mal planteado puede ser brusco. Y ni que decir, muy ambiguo. Uno puede haber planteado bien algo, pero el camino para llegar a ello es otra cosa. Planteado sugiere llegar a un objetivo, una meta. Si defines llegar a esa meta es que algo está para ser bien. Distinto es ahora la forma en como haces para llegar a ella. El expresar justamente "mal planteado" es decir que tu meta impuesta está erronea.

También hay que considerar que en el área del Análisis de Software estamos en una zona gris en donde no es que algo necesariamente está mal o bien.  ;)

Saludos,
  • 0

#5 cram

cram

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 832 mensajes
  • LocationMisiones, Argentina

Escrito 03 julio 2014 - 09:15

un corolario para los diseñadores de bases de datos:  SIEMPRE LLEGA AL MENOS A LA TERCERA FORMA NORMAL,  desnormaliza cuanto tengas argumentos sólidos para hacerlo. (esto lo digo porque la programación en web con lenguajes de script, requieren desnormalizaciones o trucos que no se deben utilizar en aplicaciones Delphi).


Así es,
Comúnmente para ello uso vistas (me refiero a la desnormalización).
Aúnque (como lo habrás notado en otro hilo) no programo para web.

  • 0

#6 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 539 mensajes
  • LocationCali, Colombia

Escrito 03 julio 2014 - 01:05

Hola

explico un poco más el punto 2.

2.  Las bases de datos tienen como fundamento las matemáticas, y Delphi se alinea perfectamente a ese modelo matemático, así que si requieres de procedimientos para consultar una base de datos,  ¡TE FALLARON LAS MATEMATICAS!.  la cosa está mal hecha.


Las consultas sobre bases de datos están basadas en "Algebra Relacional" o en "Calculo Relacional", ambos tienen bases matemáticas,  Delphi por su parte da un excelente soporte a este modelo de consultas. Así que Delphi tiene todas las herramientas para acceder a bases de datos bien diseñadas y normalizadas.

Ej. Es fácil traer un dataset a memoria y consultar sobre una llave compuesta por 5 campos.
    Es fácil hacer las operaciones del CRUD (Create, Read, Update, Delete) sobre las tablas, aún con llaves compuestas.

Si el diseño de base de datos no está adecuado al modelo matemático (Bien Normalizado), las herramientas de Delphi no funcionan y será necesario hacer "trucos" para hacer algunas cosas.

Es fácil detectar esto cuando se requiere crear indices secundarios como llaves únicas o en lugar de hacer una sola consulta SQL debe traer datos parciales para llenar el contenido del reporte de la misma tabla, o hacer recorridos de la tabla para ir por medio procedimental seleccionando los datos que se requieren.

En una base de datos bien diseñada debería bastar un solo SQL para obtener la información necesaria sobre un tema en particular.

ACLARACIÓN:  Base de datos bien diseñada = Base de datos normalizada al menos a la 3 forma normal,  eso no quiere decir que si no cumple las reglas de normalización esté mal, solo que no cumple parcial o totalmente. De hecho es posible hacer aplicaciones sin normalizar, y los Bigdata son un ejemplo de ello.


Todo esto lo digo porque mis estudiantes crean tablas no normalizadas y luego dentro del código hacen trucos para subsanar los errores del diseño, y estos trucos demoran el desarrollo y entorpecen el buen diseño de la aplicación.

ej.  Hace poco solicité una práctica donde se debía guardar los medios de pago, y crearon una tabla con varias columnas así.

Tabla Caja:

Id.  Fecha.  Efectivo, Tarjeta1, Tarjeta2, tarjeta3, cheque1, cheque2 etc.

No es posible hacer consultas SQL facilmente sobre una tabla así,  debe hacerse con CASE, If, etc.

luego en el código debían preguntar por el medio de pago que utilizaron para poder obtener el movimiento de caja, y allí es donde comienza a complicarse el asunto.

Acepto que los términos son un poco fuertes y tienes razón, sin embargo esas cosas las digo en clase, en los escritos hay que ser mucho más prudentes y redactar mejor.

todo esto es con fines formativos, no es un dogma, pero allí comienzan las buenas prácticas de programación.

espero haya servido la aclaración.

Saludos.
  • 0

#7 Rolphy Reyes

Rolphy Reyes

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.092 mensajes
  • LocationRepública Dominicana

Escrito 03 julio 2014 - 01:31

Saludos.

Es fácil detectar esto cuando se requiere crear indices secundarios como llaves únicas


No entiendo esta parte, de manera personal, usualmente tengo un llave primaria y una llave única en una misma tabla.
E.j.:

TablaXXX
Id Integer (pk)
SucursalId integer (uk)
Codigo varchar  (uk)

¿Qué es lo malo que tiene esa estructura?
  • 0

#8 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 539 mensajes
  • LocationCali, Colombia

Escrito 03 julio 2014 - 01:59

Hola Rolphy Reyes

No me mal entiendan,  cuando hablo de un buen diseño, hablo de una tabla bien normalizada, para que se puedan realizar facilmente consultas SQL o QBE (Algebra relacional o Calculo relacional). Si no está normalizada no es un buen diseño para este tipo de consultas, pero no quiere decir que esté mal diseñada para la aplicación que se desea hacer.

http://es.wikipedia...._bases_de_datos

En el caso que explicas, te diría que una de los objetivos de la normalización es eliminar la redundancia de datos, así que no se ve la necesidad de tener 3 campos que te identifiquen lo mismo.

Id Integer (pk)
SucursalId integer (uk)
Codigo varchar  (uk)

Si asumimos que la tabla es de sucursales,  bastará con el Código de la sucursal como llave primaria,  sobraría el ID y el Código.

Igualmente cuando dicen que la llave debe identificar a un único registro sin equivocación,  debe existir también una relación lógica entre el código y el contenido del registro, es decir que si el código identifica a una sucursal, la información de ese registro debe ser de la sucursal, a excepción de las llaves foráneas.

Sé que es una práctica común utilizar consecutivos o autogenerados para las tablas, pero esto presenta problemas de inserción en las tablas, que también es uno de los inconvenientes que se pretenden evitar con la normalización.  ya que se podrían insertar dos veces la misma sucursal, pero el id autogenerado sería diferente.

por lo tanto es necesario crear un indice único adicional para evitar que digiten dos veces la misma sucursal, lo cual causa problemas con las herramientas de Delphi o al menos un sobrecosto en el desarrollo.  Tal vez esto no sea cierto en PHP y JScript u otros lenguajes.



Me gustaría que analizaramos ese caso si es posible.
  • 0

#9 Rolphy Reyes

Rolphy Reyes

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.092 mensajes
  • LocationRepública Dominicana

Escrito 03 julio 2014 - 02:37

Saludos.

La tabla que pongo de ejemplo puedes nombrarla como quieras, la idea de la estructura es presentar la validez de las claves únicas (uk).

Tal vez no fui claro con el ejemplo:
TablaXXX
Id AutoIncremental (pk)
SucursalId Integer (uk)
Codigo Varchar (uk)

Con la clave única garantizo que el código digitado por el usuario sea único por sucursal. Creo que la normalización aquí llego hasta su máximo.

No podemos asumir que sea la tabla de Sucursales porque tendría una estructura como esta:
Tabla Sucursal
SucursalId Autoincremental (pk)
Codigo varchar (uk) *

Marco el campo código porque pudiera ser o no clave única.

¿Qué piensas?
  • 0

#10 cram

cram

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 832 mensajes
  • LocationMisiones, Argentina

Escrito 03 julio 2014 - 04:02

genriquez,

no inserto lo que dices antes, por ser muy largo, pero es fácil seguir el hilo.

Si no entiendo mal lo que dices es exactamente lo que no hago, ya que sigo la línea de Rolphy Reyes.
Para relacionar tablas, yo uso un campo de identificaicón unívoca siempre que pueda, más allá que algunos piensen que se sobrecarga la tabla. Conozco diseñadores (arquitectos, como quieras llamarles) que utilizan campos como DNI como clave primaria (incluso conozco el caso de aquel que lo definió como FLOAT). Yo prefiero usar el ID_PERSONA como clave primaria y dejar al DNI para propósitos de búsqueda también como clave única, pero no primaria. Para mí esto soluciona cualquier problema futuro (por ejemplo, si se desconoce el DNI, no podrá crearse la fila).
Puede entenderse que se viola un grado de normalización al tener DNI, junto con ID_PERSONA (ya que ambos identifican unívocamente), pero el caso es que uno existe a veces y el otro siempre.
Esta regla la uso para la mayoría de mis tablas y se me hizo costumbre, así como no llamar ID a secas, sino acompañarla de al menos tres caracteres para no chocar en las desnormalizaciones. ID_PER, ID_LOC, ID_PROV, etc.

Para ser más claro, aun:
En el caso de artículos:
ID_ART, llave primaria, entero y auntoincrementado
COD_INT, clave única, char(6)
COD_GTIN, clave única, varchar(13)
etc.

Con esto me aseguro de que la llave primaria sea realmente obligatoria y única, como debe. No siempre se provee el código GTIN (que puede ser EAN13, EAN7, UPC, etc.), puede ser que nunca se use el código interno (más allá que en mis trabajos actuales es autogenerado en base a otros datos).

  • 0

#11 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 539 mensajes
  • LocationCali, Colombia

Escrito 04 julio 2014 - 08:49

Hola,  creo que es interesante y práctico lo que propones CRAM, sin embargo lo que yo digo es que desnormalizar trae lios a la hora de utilizar Delphi, no quiere decir que no se pueda hacer, sino que las herramientas de Delphi están diseñadas para bases de datos normalizadas y es mucho más rápido y fácil cuando están bien normalizadas.

En mi caso particular,  procuro no utilizar (Mientras sea posible) autoincrementales, las claves siempre son únicas y procuro no generar información redundante, así es más sencillo utilizar Delphi.

Para aclararte o aclararme el concepto, me gustaría saber cómo haces el manejo de los autoincrementales cuando creas un Form?  no te presenta algunos inconvenientes al momento de obtener el ID autogenerado? (Asumiendo que utilizas un dataset conectado a la base de datos)

Otro caso es el que mencioné en el primer comentario.  si tenemos una tabla de pagos de caja, con los campos

Id, Fecha, TipoPago,..., ValorEfectivo, ValorCheque1, Banco1,  ValorCheque2, banco2, ValorTarjeta1, banco3, ValorTarjeta2, banco4...

cómo se realizaría una consulta donde deba calcular los totales por cada tipo de pago y las respectivas comisiones de las tarjetas por cada banco?  es algo bien complicado, no crees?
  • 0

#12 cram

cram

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 832 mensajes
  • LocationMisiones, Argentina

Escrito 04 julio 2014 - 10:37

Otro caso es el que mencioné en el primer comentario.  si tenemos una tabla de pagos de caja, con los campos

Id, Fecha, TipoPago,..., ValorEfectivo, ValorCheque1, Banco1,  ValorCheque2, banco2, ValorTarjeta1, banco3, ValorTarjeta2, banco4...

cómo se realizaría una consulta donde deba calcular los totales por cada tipo de pago y las respectivas comisiones de las tarjetas por cada banco?  es algo bien complicado, no crees?


No, definitivamente, nunca estuve de acuerdo con esto. Si vieras los líos que a veces hago para normalizar.
Pero ese ejemplo, si me permites o permiten es un caso de mal diseño, más allá de la desnormalización.
La técnica que solía usar mi profesor de la facultad era proponer una supertabla con todos los datos de una sola transacción y luego dividirla en tablas con entidades bien formadas y luego normalizarlas. Es una técnica interesante para enseñar.
Lo primero que se debe hacer es separar las entidades. No puedes mezclar datos de entidades diferentes en la misma tabla o vas mal.

Pero genriquez, yo me refería más a las buenas prácticas de codifciación en Delphi, más allá de las definiciones de datos. Igual, también hay prácticas aconsejables en esto.

Hola,  creo que es interesante y práctico lo que propones CRAM, sin embargo lo que yo digo es que desnormalizar trae lios a la hora de utilizar Delphi, no quiere decir que no se pueda hacer, sino que las herramientas de Delphi están diseñadas para bases de datos normalizadas y es mucho más rápido y fácil cuando están bien normalizadas.

En mi caso particular,  procuro no utilizar (Mientras sea posible) autoincrementales, las claves siempre son únicas y procuro no generar información redundante, así es más sencillo utilizar Delphi.

Para aclararte o aclararme el concepto, me gustaría saber cómo haces el manejo de los autoincrementales cuando creas un Form?  no te presenta algunos inconvenientes al momento de obtener el ID autogenerado? (Asumiendo que utilizas un dataset conectado a la base de datos)


No entiendo la conexión entre la creación del form y los autoincrementales. Por favor explícame, que es algo que no me hago la idea.

A mí lo único que me trajo de problemas los autoincrementales es que aun haciendo rollback el generador ya se incrementó igual y queda un hueco en la numeración, esto puede ser indeseable en el caso de usar el mismo número, por ejemplo para la numeración de una factura emitida. Es necesario volver atrás. En caso de generar el autoincremental en otro momento (no al insertar) se desconoce el id de la cabecera y no puedes relacionar los detalles de la factura. Pero, no es un gran problema.

El problema es que si no usas autoincrementales para las relaciones, la otra salida de enumerar es: o almacenando en el sistema el último número (te mata en ambientes con más de un cliente) o buscar el máximo valor de la tabla que termina en bajar el rendimiento, ya que MAX debe leer toda la tabla, al igual que COUNT, etc. (Al menos en Firebird).

Volviendo al tema de las prácticas no aconsejables. Ya que este hilo se hizo más amplio, quiero agregar algo.
Una práctica que hace poco casi me hace arruinar un trabajo casi terminado es el hecho de llamar desde un método controlado por un evento (por ej. OnClick) otro método que se dispara normalmente por un evento diferente (OnChange, de un TEdit) solo para evitar reescribir código. Sin querer oculté funcionalidad.
Es casi seguro que cambie esta práctica por utilizar como se debe los métodos ligados a eventos lo más puros posibles y crear procedimientos con funcionalidad común en el area de procedimientos privados y llamarlos como se debe.
El tema es que Yo incluso, ordeno los métodos "event-driven", de los públicos y de los privados, y los separo con grandes líneas de comentarios y si es posible con el uso de regiones. Además, suelo llamar casi siempre los controles comunes de igual manera (Ok, Cancel, por ejemplo)

  • 0

#13 Nikolas

Nikolas

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 604 mensajes
  • LocationMar del Plata / Bs As / Argentina

Escrito 08 septiembre 2014 - 10:36

Creo que "Las Buenas prácticas de programación" se pueden realizar desde que uno las aprende hasta que tiene su primer cliente, el cual no le para de pedir incansablemente truquitos al sistema.

Ejemplo:
tengo un listado de perros pero quiero agregarle gatos.

Ejemplo real:
tengo un sistema de facturacion el cual funciona con un controlador fiscal. ahora este sistema debe funcionar con 5 controladores fiscales (trucos everywhere)

De hecho el "polimorfismo" es el gran truco de la programacion
  • 0




IP.Board spam blocked by CleanTalk.