NuGet, le dll e il source control

Fino a poco tempo fa, la struttura dei nostri progetti, era quella “tradizionale”:

  • source: folder in cui sono contenuti tutti i sorgenti della nostra soluzione
  • libs: folder in cui sono contenute tutte le librerie di terze parti referenziate dai nostri progetti
  • database: folder in cui sono contenuti tutti gli script per la generazione/aggiornamento del db
  • docs: folder in cui è contenuta tutta la documentazione progettuale

Questa modo di organizzare la solution ci garantisce che, chiunque entri in corsa sul progetto, possa essere fin da subito operativo con un semplice checkout/update, senza bisogno di installare/configurare nulla di particolare.

Una cosa che non mi è mai piaciuta è quella di dover, per ogni progetto, dover committare tutte le volte, tutte le dll necessarie, duplicando, progetto dopo progetto, le stesse dll sul repository.

Ora però, con NuGet, abbiamo a disposizione un repository globale (e perchè no, anche locale e privato) per tutte le librerie di cui abbiamo bisogno, perfettamente integrato con Visual Studio e facilmente utilizzabile. Perchè non sfruttarlo?

Ma facciamo un passo indietro e ricapitoliamo velocemente come NuGet funziona: ogni volta che viene referenziata una nuova libreria in uno dei progetti di una solution, la dll e le relative dipendenze vengono scaricate in una folder (packages) creata a livello di solution e un nuovo file (packages.config) viene creato a livello di progetto. Quest’ultimo file è il “repository” di tutte le dll referenziate dal progetto.
Qualora un nuovo progetto della solution referenzi una dll precedentemente installata, il file packages.config del progetto viene aggiornato e viene aggiunto un riferimento alla dll già scaricata e presente nella folder packages.

Detto questo, non tutti sanno che tra i vari modi con cui possiamo interagire con NuGet, oltre che comodamente da VisualStudio, c’è anche la possibilità di sfruttarlo da riga di comando.

Si sta chiudendo il cerchio? La nebbia si sta diradando? :-)

La console a riga di comando ci da la possibilità, oltre all’utilizzo “tradizionale” (installare un package alla volta), di installare una serie di package utilizzando il file packages.config proprio come un vero repository del “necessario”.
Tramite l’istruzione:

nuget install packages.config -OutputDirectory "..\packages"

la versione console di NuGet legge il contenuto del file packages.config e scarica, solo il necessario (ovvero ciò che non è già presente), nella folder “..\packages”. Ottimo direi, no?

Ecco quindi la soluzione che abbiamo adottato:

  • solo e soltanto NuGet per la gestione delle reference
  • i file packages.config di ogni progetto vengono committati
  • è stato inserito, per ogni progetto, un prebuild event che lancia il seguente comando:
    nuget install packages.config -o "..\packages"
  • è stata finalmente droppata la folder “libs” :-)
…che non vi venga in mente di committare la folder packages che viene creata!!!!

Chocolatey: un package manager per windows

Dopo diversi mesi, e diverse migliaia (3134 per l’esattezza, al momento) di packages uploadati…NuGet non è più una novità, ma una piacevole realtà.

Sempre più utile ed integrato anche nel nostro processo di build (ne parleremo presto) è diventato uno strumento indispensabile, almeno per me, nella “cassetta degli attrezzi” del bravo dev.

Sulla scia di NuGet, è nato (da un po’) Chocolatey che ha come obbiettivo quello di diventare IL package manager (alla “apt-get”) di riferimento per il mondo Windows. E per package manager intendo qualsiasi tipologia di package e non solo quelli dev-oriented.

Come fare ad installarlo? Con NuGet ovviamente, digitando dal prompt:

nuget install chocolatey

in modo da scaricare tutto il necessario, e per completare l’installazione, da una console powershell, puntando alla cartella tools scaricata al passo precedente:

ChocolateyInstall.ps1

Attenzione: per poter eseguire lo script powershell precedente bisogna impostare l’execution-policy in modo che siano “runnabili” script remoti.

L’installazione di chocolatey imposta nelle variabili di sistema la folder di installazione di default (c:\Nuget\bin) in modo che siano sempre accessibili i comandi del package manager e l’accesso a tutti i package installati. Qualora si decidesse di installare il tutto in una folder diversa da quella di default, bisogna impostare, prima dell’installazione, una nuova variabile di sistema con chiave “ChocolateyInstall” e valore il path di destinazione.

A questo punto possiamo, per esempio, installare node.js in modo molto semplice:

chocolatey install nodejs

…ed eseguirlo dal prompt…

Buon chocolatey a tutti!!!

C#, valori di default e la leggibilità

La possibilità di definire i valori di default dei parametri di un metodo con C#, non è cosa recente, ma giusto ieri mi sono trovato ad utilizzare questa “feature” del linguaggio e a trarne alcune considerazioni.

Scenario:
descrivere uno snapshot della produttività di una macchina di un’automazione industriale dettagliandone, oltre al giorno a cui si riferisce lo snapshot stesso, tutti i relativi parametri:

  • macchina accesa
  • macchina pronta
  • macchina in lavorazione automatica
  • macchina in lavorazione manuale
  • macchina in allarme
  • macchina in assistenza

A fronte dei valori specificati da tali parametri viene di conseguenza calcolata l’efficienza “teorica” ed effettiva della macchina (logiche che non ci interessano per ora).

Utilizzare l’object initializer era fuori discussione: lo snapshot è un value-object del mio dominio e pertanto deve essere immutable. Non ho trovato altra strada che utilizzare il costruttore ed esporre i valori precedenti con delle properties in read-only.
L’implementazione “tradizionale” (pre default-parameter, per intenderci) non mi piaceva per nulla.

public class Snapshot
{ 
    public Snapshot(DateTime day, Int32 on, Int32 ready, Int32 working, 
                                  Int32 manual, Int32 alarm, Int32 service) 
    { 
        ... 
    } 
}

Dover specificare tutti i parametri, anche quelli con il valore 0, è molto prolisso, poco leggibile e, alla lunga, anche poco usabile: ogni volta mi devo ricordare (è vero ci sono l’intellisense e resharper che mi danno una mano) l’ordine con cui inserire i parametri.

In questo contesto l’utilizzo dei valori di default è stato illuminante:

public class Snapshot
{
    public Snapshot(DateTime day, 
                    Int32 on=0, Int32 ready=0, Int32 working=0, 
                    Int32 manual=0, Int32 alarm=0, Int32 service=0)
    {
        ...
    }
}

in modo da poter scrivere:

Snapshot snapshot = new Snapshot(DateTime.Today, working: 4800, manual: 2400);

Questa sintassi è sicuramente più concisa e molto, ma molto più leggibile (ovviamente IMHO)

Perchè MongoDb?

Molto spesso, e sempre più di frequente, mi viene posta questa domanda: “perchè MongoDb?”

Cercando in rete, ciò che più attira l’attenzione, in merito ai perchè del mondo nosql, sono grossi paroloni che fanno quasi paura al solo pensiero. Uno su tutti la scalabilità.
Faccio fatica a credere che la necessitá di abbracciare un cambio di filosofia cosí radicale sia dettato *solo* da un requisito di scalabilitá cosí spinto ed estremo, che una buona/corretta configurazione e gestione di un db relazionale non possa garantire (almeno nel 95% dei casi). Suvvia, non avremo sempre tutti le stesse necessità di facebook, twitter and so on…

Ma allora perchè MongoDb? Perchè “dimenticare” tutte le conoscenze acquisite negli ultimi anni, buttare le notti insonni a capire come ottimizzare le query prodotte dall’ORM di turno…?

Per una cosa semplicissima: la semplicità :-)
La semplicità di installazione, configurazione, manutenzione ed interazione che MongoDb ci permette. Questa è LA risposta alla fatidica domanda ed è per questo che sempre più spesso mi trovo a “consigliarlo” e ad adottarlo (ovviamente anche la scelta di un db nosql non può e non deve essere assolutistica) nei progetto che ci coinvolgono.

Redirect di dati binari con powershell

In questo post abbiamo visto come è stato possibile, con powershell, eseguire il dump dei nostri repositories svn e zipparli per una più facile archiviazione. Non è però tutto oro quello che luccica.

Eseguendo il dump di un repository e tentando di reimportarlo sul nuovo server, la procedura veniva sempre interrota con la segnalazione di “formato errato”, come se il dump eseguito fosse corrotto o non corretto. Provando con il command prompt tutto invece filava liscio come l’olio.

Buttando l’occhio sui dump che venivano generati con le due modalità mi sono però accorto di una differenza macroscopica: la dimensione del dump ottenuto con powershell era quasi il doppio di quello ottenuto attraverso il command prompt “tradizionale”…no bello!!!

A naso ho circoscritto il problema al solo redirect verso lo stdout di contenuto binario, perchè quando si tratta di testo PowerShell fa degnamente il suo sporco lavoro. Ho provato quindi a “travasare” il contenuto di un’immagine in un’altra:

Get-Content .\image.png |
    Out-File .\image-postprocess.png

e analizzato il risultato

ls image*.png |
    select name, length |
    ft -AutoSize
 
Name                    Length
----                    ------
image.png                98869
image-postprocess.png   199184

Andando più nel dettaglio:

(Get-Content .\image-postprocess.png).GeType() |
    select name
 
Name
----
Object[]
Get-Content .\image-postprocess-.png |
    %{ $_.GetType() } |
    group name |
    select count, name |
    ft -AutoSize
Count Name
----- ----
  327 String

Ma come? Allora powershell “trasforma” l’output binario in un array di stringhe convertendo il tutto in Unicode. Ecco il perchè della dimensione quasi doppia :-(

L’unica soluzione che ho trovato, a dir la verità grazie al solito san google, è stata quella di utilizzare il seguente script per evitare che powershell si “intrometta” nello stream decodificando i caratteri:

Function Get-ProcessOutputAsBinary([string] $processname, [string] $arguments)
 
$processStartInfo = New-Object System.Diagnostics.ProcessStartInfo
$processStartInfo.FileName = $processname
$processStartInfo.WorkingDirectory = (Get-Location).Path
if($arguments) { $processStartInfo.Arguments = $arguments }
$processStartInfo.UseShellExecute = $false
$processStartInfo.RedirectStandardOutput = $true 
 
$process = [System.Diagnostics.Process]::Start($processStartInfo)
$process.StandardOutput.ReadToEnd()
$process.WaitForExit()

…facendo diventare il nostro script per eseguire il dump dei repository un po’ più complesso:

$svnadmin = "C:\Program Files (x86)\VisualSVN Server\bin\svnadmin.exe"
 
Function Get-ProcessOutputAsBinary([string] $processname, [string] $arguments)
{
	$processStartInfo = New-Object System.Diagnostics.ProcessStartInfo
	$processStartInfo.FileName = $processname
	$processStartInfo.WorkingDirectory = (Get-Location).Path
	if($arguments) { $processStartInfo.Arguments = $arguments }
	$processStartInfo.UseShellExecute = $false
	$processStartInfo.RedirectStandardOutput = $true 
 
	$process = [System.Diagnostics.Process]::Start($processStartInfo)
	$process.StandardOutput.ReadToEnd()
	$process.WaitForExit()
}
 
Get-ChildItem "C:\Repositories" |
    Where-Object { $_.mode -match "d" } |
    ForEach-Object {
        $fullname = $_.fullname
        Get-ProcessOutputAsBinary $svnadmin "dump $fullname"  |
            Out-File -Encoding OEM "C:\temp\dump\$_.svndump" }

…e se le apps “metro style” di windows 8 non partono…

…piccola informazione di servizio: se cliccando sulla tile di una nuova applicazione in “metro-style” dallo start screen di windows 8, l’applicazione non “parte”, molto probabilmente il problema è causato dalla risoluzione dello schermo che è impostata sotto il minimo “di legge” consentito da windows8: 1024×768.

In un ambiente virtuale può capitare facilmente…a me per esempio è successo con parallels in modalitá “windowed”.

Il problema a mio avviso è la non-segnalazione del problema, ma sempre di una developer preview si tratta ;-)

A futura memoria ecco i requirements per “runnare” correttamente windows 8:

  • 1 gigahertz (GHz) or faster 32-bit (x86) or 64-bit (x64) processor
  • 1 gigabyte (GB) RAM (32-bit) or 2 GB RAM (64-bit)
  • 16 GB available hard disk space (32-bit) or 20 GB (64-bit)
  • DirectX 9 graphics device with WDDM 1.0 or higher driver
  • Taking advantage of touch input requires a screen that supports multi-touch
  • To run Metro style Apps, you need a screen resolution of 1024 X 768 or greater

Win8, parallels e i parallels tools

Oggi sono riuscito finalmente a trovare un po’ di tempo per installare windows8.

Leggendo blog, articoli e tweet sembra che su macosx, virtual box sia la soluzione migliore, o meglio…una soluzione che non crea problemi. Utilizzando però parallels sul mio mac per le virtualizzazioni di tutti i giorni, ho voluto evitare di installare un nuovo sistema di virtualizzazione, procedendo quindi a creare una nuova e fiammante macchina virtuale di win8 sfruttando parallels.

L’installazione è filata via liscia come l’olio, nessun problema, nessuna necessità particolare. Dopo pochi minuti avevo la mia VM pronta per l’uso.

I problemi hanno iniziato a verificarsi dopo l’installazione dei parallels tools. Problemi non da poco direi: black screen e impossibilità a fare qualsiasi cosa.
“Googlando” un po’ sono riuscito a trovare sui forum di parallels la soluzione:

  • shutdown della macchina virtuale
  • configure > hardware > boot order
  • nella sezione ‘boot flags’ inserire: devices.video.pci_device_id=0×5005;
  • riavviare la macchina virtuale
…good run on ‘metro’…

WPC 2011

wpc2011

Per il secondo anno consecutivo parteciperò, in qualità di speaker a WPC, una delle più importanti conferenze italiane dedicata alle più recenti tecnologie di casa Microsoft.

Durante la mia sessione parleremo di WPF e performance. Vi rimando al link della sessione con un abstract un po’ più dettagliato.

La definizione dell’elenco delle sessioni della conferenza è ancora “in progress” e vi consiglio di tenere monitorate le grosse novità che ci saranno, anche a fronte di quanto mostrato in quel di Anaheim.

Mi raccomando…non mancate!!!!

Dump di repositories svn con powershell

<invidia mode=”on”>
…mentre c’è chi sollazza in quel di Anaheim, con un nuovo tablet dotato di un windows 8 fiammante…
</invidia>

Ultimamente sto inserendo prepotentemente powershell nello stack tecnologico con cui ho a che fare, o meglio con cui voglio avere a che fare, nelle attività lavorative di tutti i giorni.

A “causa” di una ristrutturazione interna del nostro sistema di gestione della codebase e del processo di build (di cui parleremo in un prossimo post) ho avuto la necessità di “dumpare” tutti i nostri repository svn e zipparli per permetterne una facile archiviazione. Perchè non farlo con powershell, mi sono detto…ecco come me la sono cavata:

$svnadmin = "C:\Program Files (x86)\VisualSVN Server\bin\svnadmin.exe"
 
Get-ChildItem "C:\Repositories" |
    Where-Object { $_.mode -match "d" } |
    ForEach-Object { &amp; $svnadmin dump $fullname |
        Out-File -Encoding ASCII "C:\temp\dump\$_.svndump" }

In queste poche righe di codice si capisce la potenza espressiva di powershell…si paga un po’ in termini di verbosità, è innegabile, ma tant’è…non sono un po’ di caratteri in più a spaventarci :-)

Un paio di commenti a margine:

  • con l’operatore “|” concateniamo istruzioni successive: l’output della precedente viene “riversato” come input della successiva
  • l’istruzione alla riga 4 permette di filtrare tutte e solo le directory risultanti dall’operazione precedente
  • con l’operatore “&” eseguiamo un comando (in questo caso svnadmin.exe)
  • l’istruzione alla riga 6 fa il redirect dello standard output sul file indicato
Facile no?
La fase di “archiviazione” si è rivelata anche meno complicata e mostra esplicitamente l’integrazione tra powershell e ogni componente del .net framework. Ecco lo snippet:
[System.Reflection.Assembly]::LoadFrom("C:\temp\ICSharpCode.SharpZipLib.dll")
 
Get-ChildItem "C:\temp\dump" |
	ForEach-Object {
		$filename = "c:\temp\archive\$_.zip"
		$zip = [ICSharpCode.SharpZipLib.Zip.ZipFile]::Create($filename)
		$zip.BeginUpdate()
		$zip.Add($_.fullname)
		$zip.CommitUpdate()
		$zip.Close()
	}

ValueObject: questo sconosciuto

Uno dei concetti apparentemente più semplici del libro di Evans è quello di value object. Riporto fedelmente la sua definizione per non incorrere in errori e/o omissioni:

“…there are cases when we need to contain some attributes of a domain element. We are not interested in which object it is, but what attributes it has. An object that is used to describe certain aspects of a domain, and which does not have identity, is named Value Object…”

Ogni value object porta (o almeno dovrebbe) con se alcune peculiarità che lo caratterizzano come il fatto di essere immutable, “sharabile” tra varie entity e non avere alcun concetto di identità.
Queste caratteristiche si traducono in esplicite richieste implementative che vanno assolutamente soddisfatte:

  • ogni value object viene creato inizializzandone i suoi attributi e per tutto il suo life-cycle non deve avere la possibilità di modificare il suo stato interno
  • per mia scelta personale, se possibile, evito di esporre lo stato interno di un value object. Se sono costretto a farlo (sotto tortura :-) ) lo faccio comunque solo in lettura
  • se si vuole cambiare lo stato interno di un value object se ne crea uno nuovo
  • non avendo intrinsecamente un concetto di identità deve ridefinire il modo in cui è possibile valutarne l’uguaglianza con un altro value object dello stesso tipo

Individuare correttamente i value object che decorano il nostro dominio non è un’attività semplice e soprattutto è un’attività spesso trascurata/tralasciata. Solo dopo un’attenta (l’ennesima) rilettura di alcune parti del libro di Evans ho colto l’importanza che viene data a questo particolare aspetto del nostro dominio.

Con poche accortezze, il nostro anemico object model acquisisce sostanza e ogni componente del puzzle si incastra perfettamente al suo posto.