El assembly binding de los huevos

Que me ha traído de cabeza tol santo día, ¡me kagunnnn!

Aquí está el App.config que he tenido que poner para que no se me queje, para que cuando me dé un error, que fijo que me va a volver a dar, lo tenga a mano:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
 <startup>
 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
 </startup>
 <runtime>
 <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
 <dependentAssembly>
 <assemblyIdentity name="Microsoft.Expression.Interactions" publicKeyToken="31bf3856ad364e35" culture="neutral" />
 <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.5.0.0" />
 </dependentAssembly>
 <dependentAssembly>
 <assemblyIdentity name="System.Windows.Interactivity" publicKeyToken="31bf3856ad364e35" culture="neutral" />
 <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.5.0.0" />
 </dependentAssembly>
 </assemblyBinding>
 </runtime>
</configuration>

Menudo asco le he cogido a estos 2 ensamblados. Si fuesen personas les petaba la siente de un puñetazo. ¡Pues no me han dado día! Y todo por empeñarme en compilar para .NET 4.5. Esto de las versiones es una mierdaca como un camión de gordaaaaaaaaaaaaaaaa.

Hale, ya me he desahogado.

Por cierto tengo que deciros que Sacha Barber ha creado un contenedor de IoC.

http://www.codeproject.com/Articles/552514/BarbarianIOC-A-simple-IOC-Container

Mañana le voy a echar un vistazo. Seguro que es canela fina.

Principios SOLID

S – Single Responsibility Principle.

Una clase debería tener una única responsabilidad, bien definida. De esta manera solamente debería haber un motivo por cambiar su implementación.

Por ejemplo, una clase Persona nunca debería ser responsable de guardarse en un archivo a sí misma. Por lo tanto, un método Persona.Save(Stream output) viola este principio. En este caso, la clase Persona no solamente tendría como responsabilidad albergar los datos relacionados con la entidad correspondiente, sino también saber cómo guardarla. Tendría, por tanto, al menos 2 motivos para cambiar:

  • si la entidad Persona cambia
  • si los detalles del guardado (por ejemplo, el formato) cambian.

O – Open / Closed Principle

El comportamiento de una clase debería poderse modificar sin tener que cambiar su implementación.

Esto significa que la clase debe ser extensible, pero a la vez, robusta: no queremos tener que andar toqueteando todos sus métodos cada vez que una especificación cambie.

L – Liskov Substitution Principle

Una clase base debe ser SUSTITUIBLE por cualquiera de sus clases derivadas sin producir ningún efecto indeseado.

I – Interface Segregation Principle

Las interfaces deben ser reducidas. Deben permitir una granularidad alta.  Las interfaces grandes y difíciles de implementar SON CONTRAPRODUCENTES.

Es preferible tener varias interfaces pequeñas que una grande. Implementarlas será mucho más fácil y el diseño tendrá más sentido. Aparte de eso, al usar interfaces pequeñas nos forzamos a definir claramente los requisitos y las dependencias de cada método.

D – Dependency Inversion Principle

Trata de depender de abstracciones, no de implementaciones.

Cuando dependemos de abstracciones, tenemos claro qué es lo que necesitamos, aunque no definimos una forma específica de hacerlo. Una interfaz, ReproductorMusica puede tener el método Play. Sabemos qué es lo que hace, pero no cómo lo hace. Esto nos brinda una gran flexibilidad y dota al código de más capacidad semántica.

How to avoid code duplication. Case 1.

As a Clean Code lover, I really hate duplicated code.

In his homonymous book, Robert C. Martin states

”duplication may be the root of all evil in software”

And I think he IS absolutely right.

You better keep your code away from clones… or they will come back to you in the shape of a muddy monster that, for sure, will eat you.

I personally came to a situation in which I find it difficult to avoid repeating myself. This is the case:

I have a method that makes some calculations in a 2D plane (for layout and runtime design). This method takes some lengths and some points and make the necessary modifications to a control in order to a 2D transform to it. Let’s see a real sample in C#:

  • This sample method is really random, but it demostrates the problem. Each version works with one dimension, vertical or horizontal. Essentially both methods do the same, and the structure is almost identical. How to simplify these 2 into ONE?

For horizontal values:

        public static Rect DoSomethingCoolHorizontal(Rect inputRect)
        {

            var multiplyHorzPositions = inputRect.Left * inputRect.Width;

            Rect p = new Rect();

            p.Left = multiplyHorzPositions;
            p.Top = inputRect.Top;

            p.Width = multiplyHorzPositions;
            p.Height = inputRect.Height;            

            return p;
        }

For vertical values:

        public static Rect DoSomethingCoolVertical(Rect inputRect)
        {
            var multiplyVerPositions = inputRect.Top * inputRect.Height;

            Rect p = new Rect();

            p.Left = inputRect.Left;
            p.Top = multiplyVerPositions;

            p.Width = inputRect.Width;
            p.Height = multiplyVerPositions;

            return p;
        }

You may notice those 2 methods are 95% the same. But each one calculates the values for each axis. Vertical and horizontal use different properties.

The duplication in these kind of methods, follow  this simple rule:  when in the first method it says “left”, in the second it says “top”. As expected, “width” is replaced by “height”. The same would have been applicable for x and y.

In the case above, the rest is exactly the same, except for the return, that reverses the order of the Point arguments). They are so repetitive that even a text search&replace would do the job in order to replicate the same calculations for the other axis.

To clarify the method, you have to take into account that the structs that carry the properties are Rectangles with 4 attributes, that actually are 2 (2 for each dimension).

I tried to keep it beautiful, but I failed miserably again and again. That’s why I asked myself to Uncle Bob. I hope he could shed a bit light on this.

EDIT

Attention: Robert Martin did his magic again! I asked him in Twitter and has been so considerate and kind that he rewrote the sample in Java with the duplication totally eliminated. He provided a link with the source code. Just see the comments section.

WOW.

The solution to this lies in making a method that swaps vertical / horizontal dimensions. The call to the Vertical derivative is the Horizontal one with 2 swaps (argument and result):

        public static Rect DoSomethingNonDuplicateVertical(Rect inputRect)
        {
            return DoSomethingCoolHorizontal(inputRect.Swap()).Swap();
        }

With the Swap method being:

        public Rect Swap()
        {
            return new Rect(Top, Left, Height, Width);
        }

The constructor of the Rect class is:

  public Rect(double left, double top, double width, double height)
        {
            Left = left;
            Top = top;
            Width = width;
            Height = height;
        }

Now IT REALLY DOES SOMETHING COOL.

Thanks, Uncle Bob. Great tip!

¿Quieres Adorners con clipping?

Pues sí, chavalote, cuando coges la capa de Adorners, seguramente estás cogiendo la capa POR DEFECTO, que suele ser única en una ventana y está por encima del resto de los elementos.

image

AdornerLayer, ahí lo ves.

Pues el temita es que si poner un adorner ahí, y lo más seguro es que así sea, se pondrá, como es de esperar, por encima de todos los elementos. ¡Claro, tío! si la capa de adorno está por encima, lo que le metas también! Pura lógica, hermoso.

image

¿Ves que la selección se superpone no solamente por la cuadrícula, sino por el resto de la ventana? ¡Pues esto es un poco heavy! Debería recortarse. ¿Estamos? Lengua fuera

Por muy lógico que sea que esto pase, la cosa no es evidente en un primer instante.

Ahora, sabiendo esto, ¿qué pasa si yo lo que quiero es que los adornitos esos tan guays que he creado (Adorners) se superpongan a una zona y no a todo?

Pues, ¿cómo te quedas si te digo que se pueden crear más AdornerLayers? Pues sí, baby, ¡para eso está el AdornerDecorator.

El AdornerDecorator estará en el nivel del árbol visual que le corresponda según lo hayamos declarado y tiene la particularidad de que aparte de albergar un contenido, nos generará una AdornerLayer para nuestro uso y disfrute.

O sea, tal que así:

<AdornerDecorator>
        <DockPanel>

            <Grid>
                <Rectangle Width="800" Height="600" VerticalAlignment="Top" HorizontalAlignment="Left"
                           Visibility="Visible" />
                <designerCanvas:Designer Background="Transparent">                   
                    <i:Interaction.Behaviors>
                        <rubberBand:RubberBandSelectionBehavior></rubberBand:RubberBandSelectionBehavior>
                    </i:Interaction.Behaviors>                    
                </designerCanvas:Designer>
                <Grid x:Name="GridOverlay" IsHitTestVisible="False" />
            </Grid>

        </DockPanel>
    </AdornerDecorator>

La cosa interesante de esto es que la capa generada estará limitada a la zona donde se declara. Es decir, que si ponemos un adorno en esa capa y un elemento de la misma se sale de los bordes de la capa, ¡tendrá clipping! O sea, que se recortará y desaparecerá en vez de dibujarse por encima de la ventana Sonrisa

image

Ahora el adorner se queda por detrás. Way cool, boy!

Esto es la mar de interesante para, por ejemplo, hacer rectángulos de selección o agarres (handlers) para redimensionar objetos.

Vamos, que es una chulada.