Tiananmen, 20 anni dopo

Sono già passati 20 anni dalla strage di piazza Tiananmen, ma sembra che siano 1000.
Chi potrebbe infatti ricordare eventi così spiacevoli, che potrebbero turbare i rapporti con uno dei nostri interlocutori commerciali più importanti, specialmente ora, in tempo di crisi?
Pecunia non olet, nemmeno di sangue...

Implicit conversions in Scala are cool

Andy Warhol – Dollar sign

Sometimes I hear sentences like Domain Specific Languages (DSL) can be generated effectively only using dynamic languages, or This super-cool feature could not be possible in a static typed language. More and more, some people would transmit the idea that dynamic languages are agile and cool, while static ones are rigid and old. I strongly disagree! I think that in static languages lots of unit tests are generated and maintained automatically by the compiler, while in dynamic ones the programmer should create and maintain these tests. So static languages have lots more unit tests: isn't this agile programming? And what about cool features? Well, what do you think about a language in which you can write something like this?

 
(5.0 USD) + (2.0 USD) == (7.0 USD)

Cool DSL, isn't it? Sure, and I will show you that this is possible (and very easy) using a language with a strong and static type system: Scala.

As we are going to write yet another money example, we could begin with the definition of currencies.

 
abstract class Currency {
  def name: String;
  override def toString = name
}    
 
object Euro extends Currency {
  def name ="EUR"
}    
 
object Dollar extends Currency {
  def name = "USD"
}

Not very exciting. We simply define an abstract Currency class and two singleton objects that extend this class. Note that these objects are instances of anonymous subclasses of Currency. This does matter, as we'll see in a moment.

Now let's define money.

 
case class Money[C <: Currency](amount: Double, currency: C) {
  def + (otherMoney: Money[C]) = {
    new Money(amount + otherMoney.amount, currency)
  }
  override def toString = amount + " " + currency
}

Our class is parametric in the type C, and we tell to the compiler that it must be a subclass of Currency. This way we have the nice consequence that the + operator can add only money of the same currency, and this test is done by the compiler before our code is running.

It's time to get to the cool feature: implicit conversion. So, in the same file Money.scala in which we defined the Money class, we create a Money object, which has the responsibility to convert doubles, let me say, "annotated" with a currency, into Money.

 
object Money {
  implicit def doubleConverter(d: Double) = new {
    def EUR = {
      new Money(d, Euro)
    }    
 
    def USD = {
      new Money(d, Dollar)
    }
  }
}

Uhm, it sounds a bit strange. How we can use it? Let's see an example.

 
import Money._    
 
object MoneyMainProgram extends Application {    
 
  val tenDollars = (4.0 USD) + (6.0 USD)     
 
  println(tenDollars)
}

Now some explanations are required.

In the first line we import the Money object. We can see it as a kind of static import, that, among other things, adds to the scope of our code all the implicit conversions defined in that object.

When we write 4.0 USD, we try to invoke the USD method on the 4.0 object, which is a double. Obviously there isn't such a method in the Double class, but the compiler, before giving up and throwing an error, tries to see if there is some way to convert the 4.0 in an object that does understand the USD method. Luckily we have imported the doubleConverter which takes a Double and transforms it in an instance of an anonymous class with a USD method: bingo! So the compiler transforms our code in something like this:

 
  doubleConverter(4.0).USD()

But what is the result of this expression? Well, it's an instance of the Money class expressed in Dollar. This class has the + method that we can use to add another Money in the same currency. Cool!

Let's take a look to our work. We needed to add some features to the Double class. In some dynamic languages we could monkey patch this class. In Scala we did it using a dynamic conversion from Double to a class with the methods we need, so we reached the same purpose in a static and safer way.

And so, an old fashioned static language could have such cool features? It seems....

Presentazione su Scala all’XP User Group di Bergamo

Ieri, 29 maggio 2009, ho tenuto una breve presentazione sul linguaggio Scala alla riunione dell'XP User Group di Bergamo. Parlare con delle persone brillanti come gli amici dell'XP-UG-BG è stato veramente una bella esperienza. L'unico mio rammarico è quello di non essere stato in grado di creare una presentazione sufficientemente chiara. Come sempre, la cosa più complessa è essere semplici! Il principio KISS è il più difficile da seguire. Spero comunque di poter fare meglio la prossima volta.

La tessera mancante

E' stata una coincidenza fortunata. Nei giorni scorsi stavo scrivendo del codice, per la prima volta da tempo del codice altamente algoritmico. Da bravo scolaretto XP, avevo creato una serie completa di test, avevo rifattorizzato estraendo metodi, rinominando variabili, abbassando il numero ciclomatico. Le classi erano piccole, i metodi corti, eppure il codice, pur funzionando egregiamente, in qualche modo mi infastidiva.
Poi alla scorsa riunione dell'XP-UG di Milano, Matteo Vaccari ha parlato brevissimamente dell'argomento, ed è stato illuminante. Da qui il suo interessante post.
In particolare una frase pesa come un macigno su quanti, come me, pensano di essere agili solo perché fanno TDD (o qualche altra pratica XP):
"TDD could be a crouch that allows you to give up finding a good design and settle for a mediocre one".
Puoi fare tutto quello che dice il libro bianco di Kent Beck, ma forse non ti accorgi che c'è una tessera mancante....

Ruby in Scala

Ok, il titolo del post è volutamente iperbolico, ma dovete sapete che amo gli eccessi! ;-)
Comunque tutto nasce da un post sulla lista dello Scala User Group italiano.
Partendo da un articolo su Scala di Daniel Spiewak, si mettono a confronto un frammento di codice Scala

 
  def fillColor_=(fillColor:Color) = {
    if (!fillColor.equals(Color.RED)) {
      theFillColor = fillColor
    } else {
      throw new IllegalArgumentException("Color cannot be red")
    }
  }

con un (quasi) equivalente Ruby

 
  def fill_color=(color)
    raise "Color cannot be red" if color == Color::RED  
 
    @fill_color = color
  end

che è sicuramente più piacevole da leggere.

Ricordiamoci però che uno degli aspetti più interessanti di Scala è la facilità con cui è possibile creare DSL. Vediamo come possiamo in qualche modo mimare la sintassi del raise Ruby.

Definiamo prima l'oggetto RubySyntax (va bene, va bene, il nome è un po' pretenzioso, ma a me piace scherzare, dai...)

 
object RubySyntax {   
 
  def raise(exceptionText: String)(condition: => Boolean): Unit = {
    if (condition) {
      throw new IllegalArgumentException(exceptionText);
    }
  }   
 
}

Quindi lo possiamo usare in una qualsiasi altra parte del nosto codice:

 
import RubySyntax._   
 
object RubySyntaxTest {   
 
  def main(args:Array[String]) = {
    val language = "Ruby"   
 
    raise ("Language cannot be Ruby") { language.equals("Ruby") }
  }   
 
}

Certo, ci sono delle parentesi in più, ma abbiamo eliminato l'if. E poi sono convinto che voi sapreste fare di meglio! (Ovviamente in Scala).
Ancora dubbiosi su quale linguaggio scegliere? ;-)

Diventare QSECOFR

Nei sistemi Unix esiste il comando su che permette, avendone la password, di impersonare il "superutente" root.
Anche su AS400 ciò è possibile, anzi, se si possiede l'autorizzazione *USE sul profilo utente desiderato, si può far girare il proprio lavoro sotto mentite spoglie.

Ecco un semplice CL che a tale scopo usa le API di sistema QSYGETPH e QWTSETP.

             PGM        PARM(&UTENTE)

             DCL        VAR(&UTENTE) TYPE(*CHAR) LEN(10)
             DCL        VAR(&USCITA) TYPE(*CHAR) LEN(50)
             DCL        VAR(&TESTOERROR) TYPE(*CHAR) LEN(100)
             DCL        VAR(&HUSER) TYPE(*CHAR) LEN(12)

             MONMSG     MSGID(CPF0000) EXEC(GOTO CMDLBL(ERRORE))
/*------------------------------------------------------------------*/
/* RECUPERO L'HANDLE DEL PROFILO UTENTE                             */
             CALL       PGM(QSYS/QSYGETPH) PARM(&UTENTE *NOPWDCHK +
                          &HUSER)
/* PASSO AL NUOVO PROFILO UTENTE                                   */
             CALL       PGM(QSYS/QWTSETP) PARM(&HUSER)
/* INVIO UN MESSAGGIO DI COMPLETAMENTO OPERAZIONE                  */
             SNDPGMMSG  MSG('Profilo utente cambiato')
/*------------------------------------------------------------------*/
/* FINE                                                             */
/*                                                                  */
             GOTO       CMDLBL(FINE)

/* GESTIONE ERRORI                                                  */
  ERRORE:     RCVMSG     MSGTYPE(*EXCP) MSG(&TESTOERROR)
              SNDPGMMSG  MSG(&TESTOERROR)
/*                                                                  */
FINE:
     ENDPGM

Problemi spegnimento AS400 per passaggio ad ora legale

Il passaggio all'ora legale può bloccare il lavoro QSYSSCD, responsabile dello spegnimento automatico dell'AS400. Tale lavoro potrebbe bloccarsi con il messaggio CPF1076 Il valore specificato non è ammesso per il valore di sistema QIPLDATTIM. Ciò può avvenire nelle macchine per le quali la riaccensione è programmata tra le 2 e le 3 di notte. Tale orario, infatti, non esiste nella giornata di passaggio dall'ora solare all'ora legale! Il programa QSYSSCD al suo avvio verifica che l'orario di accensione previsto è impostato su un valore inesistente e si blocca.
Per risolvere il problema:
1) non programmare il riavvio della macchina tra le 2 e le 3 del giorno di passaggio all'ora legale;
2) digitare STRCLNUP per riavviare il programma QSYSSCD e quindi garantire il normale funzionamento del sistema.

Quello che gli agilisti non dicono

I vantaggi dei test unitari sono ben noti a tutti: miglioramento del design, documentazione del codice, aumento della qualità tramite la diminuzione dei bachi e la possibilità di ristrutturare il codice in modo sicuro. Quello che gli agilisti (a volte) non dicono è che i test unitari, pur portando tutti questi benefici, rappresentano anche un costo nel processo di sviluppo. Un primo costo è banalmente rappresentato dal tempo necessario per il loro sviluppo, ma questo non è l'aspetto principale del problema. L'onere principale dei test, forse più difficile da cogliere, ci è indicato proprio dalle metodologie agili: tutto il codice prodotto comporta un costo di manutenzione, anche lo stesso codice di test.
Occorre quindi saper capire quando il prezzo dei test sia ripagato dai benefici e quando no. La mia opinione è che la creazione di test approfonditi per le interfacce grafiche non è quasi mai "economicamente" conveniente. Riprendo qui alcuni esempi che ho portato in una discussione nata con Matteo Vaccari sulla lista dell'XP User group di Bergamo.

Qualche anno fa, penso fosse il 2003, assistetti ad una presentazione al Webbit nella quale Bruno Bossola mostrò come fosse possibile applicare il TDD alla realizzazione di interfacce Swing, andando a testare lo stato dei vari "model" dei componenti. Tornai a casa entusiasta e provai a mettere in pratica la lezione: fu un disastro! Questo per due motivi. In primo luogo non sono un programmatore valido come Bossola (e allora ero ancora molto meno esperto). Secondariamente lo sforzo per cercare di domare le idiosincrasie di Swing non portava alcun vantaggio. I problemi della GUI sono al 90% del tipo: "Se visualizzo la mia maschera a 800x600 anziché a 1024x768 i bottoni scompaiono", oppure "Se passo a 1280x1024 il carattere è così piccolo che non si legge una fava". Certo, il debugging di questi aspetti si può fare anche con il TDD, ma penso che il debugging umano sia insostituibile, più efficace e molto meno costoso.

Secondo esempio. All'XP UG di Milano tentammo di sviluppare l'UG-Aggregator, una mini applicazione web per inserire e visualizzare gli eventi dei vari XP-UG. Questa applicazione non aveva alcun tipo di logica significativa, ma noi, essendo agilisti DOC, dovevamo scrivere i test! Ci venne quindi l'idea di testare la struttura dell'HTML prodotto, per vedere che ci fossero determinati tag con attributi che dovevano identificarne il contenuto. Il risultato fu circa il seguente, correggimi se sbaglio: tempo per scrivere il codice 1, tempo per scrivere il test 2, tempo per debuggare il test (e non il codice) che non funzionava 4. (OK ho un po' esagerato, ma penso che la mia ricostruzione non sia troppo lontana dalla realtà). Questo a mio avviso è un esempio di programma senza logica per cui il TDD può non essere efficace. Inoltre in questa situazione modificammo non solo la struttura interna dell'applicazione per renderla più testabile, ma anche il suo comportamento. Questa ritengo sia una "puzza" del processo di test!

In questo senso mi ha confortato l'esempio di TDD presentato nell'ultima riunione dell'XP User Group di Bergamo da Alessandro melchiori e Emanuele DelBono. Partendo dai test è stata abbozzata una banale applicazione Windows secondo il paradigma Model - View - Presenter. Ebbene, tutto il codice risultava coperto da test, ad eccezione della parte di view!
(Un unico neo nella presentazione dei due amici bresciani: tutto in C#!!!) ;-)

Installare VNC da linea comando

  1. Scaricare ed installare
    Pstools
  2. Avviare psexec \\nome_o_ip > /u dominio\utente cmd
  3. Da una installazione già esistente di VNC 4, copiare il file winvnc4.exe in una cartella del PC di destinazione (ad esempio c:\programmi\vnc).
  4. Sempre da una installazione già esistente di VNC 4, dopo aver configurato l'istanza server con la password desiderata, esportare la chiave di registro HKEY_LOCAL_MACHINE\SOFTWARE\RealVNC in un file vnc.reg. Copiare quindi tale file sulla macchina di destinazione
  5. Nel propmt remoto sulla macchina di destinazione digitare
    regedit /c /s "percorso\vnc.reg"
  6. Dal propmt remoto sulla macchina di destinazione avviare winvnc4.exe -register
  7. Dal propmt remoto sulla macchina di destinazione avviare winvnc4.exe -start

Come creare un boot CD contenente Spybot

Quando un PC con sistema operativo Windows non riesce a partire, sarebbe utile avere un CD, dal quale effettuare il boot, che contenesse qualche strumento di diagnostica. Ecco come crearne uno contenente Spybot.
Continue reading ‘Come creare un boot CD contenente Spybot’ »