Ça y'est, c'est officiel, les inscriptions à la conférence Agile Open France 2009 sont désormais ouvertes. Bien évidemment, je me suis précipité sur le formulaire d'inscription dés réception de l'annonce. J'ai eu la chance de participer à l'édition 2008 et je dois dire que j'en suis revenu enthousiasmé par le format Forum Ouvert (ou Open Space) qui, à mon sens, est la meilleure manière de produire un tel événement.
J'aurais voulu utiliser ce format pour Agile Tour Lille 2008 mais celui-ci suppose que les participants aient déjà une idée de ce qu'ils viennent trouver et apporter, ce qui n'était pas nécessairement le cas du public de l'Agile Tour.
La deuxième journée des Valtech Days était aussi organisée selon ce modèle et je dois dire que c'est la partie que j'ai le plus appréciée.
J'attends avec impatience le mois de janvier pour être de nouveau surpris.
I am struggling to improve my Muse parsing software, a project that I have been working on for couple of years now and which I use to publish this blog and the whole OQube's site. It is based on the Emacs Muse wiki format which means that I can operate within the context of Emacs with all the useful tools and keyboard shortcuts I find there, and be able to serve muse content over the web in various backend formats, HTML and RSS feeds being the most useful.
As all software, especially software that is used and maintained by a single person, it is made of layers of code injected haphazardly from urgent needs or nigthly ideas.
There are some basic flaws in the design of the key elements of this software that are now impediments for further evolutions:
ContentHandler interface from SAX which means events are nothandled uniformly,This means that the time spent implementing new features is raising. I am trying to implement a simple slide formatter, something that I could use to produces slide-shows for talks, including code samples for online execution and examples in Javascript, something along the line of what John Resig published on his site
To implement this, I need one of the following but both are hards to implement using the current state of my muse parser:
div elements with ids from each hXelement and its siblings, up to the following hX element,I have already had 3 false starts trying to implement this, which is a sure sign that something gets wrong: either me or the software is becoming very reluctant to change.
Aujourd'hui au dojo, nous avons fait en randori du refactoring d'un bout de code Java (voir cette page). Nous avons eu le plaisir d'accueillir de nouveaux venus dont certains que je connaissais par ailleurs (Michael et Vincent, que j'ai rencontré dans le groupe PYLULE), d'autres que je ne connaissais pas. Il semblerait que l'Agile Tour ait porté ses fruits et intéressé des gens à la pratique de l'agilité.
Le code de départ est le suivant:
/** * Split a signature string into its constituent parts and fills the list * argument. * * @param sig * java standard signature * @param ret * a List where parsed arguments will be stored. May be null. * @return a List<String> of arguments' types plus return type. The strings * correspond to the standard internal encoding of the JVM. */ public static List parseSignature(String sig, List ret) { if (ret == null) ret = new ArrayList(); int i = 0; int j = 0; int ln = sig.length(); StringBuffer arr = new StringBuffer(); parse: while (i < ln) { switch (sig.charAt(i)) { case '(': i++; break; case 'L': j = sig.indexOf(';', i); arr.append(sig.substring(i, j + 1)); ret.add(arr.toString()); arr.delete(0, arr.length()); i = j + 1; break; case ')': i++; break; case '[': i++; arr.append("["); break; default: arr.append(sig.charAt(i)); ret.add(arr.toString()); arr.delete(0, arr.length()); i++; } } return ret; }
Nous n'avons pas achevé le remaniement du code, l'objectif initialement fixé étant de restructer le code pour le rendre plus lisible et maintenable tout en gardant le comportement identique. La motivation est d'envisager une évolution future de code, par exemple une modification de signature pour rendre explicite des conditions d'exception, ou une suppression de paramètres du fait du non-respect du Principe de Responsabilité Unique
La stratégie adoptée a consisté:
NullPointerException mais quipourra évoluer par la suite;switch interne, ce qui nous permettra d'extraire cesdifférents cas particuliers dans des fonctions/objets connexes etdonc de simplifier le code.Dans le cas de cette fonction, il est clair que l'on est en présence d'un parseur donc que l'utilisation d'expressions régulières ou d'autres mécanismes d'analyse syntaxique serait pertinents et rendrait le code beaucoup plus explicite.
Aucune vérification de correction n'est faite sur les constituants de la signature, par exemple sur le nom d'une signature représentant une classe ou sur les différents codes possibles pour les types primitifs. Cette fonctionnalité pourrait être facilement ajoutée une fois l'analyse syntaxique correctement réalisée.
This is an interesting idiom found in the paper on reactive programming in Haskell, that constructs new types using layers of type constructors, each layer providing additional properties through instances of type classes:
It is used to define an improved time type with some useful properties to work on timed-streams:
previous type FTime = Max (AddBounds (Improving Time)) newtype Max a = Max a deriving (Eq, Ord , Bounded ) instance (Ord a, Bounded a) => Monoid (Max a) where mempty = Max minBound Max a `mplus` Max b = Max (a `max` b) data AddBounds a = MinBound | NoBound a | MaxBound deriving Eq instance Bounded (AddBounds a) where minBound = MinBound maxBound = MaxBound -- An improving value. Invariant: -- compare I iv compare (exact iv ) data Improving a = Imp{exact :: a, compare I :: a -> Ordering } compare :: Ord a => Improving a -> a -> Ordering exactly :: Ord a => a -> Improving a exactly a = Imp a (compare a)
list of topics:
voting: -> Arguments to convincing
What's worked ?
cf Guitart, "l'envie de s'y mettre"
Paul Graham in Hackers and Painters: "Language matters, and LISP is the best one because of macros/meta-programming and its sheer rarity."
Session présentée par Julien Delhomme, consultant chez Valtech, sur les différents modèles de concurrence et l'avenir de ce type de programmation pour le commun des mortels. Plusieurs modèles ont été présentés:
Kata présenté par Emmanuel Gaillot et Etienne Charignon, sur le théme du Mastermind. Excellente préparation, avec un bon déroulé du problème et un gros effort d'explication de la part du copilote et du pilote. La solution obtenue est effectivement assez élégante, encore que l'on aurait pût - dût ? - remanier le code plus tôt de manière à introduire les abstractions objets plus facilement (eg. le comptage des jetons bien et mal placés).
Questions intéressantes sur:
I have (nearly) the skeleton of a working web application in Haskell, using FastCGI interface, storing session in a map keyed by some integer value, and allowing users to login, register, logout... The UI is pure HTML with javascript based on jQuery and its rich API: data is requested from the server that is supposed to return javascript or JSON objects, which will be used by the client side to update the UI. This last part is still missing, but I am feeling I have reached, once again, some dead end.
The structure of the application is embedded within the services it exposed, meaning that, for example, that register updates the session to allow login action, which in turns update the session to allow logout and unregister, etc. As those functions work on with a database, this implies that to both work with I/O and with the state of the application, they must work within a StateT monad transformer parameterized with IO monad. We can foresee that composing additional behavior will entail more and more monad stacking for eg. logging, error tracking.
What we really is, as usual, decouple the various components and layers we are working with so that each function serves one and only one purpose and that the top-level application orchestrates them. At this stage, without thinking about additional monadic behaviours, we would like to distinguish at least two layers:
Being a very flexible language, Haskell should allow us to express composition of fucntions and behaviours externally, without the individual elements ever noticing they are part of some composite application. What is done with XML configuration files in Spring-like frameworks should be done in Haskell within the Haskell framework.
This idea I have already implemented in Java while developing the M-Commerce framework, which used an underlying finite-state machine to orchestrate access to service and the Pico container framework for dependency injection. DI within Haskell can be done:
Sujet
rake journalisé et versionnéWhile researching a way to represent pattern-matching easily within the My Language is Bigger than Yours boardgame, I came upon a book chapter on google-books that precisely defines a program transformation for eliminating pattern-matching and recursive data-types definitions from Haskell progras, thus making them composed only of functions and primitive constants.
The key to this transformation is to observe that any datatype can be equivalently transformed, using what is called Church-encoding into a set of constructor and desctructor functions. This I have already shown in a preceding article (see this article ). Given the following data-type for binary trees:
previous data Tree a = Leaf a | Node a (Tree a) (Tree a)
we can define the constructor functions:
previous type Tree a = ((a -> c) -> (a -> t -> t -> c) -> c) Leaf a = (\l n -> l a) Node a t t' = (\l n -> n a t t')
If we want to know the value stored at a tree, we can either write, using pattern-matching:
previous value Node x = x value Leaf x _ _ = xor, using constructor functions:
previous value t = t (\a -> a) (\a _ _ -> a)
The key insight to this transformation is to notice that:
So we can hopefully generalize this transformation to any datatype: given a type defined as a sum of products as:
previous data Type = Ctor1 p11 p12 ... p1n | Ctor2 p21 ... p2m | ... | Ctork pk1 ... pkl
we can define the type Type and a set of constructor functions ctor1, ..., ctorl defined as:
previous type Type = (t11 -> ... -> t1n -> c) -> (t21 -> ... -> t2m -> c) -> ... -> (tk1 -> ... -> tkl -> c) -> c ctor1 v11 ... v1n = (\ f1 f2 .... fk -> f1 v11 ... v1n) ctor2 v21 ... v2m = (\ f1 f2 .... fk -> f2 v21 ... v2m) ... ctork vk1 ... vkl = (\ f1 f2 .... fk -> f2 vk1 ... vkl)and then each function operating on
Type that wants to pattern-match against its instances should be implemented by passing the specialized function to the given instance of Type that it is passed.
This can be generalized to n-ary pattern matching in the obvious way, ie. by currying.
It took me quite a few hours to implement a feature that, at first sight, appears quite simple: Extract and display a single entry from a log file as an HTML page. This feature is meant to be used as the target of links from RSS feeds. Given the unexpected difficulty of the task, and the somewhat contorted solution I found, I felt it would be worthwhile to provide details of the problem, the various paths I took and the (partial) solution I found.
I am developing a set of Java components based on the Emacs Muse publishing format, a simple wiki-like text format that I discovered a few years ago while using EmacsPlanner tool. Among other things, this blog and the whole OQube's site are written in Emacs Muse and published on the web using a dedicated web application.
This system is composed of, among others, the following components:
The Feed backend produces a RSS 2.0 formatted news feed from a muse file: Each level one title is considered a news item if the title contains a date formatted as YYYYMMDD. In the RSS 2.0 format, each entry is identified with a supposedly unique URI, which is formed by transforming the date to YYYY/MM/DD format and suffixing it with the title from which all non-ascii characters have been escaped (I should use the standard urlEscape() function).
For example, this news item is transformed to:
<?xml version="1.0" encoding="UTF-8"?> <rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0"> <channel> <title>OQube's Blog</title> <link /> <description>Random things I am working on...</description> <dc:creator>Arnaud Bailly</dc:creator> <item> <title>Filtering sections from Muse RSS Feed</title> <description>20081018: Filtering sections from Muse RSS Feed <h2>The context </h2> <p>I am developing a set of <em>Java</em> <pubDate>Fri, 17 Oct 2008 22:00:00 GMT</pubDate> <guid isPermaLink="false">http://localhost:4444/journal/journal/2008/10/18/Filtering-sections-from-Muse-RSS-Feed</guid> <dc:date>2008-10-17T22:00:00Z</dc:date> </item> ...
The problem lies in the <guid> tag: Using the given URI in a browser should provide the given news in XHTML format. The news item should be extracted from the muse file which contains all the news. The question is: how to extract the selected news (or any other subset of the file) from the muse file and format it ?
Abstracting away from the details, this problem can be narrowed to the following: Given a stream of objects, how to select a subset of this stream using simple rules ? For example, if we consider a stream of a-z letters, we want to select the substream that is contained between the letters ab and the letters yz. Applying this rule to the word jlkjlkabcdeffdsfyzflsfdkj, we obtain the word abcdeffdsfyz
It is obvious that, in the case of letters, this problem boils down to regular languages matching: extract some rational pattern from a stream (ie. a word). But in the case of events, we are facing a somewhat different problem: the alphabet is infinite which implies the language is not regular. Furthermore, writing a finite state machine ie. a regular language acceptor, while not an extremely complex task, is not immediate and quite error-prone.
The idea I explored is based on event filtering and the Decorator pattern:
filter() method which returns whether ornot the event should be filtered,The problem I faced was managing the state of the underlying FSA so that parsing events can be passed in a timely fashion:
Neither of this solutions is satisfying:
The idea is to define the filter as a SinkEvent transformer, a function from SinkEvent to SinkEvent that returns the event to be passed to the real sink. A special event is defined, NullEvent that is a non-event and, when asked to activate a sink, does nothing. By defining filters as transformers, they can be composed.
previous public interface SinkFilter { SinkEvent filter(SinkEvent e); }
Filters are then made into combinators that operate on stream of sink events and, together with filter operators, can form a whole algebra of stream transformers and selectors.
For this to works, I also needed to create a CompoundEvent object that implements the SinkEvent interface and that passes all accumulated events to its underlying sink. This is needed because, when the filter needs more than one event lookahead, it buffers the events passed so far and it cannot produce the correct event before having matched the whole pattern.
previous public interface SinkEvent { SinkEvent NULL_EVENT = new SinkEvent() {...}; void passTo(MuseSink sink); }
The interesting thing about a combinator-based implementation is that, being in essence purely functional, it has a number of interesting properties:
The current implementation suffers however from some defects and is not fully functional
previous double_negation_property :: (SinkEvent -> SinkEvent) -> Bool double_negation_property f = not . not . f == fbut this does not work as a simple test using a
StartFiltercombinator can easily shows: Actually, one would like filters to be much like a boolean algebra, closed under the usual operators: negation, intersection, union, difference, much like lists are in most functional languages, and like rational languages are.
Ça y'est, l'Agile Tour 2008 est passé par Lille ! En voici un bref résumé, plus quelques idées pour une prochaine manifestation.
Nous avons eu pas mal de désistements, mais il faut dire que nous n'avons vraiment pas assuré côté relance: un mail tardif et une relance téléphonique la veille pour le lendemain. Seuls les gens que François et moi connaissions personnellement sont finalement venus.
Les sessions proposées étaient donc les suivantes:
Les sessions étaient découpées en créneaux de 30', plus 5' de temps élastique permettant de laisser aux gens de bouger.
Comme nous n'avions pas plus de sessions que de créneaux (18 au total), les participants ont "voté" en arrivant avec des gommettes pour nous permettre de répartir au plus juste les salles. La répartition des votes semblait indiqué en grand besoin d'information, plutôt que du pratiques, probablement parce que beaucoup de participantsn n'étaient pas des experts de l'agilité et venaient là pour découvrir, apprendre et surtout discuter.
J'ai fait le planning après avoir introduit Agile Tour et les grandes lignes de l'organisation, tandis que les orateurs se présentaient, eux et leurs sessions.
Nous avions donc trois salles:
Les locaux de TELECOM Lille 1 sont très bien, mais la disposition des salles, très éclatées les unes des autres n'étaient pas idéale. Heureusement, le fléchage était bien fait et les salles quand même situées dans des endroits évidents, pas au fin fond d'une aile. Personne ne semble s'être perdu, ou du moins pas suffisamment longtemps.
Il y avait 85 inscrits, et il me reste 22 badges, donc j'en déduis qu'il y avait au moins 63 participants. EN réalité, il devait y en avoir légèrement plus puisque des gens non inscrits se sont présentés spontanèment.
Les profils étaient très variés. Je n'ai pas de statistiques précises, dont le sens sur un échantillon de 60 personnes serait de toute façon douteux, mais j'ai perçu les grandes lignes suivantes:
Tout le monde a salué l'organisation de l'événement, ce qui ne laisse pas de me surprendre car j'ai vraiment eu l'impression qu'on a fait ça à l'arrache et que c'était un peu... chaotique. Je pense, cela dit, que beaucoup ont apprécié le côté informel. Le groupe était de petite taille, la manifestation de courte durée et le lieu compact, donc l'improvisation pouvait suppléer à la préparation.
Je n'ai eu que de bons échos, aussi bien de la part des participants que des orateurs. Il faudrait avoir dépouiller les questionnaires de satisfaction pour en savoir plus. J'ai le sentiment que tout le monde a trouvé ce qu'il venait chercher ou a pu dire ce qu'il avait à dire.
Je regrette un peu le manque d'ateliers et la faible participation au dojo présenté par Eric Mignot et Laurent Cobos. Il me semble pourtant de plus en plus que le développement de l'agilisme passe par là, que c'est un outil extraordinaire pour progresser et faire progresser. Comme si beaucoup de gens avaient un peu peur de se mettre en danger en codant collectivement, comme si le code était toujours quelque chose que l'on faisait solitairement.
J'ai vraiment envie de trouver d'autres formes que la classique conférence où l'on vient écouter la bonne parole, confortablement assis dans un amphithèâtre. Il me paraît essentiel, partie intégrante des valeurs et des principes de l'agilité, que les participants contribuent activement au contenu de la conférence.
Les ateliers sont un bon moyen de parvenir à ce résultat, et en discutant avec Marie-Aimée, nous avons imaginé d'autres types d'organisation:
An old post by Michael Feather that talks about things I would like to present at SPA2009: different approach to code quality than TDD. Here it talks about the Clean Room method that, back in the 80's, enforced quality through formal expression of code behavior with logical predicates (presumably Hoare's logic predicates).
Things are getting more and more complicated as I am closing in on the client-side of the web app. Thanks to some help from the haskell-cafe mailing list denizens, I managed to got a running FastCGI web application working, with the shared state passed around, although this feature is untested.
The basic idea is to initialize the World once in a shared variable reference, preferably a thread-safe one, then to pass that value to the worker functions that could well be some IO threads.
previous main = do world <- newTVarIO initialState -- initialize shared variable containing state runFastCGI $ work world -- service requests work :: TVar World -> CGI CGIResult work world = do sid <- fmap (maybe 0 id) $ readInput "sessionId" -- extract session identifier sname <- fmap (maybe "index" id) $ getInput "service" -- extract service name world' <- liftIO $ atomically $ readTVar world -- extract state of the world setHeader "content-type" "text/plain" output $ service sname world'
I am presently struggling with the client side, trying to use jQuery and its Form plugin. I found the hard way that although they are somewhat equivalent, and sometimes use equivalently in HTML, id and name are not the same. jQuery selectors use id while form submission uses the name attribute. So one usually define both or use [name='toto'] selector to extract the needed field.
I am still stuck with the intricacy of submitting forms, between the subtleties of submit(), ajaxForm() and ajaxSubmit(), but I can now pass around values from the client to the server, and most notably the requested service and probably the session id if it is defined.
I plan to make the application in client/server architecture, with the Haskell code providing services and JSON data, and the client code using jQuery to update the UI.
I managed to refactor the code to use explicitly State and StateT monad, thanks to this thread on Haskell-café and this blog post. In the process I got to understand a few things about those dreaded monads and the way to combine them, although this obviously only scratch the surface of things.
The code of authenticate now looks like:
previous getUser :: String -> String -> IOWorld (Maybe User) getUser login password = lift $ readResource (User login password) authenticate :: String -> String -> IOWorld (Maybe Session) authenticate login pwd = do u <- getUser login pwd liftState (createSession [("unregister", unregister),("logout", logout)] (checkPassword u))
All top-level actions are done in the IOWorld context which is a State monad encapsulating IO monad. We need IO because we are dealing with the persistence layer.
The tests look a lot nicer, although some duplication obviously persists:
previous aLoggedInUserCanUnregisterWithKey = "Logged in user can access unregister action with key" ~: (withDB "test.db" (evalStateT (do register "nono" "password" Just session <- authenticate "nono" "password" let Just action = lookup "unregister" (actions session) action session authenticate "nono" "password") initialState >>= assertEqual "unexpected user" Nothing))
The sequencing of actions that the monad allows - and imposes - is not cluttered anymore by explicit arguments passing. The extraction of the action could encapsulated too in a nice monadic action.
The important lesson about monads is: you can't mix apples and oranges. Monad sequencing is just a special kind of composition:
. operator, yielding function `g . f: a\rightarrow c`>> and <code>>>=</code> (ie. bind) operators, yieldingfunction `f join g: a \rightarrow m c`The important thing to note is that both encapsulated type and monad type have to be compatible (ie. the same) for this to work. One cannot compose actions occuring in different monads without some kind of transformation which is just why monad transformers are useful: they allow one to unify different kind of actions/effects within a single layered monads.
One important function in this context is the lift operator that allows, as it name implies, lifting functions operating within one monad to another layer of monad. This means that given a IO a action, you can lift it to a StateT s IO a action by lift, but given a State s a action, how do you lift it to StateT s IO a ? You need to apply the IO monad to the result of the State monad before returning it.
One solution given by the cited posts is to define a liftState function:
previous liftState :: Monad m => State s a -> StateT s m a liftState s = do state1 <- get let (result, state) = evalState (do result <- s state <- get return (result, state)) state1 put state return result
But there is another, more elegant, solution: use the interface MonadState to constrain the context of the createSession function and all other functions that operate at the state level and could need to be lifted at some other level. We can thus now write:
previous createSession :: MonadState World m => [(String,Action)] -> Maybe User -> m (Maybe Session) authenticate login pwd = getUser login pwd >>= (createSession [("unregister", unregister),("logout", logout)] . checkPassword)
I can understand this barely but will try to explain it:
createSession must be some monad mthat is also an instance of MonadStateMonadState s m, one finds MonadState s(State s) and MonadState s (StateT s m)authenticate has return type IOWorld a, or moreprecisely that the right hand side of the equation for authenticatehas this type, we know that monadic actions will take place withinthis monad (a type alias for StateT World IO agetUser l p has such a type, so we can bind its result within themonad to another monadic action,checkPassword is a simple function that takes a Maybe User, checks the supplied password is correct and returns the user or Nothing,createSession,our MonadState dependent action. Thus the whole type of(createSession ... checkPassword) is <code>MonadState World m =>Maybe User -> m (Maybe Session)</code> which is monadic but withthe monad as a parameter m, which is then instantiated with IOWorldan alias for StateTWhile working on Haskell implementation for Colivri, I got stuck within the complexity of monad transformers, most specifically with the wiring of the State monad with the IO monad. The code uses state to store session informations when users log in and out of the system. For example, the authenticate function looks like:
previous authenticate :: String -> String -> World -> IO (World, Maybe Session) authenticate login pwd s = readResource (User login "") >>= return . (createSession s [("unregister", unregister), ("logout", logout)] . checkPassword) where checkPassword Nothing = Nothing checkPassword u@(Just (User uid pwd')) | pwd' == pwd = u | otherwise = Nothing
The StateT is defined as
previous newtype StateT s m a = StateT (\s -> m (a,s))
so I am tempted to rewrite authenticate as:
previous type IOWorld a = StateT World IO a authenticate :: String -> String -> IOWorld (Maybe Session)
The problem is that I am not able to write the code that would make this to typecheck or compile !
Otherwise, I managed to write a simple command-line interface through which I can login/logout and register/unregister users within the database. Next step is to wire that logic through FastCGI. But how do we maintain state on a FastCGI server ?
In a recent entry of Testing in the Toilets, a technique is described for testing asynchronous handlers tied to setTimeout et al. family of functions, available at the global scope. This is something I tried to do in Benefit for the scheduling code of test executors, but much better as here the passing of time is controllable.
I spent part of the morning switching from flat file storage to DB storage for the tiny little embryonic web app in Haskell I am working on. I managed to use Sqlite3 bindings for HDBC which is quite low-level but at least works smoothly once you recall how to code in SQL.
Installation was easy once I removed the .cabal and .ghc directories from my $HOME
sudo aptitude install libghc6-hdbc-sqlite3-dev
I then made User type an instance of IResource and implemented the CRUD operations there:
previous import Database.HDBC import Database.HDBC.Sqlite3 ... handleError str err = error $ str ++ ":" ++ ( seErrorMsg err) ++ ", code:" ++ show (seNativeError err) instance IResource User where keyResource User {login = uid} = uid writeResource User {login = uid, password = pwd} = handleSql (handleError "in write resource") (do con <- connectSqlite3 "test.db" run con "insert into auth_user (username, password) values (?,?);" [SqlString uid, SqlString pwd ] commit