Archivos de la categoría arquitectura

Avance sobre la VAN sobre integracion continua

UPDATE: les dejo el video de la VAN mas abajo y la presetnación.

Mañana viernes tendremos otra VAN interesante en AltNetHispano.

Esta vez el tema es Integración Contínua desde el punto de vista de las herramientas y las prácticas. Ya nos presentó el concepto hace unos meses el Sensei Martin Salias en otra VAN sobre automatización en general.

Esta vez me gustaría hablar sobre la orquestación de un entorno de integración contínua con herramientas como: un repositorio (ya sea Subversion, Git, Hg o TFS), una herramienta para escribir scripts (ya sea NAnt, MSBuild, Rake?) y una herramienta de integración contínua (ya sea CruiseControl.NET, TeamCity, TFS o Hudson).

También hablaré sobre distintas políticas de branching de acuerdo a las necesidades de cada proyecto y como utilizar estas políticas junto con integración contínua.

Luego vendrá la parte en que varios amigos me ayudarán mostrando casos reales describiendo situaciones reales en las cuales la integración contínua los ayuda día a día.

Andres Vettori (@andresvettori) va a contar como se utiliza integración contínua con Team Foundation Server 2010 en la empresa VMBC para desarrollar aplicaciones multi-cliente basados en plataforma Microsoft (Hyper-V 2.0, Windows 2008 R2, SQL Server 2008, IIS 7.5, .NET 4.0, ASP.NET, ASP.NET MVC, Silverlight, Retina.NET como ORM). Hablará de los retos que tuvieron y las etapas de madurez por las que pasaron como equipo, mostrando brevemente la solución implementada actualmente y algunas ideas que tienen para el futuro.

Jose Romaniello (@jfroma) va a mostrar las distintas facilidades de configuración de TeamCity configurando un miniproyecto (que ya tendrá listo para lAN) desde cero con Mercurial/NUnit/etc.

Vicenç Garcia (@vgaltes) nos contará sobre la situación en una empresa anterior a la utilización de la integración contínua, el estado de caos y descontrol en el que se encontraba el equipo. Un análisis de la situación los llevó al camino obvio de empezar con un repositorio de código y un servidor de integración continua. Se decidieron por Hudson por su facilidad de configuración. También detallará su situación actual y dónde les gustaria llegar. Trabaja sobre una aplicacion cliente/servidor WinForms sobre SqlServer, Oracle, Progress
y Firebird.

Por último y si nos queda tiempo, yo hablare de algunas experiencias reales sobre complilación, prueba y despliegue automatizado de aplicaciones ASP.NET utilizando CruiseControl, NAnt, MSBuild, etc.

De como Charly cantó sobre software

En su tema Dinosaurios Charly dice:

Los amigos del barrio pueden desaparecer
los cantores de radio pueden desaparecer
los que están en los diarios pueden desaparecer
la persona que amas puede desaparecer.

y sigue en la segunda estrofa:

Los que están en el aire pueden desaparecer, en el aire.
Los que están en la calle pueden desaparecer, en la calle.
Los amigos del barrio pueden desaparecer,
pero los dinosaurios van a desaparecer.

En el último renglón pronostica que los dinosaurios van a desaparecer como han aparecido y desaparecido innumerables dinosaurios en la industria del software.

Por supuesto que no entraré aquí en detalles sobre cuales son “mis” dinosaurios, seria una discusión inútil puesto que cada uno tendrá los suyos.

Lo mas importante viene a continuación:

Si los pesados, mi amor,
llevan todo ese montón
de equipaje en la mano
Oh! mi amor
yo quiero estar liviano.

y remata con el consejo:

Cuando el mundo tira para abajo
es mejor no estar atado a nada,
imaginen a los dinosaurios en la cama.

Aunque no hace falta que el mundo tire para abajo, la enseñanza para los que diseñamos software es bien directa: debemos andar livianos.

Andar livianos en en diseño de software es elegir con criterio y libertad los frameworks que necesitamos y, sobre todo, descartar lo que no necesitamos. Cuanto mas pequeños e independientes mejor.

No recomiendo esos frameworks que arrastran un montón de otros componentes, muchos menos los monolíticos que “solucionan todo”, desde la persistencia hasta la interfaz a usuario.

Andemos livianos colegas, no nos atemos a nada.

Sabiendo que soy mal comentarista, les dejo la letra y la versión cantada por Charly

Nos vemos.

Dependencias ocultas entre clientes y servicios

Hace unos días, en una revisión de código, encontré una definición de interfaz de un servicio que no me gustó. No fue inmediatamente evidente para mi pero uno de sus métodos era un code smell.

Esta es la interfaz:

<span style="color: blue;">public interface </span><span style="color: #2b91af;">IIpStsStore</span>{
    <span style="color: blue;">void </span>AddCredential(<span style="color: blue;">string </span>userName, <span style="color: blue;">string </span>password);
    <span style="color: blue;">void </span>RemoveCredential(<span style="color: blue;">string </span>userName);
    <span style="color: blue;">bool </span>CredentialExist(<span style="color: blue;">string </span>userName);
}

El método que me olía mal es el último. Luego de exprimir el cerebro un poco me di cuenta del motivo. Ese método, a mi juicio, propicia un acoplamiento innecesario entre el cliente del servicio y la implementación de dicho servicio.

Si exponemos ese método seguramente el cliente del servicio lo va a usar y no tendremos control de este uso, es decir, no sabremos exactamente cuando van a utilizarlo.

Supongamos que la primera implementación de ese servicio accede directamente al recurso donde se almacenan las credenciales. En ese caso, si el cliente llama a AddCredential() e inmediatamente llama a CredentialExist(), todo funcionará correctamente.

El problema aparecerá cuando hagamos otra implementación del servicio IpStsStore que funcione en forma asíncrona. En ese caso ya no habrá garantía de que la secuencia de métodos mencionada mas arriba siga funcionando.

En definitiva, tenemos un acoplamiento entre el cliente y la implementación del servicio, algo que siempre debe tratar de evitarse, además, como suele ocurrir en estos casos, luego de pensar un poco el diseño, ese método tampoco era necesario, un típico caso YAGNI.

Que nunca falte un registro de actividad en tu aplicación. Nunca.

La semana pasada un cliente me llamó debido a que una de sus aplicaciones recién lanzada estaba un tanto inestable. Quiero compartir hoy con ustedes la recomendación que le di, la mas simple y mas efectiva que recuerdo haber dado.

Mas allá de revisar algunas cuestiones directamente relacionadas con las inestabilidades reportadas por usuarios finales, lo primero que les pedí es que me mostraran los logs para enterarme de que no los tenían.

Hoy no hay excusas para no tener información de este tipo en la plataforma .NET, todos los tipos de aplicaciones (Web, Desktop, Servicios, etc.) proveen un mecanismo centralizado de

Aquí algunos consejos básicos:

  • Registren todas las excepciones (básico)
  • No es necesario utilizar try – catch innecesariamente en todo su código, es suficiente con engancharse en el handler centralizado.
  • Registre información con distinto nivel de detalle (los niveles corresponden a log4net pero los demás utilitarios tienen niveles similares), al menos:
    • ERROR: las excepciones, deje que el framework se encargue de mostrar mensajes, callstacks, etc. También registre errores de formato, de protocolo, etc, aunque también podría utilizarse el nivel WARNING (o WARN).
    • INFO: algunos puntos importantes del funcionamiento de la aplicación tales como el inicio, datos de configuración utilizados, finalización, etc.
    • DEBUG: en esta modalidad puede registrarse información mas detallada del funcionamiento de la aplicación.
  • Configure correctamente el nivel de registro en cada ambiente. Generalmente uso nivel INFO en ambientes de producción (que también registra WARN, ERROR y CRITICAL) y nivel DEBUG en ambientes de desarrollo.
  • Use herramientas sencillas (log4net, NLog) y registre la información en simple archivos de texto. Nunca me resulto cómodo utilizar el registro de eventos de Windows.

Para aplicaciones ASP.NET

<span style="color: blue;">protected void </span>Application_Start()
{
    Error += Application_Error;
}

<span style="color: #0000ff; font-size: x-small;"><span style="color: #0000ff; font-size: x-small;">private</span></span><span style="font-size: x-small;"> </span><span style="color: #0000ff; font-size: x-small;"><span style="color: #0000ff; font-size: x-small;">void</span></span><span style="font-size: x-small;"> Application_Error(    </span><span style="color: #0000ff; font-size: x-small;"><span style="color: #0000ff; font-size: x-small;">object</span></span><span style="font-size: x-small;"> sender, </span><span style="color: #2b91af; font-size: x-small;"><span style="color: #2b91af; font-size: x-small;">EventArgs</span></span><span style="font-size: x-small;"> e)

{
</span>
<blockquote><span style="font-size: x-small;">
</span><span style="color: #2b91af; font-size: x-small;"><span style="color: #2b91af; font-size: x-small;">Exception</span></span><span style="font-size: x-small;"> ex = Server.GetLastError();
</span></blockquote>
<span style="font-size: x-small;">
</span>
<blockquote><span style="font-size: x-small;">
log.Error(</span><span style="color: #a31515; font-size: x-small;"><span style="color: #a31515; font-size: x-small;">"Application_Error", ex</span></span><span style="font-size: x-small;">);
</span></blockquote>
<span style="font-size: x-small;">
<blockquote>
Server.ClearError();</blockquote>
}

</span>

Para aplicaciones Desktop

<span style="color: blue;">static void </span>Main()
{
<span style="color: #2b91af;"><span style="color: #333333;">    </span>AppDomain</span>.CurrentDomain.UnhandledException +=
        UnhandledExceptionHandler;

    <span style="color: #2b91af;">Application</span>.Run(<span style="color: blue;">new </span><span style="color: #2b91af;">Principal</span>());
}
<span style="color: blue;">private static void </span>UnhandledExceptionHandler(
    <span style="color: blue;">object </span>sender, <span style="color: #2b91af;">UnhandledExceptionEventArgs </span>args)
{
    <span style="color: blue;">var </span>e = (<span style="color: #2b91af;">Exception</span>)args.ExceptionObject;

    log.Error(<span style="color: #a31515; font-size: x-small;"><span style="color: #a31515; font-size: x-small;">"Application_Error", ex</span></span><span style="font-size: x-small;">);

</span>    <span style="color: blue;">if </span>(<span style="color: #2b91af;">MessageBox</span>.Show(<span style="color: #a31515;">"Reporte este error:\n" </span>+         e + <span style="color: #a31515;">"\n\n¿Desea copiarlo al portapapeles?"</span>,
        <span style="color: #a31515;">"Error en Clasificador"</span>,
        <span style="color: #2b91af;">MessageBoxButtons</span>.YesNo, <span style="color: #2b91af;"><span style="color: #333333;">        </span>MessageBoxIcon</span>.Error) == <span style="color: #2b91af;">DialogResult</span>.Yes)
    {
        <span style="color: #2b91af;">Clipboard</span>.SetText(e.ToString());
    }
    <span style="color: #2b91af;">Environment</span>.Exit(1);
}

Mas informacion:

Aggregates and repositories

This an informal post about this message in the DDD  list.
I really know that this should be answered by a DDD guru but, seeing that no one showed up, I’ll try to fill the space.
UPDATE Nov/19: Added section titles, service implementation to answer Tom’s comment, changed wrong method name from GetActorsNotAssociatedWithPictures to GetActorsNotAssociatedWithMovies (thanks Tom).
Specifications
Let’s say we have this domain: movies and actors acting in that movies.
The goal of this article is to outline how to design this simple domain, to define aggregates (and identify aggregate roots) and the corresponding repositories.
The domain model specifications:
  • Many actors can act in a movie
  • An actor could act in many movies
  • I should be able to remove movies (actors shouldn’t be removed)
  • I should be able to remove and actor (provided it is not associated with any movie)
Let me detail aside the query specifications:
  • I want to retrieve all the movies in what an actor participated
  • I want to retrieve all the movies older that 10 years
Model design
Now let me design the model. We should have at least two objects, Movie and Actor, so let’s start with that classes:
NOTE: code is in C# without IDE assistance and incomplete, for example, trivial accessors omitted.
public class Movie {
private string name;
private int yearPresented;
}
public class Actor {
private string name;
private int yearBorn;
}
OK, pretty simple. Now I’ll try to connect actors and movies. Let’s look for a classic in IMBD, Gone with the wind. If you scroll a page you can see the actors on that movie, they are the Cast, we could build an object Cast but I’ll choose a simple path, more on that later.
Let’s see, for example, for the Scarlett O’Hara character, the actress was Vivien Leigh.
OK, it’s enough of IMDB, let’s go to the model but let me clarify, it’s very important to make the best effort to find the formal (and ubiquitous) language, that’s why I gone to IMDB.
So, seems like a good first step is to build the Character object.
public class Character {
private Actor actor;
private string name;
}
Now is time to define aggregates, I see two:
  • The Actor aggregate including just an Actor instance as aggregate root.
  • The Movie aggregate including a Movie instance as an aggregate root and one or more Character instances. Each Character instance references one Actor aggregate (kind of foreign key in RDMS parlance).
Let me do another round adding some code to my classes (I’m showing code in the  Fowler‘s way):
Mental note: if Martin changed that old picture in his home page I think it’s time to change mine, it’s 10 years old.
public class Movie {

private IList cast = new List();
public Character AddCharacter(Actor actor, string characterName) {
Character newCharacter =
new Character(this, actor, string characterName);
cast.Add(newCharacter):
return newCharacter;
}

}
And the Character class
public class Character {

internal Character(Movie movie, Actor actor, string name) {
this.movie = movie;
this.actor = actor;
this.name = name;
}
private Movie movie;

}
Repositories design
Now I have this domain model pretty much I like it, let me outline the repositories interfaces (one for each aggregate). As you will see, I use the “one method per query” approach, I could use the more concise GetByCriteria approach but it tends to force me to leak the query API to the model.
public interface MovieRepository {
Movie GetByName(string name);
(1) IList GetByActor(Actor actor);
(2) IList GetByCharacterName(string characterName);
(3) IList GetAgedMoreThan(int years);
(4) void Delete(Movie movie)
}
public interface ActorRepository {
Actor GetByName(string name);
(5) IList GetActorsNotAssociatedWithMovies();
(6) void Delete(Actor actor)
}
(1) Should retrieve movies doing a simple join to compare the actor. Pretty easy to do with a good ORM.
(2) and (3) This is a easy queries as well.
(4) Should delete the Movie instances and all the Character instances associated. Actor instances remain untouched.
(5) Not a difficult query, after obtaining the Actors list we could use (6) to delete un referenced actors.
Services design (some of them)
Tom is curious on how to implement the “I should be able to remove and actor (provided it is not associated with any movie)” specification.
I would like to put this into a more real specification like that: “I should be able to purge old pictures and unreferenced actors”. For this spec I would build a maintenance domain service like that:
public interface CatalogMaintenanceService {
public void DeleteDataOlderThan(int yearsOld) {
IList oldMovies = moviesRepository.GetAgedMoreThan(yearsOld);
foreach (Movie movie in oldMovies)
moviesRepository.Delete(movie);

IList orphanedActors =
actorsRepository.GetActorsNotAssociatedWithPictures();
foreach (Actor actor in orphanedActors)
actorsRepository.Delete(actor);
}
}
This service call should be wrapped by a unit of work. The implementation depends on the persistence layer and application platform, for example, in a Web application with NHibernate, it’s usually implemented with a HttpModule.
Please, feel free to ask any question, I would try to answer according my possibilities.
See you

Miercoles 20 en Resistencia

El miércoles 20 visitaré Resistencia, la capital de la provincia del Chaco por primera vez.

Participaré en un evento en el marco de la Gira Nacional organizada por el MUG. Me toca exponer sobre arquitectura de aplicaciones Web y en esta ocación presentaré mis experimentos con Castle Project, en especial con los subproyectos MonoRail y ActiveRecord.

En otra entrada publicare el material.

Nos vemos.