This blog is no longer being maintained, please go to The missing link of Agile instead

Tuesday, March 31, 2009

the beauty of scala traits and self types

So I'm working on a small throw-away project to check out the Scala+Jersey+XStream stack and I've come across a nice implementation pattern (more precisely I found a way to use one I've heard of previously in the slight different context, see James Coplien presentation on DCI and the article on the subject).

I hold a reference to an instance of XStream class somewhere in my app. It is responsible for marshalling objects and it looks like this (examples are shortened for clarity):

val XML = new XStream(new xml.JDomDriver()) {{
setMode(XStream.NO_REFERENCES);
alias("courses", ScalaCollectionClasses.ListBuffer)
alias("course", classOf[resources.Course])
}}

That looks nice - the initialisation block gives the instantiation of XStream object nice DSLish look of a spec. But when I decided to use both XML and JSON and following chunk of code appeared on the screen.

val XML = new XStream(new xml.JDomDriver()) {{
setMode(XStream.NO_REFERENCES);
alias("courses", ScalaCollectionClasses.ListBuffer)
alias("course", classOf[resources.Course])
}}
val JSON = new XStream(new json.JsonHierarchicalStreamDriver()) {{
setMode(XStream.NO_REFERENCES);
alias("courses", ScalaCollectionClasses.ListBuffer)
alias("course", classOf[resources.Course])
}}

Ok.. duplication strikes you right away. So how do you fight that monster? There are actually a few options to choose from:

  • inheritance

    class MyXStream extends XStream {
    setMode(XStream.NO_REFERENCES);
    alias("courses", ScalaCollectionClasses.ListBuffer)
    alias("course", classOf[resources.Course])
    }
    val XML = new MyXStream(new xml.JDomDriver())
    val JSON = new MyXStream(new json.JsonHierarchicalStreamDriver())


  • delegation

    val XML = new XStream(new xml.JDomDriver()) {{ configure(this) }}
    val JSON = new XStream(new json.JsonHierarchicalStreamDriver()) {{ configure(this) }}
    def configure(xstream : XStream) = {
    setMode(XStream.NO_REFERENCES);
    alias("courses", ScalaCollectionClasses.ListBuffer)
    alias("course", classOf[resources.Course])
    }

    or

    val XML = configure(new XStream(new xml.JDomDriver()))
    val JSON = configure(new XStream(new json.JsonHierarchicalStreamDriver()))
    def configure(xstream : XStream) = {
    xstream.setMode(XStream.NO_REFERENCES);
    xstream.alias("courses", ScalaCollectionClasses.ListBuffer)
    xstream.alias("course", classOf[resources.Course])
    xstream
    }


  • implicit conversion

    val XML = new XStream(new xml.JDomDriver()).configure()
    val JSON = new XStream(new json.JsonHierarchicalStreamDriver()).configure()
    def xstreamToConfigurableXStream(xstream : XStream) = new {
    def configure() = {
    setMode(XStream.NO_REFERENCES);
    alias("courses", ScalaCollectionClasses.ListBuffer)
    alias("course", classOf[resources.Course])
    }
    }

Ok as for the first one - inheritance sux.. I mean really.. inheritance is for most of the time the last resort and you know it.

Second and the third one are ok.. I mean most of the time I'd say ok to this solution and implement something like this in Java.

Fourth one.. imho this is a hack and clear abuse of implicit conversion in Scala. Personally I believe that the use of implicit conversion can be justified when trying to bend the existing API for your purposes (ie. trying to seamlessly extend non-functional Java classes to full-blown Scala versions).

So what is the best solution I've found?

trait Configuration
/* 1. */ trait DefaultConfiguration extends Configuration { /* 3. */ this: XStream =>
/* 4. begin */
setMode(XStream.NO_REFERENCES);
alias("courses", ScalaCollectionClasses.ListBuffer)
alias("course", classOf[resources.Course])
/* 4. end */
}

/* 2. */val XML = new XStream(new xml.JDomDriver()) with DefaultConfiguration;
val JSON = new XStream(new json.JsonHierarchicalStreamDriver()) with DefaultConfiguration;


  1. Create a trait that will bind the reference to an instance of a class it extends to "this"

  2. Create an instance XStream for XML marshalling and extend with 'DefaultConfiguration' trait which..

  3. in fact will bind the instance of XStream to 'this' and..

  4. perform an initialisation of a bound object

A powerful (and strikingly easy after you see it for the first time and get the 'aha moment') mechanism for introducing behavior into existing classes. It gives you a perfect decoupling and let you introduce an explicit abstraction for the extension ('configuration' in this case). And now I can do:

def foo(xstream : XStream with Configuration) = "thanks for configured xstream instance bro"

Which basically means: "give me an xstream instance.. but the configured one if you may!"

I am not sure I have fully explained the reason why I like the last one the most.. I got the gut-feeling this is the right path to go. Reusable, expressive, explicit.

Keywords vs API, continued

Przekonany postem Jeffa Atwooda (którego mimo wszystko jeszcze czytam :P) postanowiłem, że decyzją pragmatyczną będzie zmiana języka bloga na 'informatyczne esperanto' czyli angielski. Z dniem dzisiejszym wszystkie posty będą ukazywały się w tymże języku.
-- Translation --
Jeff Atwood (whose blog I continued to read in spite of everything :P) convinced me in his latest post that it'd be a pragmatic decision to switch the langugage of posts to 'Esperanto of software world', ie. English. Therefore starting today all posts are written in English.



Here we go then!

In one of the older posts I mentioned that it may be quite a problem to migrate from Scala to Java world. The keywords chosen for Scala might have been used already for name of the methods or classes in existing Java APIs (e.g. 'match' or 'yield') thus preventing us from using them in our code. BTW the well known example of such a case is Java evolution itself (1.4 -> 1.5 and the appearance of 'enum' keyword')

It appears that in Scala nothing is impossible! Well it is not feasible to define/use functions as presented below:

def match() = "Hello world! I am a 'match'!"
def yield() = "Hello world! I am a 'yield'!"

match()
yield()

Yet nothing prevents us from doing it this way:

def `match`() = "Hello world! I am a 'match'!"
def `yield`() = "Hello world! I am a 'yield'!"

`match`()
`yield`()

It is incredibly useful not only for Scala adoption among Java developers but also quite helpful during the development of 'Scala greenfield projects'. While in Java it is not that big issue (due to relatively small number of keywords) in Scala it'd have probably started being a bit of pain in the ass (with keywords like 'val' or 'match').

The conclusion? Scala rox! :D

Sunday, March 15, 2009

404 done the right way

Ponieważ po raz kolejny napotykam się na beznadziejny komunikat 404 .. postanowiłem poprawić jeden z nich. Na poprawce spędziłem +/- 30 sekund i przepraszam za ewentualne błędy.

Przed Pawłem:

Po Pawle:

Po Pawle wersja minimalistyczna:


Dlaczego uważam, że moje wersje są lepsze? Pozwolę sobie skomentować niektóre fragmenty komunikatu:
1) "Welcome to 404 error page"
Przeciętnego użytkownika Internetu doprawdy niewiele obchodzi czy kod błędu w protokole HTTP to 404, Alfa8 czy Dupa16.. Chciałbym, żeby programiści wreszcie zaczęli sobie z tego zdawać sprawę. Z drugiej strony świadomy użytkownik internetu zdaje sobię sprawę że nie istniejąca strona to kod 404 - więc po co mu o tym przypominać?! Kolejna rzecz, że obsługa błędów powinna być transparentna dla użytkownika i wtedy nie będzie musiał się uczyć różnicy między 404 a dajmy na to 410. Informacje czytelne dla komputerów zostawmy komputerom.

2) "Welcome to this customized error page. You've reached this page because you've clicked on a link that does not exist."
Ok.. odniosłem wrażenie jakbym celowo otworzył tę stronę i to co czytam było początkiem artykułu o kodzie błędu 404. Naprawdę nie wystarczyło krótkie i treściwe "Page does not exist" ?

3) "This is probably our fault..."
Nie miejsce i czas na unoszenie się honorem. Stare porzekadło ludowe mówi: "Klient ma zawsze rację". Komunikat powinen brzmieć: "This is totally our fault! We beg for forgiveness!"

4) "but instead of showing you the basic '404 Error' page that is confusing and doesn't really explain anything, we've created this page to explain what went wrong."
I co? Mam być wdzięczny, że straciłem 10 cennych sekund mojego życia czytając komunikat błędu ?!?!

5) "You can either (a) click on the 'back' button in your browser and try to navigate through our site in a different direction, or (b) click on the following link to go to homepage."

Chociaż mogli a i b pogrubić bo zajęło mi z dobre kilka sekund (a to dużo; odsyłam do badań z usability) żeby się dowiedzieć co mogę zrobić.

Reasumując:
Tworząc komunikaty z błędami kierujmy się zasadą KISS. Zaoszczędzimy użytkownikom dużo cennego czasu, który mogą spędzić, np. stymulując polski rynek browarniczny ;)

Tuesday, March 03, 2009

Scala nabiera prędkości

Widać, że zainteresowanie Scalą rośnie (Hura!). Chyba czas najwyższy poważnie zacząć w nią inwestować (np. ruszyć Dage'a :P).

Książki o Scali które są - lub w najbliższej przyszłości będą - wydane.

Ponieważ już wiele osób mnie pytało jak zacząć przygodę ze Scalą, poniżej zamieszczam kilka przydatnych linków:

Prezentacja o Scali - Konkretna, pragmatyczna, krótka (108 slajdów :P).

Tutorial - szybkie wyprowadzenie do języka. (15 stron)

Przegląd możliwości języka - naprawdę "mind-blowing". Polecam!! (kiedyś 55 stron w PDF - teraz dostępne na stronie)

Scala poprzez przykłady - wprowadzenie do języka. (145 stron)

Specyfikacja języka - tylko jeśli wybrałeś czerwoną pigułkę ;) (180 stron)

Monday, March 02, 2009

Streszczenie: Investigating architecture and design

Jedną z rad w przeczytanej ostatnio przeze mnie książce "Pragmatic Thinking & Learning: Refactor your wetware" autorstwa Andy'ego Hunta jest prowadzenie wiki. W takiej wiki może znaleźć się wszystko od ciekawych cytatów, poprzez przemyślenia aż do streszczeń książek oraz artykułów (itd. itp.). Streszczanie książek/artykułów, podkreślanie ważnych fragmentów, dopisywanie komentarzy etc. samo w sobie jest polecane przez Hunta jako świetny sposób na lepsze przyswojenie tematu... Nie będę jednak przepisywał porad z książki Andy'ego bo nie o tym miało być :) (choć gorąco zachęcam do jej przeczytania!).

Zamiast tego zamieszczam streszczenie artykułu Neal'a Forda "Investigating architecture and design" przeplatane moimi przemyśleniami.


Jeśli komuś spośród garstki osób, które odwiedza mojego bloga ;) podoba się pomysł takiego właśnie dzielenia się wiedzą będę od czasu do czasu publikował notki tego typu. W przeciwnym razie, żeby się nie pozbawiać i tak nielicznego grona czytelników :P odpuszczę sobie.
Czekam na feedback!




Notatka powstała przy użyciu pluginu do VIM'a - viki oraz konwertera deplate (dla zainteresowanych wystarczy: sudo gem install deplate).



Źródło:
Evolutionary architecture and emergent design: Investigating architecture and design[1]


1 Introduction
==============

Architecture is being separated into two categories:

* application architecture - coarse-grained pieces that compose an
application - which is further dived into:
+ framework-level architecture - the combination of frameworks,
+ application architecture - logical separation of concerns.
* enterprise architecture - how enterprise as a whole consumes
application.

+++ Metaphor for software architectures

Enterprise architecture => city planning

Application architecture => building architecture


2 Definitions of architecture
=============================

"In most successful software projects, the expert developers working on
that project have a shared understanding of the design system design.
This shared understanding is called 'architecture'. This understanding
includes how the system is divided into components and how the
components interact through interfaces." Ralph Johnson

"Architecture is about the important stuff. Whatever it is." Martin
Fowler

"Stuff that's hard to change later." Neal Ford


3 Important note
================

!!! Architecture -> Evolves !!!

Because it consists of elements that must exist before you start
building an application.

!!! Design -> Emerge !!!

Because it is grown over time.


4 Useful equations
==================

"Flexible architecture" + "Reversible decisions" = "Evolving
architecture"

"Just-in-time dirty hacks" = "Technical debt" = "Rising entropy"


5 Complexity
============

* essential,

!!! Watch out for essential complexity! It might be possible to
!!! lower it by asking customer to consider her/his choices more
!!! carefully. Money argument is the ultimate way of doing that.
* accidental.

Accidential complexity:

1. Just-in-time hacks.
2. Duplication.
3. Irreversibility.

+++ Because genericness adds entropy, you damage your ability to evolve
the design in interesting ways early in the projects.

[1] http://www.ibm.com/developerworks/java/library/j-eaed1/index.html