26 de Octubre 2005

Metodos de una linea

Nadie dice que sea razonable pensar en métodos de una sóla línea, pero todos
sabemos que uno de 20 es mejor que uno de 200 ¿o alguien lo duda?

El caso es:¿por que no 10 en vez de 20? Y sólo 5? llevar la ídea al extremo y
pensar en métodos de una línea nos puede ayudar a aprender algo que luego
podamos aplicar en nuestros métodos de 100+ líneas.

(Mejor explicado en: http://blogs.msdn.com/jaybaz_ms/archive/2004/06/13/154918.aspx y
http://www.langrsoft.com/articles/smallMethods.shtml y
http://c2.com/cgi/wiki?LotsOfShortMethods )


Y por supuesto no estamos hablando de "concentrar" el código en una sóla
línea que haga muchas cosas (tipo cosas Perl o C++)


Ejemplos


En las pruebas unitarias de la EnterpriseLibrary hay métodos de una línea:


[TearDown]
public void CleanOutDatabase()
{
backingStore.Flush();
}

[Test]
public void CanGetCountOfItems()
{
Assert.AreEqual(0, backingStore.Count);
}

Y una clase de código de producción de entlib con métodos de una sóla línea

namespace Microsoft.Practices.EnterpriseLibrary.Caching
{
internal class StartScavengingMsg : IQueueMessage
{
private BackgroundScheduler callback;

public StartScavengingMsg(BackgroundScheduler callback)
{
this.callback = callback;
}

public void Run()
{
callback.DoStartScavenging();
}
}
}

El otro día viendo el código de BTSUnit nos encontramos con la clase.


public class StreamFromString : MemoryStream
{
public StreamFromString(string input) : base(Encoding.UTF8.GetBytes(input))
{

}
}

Que no tiene más métodos que el constructor con una sóla línea.

Mi conclusión personal, es que siempre que me encuentro con métodos de
pocas líneas suelen representar un buen diseño.

Por otro lado, pensar en que la recomendación "muchos métodos cortos mejor
que pocos métodos largos" no creo que haga daño a nadie y es el primer paso
para realizar la transición entre programación estructurada y OO.


Normalmente no es fácil preveer a priori el número de clases que vamos a
necesitar para implementar una determinada funcionalidad, siempre se puede
empezar con una clase a la que añadir una gran método, después partirlo más
métodos y cuando tenga muchos agruparlos en clases, después de unos pocos
Refactorings se puede ir "moldeando" el diseño, con el número de clases por
assembly, métodos por clase, y líneas por método justos y necesarios para
expresar el dominio del problema con código que funcione


Clean code that works !!

Posted by rido at 10:17 PM

20 de Julio 2004

Escribir algo

Desde que tengo mi blog en msdn practicamente no escribo nada aqui, y es que no se si a alguien le resultaria interesante leer lo que escribo en inglés traducido al castellano.


Además ultimamente no paro de tener esa sensación de que las cosas se quedan obsoletas tan rápido que a veces no da tiempo ni a escribir nada acerca de ellas.

Posted by rido at 11:29 PM | Comments (0)

24 de Enero 2004

XSD como sistema de tipos

Esta es la gran apuesta de la industria, debemos usar XSD para definir los tipos de nuestros interfaces publicos

al fin y al cabo es lo que necesita SOA no

Una buena discusion acerca de XSD en Whidbey, la tenemos
aqui

Posted by rido at 11:18 AM | Comments (12)

22 de Enero 2004

Toolbox

De vez en cuando me gusta echar un vistazo a las herramientas que van saliendo para .NET.
En sitios como http://sharptoolbox.madgeek.com/Default.aspx mantienen una lista bastante completa y bien ordenada de las mejores herramientas que nos podemos encontrar.

Posted by rido at 11:38 AM | Comments (18)

9 de Diciembre 2003

1591

Este es el numerito mágico que hay que dar a VS para que deje de dar la coña con los comentarios XML...

Posted by rido at 6:04 PM | Comments (1)

19 de Noviembre 2003

I Love Compiler Errors

No se cual es la frase exacta en inglés, pero el caso es que los
errores generados por los compiladores pueden ser una gran
herramienta que nos ayude a generar la lista de tareas
para la implementación, siempre y cuando claro, usemos TDD.


A continuación un ejemplo de una lista de tareas para implementar la clase RequestDAL (DataAccessLayer) generado por el compilador de VS.

line (29): 'GdN.AsyncDispatcher.Test.DbUtil.TestDbCommands' does not contain a definition for 'DeleteRequest'
line (37): The type or namespace name 'RequestDAL' could not be found (are you missing a using directive or an assembly reference?)
line (37): The type or namespace name 'RequestMode' could not be found (are you missing a using directive or an assembly reference?)
line (38): The best overloaded method match for 'GdN.AsyncDispatcher.Test.RequestDALTester.assertOperation_expectedFromDb(System.Guid, string, string)' has some invalid arguments
line (38): Argument '1': cannot convert from 'int' to 'System.Guid'
line (44): The type or namespace name 'RequestDAL' could not be found (are you missing a using directive or an assembly reference?)
line (45): The type or namespace name 'RequestDAL' could not be found (are you missing a using directive or an assembly reference?)
line (46): The best overloaded method match for 'GdN.AsyncDispatcher.Test.RequestDALTester.assertOperation_expectedFromDb(System.Guid, string, string)' has some invalid arguments
line (46): Argument '1': cannot convert from 'int' to 'System.Guid'
line (52): The type or namespace name 'RequestDAL' could not be found (are you missing a using directive or an assembly reference?)
line (53): The type or namespace name 'RequestDAL' could not be found (are you missing a using directive or an assembly reference?)
line (65): 'GdN.AsyncDispatcher.Test.DbUtil.TestDbCommands' does not contain a definition for 'GetRequest'

Posted by rido at 11:55 PM | Comments (28)

7 de Noviembre 2003

Como configurar un Proxy para System.Net

Ayer estaba programando en casa, donde tengo salida directa a internet.

Cuando he llegado hoy a la oficina, habia un par de pruebas que ya no funcionaban, el error era que no podia resolver el nombre
de un web service remoto, ya que desde la ofi siempre salimos con un proxy,

Como no parecia muy buena idea añadir código para indicarle el proxy, me he puesto a buscar cual seria la mejor forma de de hacerlo con
ficheros de configuración.

Y aqui esta la solución:

<br /> <system.net><br /> <defaultProxy><br /> <proxy proxyaddress="http://madproxy:80" <br /> bypassonlocal = "true" /><br /> </defaultProxy><br /> </system.net><br />

Posted by rido at 4:13 PM | Comments (15)

29 de Octubre 2003

Configuración de VS + NUnit

Hoy he vuelto a intentar la macro, sigue dando problemas,
el UI no es útil, y hacerlo bien me va a llevar tiempo asi que lo
necesito es algo ... "quick and dirty".

Paso de UI, y con unas ctes me apaño, de paso hago
un poco de Refactoring y para terminar lo dejo todo en un ficherito como este..


'--------------------------------------------------------------
'written by rido'03 (rido@ya.com)
'------------------------------------------------------------
Imports System
Imports EnvDTE
Imports System.Diagnostics
Imports VSLangProj

#Region "Path to NUnit"
Public Module NUnitConstants
Public Const BASE_PATH As String = "c:\Program Files\NUnit v2.1\bin\"
Public Const NUNIT_FX_ID As String = "nunit.framework.dll"
Public Const NUNIT_FX As String = BASE_PATH & "nunit.framework.dll"
Public Const NUNITGUI_RUNNER As String = BASE_PATH & "nunit-gui.exe"
End Module
#End Region

Public Module TestProjectConfigurator

Dim currentProject As VSProject

#Region "Private"

Private Sub removeReference(ByVal referenceIdentity As String)
currentProject.References.Find(referenceIdentity).Remove()
End Sub
Private Sub addReference(ByVal referencePath As String)
currentProject.References.Add(referencePath)
End Sub

Private Sub resetDebugProperties()
Dim configProps As Properties = currentProject.Project.ConfigurationManager.ActiveConfiguration.Properties
With configProps
.Item("StartAction").Value = prjStartAction.prjStartActionProject
.Item("StartProgram").Value = ""
.Item("StartArguments").Value = ""
End With

End Sub

Private Sub setDebugProperties(ByVal runnerPath As String)
Dim assemblyName As EnvDTE.Property = CType(currentProject.Project.Properties.Item("AssemblyName"), EnvDTE.Property)
Dim configProps As Properties = currentProject.Project.ConfigurationManager.ActiveConfiguration.Properties
With configProps
.Item("StartAction").Value = prjStartAction.prjStartActionProgram
.Item("StartProgram").Value = runnerPath
.Item("StartArguments").Value = assemblyName.Value + ".dll"
End With
End Sub

Private Sub resetProject()
removeReference(NUNIT_FX_ID)
resetDebugProperties()
End Sub
Private Sub configureProject()
addReference(NUNIT_FX)
setDebugProperties(NUNITGUI_RUNNER)
End Sub
#End Region
Public Sub Run()
currentProject = DTE.ActiveSolutionProjects(0).Object
configureProject()
End Sub

Public Sub ResetConfig(ByVal nada As Object)
currentProject = DTE.ActiveSolutionProjects(0).Object
resetProject()
End Sub
End Module

Posted by rido at 10:59 PM | Comments (11)

28 de Octubre 2003

Ejecutar un BAT

He tenido problemas para ejecutar un bat y redirigir la salida a la consola, aqui está el ejemplo:

Process p = null;
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = Path.GetFullPath( MOCK_BASE_PATH + "buildMockAssemblies.bat");
psi.WorkingDirectory = Path.GetFullPath(MOCK_BASE_PATH);
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
p = Process.Start(psi);
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Console.WriteLine(output);

Posted by rido at 1:01 PM | Comments (23)

20 de Octubre 2003

Memento Design Pattern

La serialización de objetos es una tecnología que nos permite persistir el estado de un objeto y rehidratarlo después.

Gracias a este mecanismo podemos desacolar subsistemas facilmente.

Pero a veces nos econtramos con objetos que no cumplen con los requisitos de serialización estándar.

Estos objetos se pueden serializar gracias al Memento Design Pattern ...

http://www.ondotnet.com/pub/a/dotnet/2002/09/09/memento.html

Posted by rido at 8:55 AM | Comments (21)

3 de Octubre 2003

Serializar Objetos

La serialización de objetos siempre me ha parecido una característica muy importante en cualquier arquitectura, nos permite:



  • Desacoplar sistemas basándonos en su representación serializada
  • Crear value objects con datos desde su representación serializada

En .NET tenemos dos tipos de serializadores: XmlSerializer y SoapFormatter (tb está el BinaryFormatter, pero ese lo dejamos para otro día).
La principal diferencia radica en que el primero serializa el interfaz público de la clase y los Formatter serializan el ObjectGraph de la instancia en memoria.

Gracias a esta clase podemos serializar objetos como strings XML, lo mejor es que no es necesario crear un fichero físico y podemos serializarlo en memoria:

 using System;
 using System.IO;
 using System.Xml.Serialization;
 
 

namespace ListSerializerDemo
{
···public class XmlSerializerHelper
···{
······static public string Serialize(object o)
······{
·········string result = String.Empty;
·········XmlSerializer ser = new XmlSerializer(o.GetType());
·········MemoryStream s = new MemoryStream();
·········ser.Serialize(s, o);
·········s.Position = 0;
·········StreamReader sr = new StreamReader(s, System.Text.Encoding.UTF8);
·········result = sr.ReadToEnd();
·········sr.Close();
·········s.Close();
·········return result;
·········}
······}
}

Posted by rido at 9:25 PM | Comments (14)

24 de Septiembre 2003

Generador de clases de Test

Hoy me ha tocado añadir UnitTests a un proyecto ya empezado, por lo que no he podido usar TDD.

Buscando he encontrado una macro que genera el equeleto de las pruebas basado en el codigo actual.

http://www.pcisys.net/~gweakliem/Gordon/UnitTesting.html

Posted by rido at 4:26 PM | Comments (30)

16 de Septiembre 2003

Utilidades .NET

Otro web con buenas utilidades para .NET

http://www.sliver.com/dotnet/index.aspx

Posted by rido at 4:54 PM | Comments (17)

15 de Septiembre 2003

.Net y Código Confibale

Esta entrada en el blog de Iván da un buen resumen de lo que se puede hacer y como con Code Access Security

Posted by rido at 11:51 AM | Comments (27)

dotNet Reflector

dotNet Reflector es una gran herramienta para examinar el contenido de Assemblies. Como dicen en inglés "a must tool"



Se puede encontrar en : http://www.aisto.com/roeder/dotnet/

Posted by rido at 11:38 AM | Comments (15)

4 de Septiembre 2003

Test Projects con VS

Ahora el 95 (%) del código que escribo está acompañado de PruebasUnitarias.

Esto significa que cada vez que quiero (ejecutar, depurar, probar..) tengo varias opciones.


1)Abrir NUnit, cargar el assembly y RunTests !
2)Pegarme al proceso con DebugProcess de VS
3) configurar el proyecto para que al ejecutar arranque NUnit.

Esta ultima es la que hago más amenudo, asi que harto de repetir
la misma tarea una y otra vez he decido hacer una macro:

 Imports EnvDTE
 Imports System.Diagnostics
 Imports VSLangProj
 
 

Public Module NUnitProjectEnabler

Private CurrentProject As VSProject
Private Const NUNIT_PATH As String = "c:\Program Files\NUnit V2.0\bin\nunit.framework.dll"
Private Const NUNITGUI_PATH As String = "c:\Program Files\NUnit V2.0\bin\nunit-gui.exe"

Private Sub setTargetProject()
CurrentProject = DTE.ActiveSolutionProjects(0).Object
End Sub
Private Sub AddNUnitRef()
CurrentProject.References.Add(NUNIT_PATH)
End Sub

Private Sub SetDebugProperties()

Dim assemblyName As EnvDTE.Property = CType(CurrentProject.Project.Properties.Item("AssemblyName"), EnvDTE.Property)

Dim configProps As Properties = CurrentProject.Project.ConfigurationManager.ActiveConfiguration.Properties

With configProps
.Item("StartAction").Value = prjStartAction.prjStartActionProgram
.Item("StartProgram").Value = NUNITGUI_PATH
.Item("StartArguments").Value = "/assembly:" + assemblyName.Value + ".dll"
End With

End Sub

Public Sub EnableProject()
setTargetProject()
AddNUnitRef()
SetDebugProperties()
End Sub
End Module

como veis las rutas estan puestas a "capon"..

Posted by rido at 8:43 PM | Comments (2)

Consultas XPath

El parser XML con el que estoy más familiarizado sigue siendo MSXML, sorprendente ¿no?

Tiene una explicación, en .NET vemos XML en todos sitios (ficheros de configuración, DataSets, esquemas...)
pero siempre encuntras unas clases que te abstraen de la tediosa tarea de masticar el XML.

Hoy ha sido el primer día que me he visto en la necesidad de consultar un stream XML, ha costado un
poco, sobre todo por que los Namespaces que definian el documento.

El documento:

<br /> <?xml version="1.0" encoding="utf-8" ?><br /> <soap:Envelope xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing" <br /> xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility"<br /> xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><br /> <soap:Header>....</soap:Header><br /> <soap:Body><br /> <soap:Fault><br /> <faultcode xmlns:code="http://schemas.xmlsoap.org/ws/2002/12/secext"><br /> code:FailedCheck<br /> </faultcode><br /> <faultstring><br /> ..The signature or decryption was invalid at..<br /> </faultstring><br /> <faultactor>http://localhost/RidoCode.WSEDemos.Web/HRSystem.asmx</faultactor><br /> </soap:Fault><br /> </soap:Body><br /> </soap:Envelope><br />

Obtener el contenido del nodo faultcode con MSXML es tan sencillo como

 Public Function parseSoapFault(xml as String) as String
 ···Dim doc as new MSXML.DOMDocument
 ···Dim node as MSXML.IXMLNode
 ···doc.loadXml(xml)
 ···node = selectSingleNode("/soap:Envelope/soap:Body/soap:Fault/faultcode")
 ...parseSoapFault = node.value
 End Public
 

Lo que no me gusta de este método es que necesito guardar todo el DOM en memoria,
igual que si fuese a modificar el documento, con System.Xml tenemos otra alternativa,
que se basa en usar la clase XPathNavigator para poder cargar el DOM en modo
sólo lectura. Además en vez de trabajar con strings cargamos el documento
directamente desde un Stream. Este el código resultante:

 public static string parseSoapFault(Stream responseStream)
 {
 	string result = String.Empty;
 	XPathDocument doc = new XPathDocument(responseStream);
 	XPathNavigator nav = doc.CreateNavigator();
 	XPathExpression expr = nav.Compile("/soap:Envelope/soap:Body/soap:Fault/faultcode");
 	XmlNamespaceManager context = new XmlNamespaceManager(nav.NameTable);
 	context.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
 	expr.SetContext(context);
 	XPathNodeIterator iter = nav.Select(expr);
 	iter.MoveNext();
 	result = iter.Current.Value;
 	responseStream.Close();			
 	return result;	
 }
 
Posted by rido at 9:35 AM | Comments (36)

27 de Agosto 2003

ToDo List

Desde que leí Test Driven Development siempre
trabajo con Lista de "por hacer", en inglés:
ToDo List.

Las "TODO Lists" Son una herramienta muy util para ayudar a gestionar las prioridades a medida que avanza el desarrollo.

Como ejemplo la lista que tengo para el sencillo control XMLViewer.


  • Eliminiar referencia a MSHTML

  • Gestión de Excepciones

  • Mejorar la transformación xsl ¿Usar Streams en vez de strings?

El problema (como siempre) es tener tiempo para implementar todo.

Posted by rido at 11:06 PM | Comments (17)