martes, julio 28, 2009

TDD - Desarrollo Guiado Por Pruebas

En la reunión 30 de la comunidad TjNet estaré presentando el tema TDD (Test Driven Development), el cual es una práctica de programación que consiste en escribir primero las pruebas unitarias, después el código que cumple con las pruebas y refactorizar el código escrito.

La idea principal es que el comportamiento esperado del objeto que estamos probando lo definamos en pruebas y después nos preocupemos por que el objeto cumpla con lo que se definió en las pruebas.

Cabe aclarar que el TDD es una actividad del equipo de desarrollo y no del equipo de QA que realiza las pruebas al software. La intención de las pruebas unitarias no es que el equipo de calidad las use para realizar su trabajo. Las pruebas unitarias son para definir el comportamiento del código que vamos escribir, es decir es parte del diseño. Aunque sí aumentan en cierta forma la calidad del código escrito.

Efectos del desarrollo guiado por pruebas

Algunos de los efectos notables sobre el desarrollo guiado por pruebas es que se evita escribir código que no se utilizará. Ya que se trata de realizar solamente el código necesario para poder satisfacer las pruebas definidas.

Otro efecto que se obtiene al trabajar de esta manera es que como nuestras clases ya no solo van a ser utilizadas por la aplicación, sino también por el código de prueba, esto nos obliga a tener clases débilmente acopladas y que hacen uso de dependencias solo a través de interfaces, independientemente de la implementación. De tal forma que sea fácil utilizar ciertas clases concretas para la aplicación y otras para las pruebas. Para esto es común aplicar el principio de inyección de dependencias.

El mantenimiento del código es más manejable, la confianza en el código mejora, por que las pruebas nos sirven como alerta cuando introducimos código que hace que nuestras pruebas fallen. En lugar de introducir cambios al código sin saber cómo afectan a otras clases del sistema.

El uso del depurador disminuye ya que cuando existe un error en el código es más fácil encontrarlo en las pruebas que corriendo la aplicación en modo debug.

Ciclo de desarrollo

1. Escribir el comportamiento deseado (requerimiento) a manera de prueba unitaria, Este paso fuerza al programador a tomar la perspectiva de un cliente considerando el código a través de sus interfaces. Obviamente la prueba fallará ya que aun no está escrito el código para satisfacerla.

2. Escribir solo el código necesario para que la prueba pase.

3. Correr las pruebas para confirmar que efectivamente el código escrito cumple con los establecido por las pruebas.

4. Refactorizar el código, para eliminar código duplicado y dejarlo de tal forma que sea fácil hacerle modificaciones en el futuro.

5. Verifica que las pruebas no fallen después de la refactorización.

Conclusión

El desarrollo guiado por pruebas no es parte del proceso de calidad de un sistema en desarrollo (aunque si aumenta la calidad del código escrito) sino que forma parte del diseño de cada clase; define el comportamiento esperado de la clase desde el punto de vista del cliente que la usará.

Los espero en la reunión 30 de la comunidad TjNet.

miércoles, junio 17, 2009

Agile Programming Coffee Camp



Tijuana Agile Programming Coffee Camp en el devolada de otay (el lugar de costumbre) el sábado 4 de Julio, a partir de las 9:00am.

La idea surgió de una conversación en twitter entre @mario_chavez y @fcastellanos a la que nos sumamos @gabo y yo. Y como 140 caracteres no es suficiente y varios queremos participar; pues mejor platiquemos sobre el tema tomando café.

Cualquiera puede participar, es una platica entre colegas, el costo es según el tamaño del café que pidas.

Si conoces del tema asiste a compartir tus experiencias, y si no, es una buena oportunidad para aprender.

Mas información (mapas, fotos y Dilbert) en:
TjNet
blog de Mario Chavez
blog de Fernando Castellanos

sábado, mayo 30, 2009

ASP.NET MVC Routing Validations

Ayer asistí a la reunión de la comunidad TjNet fue la presentación sobre ASP.Net MVC que dieron Mario Chavez y Fernando Castellanos. Hubo pocos asistentes sin embargo hubo varias preguntas interesantes, incluso falto tiempo para seguir con las preguntas.

Algo que se preguntó ahí en la reunión fue: ¿Como restringir el routing en ASP.NET MVC con expresiones regulares? Mencioné que si se podía pero en ese momento no me acorde como hacerlo ;), bueno pues aquí muestro un ejemplo.

Una vez creado un nuevo proyecto de asp.net mvc desde visual studio, voy a agregar dos métodos al HomeController
public ActionResult WelcomeByName(string name)
{
ViewData["Message"] = "Bienvenido, tu nombre es: " + name;
return View("Index");
}

public ActionResult WelcomeById(int id)
{
ViewData["Message"] = "Welcome, your user ID is " + id;
return View("Index");
}
mi idea es que si el usuario pone la dirección /Welcome/{cadena}
se ejecutará el metodo WelcomeByName (mensaje en español) y si el usuario escribe /Welcome/{entero} se ejecutará el metodo WelcomeById (mensaje en ingles).

Para ello debo de agregar entradas a mi tabla de rutas que se crea en el archivo Global.asax
routes.MapRoute(
"Welcome int",
"Welcome/{id}",
new { controller = "Home", action = "WelcomeById" },
new { id = @"^\d+$" }
);

routes.MapRoute(
"Welcome s",
"Welcome/{name}",
new { controller = "Home", action = "WelcomeByName", name = "anonimo" }
);
Estas dos entradas las puse antes de la entrada "Default". La primera ruta indica que espera una dirección con la forma "Welcome/{id}" para ejecutar la acción WelcomeById del HomeController, pero ademas agrega una restricción (usando expresiones regulares) que indica que solo se usara esta ruta si el parámetro "id" es entero positivo (o cero). Entonces si el valor de id no cumple con la condición no se usará esa ruta y se buscará otra para ser utilizada.

La segunda ruta es similar a la primera solo que no tiene restricción alguna, por lo tanto si es entero el valor se ejecuta la primera, para las demás (que inicien con "Welcome") se ejecuta la segunda.

Corro la aplicación y escribo la dirección en el navegador y compruebo que las rutas funcionen















Pueden encontrar mas información sobre esto en la grabación de la VAN de Alt.Net Hispano. Sobre ASP.NET MVC Avanzado explicada por Hadi Hariri.

miércoles, abril 29, 2009

ASP.NET MVC MyTwitter (Parte 2)

Como parte de la serie sobre el desarrollo de una aplicación similar a Twitter para aprender ASP.NET MVC. Voy a seguir con la parte de registro (Signup). Esta semana he estado ocupado con trabajo, por eso agregaré poca funcionalidad en este post, la cual consiste en que una vez que el usuario se registre debemos de iniciar sesión con ese usuario, es decir identificarlo como un usuario Autentificado.

Para ello es necesario escribir una clase (y una Interfaz) que me ayude en esta funcionalidad, para después hacer un mock de ella en el test del AccountController.

namespace MyTwitter.Models
{
public interface IFormsAuthenticationTasks
{
void SetAuthCookie(string username, bool createPersistentCookie);
void SignOut();
}
}
using System.Web.Security;
namespace MyTwitter.Models
{
public class FormsAuthenticationTasks
: MyTwitter.Models.IFormsAuthenticationTasks
{
public void SetAuthCookie(string username,
bool
createPersistentCookie)
{
FormsAuthentication.SetAuthCookie(
username, createPersistentCookie);
}

public void SignOut()
{
FormsAuthentication.SignOut();
}
}
}

agrego una variable de tipo IFormsAuthenticationTasks al AccountController y al constructor usado para las pruebas

public class AccountController : Controller
{
private IUserRepository userRepository;
private IFormsAuthenticationTasks formsAuthenticationTasks;

public AccountController(IUserRepository userRepository,
IFormsAuthenticationTasks formsAuthenticationTasks)
{
this.userRepository = userRepository ?? new UserRepository();
this.formsAuthenticationTasks =
formsAuthenticationTasks ?? new FormsAuthenticationTasks();
}

public AccountController()
: this(null, null)
{
}
...

escribo el test para la nueva funcionalidad

[TestMethod]
public void Login_User_After_Signup()
{
formsAuthenticationMock.Setup(
fa => fa.SetAuthCookie(It.IsAny<string>(), It.IsAny<bool>()));
controller.Signup(null);
formsAuthenticationMock.VerifyAll();
}

implemento la funcionalidad en el método Signup del Account Controller para que la prueba pase, es solo agregar una línea antes del redirect

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Signup(FormCollection formValues)
{
var user = new User();
UpdateModel(user);
userRepository.Add(user);
userRepository.Save();

formsAuthenticationTasks.SetAuthCookie(user.Username, true);

return Redirect("/invitations");
}
Hasta aquí con esta parte. Estuve tentado a llamarla “Parte 1.5” en lugar de “Parte 2”, por el poco contenido, pero se iba a empezar a complicar la numeración, continuaré con la serie en siguientes posts.

viernes, abril 24, 2009

ASP.NET MVC MyTwitter (Parte 1)

En la parte 0 de esta serie sobre ASP MVC MyTwitter hice la base de datos (la cual cambie un poco desde el pasado post) para iniciar el desarrollo de la aplicación. Ahora voy a generar el modelo de datos (LINQ to SQL classes) para eso en el folder de Models agrego el modelo de datos.

image

Le doy clic con el botón derecho en el folder de Models y le hago clic en “Add/New Item” y selecciono “LINQ to SQL Classes” y le pongo el nombre MyTwitter.dbml

image Arrastro desde el server explorer las tabla de la base de datos al modelo de datos, para que mi modelo quede así.

Cambie el nombre de la tabla UserFriends por Friends y la columna Friend por FriendName. Esto fue con el propósito de que quedaran con mejor nombre las clases generadas por LinqToSql.

Ahora empiezo con la pagina de inicio, esta seria solo un formulario para iniciar sesión y un link para registrarse si es que no se tiene una cuenta. Para ello abro la página Views/Home/Index.aspx y escribo el la forma en el HTML

<form action="/account/login" method="post">
<
fieldset>
<
p>
<
label for="username">Usuario</label>
<%= Html.TextBox("username") %>
<%= Html.ValidationMessage("username", "*") %>
</p>
<
p>
<
label for="password">Contrase&ntilde;a</label>
<%= Html.Password("password") %>
<%= Html.ValidationMessage("password", "*") %>
</p>
<
p>
<
input type="submit" value="Ingresar" />
</
p>
<
p>Si no tienes una cuenta registrate <a href="/signup">aqui</a>.</p>
</
fieldset>
</
form>

De igual manera también modifico la prueba unitaria que viene por omisión en nuestro proyecto de test (MyTwitter.Tests) dentro del archivo HomeControllerTest.cs.

[TestMethod]
public void Index()
{
HomeController controller = new HomeController();
var result = controller.Index();
Assert.IsNotNull(result);
}

Solo pruebo que el método Index() del HomeController regrese un View que no sea null.

Para realizar el registro de usuario voy a agregar un controller llamado AccountController, similar al que venia por default al crear al proyecto.


image



Hago clic en el folder Controllers y selecciono la opción “add controller”. y le pongo el nombre de “AccountController”.

Esto me agrega una nueva clase AccountController que hereda de la clase Controller con un método llamado Index. por el momento elimino el método Index, ya que todavía no lo voy a usar (casi no me gusta tener código que no hace nada) y agrego un método llamado Signup().

namespace MyTwitter.Controllers
{
public class AccountController : Controller
{
public ActionResult Signup()
{
throw new NotImplementedException();
}
}
}
Ahora el unit test

image



En el folder Controllers del proyecto MyTwitter.Tests selecciono “Add > New Test..” y selecciono “Unit Test” y le doy el nombre de AccountControllerTest. Esto me agrega una clase con código de ejemplo.

Quito el código que genera para quedar con una prueba sencilla que verifica que se regrese un view para realizar el registro.

[TestMethod]
public void Return_A_View_For_Signup()
{
var result = controller.Signup();
Assert.IsNotNull(result);
}
Implemento el método de Signup en el AccountController, este simplemente (como el test lo indica) regresará el view necesario para que el usuario ingrese sus datos de registro
public ActionResult Signup()
{
return View();
}
Para agregar el View abro el menú contextual sobre el método Signup y selecciono “Add View”
image

image



Aparece un dialogo para agregar un view. aquí habilito la opción “Create a strongly-typed view” y selecciono (en “View data class:”) la clase MyTwitter.Models.User, En “View content” selecciono la opción Create. Esto para que VisualStudio escriba la mayoría del HTML por mi. Esto agrega un archivo (Views\Account\Signup.aspx) , lo abre en el editor y lo modifico para que quede en español.

El view queda así:

<% using (Html.BeginForm()) {%>

<fieldset>
<
legend>Fields</legend>
<
p>
<
label for="Username">Usuario:</label>
<%= Html.TextBox("Username") %>
<%= Html.ValidationMessage("Username", "*") %>
</p>
<
p>
<
label for="FullName">Nombre Completo:</label>
<%= Html.TextBox("FullName") %>
<%= Html.ValidationMessage("FullName", "*") %>
</p>
<
p>
<
label for="Password">Contraseña:</label>
<%= Html.Password("Password") %>
<%= Html.ValidationMessage("Password", "*") %>
</p>
<
p>
<
label for="ConfirmPassword">Confirmar Contraseña:</label>
<%= Html.Password("ConfirmPassword") %>
<%= Html.ValidationMessage("ConfirmPassword", "*") %>
</p>
<
p>
<
label for="Email">Correo Electronico:</label>
<%= Html.TextBox("Email") %>
<%= Html.ValidationMessage("Email", "*") %>
</p>
<
p>
<
label for="Url">Sitio Web:</label>
<%= Html.TextBox("Url") %>
<%= Html.ValidationMessage("Url", "*") %>
</p>
<
p>
<
label for="Bio">Biografia:</label>
<%= Html.TextBox("Bio") %>
<%= Html.ValidationMessage("Bio", "*") %>
</p>
<
p>
<
label for="Location">Ubicacion:</label>
<%= Html.TextBox("Location") %>
<%= Html.ValidationMessage("Location", "*") %>
</p>
<
p>
<
input type="submit" value="Create" />
</
p>
</
fieldset>

<% } %>
Las funciones de la clase Html me ayuda a no tener que escribir todo el HTML a pie (o mejor dicho a mano), no explicare como funcionan (creo que el nombre de cada método describe bien lo que hace) basta decir que escriben HTML. Uso Html.BeginForm sin parámetros en lugar de escribir el HTML para un <form> y así el action es al mismo url actual pero con el method=”post”. en este caso seria equivalente a escribir <form action=”/signup” method=”post”> y al cerrar el using (<% } %>) se escribe el </form>.

Ahora voy a implementar el código que se ejecutará cuando el usuario haga submit a esta forma, para esto creo un nuevo método en el AccountController llamando también Signup la diferencia con el otro son los parámetros que recibe (en este caso los valores de la forma) y un atributo para que solo reciba peticiones de tipo POST.

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Signup(FormCollection formValues)
{
throw new NotImplementedException();
}

Antes de implementar la función quiero escribir un test para probar que el método Signup trate de guardar la información en la base de datos, pero sin hacer una llamada real a la base de datos, para esto voy a crear una clase UserReposotory que será la que se encargue de cargar los datos. También voy a crear una Interfaz para poder hacer un mock del repository. Esta clase e interfaz las pongo dentro del folder Models cada una en su propio archivo.

namespace MyTwitter.Models
{
public interface IUserRepository
{
void Add(User user);
User GetUser(string username);
void Save();
}
}
namespace MyTwitter.Models
{
public class UserRepository : IUserRepository
{
private MyTwitterDataContext db;

public UserRepository()
{
db = new MyTwitterDataContext();
}

public User GetUser(string username)
{
return db.Users.FirstOrDefault(u => u.Username == username);
}

public void Add(User user)
{
db.Users.InsertOnSubmit(user);
}

public void Save()
{
db.SubmitChanges();
}
}
}
Ahora sí, ya puedo empezar a escribir mi prueba en AccountControllerTest. Para no tener que hacer uso de la base de datos en las pruebas unitarias utilizo Moq, el cual es un mock framework que se puede descargar aquí.

image Una vez descargado moq, agrego una reference al moq.dll en el proyecto MyTwitter.Tests y agrego el using Moq; en el AccountControllerTest.cs. Con la ayuda de este framework vamos probar que el AccountController llame el metodo Add y Save del UserRepository.

Para no repetir la inicialización del repositoryMock y del controller, voy a agregarlos como variables de clase e inicializarlos en un método SetUp

[TestClass]
public class AccountControllerTest
{
private AccountController controller;
private Mock<IUserRepository> repositoryMock;

[TestInitialize]
public void Setup()
{
repositoryMock = new Mock<IUserRepository>();
controller = new AccountController(repositoryMock.Object);
}
...
Ahora agrego los métodos de prueba
[TestMethod]
public void Add_And_Save_User_To_Repository()
{
repositoryMock.Setup(r => r.Add(It.IsAny<User>()));
repositoryMock.Setup(r => r.Save());

controller.Signup(new FormCollection());

repositoryMock.VerifyAll();
}

Además voy a agregar un test para probar que, una vez que se realice el registro del usuario, se envíe al usario a la pagina “/invitations” para que ahí el usuario pueda agregar amigos (friends) a quien seguir.

[TestMethod]
public void Redirect_To_Invitations_After_Signup()
{
var result = controller.Signup(new FormCollection()) as RedirectResult;

Assert.AreEqual("/invitations", result.Url);
}
Si corro el test ahora fallará porque no lo he implementado, entonces ahora lo que debo de hacer es que el test pase. Para ello declaro un IUserRepository en la clase AccountController y 2 constructores, uno que usare en el código en producción y el otro para las pruebas.
public class AccountController : Controller
{
private IUserRepository userRepository;

public AccountController(IUserRepository userRepository)
{
this.userRepository = userRepository ?? new UserRepository();
}

public AccountController()
: this(null)
{
}
...
ahora si, por fin implemento el método Signup en el AccountController
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Signup(FormCollection formValues)
{
var user = new User();
UpdateModel(user);
userRepository.Add(user);
userRepository.Save();

return Redirect("/invitations");
}
[tanto blog post para este método tan sencillo :) ]

image Ejecuto las pruebas unitarias y verifico que el código hace lo que se supone debe hacer.

Si ejecuto la aplicación y en la pagina de inicio hago clic en el enlace para registrase me manda a “/signup” y me marca error por que no encuentra el recurso. Para que al buscar el recurso /signup se ejecute el action Signup del AccountController, debo de agregar un Route en el archivo Global.asax ( lo agrego antes del Route “Default”).

public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
"Signup",
"signup",
new { controller = "Account", action = "Signup" });

routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);

}

protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
}

con esto ya puedo hacer una pequeña prueba de integración.En la siguiente parte continuare con el desarrollo de esta aplicación.

miércoles, abril 22, 2009

ASP.NET MVC MyTwitter (Parte 0)

Para aprender acerca de ASP.NET MVC voy a realizar una aplicación de prueba que sería la versión en español de twitter (con esta aplicación solo pretendo aprender, no pretendo competir con twitter) que llamaré MyTwitter. Este post lo he titulado parte 0 de la serie por que solo escribiré el setup de la aplicación y a partir de la parte 1 empezare (ahora si) con el desarrollo.

Antes de iniciar debo instalar el ASP MVC Framework, el cual se puede descargar aquí.

 

image

Una vez que instalé el MVC Framework puedo crear un nuevo proyecto en visual studio (no es un Web Site, sino un project).

 

 

 

 image

Después selecciono la plantilla de ASP.NET MVC Web Application y le doy el nombre de MyTwitter

 

 

 

 

 

image

Una vez hecho esto aparece una ventana que me pregunta si quiero un proyecto para las pruebas unitarias. Seleccione la opción de “Yes”. Esto creará una aplicación con 2 controllers (Home y Account). Adema incluye algunas pruebas unitarias para el proyecto de ejemplo. Para este ejemplo voy a quitar el AccountController (y su respectivo test) para crear uno propio.

image

Ahora voy a crear la base de datos. Haciendo clic con el botón derecho en el folder App_Data. Esa opción aparece si se le da con el botón derecho en cualquier parte del proyecto pero me gusta hacerlo sobre el App_Data folder por que así me aparecen los ítems filtrados.

 

image

Selecciono SQL Server Database y le doy el nombre de MyTwitter.mdf. Una vez hecho esto me aparece la nueva base de datos bajo el folder de App_Data Dandole doble clic, me agrega una nueva conexión en el Server Explorer y la abre.

 

 

image

 

Ahora agrego algunas tablas para iniciar el desarrollo del sitio. Por lo pronto agregaremos  Users, Posts y UserFriends.

 

 

 

 

 

 

 

Con esto queda listo nuestro proyecto para empezar a agregarle funcionalidad. En el siguiente post (Parte 1) seguiré con el desarrollo de este proyecto de prueba “MyTwitter”.

martes, marzo 17, 2009

Web 2.0 Coffee Camp TJ

El Sábado 7 de marzo de 2009 nos reunimos en el Café D’Volada de Otay Constituyentes para discutir que es el Web 2.0. Fue una reunión que duro aproximadamente 2 horas. Lo que aprendí de la reunión es que para que una aplicación se pueda considerar como WEB 2.0 debe de cumplir con algunas (no todas) características:

Característica Social

Los usuarios participan activamente en el contenido de la misma. El contenido son opiniones o expresiones personales y no simplemente datos, es decir el contenido es mas subjetivo que objetivo por lo tanto esta abierto a discusión y comentarios. En estos casos podemos encontrar sitios como YouTube, Wikipedia (contenido objetivo, pero abierto a discusión), flickr, twitter.

 

Característica Tecnológica

El sitio utiliza Ajax, tiene un API para ser consumido por clientes desarrollados por terceros. Y pueden o no utilizar RIAS. Esta es una característica no obligatoria. En lo personal al inicio del termino Web 2.0 consideraba esta característica mas importante que la social (tal vez por que soy desarrollador).

 

Característica Visual

Comentaron en la reunión (en lo personal no me ha tocado por que no soy diseñador) que algunas personas relacionan el termino web 2.0 con el aspecto visual de la aplicación. En lo general estuvimos de acuerdo en que esto no basta para que la aplicación sea considerada como WEB 2.0 (tómese en cuenta que a la reunión asistimos desarrolladores y diseñadores). Sin embargo eso me hizo pensar que si preguntamos en la calle a la mayoría de la gente tal vez para ellos web 2.0 requiere esta otra característica que para nosotros (desarrolladores y diseñadores) no es necesaria. Si para los que pagan los desarrollos y los diseños, el web 2.0 se refiere a lo visual y los efectos (muchas veces como resultado de la característica tecnológica) quizás esto deba ser considerado como una característica valida (aunque no me guste la idea).

 

Solo discutieron aplicaciones publicas en el Internet, parece que una aplicación privada que corre dentro de una intranet no es considerada como Web 2.0 aunque la mayoría del contenido de estas aplicaciones es generados por los mismos usuarios de la empresa y pudiera utilizar Ajax. Tal vez si el contenido es social, es decir de opinión de los empleados y no datos generados por el negocio, si se considere Web 2.0 (Creo que es algo que debí preguntar)

 

Algunas de las conclusiones personales de la reunión fueron que: siendo Web 2.0 un termino subjetivo, lo que para unos es web 2.0 para otros no lo es (generalmente depende de la perspectiva). Aunque creo que en lo que todos estuvimos de acuerdo es que: twitter si es Web 2.0. por su característica social.

 

Me quedó pendiente una pregunta...Si los comentarios de mi blog no son filtrados y cualquiera puede opinar ¿Los comentarios de mi blog son Web 2.0?

 

Puedes escuchar la reunión en:

http://www.dev3cast.com/

miércoles, marzo 04, 2009

Podcasts

Esta una lista de los podcasts que actualmente escucho

.Net Rocks
Ya un clasico de los podcasts, tiene la mejor calidad de audio y muy buenos invitados y temas sobre .Net

Deep Fried Bytes
Hablan principalmente sobre desarrollo en .net

Hanselminutes
Scott Hanselman web developer y ahora empleado de Microsoft trata varios temas

Polymorphic Podcast
Arquitectura y programación orientada a objetos en .Net (Ya tiene tiempo que no salen nuevos episodios)

The Poscast @ Delphi.org
podcast sobre Delphi

RunAs Radio
Para profesionales de IT, no es desarrollo pero es bueno conocer sobre IT

The Startup Success Podcast
Podcast para Startups o MicroISVs varios consejos para iniciar tu propio negocio de software

stackoverflow
Tratan temas sobre desarrollo y administración de equipos de desarrollo, principalmente hablan del sitio stackoverflow.com

The Thirsty Developer
Este de los mas recientes en mi lista, hablan principalmente de como se esta usando la tecnología.

dev3cast
Podcast de la comunidad .Net en Tijuana

Software Engineering radio
Ingeniería de software tratan temas que aplican a todas las plataforma y lenguages

miércoles, febrero 25, 2009

Reunión 27 de la comunidad TJ.NET

Hoy será la reunión 27 de la comunidad TJ.NET donde estaré presentando el tema de XML Literals en Visual Basic.

Mostrare como carga un archivo XML y con los datos crear un objeto del dominio y a partir de un objeto del dominio del problema crear un archivo XML. Ademas de mostrar como realizar una búsqueda en el documento XML utilizando LinqToXml.

Debido al poco tiempo sera una presentacion sencilla sin entrar mucho a detalle. Espero que los asistentes tengan preguntas, para hacerlo mas interesante.

domingo, febrero 01, 2009

Iniciando con Test Driven Development (TDD)

Al iniciar con TDD , en algunos proyectos, note que esto ha hecho que cambie mi manera de programar. Ya que al tratar de escribir código de manera que sea testeable, termino escribiendo código mas desacoplado y con mas clases que hacen un trabajo mas especifico y con un poco de dependency injection. también he notado que ahora escribo mucho mas código y el resultado a veces es el mismo que antes (con la desventaja que me tarde mas). Aunque muchas veces los tests me han ayudado a encontrar errores mas rápido y me siento mas seguro de que el código que escribo funciona correctamente.

Por el momento estoy utilizando NUnit y NMock para mis unit test en .Net. Para mi gusto estos frameworks están bien para el tipo de tests que realizo.

Por ejemplo, supongamos que estamos construyendo un registro para usuarios. Y queremos que (cuando un usuario nuevo se registre) se validen los datos del usuario, se inserte a la base de datos y se envié correo de bienvenida.

Al escribir el test para el método de registro, debemos de evitar que este tengan dependencias en otras partes del sistema ya que solo queremos validar que se realicen las reglas de negocio y no tanto como se implementa cada tarea (para cada tarea se realizarán sus propias pruebas unitarias) esto me hace escribir mas clases de tal forma que pueda hacer mock objects para las dependencias.

Entonces en lugar de una sola clase para el registro (RegistrationService) que se encargue de validar, insertar y enviar correo, tendremos varias clases que colaboran para realizar el registro. Como pueden ser: RegistrationService, RegistrationValidator, EmailService y RegistrationDAL. Así podemos probar que el RegistrationService realice la regla de negocio y por separado probar cada una de las tareas. Ademas, si por alguna razón cambia la manera de validar el registro, solo tendríamos que modificar la clase RegistrationValidator y no tenemos que cambiar el resto del proceso de registro. Como ven esto implica realizar mas código, pero se supone que a la larga es mejor, Ahora tenemos código que valida nuestro código.

En mi caso realizar unit tests si me ha ayudado a encontrar errores y a estar seguro de que el código hace lo que tiene que hacer. Aunque debo admitir que hay veces que quisiera no tener que escribir tantas clases y pruebas para cada una de estas clases. En fin todo es cosa de saber que no todo requiere unit test y encontrar el balance entre lo que lo requiere y lo que no.

Firebird 2.1 List Function

The List function in Firebird 2.1.

This is an aggregate function that returns a string with the field values concatenated using a delimiter. the default delimiter is the comma. So it's similar to the SUM function, but instead of adding numbers, this function concatenate strings. if some of the values is null then the function returns null.

So suppose I have 2 tables, projects and resources, and I know that a project will have a few resources assigned. Now I need to write a report of projects showing their resources assigned.

CREATE TABLE projects(
project_id INTEGER,
name string
);

CREATE TABLE resources(
project_id integer,
user_name string
);



Without the LIST function I have to write this query

SELECT
p.project_id as id,
p.name,
r.user_name
FROM
projects p INNER JOIN
resources r ON p.project_id = r.project_id

my result will be like this

id name user_name
-------------------------
1 Project_1 Steve
1 Project_1 John
2 Project_2 Jim
2 Project_2 Ed

Then in the report I will need to group the records with the same project_id so I don't show duplicate projects for each resource assigned.

Now with Firebird 2.1 I can write the query using the LIST function

SELECT
p.project_id AS id,
p.name,
LIST(r.user_name, ', ') AS resources
FROM
projects p INNER JOIN
resources r ON p.project_id = r.project_id
GROUP BY
p.project_id,
p.name


my result will be like this

id name resources
-----------------------------
1 Project_1 Steve, John
2 Project_2 Jim, Ed


then in my report I only need to show the results of my query, I don't need to create groups.

The list function returns a BLOB data type, so if I need to display the result in a grid I often CAST the result to varchar. The delimiter parameter is not required (I added because I like to add a space after the comma). You can see more details of how to use the LIST function in the Firebird 2.1 Release Notes

This function is also useful in reports when you need details values in the same row as the master data like in reports headers or footers.

domingo, diciembre 07, 2008

Firebird 2.1 UPDATE OR INSERT

Another great feature that I like in Firebird 2.1 is the UPDATE OR INSERT statement. It's a really time saver and it makes the SQL cleaner.

For example suppose I have a products table like the one I use in my last post and an inventory table to store the product stock. Before Firebird 2.1 if I want to set the stock for a product I needed to check if a record for that product_id already exists; if the product_id already exists then I write an update. If not then I write an insert statement. So I ended up with something like this:


IF EXISTS(SELECT * FROM inventory WHERE product_id = :product_id ) THEN
UPDATE
inventory
SET
stock = :stock
WHERE
product_id = :product_id;
ELSE
INSERT INTO inventory
(product_id, stock)
VALUES
(:product_id, :stock);

In this example I only update one field but when I have to update a big table I ended up with a big chunk of code and thinking: "there should be another (better) way to do this".

Fortunately now with Firebird 2.1 there is a better way to do it, I only need to use the UPDATE OR INSERT statement and the engine will take care of checking if the record already exists, based on the primary key value. If the table does not have a primary key defined then I should use the MATCHING keyword with the columns I want to match. So in this example the sql can look like this:

--product_id is the primary key

UPDATE OR INSERT INTO inventory
(product_id, stock)
VALUES
(:product_id, :stock);

or like this

--product_id is not defined as the primary key

UPDATE OR INSERT INTO inventory
(product_id, stock)
VALUES
(:product_id, :stock)
MATCHING
(product_id);


This code looks much cleaner and does not need any comments to explain what is going on.

I really like this new feature.

martes, septiembre 02, 2008

Firebird 2.1 Domains in PSQL

I Often use this domains in my Firebird databases

CREATE DOMAIN STRING AS VARCHAR(50) CHARACTER SET ISO8859_1 COLLATE ES_ES_CI_AI; /* for Spanish text */
CREATE DOMAIN MONEY AS DECIMAL(15, 2);
CREATE DOMAIN BOOL AS SMALLINT CHECK VALUE = 0 OR VALUE = 1;

So I can use them in my tables definitions like this:

CREATE TABLE PRODUCTS(
ID INTEGER,
DESCRIPTION STRING,
PRICE MONEY,
ACTIVE BOOL
)
ALTER TABLE PRODUCTS ADD CONSTRAINT PK_PRODUCTOS PRIMARY KEY (ID);

Before Firebird 2.1 when I wanted to create a stored procedure I had to write the data type of the domain instead of the domain name, like in the table definition, so I had to check the domain definition and write the data type on the procedure definition, although IBExpert help with that, my Stored Proc definition end it up not using the domains like this:

CREATE PROCEDURE INSERT_PRODUCT(
DESCRIPTION VARCHAR(50),
PRICE DECIMAL(15, 2),
ACTIVE SMALLINT
)
BEGIN
...
END

Now with version 2.1 I can use domain in PSQL. I just need to type the domain name if i want to inheriting the check clause and the default value, or I can use the TYPE OF keyword if I just want the data type so I can define something like this:

CREATE PROCEDURE INSERT_PRODUCT(
DESCRIPTION STRING,
PRICE TYPE OF MONEY,
ACTIVE BOOL
)
BEGIN
...
END

This way it seems that there is more consistency on my data types.