Usando PowerShell para hacer un backup de sql server express

Viernes, 5 de abril de 2013

Tengo una pequeña base de datos y estoy muy atento a ella. He hecho copias de seguridad de forma más o menos manual durante demasiado tiempo, y ayer durante un muy buen webcast sobre Windows 8 de Samuel Lopez (@samuelltr) se explicaron algunas cosillas sobre PowerShell y me ha entrado el gusanillo.

¿Y si hago un pequeño script que me haga la copia de seguridad, la comprima en zip, me la mande por mail los viernes a mediodía y borre luego los archivos?

Pues manos a la obra… porque como veréis se hace en un plís. Creamos un nuevo script con PowerShell ISE (o con el notepad, que no vamos a hacer grandes maravillas) y comenzamos a teclear:

## para copias de seguridad        
[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.ConnectionInfo');            
[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.Management.Sdk.Sfc');            
[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO');                     
[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMOExtended'); 
[void][System.Reflection.Assembly]::LoadWithPartialName("WindowsBase");

##Config
$Server = "(local)";           
$Dest = "C:\Temp\";
$DBname =  "NombreBaseDatos";
$srv = New-Object Microsoft.SqlServer.Management.Smo.Server $Server;

Hasta aquí nada del otro mundo, tan solo los namespaces necesarios y unas variables de configuración. $Dest es solo una carpeta temporal.

Ahora vamos a comenzar con una función que cree la copia de seguridad en sí misma:

function CreateBackupFile($db)
{
    $timestamp = Get-Date -format yyyyMMdd-HH-mm-ss;  
    $filename = $Dest + $timestamp +  $db.Name + ".bak"         
    $backup = New-Object ("Microsoft.SqlServer.Management.Smo.Backup");            
    $backup.Action = "Database";            
    $backup.Database = $db.Name;            
    $backup.Devices.AddDevice($filename,"File");            
    $backup.BackupSetDescription = "BackUp completo de " + $db.Name + " a fecha " + $timestamp;            
    $backup.Incremental = 0;                          
    $backup.SqlBackup($srv);     
    return $filename;
}

Tampoco hay mucho que explicar de esta función. Tan solo que recibe una base de datos, crea un nombre de archivo a mi gusto  y hace una copia de seguridad de la misma usando ese nombre. En todo caso, debemos darnos cuenta de que estamos suponiendo que la base de datos que buscamos tiene un recovery model simple. De otro modo nos interesaría traernos también los archivos de log.  Comprobar si el recovery model es full es se podría hacer así

If ($db.RecoveryModel -ne 3)            
{    
    ### Lo mismo, pero paracopiar tambien los Log
    ###...
    $backup.Action = "Log";
    $backup.LogTruncation = "Truncate"; 
    ###...  
};

Ahora necesitamos una función que dado un fichero, lo meta en un zip.

function CreateZIP($fileName)
{
   $ZipPackage=[System.IO.Packaging.ZipPackage]::Open($fileName + ".zip",[System.IO.FileMode]"OpenOrCreate", [System.IO.FileAccess]"ReadWrite")
   $Relativefile = "/" + (split-path $fileName -Leaf)

   $partName=New-Object System.Uri($Relativefile, [System.UriKind]"Relative")
   $part=$ZipPackage.CreatePart($partName, "application/zip", [System.IO.Packaging.CompressionOption]"Maximum")
   $bytes=[System.IO.File]::ReadAllBytes($fileName)
   $stream=$part.GetStream()
   $stream.Write($bytes, 0, $bytes.Length)
   $stream.Close()

   $ZipPackage.Close()
   return $fileName + ".zip"
}

Como la función CreatePart como primer argumento una URI relativa, de la ruta completa del fichero hemos extraido el nombre para crear una ruta relativa usando Split-path. El fichero .Zip lo dejamos en el mismo lugar que el .Bak

Vamos a por una función que reciba la ruta de un fichero y mande el mail con ese fichero adjunto.

function SendMail($AttachedFile)
{
    $EmailFrom = "<CopiasSeguridad@MiEmpresa.es>"
    $EmailTo = "<receptor@receptor.es>"
    $EmailSubject = "Copia de seguridad Automática" 
    $emailbody = "Copia de seguridad realizada con éxito" 
    $SMTPServer = "smtp.miempresa.es"
    $SMTPAuthUsername = "Rosebud"
    $SMTPAuthPassword = "MyVoiceIsMyPassword"

    $emailattachment = $AttachedFile

    $mailmessage = New-Object system.net.mail.mailmessage
    $mailmessage.from = ($emailfrom)
    $mailmessage.To.add($emailto)
    $mailmessage.Subject = $emailsubject
    $mailmessage.Body = $emailbody

    $attachment = New-Object System.Net.Mail.Attachment($emailattachment, 'text/plain')
    $mailmessage.Attachments.Add($attachment)

    #$mailmessage.IsBodyHTML = $true
    $SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 25) 
    $SMTPClient.Credentials = New-Object System.Net.NetworkCredential("$SMTPAuthUsername", "$SMTPAuthPassword")
    $SMTPClient.Send($mailmessage);
    $attachment.Dispose();
    $mailmessage.Dispose();
}

Ojo a las dos últimas líneas. Si no hacemos los Disposes correspondientes, luego no podremos borrar los archivos: Nos dirá que están siendo usados por otro proceso. También hay un cmdlet que lo hace: Send-MailMessage, por si queda más claro.

Una vez que tenemos las funciones accesorias programadas, vamos a unirlo todo.

Write-Output ("Comenzando: " + (Get-Date -format yyyy-MM-dd-HH:mm:ss));                     
foreach ($db in $srv.Databases)            
{            
    If($db.Name -eq $DBname)            
    {            
        $backupfilename = CreateBackupFile($db);
        $zipfilename = CreateZIP($backupfilename);
        SendMail($zipfilename)
        If (Test-Path ($zipfilename))
        {
	       Remove-Item ($zipfilename);
           Write-Output ($zipfilename + " Borrado");
        };     
        If (Test-Path ($backupfilename))
        {
	       Remove-Item ($backupfilename);
           Write-Output ($backupfilename + " Borrado");
        };  
    }

};            
Write-Output ("Finalizado: " + (Get-Date -format  yyyy-MM-dd-HH:mm:ss));

Como veis, Localizamos la bbdd que nos interesa, creamos el archivo de copia de seguridad, el zip que lo contiene, enviamos el mail y si todo va bien borramos los archivos residuales.

Solo nos queda ir al programador de tareas y decirle cuando queremos que se ejecute el script. Le decimos que queremos que se ejecute un programa, que será powershell.exe, y en los argumentos  escribimos –File <Ruta completa del script>

Y eso es todo. Por supuesto no estaría mal usar control de errores (Try-Catch) para que nos avise por mail si falla la copia de seguridad, o si el servidor está caído. Hay mucho espacio para la mejora, pero un ejemplo es un ejemplo ;) ¡Y al menos no dice Hola Mundo!

Sin categoría

Diferencias en nulos y valores por defecto entre C# y Vb.Net

Domingo, 27 de enero de 2013

En muchas ocasiones un programador habituado a Vb.net debe saltar a C#, (e incluso algún caso se ha dado en que el programador debe recorrer el camino contrario). Realizar el cambio no es complicado.

Hoy voy a hablar de algo muy de base: ¿Qué deferencias existen a la hora de tratar los valores nulos entre ambos lenguajes? Muchas no, pero alguna hay y merece la pena comentar como se trata el tema en ambos.

Comenzando por Vb.Net, nos encontramos con dos posibles formas de ver si una variable es nula: Variable Is nothing… o IsNothing(variable)

A primera vista ambos tienen el mismo comportamiento… pero solo a primera vista. Cuando ejecutamos el código variable Is Nothing y el tipo de nuestra variable es un tipo valor (value type) el código no compilará (Error: El operando de esta función debe ser un tipo referencia o un tipo nulable). En cambio si usamos la sintaxis IsNothing(Variable) no se producirá ningún tipo de error de compilación, aunque la función siempre devolverá False.

De hecho, lo que está ocurriendo es que el método IsNothing hace un cast a object y luego retorna el resultado de Variable Is Nothing, pero ya siendo la variable de tipo Object. Ojo, he escrito “el método IsNothing” con toda la intención, ya que realmente se está produciendo una llamada a un método implementado en Microsoft.VisualBasic.Information en lugar de resolverse la expresión “in line”.

Por todo lo anterior, parece que IsNothing(variable) es algo a evitar en favor de su alternativa  variable Is nothing ¿No?… pues sí. Punto pelota. No parece haber ninguna situación en que sea mejor usar el método (Y digo parece porque en este mundo, seguro seguro, solo la muerte).  Pero me voy a esforzar… supongamos una clase que usa genericidad como la que expongo:

'Vb.Net
Public Class Generica(Of T)

    Private Property Variable As T

    Public Sub AVerQuePasa()
        Console.WriteLine(Variable Is Nothing)
    End Sub

End Class

Esta clase no sabe de qué tipo es T… y si la declaro siendo T un entero, va a realizar un Is Nothing en tiempo de ejecución teniendo como operando un tipo valor, así que lo mismo al llamar al método, casca ¿No? Pues ya os digo yo que no. Funciona bien.

Demos un breve y agradable salto a C# para ver cómo se toma estas cosas. En C# No hay ningún problema en escribir un código como el siguiente:

int i = 0;
Console.WriteLine(i == null);

Eso sí, si contáis con ReSharper veréis que os advierte de que el resultado siempre será false (Cosa que no hace ReSharper para Vb.Net) Es decir, que esta comparación con Nulo se comporta como Isnothing(), pero con la salvedad de que se resuelve la expresión In Line, sin tener que llamar a un método externo.

En cambio si escribimos lo mismo en Vb.Net:

Dim i as integer= 0
Console.WriteLine(i = nothing)

Parece que funciona, Pero ¿Estamos imprimirendo realmente si el valor es nulo? ¿Hay entonces 3 formas de comprobarlo en lugar de 2? Pues no. No estamos realmente comprobando si la variable i es nula, lo que estamos comprobando es si i tiene su valor por defecto. (Ahí lo llevas) Lo explico:

Esta sentencia es perfectamente legal en Vb.Net:

Dim j As Integer = Nothing

Mientras que no se puede hacer nada parecido en C#, porque ¿No hemos quedado en que es un entero y no un tipo nulable? Pues sí, pero resulta que en Vb.Net cuando asignas Nothing a un tipo valor, lo que en realidad estás haciendo es asignarle su valor por defecto. Lo mismo que hace Default(T) que se usa en C# para genéricos, pero tocando más los… digo más críptico. Esta es la razón por la cual el ejemplo anterior no cuenta como una forma de comparar si una variable es nula.

Este detalle que parece una tontería, nos puede llevar a tirarnos de los pelos, por ejemplo, al trabajar con genericidad y comparar si un tipo tiene el valor por defecto sin saber si el tipo será valor o referencia.

 En C# en una clase genérica, para comprobar que una variable tipo T tiene su valor por defecto, hacemos algo como:

if(EqualityComparer<T>.Default.Equals(variable, default(T)))
{

}

Mientras que en Vb.Net tendríamos que hacer algo así:

If EqualityComparer(Of T).Default.Equals(variable, Nothing) Then

End If

Que aunque no lo parezca a primera vista, resuelve si el objeto tiene su valor por defecto. Es decir que para un T entero y una variable con valor cero, devuelve true, pero si la variable tiene otro valor, retorna false, y para una clase funciona igual de bien.

O, si T no tiene un coste de construcción muy alto, podemos aprovecharnos de que en Vb.Net no tenemos que definir las variables con una expresión y hacer algo más costoso pero más claro:

Dim defaultVar As T    
If variable.Equals(defaultVar) Then
    ''
End If
Y esto es todo por hoy ;)

.Net ,

El Tipo Lazy en .Net 4.0

Lunes, 25 de junio de 2012

Todo buen programador necesita un poco de pereza. Algo que le lleve a intentar escribir poco, a no repetirse, a hacer las cosas cada día mejor y a no caer en tareas repetitivas. Últimamente el código “vago” también está en boca de todos, ya sean clases que no se inicializan hasta que se usan o consultas a la BBDD que no se lanzan hasta el último momento.

Tradicionalmente, cuando teníamos una dependencia con una inicialización pesada y que además no sabíamos si se iba o no a ejecutar, hacíamos algo parecido a esto:

//C#

     private Dependencia _Fdependencia;
     private Dependencia _Dependencia
     {
        get { return _Fdependencia ?? (_Fdependencia = new Dependencia()); }
        set { _Fdependencia = value; }
     }
'VB.NET
     private  _Fdependencia as Dependencia
     private Property _Dependencia as Dependencia
        get
          If IsNothing(_Fdependencia) Then _Fdependencia = New Dependencia()
          Return _Fdependencia
        End Get
        Set(value As Dependencia)
           _Fdependencia = value
        End Set
     End Property

Pero desde el lanzamiento del framework 4.0, diponemos del tipo Lazy<> que se ocupa del trabajo por nosotros. En este ejemplo la propiedad no se inicializará hasta que se use por primera vez.

 

//C#
private Lazy<Dependencia> _Dependencia { get; set; }
'VB.NET
private property  _Dependencia as Lazy(Of Dependencia)

En ocasiones no se trata de llamar simplemente a un constructor, sino que el proceso de inicialización de la dependencia puede ser más complejo, requiriendo quizá la llamada a un método:

 

//C#
private Lazy<Dependencia> _Dependencia = new Lazy<Dependencia>(InicializarDependencia);
private static Dependencia InicializarDependencia()
{

     //hacer cosas
     return new Dependencia();

}
private  _Dependencia as Lazy(Of Dependencia) = new Lazy(Of Dependencia)(AddressOf InicializarDependencia)
private shared Function  InicializarDependencia() As Dependencia 
     'hacer cosas
     return new Dependencia()
End Function

O si lo preferimos podemos usar expresiones lambda para conseguir esto mismo:

//C#
private Lazy<Dependencia> _Dependencia = new Lazy<Dependencia>(()=>
          {
           //hacer cosas
           return  new Dependencia();
          });

 

        private property _Dependencia as Lazy(Of Dependencia)  =new Lazy(Of Dependencia)(function()
                                'hacer cosas
                                 Return New Dependencia
                                 End Function)

En todos estos casos, el proceso de inicialización solo se llevará a cabo al usar la propiedad (o campo) y solo la primera vez.  Para acceder al “tipo interno” lo hacemos mediante la propiedad Value. Es decir, que si queremos llamar al método Metodo1 de _Dependencia lo que haremos es _Dependencia.Value.Metodo1.

Así mismo, el constructor de Lazy<> dispone de una sobrecarga para indicarle si queremos que sea Thread-Safe. (por defecto es true):

//C#
private Lazy<Dependencia> _Dependencia = new Lazy<Dependencia>(InicializarDependencia,false);
'VB.NET
private  _Dependencia as Lazy(Of Dependencia) = new Lazy(Of Dependencia)(lazythreadsafetymode.PublicationOnly)

También tenemos sobrecargas para indicarle el tipo de Thread-Safe que queremos que se aplique:

//C#
private Lazy<Dependencia> _Dependencia = new Lazy<Dependencia>(InicializarDependencia,LazyThreadSafetyMode.PublicationOnly);
'VB.NET
private  _Dependencia as Lazy(Of Dependencia) = new Lazy(Of Dependencia)(lazythreadsafetymode.PublicationOnly)

Pronto veremos como hacer casar todo esto con conceptos como inversión de control, mientras, como ejemplo de uso, os recomiendo este enlace de John Skeet sobre del patrón Singleton que finaliza en una implementación usando Lazy<> John Skeet Singleton.

.Net

Sobre los test unitarios y la capa de acceso a datos

Lunes, 5 de marzo de 2012

Este viernes, durante una cena con integrantes de Gusenet y con Javier Torrecilla, que muy amablemente vino a darnos una charla sobre EF, saltó el comentario de que si decidía no hacer test unitarios a mi capa de datos el resto de tests de mi aplicación no serviría para nada, la casa se me caería sobre los cimientos y acabaría siendo víctima de la moda programando tests que no aportan nada a mi aplicación.

De buenas a primeras yo no estaba muy de acuerdo con la afirmación, pero hay que ser prudente, así que me he dado un par de días para pensarlo bien… y la verdad es que sigo sin pensar que sea cierto.

Por supuesto, hacer test unitarios a la DAL es algo deseable si se cuenta con el tiempo y los recursos (aunque hay que reconocer que es un grano en el culo). Si pudiera haría test unitarios hasta al desayuno de por las mañanas, pero hay que pensar que no siempre se cuenta con los recursos necesarios para hacer todo lo que queremos.

Unos buenos test unitarios deben tener unas características de sobra conocidas: Automatizables, completos (con respecto a lo que se está probando), independientes, repetibles, sencillos, etc. Si tenemos una buena separación en capas, y hemos cumplido estos principios le habremos dado un valor añadido al código de esa capa, independientemente de que otras capas carezcan de ese valor, porque los test deben ser UNITARIOS ¡Es su principal característica! No pasa nada si un test en la capa de negocio no me detecta un mal funcionamiento en la DAL. No solo no pasa nada, sino que es normal, porque lo deseable es que un test pruebe solo una cosa, y por eso usamos mocks y stubs: Para que aislandolo de sus dependencias nuestro test pruebe “una sola unidad de código”, y estar seguros en la medida de lo posible de que esa unidad en concreto funciona como esperamos.

No debemos esperar que los test nos detecten todos los errores porque sabemos que eso no va a pasar, pero sí es importante que las clases con lógica de negocio funcionen como nosotros pensamos que van a funcionar y que los bugs arreglados no vuelvan nunca a repetirse.

Lo que realmente me gustaría es probarlo todo, pero si no lo hago así, creo que un 20% de buena cobertura es mejor que un 0%, independientemente de las capas sobre las que esté hecho. ¿Y qué pasa entonces con los errores de la DAL? ¿Nos los comemos? No, por supuesto que no. ¿O acaso solo probamos nuestras aplicaciones con test unitarios? Tener una buena cobertura no es excusa ni de lejos para seguir haciendo las pruebas manuales de toda la vida.

Como diría Steven Sanderson, no es cierto que cualquier test unitario sea mejor que ninguno, pero sí que un buen test unitario es mejor que ninguno. A lo que yo añadiría “No importa en la capa que esté”.

Llegados a este punto corro el peligro de comenzar a repetirme y ponerme pesado, pero nunca podrán decir que me asusto del peligro: Voy a poner un par de ejemplos prácticos donde se clarifica mi postura:

–          Nos toca desarrollar una capa de negocio sobre una capa DAL que ya está hecha, tengo dos opciones:

a) No hacer pruebas unitarias a la nueva capa porque… total, la DAL no las tiene así que las que yo haga no aportan nada.

b) Hacer pruebas unitarias a la nueva capa conforme la estoy desarrollando.

En este caso, mi opción es la B.

–          Me toca mantener una aplicación que no tiene test unitarios, encuentro y arreglo un bug, tengo 2 opciones:

a)      Hago un test unitario que pruebe ese caso, para que el error no vuelva a repetirse misteriosamente.

b)      No hago un test unitario, porque cubrir solo ese 0.001% del código no me aporta nada, son solo modas.

 Esta vez… mi opción es la A.

Tests Unitarios ,

Tipo de dato Tupla en .Net

Jueves, 23 de febrero de 2012

En .Net una tupla es un tipo de dato que representa exactamente lo mismo que en el ambito matemático: Una secuencia o lista de un número concreto de objetos. El tipo tupla se ha integrado en el framework 4.0.

El manejo de tuplas es bien sencillo.  Si quisiéramos crear una tupla de tres elementos (una cadena, un entero y una clase propia, por ejemplo) y luego acceder a ellos lo haríamos de la siguiente manera.

//C#
 //clase propia
 var myInstance = new myclass();

 //creando una tupla de tres elementos
Tuple<string, int, myclass> myTuple = Tuple.Create("Valor", 1, myInstance);

//accediendo a los elementos de una tupla
Console.WriteLine(myTuple.Item1);
Console.WriteLine(myTuple.Item2);
Console.WriteLine(myTuple.Item3);
'VB.Net
'clase propia
Dim myInstance As New CustomClass()

'creando una tupla de tres elementos
Dim myTuple As Tuple(Of String, Integer, CustomClass) = Tuple.Create("Valor", 1, myInstance)

'accediendo a los elementos de una tupla
Console.WriteLine(myTuple.Item1)
Console.WriteLine(myTuple.Item2.ToString)
Console.WriteLine(myTuple.Item3.ToString)

Como podéis ver, el acceso a los miembros de la tupla se hace mediante item1, item2… item X, y podemos crear tuplas de hasta 8 elementos, pero ¿Para que nos puede servir realmente una tupla? Pues imaginemos que tenemos que empaquetar información de alguna manera para luego procesar esa información. Lo más habitual es crear una clase, pero en ocasiones esa información no está directamente relacionada entre sí y además se va a usar en un solo lugar, por lo que no queremos crear una nueva clase. En ese momento, las tuplas pueden echarnos una mano. Si necesitamos que un método retorne varios valores, una tupla es una de las muchas formas de conseguirlo.

¿Se te ocurren muchas situaciones en las que usar una tupla? Si es así, mal vamos. Recuerda el refrán: “A un tonto con un martillo, del cielo le caen los clavos”.  No hay que ser vago, si tienes que devolver un conjunto de datos relacionados, lo mejor es usar una clase. Si tienes dudas, crea una clase. Está bien usar una tupla para que métodos privados retornen datos localizados dentro de clases. Datos que no se van a exponer y a los que incluso te costaría poner un nombre porque no están fuertemente ligados.

Un método público nunca debería retornar una tupla. Piensa que el uso de estos tipos de datos hace que el código no sea autodocumentado. Item1, Item2…ItemX no son precisamente lo que llamaríamos nombres descriptivos. Nos obligarán a poner comentarios indicando qué es cada cosa.

Como curiosidad. ¿No podemos conseguir lo mismo usando tipos anónimos? Pues la verdad es que sí, podemos empaquetar los datos necesarios en un tipo anónimo y luego procesarlos.

Puede que estéis pensando “Ya, pero ¿Cómo retorno un tipo anónimo?” Bueno… lo primero que debo decirte es que nunca deberías retornar un tipo anónimo. Ni siquiera de un método privado y mucho menos de uno público. Además hacerlo es un poco artificial, pero… “Cuando un buen programador está decidido a hacer las cosas mal, ninguna dificultad técnica puede detenerlo”.

//C#
private void ejemplo()
{
    object o = DameUnTipoAnonimo();
    var tipoAnonimo = Cast(o, new { Nombre="", Apellido="" });
    MessageBox.Show(tipoAnonimo.Nombre + " " + tipoAnonimo.Apellido);
}

private object DameUnTipoAnonimo()
{
    return new {Nombre="Jonathan",Apellido="Fernández"};
}

private T Cast<T>(object obj, T type)
{
    return (T)obj;
}
'VB.Net
Private Sub Ejemplo()
    Dim o As Object = DameUnTipoAnonimo()
    Dim tem = New With {.Nombre = "", .Apellido = ""}
    Dim tpo = tem.GetType
    Dim tipoanonimo = CTypeDynamic(o, tpo)
    MessageBox.Show(tipoanonimo.Nombre + " " + tipoanonimo.Apellido)
End Sub

Private Function DameUnTipoAnonimo() As Object
    Return New With {.Nombre = "Jonathan", .Apellido = "Fernández"}
End Function

También tiene su ciencia eso de crear una lista de tipos anónimos:

//C#
private void Ejemplo()
{
    var tipoAnonimo = new { Nombre = "Jonathan", Apellido = "Fernández" };
    var tipoAnonimoList = (new[] { tipoAnonimo }).ToList();
    tipoAnonimoList.Add(new { Nombre = "Kirill", Apellido = "Osenkov" });
    //Kirill Osenkov es el autor de un post en él que ví este ejemplo.
}
'VB.Net
Private Sub Ejemplo()
	Dim tipoAnonimo = New With {.Nombre = "Jonathan", .Apellido = "Fernández"}
	Dim listaTipoAnonimo = CrearListaDesdeElemento(tipoAnonimo)
	listaTipoAnonimo.Add(New With {.Nombre = "Kirill", .Apellido = "Osenkov"})
End Sub

Public Function CrearListaDesdeElemento(Of T)(ByVal p1 As T) As List(Of T)
	Dim lista As New List(Of T)
	lista.Add(p1)
	Return lista
End Function

Con estos ejemplos de código que no deberían ser usados espero haber mostrado que los tipos anónimos no son una buena alternativa a las tuplas, pero volviendo al principio… las tuplas están ahí para ser usadas, pero su uso debe ser moderado y es probable que si aparece la necesidad de usarlas debamos platearnos si estamos haciendo las cosas bien.

.Net ,

Razones para no abrir un blog

Martes, 21 de febrero de 2012

En los últimos dos años he aprendido más que en el resto de mi vida como programador, llegando incluso a vislumbrar los cimientos del oscuro arte de la arquitectura del software, y eso tiene graves consecuencias: Cada vez soy más consciente de todo lo que se me escapa, y de que me es imposible estar mínimamente al día de todo lo que se mueve en el mundo de .Net. Cada cosa en la que meto la nariz resulta ser un mundo.

Casi todo lo que he aprendido me ha venido de otras personas, de libros, de blogs… y solo una pequeña parte de la investigación propia. Puedo citaros sin esfuerzo una docena de blogs en castellano que son mejores de lo que va a ser este. Es lo que hay.

Cualquier pieza de código que escriba aquí podría ser reescrita de forma más eficiente por muchos otros programadores, y cualquier explicación que ofrezca podrá ser reinterpretada de forma que se entienda mejor.

Cuanto más conoce uno, más sube el listón de lo que considera un buen programador. A poco inteligente que se sea con el conocimiento llegará la humildad. Cuando me preguntan si estoy seguro de algo pienso “Seguro solo estoy de la muerte” y a veces digo “Estoy razonablemente seguro” o “Tengo cierto grado de certeza”. Podría dejar el trabajo de escribir un blog a gente más preparada, y dedicarme a pasar más tiempo con mi familia cuando salgo de trabajar. Yo solo quiero hacer las cosas bien y no tener que avergonzarme nunca de mi código, que no es poco.

A pesar de todo, estoy razonablemente seguro de que más pronto que tarde alguien leerá uno de mis posts y dirá “Ahhh… ¡Ya veo por dónde vas!” y le ahorraré un par de horas de esfuerzo. Antes o después llegará una persona distinta que dirá que él lo habría hecho mejor y me explicará como aquí mismo o en su propio blog. Entonces habré ayudado, habré aprendido, y habrá merecido la pena.

Así que he abierto un blog, y sirvan estas reflexiones como disculpa por adelantando, porque tengo cierto grado de certeza en que voy a meter la pata de vez en cuando. Espero también haceros pensar, y haceros reír de vez en cuando.

Blogs ,