martes, 12 de julio de 2011

Generadores de código - Un programador más

¿Han pensado en este concepto? Un programador en la Argentina es un analista, un codeador, una persona que resuelve problemas. A veces incluso es organizador, anticipador, y se prepara para lo que viene. Toma decisiones y colabora junto a los demás para realizar sus tareas.

En cambio un generador de código es una máquina boba de escupir código. Es un mono que programa a una velocidad rampante. Pero no sabe ni qué está programando, ni qué está escribiendo. Él sólo escupe código. Para eso lo inventaron, y para eso está. No realizará análisis ni tomará decisiones.

Quien puede hacer eso es quien usa al generador de código como una herramienta. El decide qué debe crearse y cómo.

Ahora, todo esto me parece correcto pero quedándonos con sólo esta idea nos podríamos confundir un poco. Podríamos pensar que el código que se "escupe" puede ser redundante y sin reutilización. ¡Total, se re-hace en un segundo!. Es una de las principales premisas que veo en los generadores de código empresariales. Hacen un código desastroso, con casi ninguna herencia ni orientación a objetos, porque igualmente lo podemos re-generar con los cambios en un segundo. El tema es que nos encontramos con los siguientes problemas con el código una vez generado.

La reutilización no se tuvo en cuenta, por ende se hace difícil utilizarlo el código hecho en un futuro.

Por ejemplo, generamos automáticamente las clases de acceso a datos. Lo que no se tuvo en cuenta es que dicho código utilice algún framework ORM propietario o de terceros, cosa de que el código sea más reutilizable y legible.

Por ejemplo, quizás estas clases de acceso a datos se generan con SQL Server en la cabeza, y cuando necesitamos pasar a Oracle tenemos que ir a re-generar el código (en el mejor de los casos!). Y cuando re-generamos nos encontramos con que:

  1. El comportamiento del código es diferente
  2. Interfaces desactualizadas o incompatibles.
  3. Hay métodos que recibían objetos de un tipo y ahora reciben de otro
  4. La nomenclatura de procedures y parámetros que está utilizando es diferente al implementado
  5. Los scripts SQL generados tienen errores
  6. Los templates de generación de código nunca se probaron

O sea que podemos caer en una situación incómoda. En realidad nosotros deberíamos tener una clase de LÓGICA de acceso a datos. De ahí viene el nombre "DAL". Data access LOGIC. Pongo LÓGICA en caps porque para mí eso significa que debe manejar "cómo" se deben acceder los datos y de qué forma se traducen a entidades/objetos del sistema. Para mí NO debe tener detalles de bajo "qué" están dichos datos.

Utilicemos clases de acceso a datos inteligentes, como si las hubiera programado un programador decente. Que utilicen un framework que nos permita cambiar la base de datos simplemente cambiando la configuración, no re-generando todo el código.

Terminamos con un archivo donde "tocar" y un archivo donde "no tocar"

Esta también es típica. Para una clase nos genera dos archivos de partial class, donde uno tenemos un cartel gigante que dice "NO MODIFICAR". Esto para mí es un conocidísimo anti patrón. Tener 2 archivos para una clase es un tema. Tener 100 archivos para 50 clases es otra.

Otra cosa que he visto a veces es que todo el código generado lo pegan en un sólo archivo universal (que a veces alcanza las decenas de miles de líneas de código) y luego es un desastre regenerar algo. Esto es obviamente una respuesta poco pensada al hecho de darse cuenta que tener tantos archivos que no se pueden pisar es inútil.

Lo cierto es que nuestros generadores deberían ser inteligentes. Tomar el código que deben reemplazar y listo. No que debamos regenerar todo y pisar los fuentes, eso es medio negrada. Simple y puede ser efectivo si se controla como corresponde, pero a la larga trae problemas.

Para lograr esto tendríamos que tener metainformación sobre las clases generadas. Y qué mejor para eso que Reflection!. En .NET al menos podemos consultar cómo está compuesta una clase, y luego el generador puede decidir qué reemplazar y qué no, y ante un código que no sabe que hacer, dejarnos la decisión a nosotros.

Esto nos permitiría, además, pensar en regeneraciones parciales de clases. El código que debe crearse debe tener la menor cantidad de correspondencias privadas internas entre métodos y propiedades posibles, sin sacrificar la cohesión y la reutilización.

De repente algunos eslabones de la cadena de archivos generados no sirve

A veces, por la arquitectura seleccionada, algunos eslabones no sirven para nuestro sistemas. Imaginemos, por ejemplo, que nuestro generador nos crea unos webservices que luego llama desde la UI, por decir una boludez. Quizás nuestro sistema posee una arquitectura donde la UI se comunica directamente con la capa de negocio. Por ende, estaríamos teniendo que realizar un trabajo manual de adaptación sólamente para nuestro sistema.

Lo que deberíamos tener es una configuración de cómo se interconectan las capas generadas. Cada capa tiene sus propios templates que generan sus archivos, pero sería bueno que nuestro generador reconozca la configuración que nosotros deseamos, y nos genere las dependencias correctamente con nuestra arquitectura. Entonces puedo generar que la UI se enlace a WebServices, o que la UI se enlace a Negocio, o que la UI se enlace a la base de datos (horrible) según me convenga a mí. Y eso sólo con unas configuraciones. Es más fácil de armar de lo que parece.

Tomamos decisiones de arquitectura basándonos en nuestras herramientas y no en nuestros conocimientos

Este punto es importantísimos. Supongamos que creamos un generador de código que nos crea las siguientes capas:

  • Capa de Acceso a datos
  • Capa de Entidades
  • Objetos Estáticos tipo Facade que se comunican con la base de datos (una especie de Negocio pero con una implementación fea)
  • UI en archivos ASPX que se comunican sólamente con los objetos estáticos.

Cuando nuestros profesionales analicen y decidan "che, tengo una arquitectura mucho mejor", no la podrán aplicar hasta re-escribir los templates (en el mejor de los casos) o el generador de código. Los proyectos iniciarán y habrá una desmotivación por no poder aplicar una mejor arquitectura solucione los problemas de esta arquitectura auto-generada, simplemente por temas de tiempo (Que probablemente perdamos mas adelante).

Y así podríamos seguir mencionando problemas de los generadores de código actuales. Lo mejor sería tener un generador compuesto por pequeñas partes que nosotros podamos ir mejorando de forma independiente, manteniendo ciclos de desarrollo cortos, como para poder irlo mejorando seguido, y no tener que esperar a tener 3 meses con poco trabajo, que generalmente nunca ocurre. Todos los software se actualizan constantemente. Pero los de uso interno rara vez. ¿No habrá un problema ahí?

Los dejo con esta idea.

jueves, 7 de julio de 2011

Piqueteros y fanáticos de Harry Potter cortan todas las Autopistas de Capital

Se encuentra colapsado el sistema vial debido a manifestantes que exclaman por mayores salarios y la continuación de la saga de Harry Potter. La presidenta ha salido con pancartas a la calle a protestar por lo sucedido.

martes, 8 de febrero de 2011

.NET: Getting current method name or a method in the stack frame

I would love to go into the details of what is and how the StackFrame object works. However, I'm a little short on time right now, but I'm pretty sure I will make a post about it in the future.

For now, let's focus on how to get a very common functionality, but that isn't applied much yet. First, let's see what we can get and how. Next, I will give you some ideas on where to apply it.

You can 2 things to get the current method name. Using reflection:

string MethodName = System.Reflection.MethodBase.GetCurrentMethod().Name;

Or using the StackFrame:
string MethodName = new StackFrame(0).GetMethod().Name;
Cool, now we get the current method name. Now what if we wanted the previous method? Perhaps my method is called from various places and I do not wish to have their name as a parameter.
We can use StackFrame for this:
string MethodName = new StackFrame(1).GetMethod().Name
So, what can we use this for? Let's see some ideas:
  • Now our loggers can keep track of the method that's logging the information.
  • Gettng the methods (not the name) can help you retrieve the parameters it has received. We will see this in a future post. This information can be excellent when your application is deployed and you are getting an error that you can not reproduce.
  • In a certain way, you could limit the methods that can call your method. This seems weird at first, but perhaps some security folks can use this to their advantage.
  • Remove all those hardcoded strings!! Or constants at least :)

Being busy!

Hey! I am planning to create some Architecture post about Microsoft SharePoint and it's diabolic SPListItem object, an object that everyone has to deal with.

I also hope to be able to include some UML screenshots =).

Also, I want to create a post about how to start working as a freelancer. What you need, what software you should have, where to seek clients and how to deal with them :).

Regards,
Christian

jueves, 3 de febrero de 2011

SQL Server: Temporary tables

In stored procedures you can create temporary tables, save data into it and use it like some sort of temporary repository, or anything you can think of. This is specially useful in complicated stored procedures. Remember, not every single client you have will prefer having the data logic in a data access layer in your application, some will prefer implementing that logic in the database itself. Heck, some even will want their business logic there.

This type of tool can come in very handy. You can just create a table like:

CREATE TABLE #Tmp (
ID int,
Name varchar(30) )

Note the # at the begining of it's name. This table will last during the whole sql server session, and will get deleted inmediately after that. However, if you can to delete it yourself with a DROP TABLE instruction, you can just do that. No error will be thrown.

PD: I promise one day I'll format the code on the blog a little better. It has a very rustic formatting right now.

SQL Server: Inserted and Deleted special tables in stored procedures

This is something I've never used before, because I didn't use triggers at all. Check this quote from MSDN, full link at the bottom of the post.

Two special tables are used in trigger statements: the deleted table and the inserted table. Microsoft® SQL Server™ 2000 automatically creates and manages these tables. You can use these temporary, memory-resident tables to test the effects of certain data modifications and to set conditions for trigger actions; however, you cannot alter the data in the tables directly.
The inserted and deleted tables are used primarily in triggers to:
  • Extend referential integrity between tables.
  • Insert or update data in base tables underlying a view
  • Check for errors and take action based on the error.
  • Find the difference between the state of a table before and after a data modification and take action(s) based on that difference.
The deleted table stores copies of the affected rows during DELETE and UPDATE statements. During the execution of a DELETE or UPDATE statement, rows are deleted from the trigger table and transferred to the deleted table. Thedeleted table and the trigger table ordinarily have no rows in common.
The inserted table stores copies of the affected rows during INSERT and UPDATE statements. During an insert or update transaction, new rows are added simultaneously to both the inserted table and the trigger table. The rows in the inserted table are copies of the new rows in the trigger table.
An update transaction is similar to a delete operation followed by an insert operation; the old rows are copied to thedeleted table first, and then the new rows are copied to the trigger table and to the inserted table.
When you set trigger conditions, use the inserted and deleted tables appropriately for the action that fired the trigger. Although referencing the deleted table while testing an INSERT, or the inserted table while testing a DELETE does not cause any errors, these trigger test tables do not contain any rows in these cases.

Source(s): MSDN

SQL Server: Update a table based on another table

When I worked in a small software factory many years ago (it was my first IT job) I always wanted to know how to do this, and couldn't find satisfactory solutions in the web. Now that I'm back to SQL Server programming, it was time to unveil this mistery. Here it goes!


UPDATE TargetTable SET
Field1 = t1.Value1,
Field2 = t2.Value2
FROM OtherTable T1
LEFT JOIN YetAnotherTable T2 ON T1.SomeID = T2.ID
WHERE T1.ID = 1


So there you have it. It is very simple and it can be very handy, specially in stored procedures where sometimes you want to make the less Select instructions possible.


You can also do the same using INSERT SELECT FROM, but that's very easy to find on the web.


Have fun refactoring!