Saturday, November 2, 2019

I metodi "leggeri" servono?

Via twitter ho scritto:

Adottare una metodologia di sviluppo software leggera [i.e. "agile"] non serve.

1) Se le persone sono competenti ed oneste, non hanno bisogno di adottare alcun metodo [esterno], perché un metodo già ce l’avranno e sapranno usarlo in sintesi tra di loro.
2)Se le persone sono incompetenti o disoneste, nessuna metodologia leggera può essere di aiuto. Infatti: 
se sono incompetenti, allora è ovvio
se sono disoneste, allora può aiutare solo un metodo pesante, un Leviatano, ovvero un metodo tipo Waterfall.


Ora elaboro questa tesi.

Ho usato due termini: “competente” e “onesto".

Nella mia accezione “essere competente” vuol dire non solo “saper fare” ma anche conoscere i propri limiti.
I programmatori sapranno (singolarmente) realizzare, con gli strumenti che conoscono, delle soluzioni software in grado di eseguire uno o più compiti che vengono comunicati in modo chiaro dai richiedenti. Sanno anche cosa manca alle loro conoscenze, e quanto ci vorrà per acquisirle.


Coloro che commissionano un lavoro di programmazione sono competenti se: 
  1. conoscono il problema che vogliono risolvere, 
  2. conoscono il dominio (o ambito) del problema stesso, 
  3. sono in grado di spiegarlo in modo chiaro.
  4. conoscono i propri limiti in relazione a punti precedenti, e non lo nascondono (spesso certe cose si devono necessariamente scoprire nel corso del tempo).



Ora cerco di argomentare la prima delle due tesi.

Punto 1. Se le persone sono competenti ed oneste, non hanno praticamente alcun bisogno di adottare un metodo esterno. A loro basta adottare un metodo che sia la sintesi di quelli che già avrebbero adottato come singoli.


Per ipotesi i committenti conoscono in buona parte il compito per il quale richiedono una soluzione, e sanno comunicarlo in modo chiaro. Evitano quindi di scrivere cose fumose e polverose. Se invece lo fanno, con vaghezze o ambiguità nella comunicazione, forse la cosa indica un qualche interesse a farlo, per esempio per nascondere delle proprie eventuali lacune nella conoscenza del problema (cosa che è contro l’ipotesi).

Quanto detto sopra suggerisce che esiste la possibilità di adottare una buona comunicazione, a prescindere dal linguaggio o dai formalismi. Un modo di definire la buona comunicazione in effetti esiste, ed è principio cooperativo di Paul Grice, che consiste nelle seguenti regole: Qualità, Quantità, Rilevanza, Maniera.
La regola di quantità raccomanda il giusto equilibrio tra il non dire troppo e il non dire troppo poco.
La regola di qualità raccomanda di non dire ciò che sai essere falso né ciò per cui non hai sufficienti prove per assumere che sia vero.
La regola di rilevanza raccomanda di dire cose pertinenti all’argomento e al contesto.
La regola di maniera raccomanda di evitare espressioni oscure o ambigue, e raccomanda piuttosto di essere succinti e di rispettare un opportuno ordine (sequenza).

Dunque i committenti possono comunicare bene quello che sanno, perché esistono i principi del comunicare bene.

Oltre a saper comunicare il cosa, è utile saper comunicare il perché, lo scopo, secondo il principio sistemico per cui “per decidere in modo appropriato il come [fare una cosa], bisogna conoscere anche il perché [cioè lo scopo], oltre al cosa”.

Per ipotesi, i programmatori del gruppo sono persone che singolarmente sono competenti ed oneste. In generale questa condizione è necessaria affinché l’intero gruppo nel suo complesso possa essere considerato “competente” ed “onesto”,  ma, pur essendo necessaria, in effetti non è una condizione sufficiente. Commetterei una fallacia di composizione se dicessi che è anche una condizione sufficiente. "Fallacia di composizione" significa sostenere che “quando qualcosa vale per le parti di un insieme, allora vale anche per tutto l’insieme” (il che è falso, e quindi fallace).

Provo a tentare di superare la fallacia di composizione in modo semplice.

Accenno alle singole tecniche comunemente usate, ed al fatto che esse stesse in effetti sono già predisposte per il lavoro di gruppo. Cioè possono “scalare”. Alcuni esempi:

  • Gestione del codice sorgente. Un po’ tutti i programmatori bravi usano sistemi di controllo di versione, come bitbucket, gitlab, o github per i loro progetti, che si tratti di toy project, che si tratti di progetti professionali, open source o meno. Questi sistemi li usano proficuamente gruppi anche distribuiti geograficamente, e ci sono tanti progetti, soprattutto open source, che lo confermano. Tecnicamente ci potranno essere dei conflitti di codice durante gli allineamenti/aggiornamenti, ma sapendo programmare “bene” è sempre più difficile che ciò accada. Infatti il più delle volte, nell’aggiungere una funzionalità, possiamo evitare di introdurre side effect che coinvolgano altre funzionalità, o comunque possiamo essere in grado di rilevare e correggere un eventuale errore per tempo (considerano anche normali periodi di beta testing). Ci saranno sempre difficoltà e conflittualità, ma il punto è che queste difficoltà e conflittualità devono essere produttive ed orientate alla soluzione (e tra persone collaborative si dovrebbe poter fare). 
  • Gestione dei requisiti. Se personalmente i singoli programmatori sono abituati ad usare un documento per tenere traccia delle cose da fare, scritto in linguaggio chiaro (tornando al principio cooperativo conversazionale), allora questo stesso documento lo potranno anche condividere in rete con tutti i compagni del gruppo, aperto in lettura, in scrittura, per aggiunta di commenti, eccetera. Bisogna solo decidere un minimo di standard comune, (poco male se poi questo standard rifletterà certi formati suggeriti dai metodi "leggeri": non c’è copyright sul buon senso).
  • Gestione dell’ambiente di “deploy”/“esecuzione”. I cosiddetti container consentono una configurazione di esecuzione identica per tutti, sui propri laptop/desktop di lavoro, indipendentemente dal tipo o dalla specifica configurazione di questi. Nessuno potrà dire che "funzionava sulla mia macchina".

Magari ci vorrà una qualche sintesi tra queste pratiche se ognuno le usa in modo un po’ diverso, ma se si è onesti, si deve poter arrivare ad una sintesi senza conflitti infantili. 

In sintesi, nell’ipotesi fatta dovremmo avere relativamente pochi problemi organizzativi e di comunicazione, e come metodo ci basta una sintesi dei metodi che si presume dovremmo già sapere usare singolarmente.

Quindi la tesi del punto 1 mi sembra abbastanza sostenibile: non ci serve che ci venga instillato un metodo esterno.

Allora possiamo decidere di cercare di trovarci sempre nel punto 1, oppure dobbiamo dare quel minimo di supporto per creare le condizioni affinché valga il punto 1 (visto che l’ambiente e le motivazioni contano), e non andare oltre, ovvero non istituire un metodo "esterno" solo perché lo abbiamo letto da qualche parte, o visto in qualche conferenza.

Comunque, per pura ipotesi, supponiamo invece che il gruppo sia fatto di persone “disoneste” o “incompetenti”, in maniera praticamente incorreggibile. Allora il metodo non ci aiuta  più di tanto. Ci potrebbe aiutare solo un metodo pesante, prescrittivo, stile waterfall.

Non indago sull’ipotesi per cui “siamo incompetenti”, perché è un caso tutto abbastanza scontato. Non possiamo fare una certa cosa perché non ne abbiamo appunto le competenze, e questo è quanto.

Se invece siamo competenti ma comunque disonesti, allora un metodo può esistere, ma non sarà certo un metodo di tipo leggero.

Se siamo “disonesti”, allora siamo in perenne stato di guerra contro gli altri, in particolare con i compagni di gruppo, magari a causa dei propri anche legittimi interessi personali, per egoismo, egocentrismo e così via.
Thomas Hobbes sosteneva appunto che gli umani, nel loro stato di natura, sono in “guerra” tra loro. Sosteneva che quindi le persone si sarebbero dovute dare un “patto”, un “contratto sociale”, un “Leviatano” come la soluzione. Il “Leviatano”, cioè lo Stato, sarebbe servito a proteggere le persone le une dalle altre. Se adottiamo questa descrizione come metafora per un gruppo di lavoro che deve portare a termine un progetto, allora il “patto”/“contratto sociale”/“Leviatano” sarà appunto il metodo che si danno per lavorare. Allora non credo che il metodo adeguato possa essere di tipo leggero, perché questo non protegge affatto le persone le une dalle altre, quanto piuttosto le mette letteralmente le une contro le altre, anche nel del modo di gestire lo spazio fisico!

Introdurre un metodo leggero può portare a situazioni addirittura parossistiche: per ipotesi, siamo in guerra l’uno con l’altro, eccetera eccetera, ma durante le cosiddette retrospettive dobbiamo invece cambiare mentalità, in modo netto e radicale. Per esempio, magari la settimana scorsa ci azzuffavamo perché non riuscivamo ad accordarci su qualche scelta tecnica o di altro tipo (per motivi forse egoistici o strumentali, il che è concorde con l’ipotesi data). Poi alla fine di tutti  questi parapiglia, arriva la retrospettiva e tutti dobbiamo assumere un paradigma completamente diverso, e conformarci all’assunzione che “ognuno ha fatto sicuramente del suo meglio”. Ma questa cosa non può funzionare se non la pensi per davvero.

E’ un “Comma 22”: devi chiedere feedback o cercare aiuto se serve, ma non ti conviene farlo, visto che così fornisci un pretesto ai tuoi nemici perché ti possano colpire.

Preciso che il fatto di dover chiedere feedback, “aiuto” e quant’altro non è contraddizione con il fatto di essere competenti perché essere competenti non significa essere incapaci di sbagliare. Essere competente prevede anche il fare errori, purché il sistema ci consenta di rilevarli e risolverli il prima possibile, e per rilevarli e risolverli serve in effetti anche l’apporto dei compagni di gruppo. Ci sono in effetti principi di certi metodi, per esempio stile Lean-Toyota, che forniscono un aiuto. Parlo del Poka  Yoke, che descrive una cosa di questo tipo appena descritto. Quindi è opportuno confrontarsi e anche usare delle tecniche come questa, ma per farlo non bastano, né sono strettamente necessari, metodi e cerimonie, benché i singoli principi e pratiche possono essere utili purché ci sia innanzitutto l’attitudine che descrivevo.

Naturalmente ci sono anche altre ipotesi sulla nostra natura che sono meno estreme.
Per esempio può essere che non si dà il caso che siamo in uno “stato di guerra” con tutti, ma magari possiamo simpatizzare almeno per le persone più vicine a noi. In fondo si tratta un po’ del concetto di famiglia, di amicizia… . Nel nostro codice genetico è previsto che avremo simpatia, empatia, compassione, solidarietà nei confronti di qualcuno. Tra l’altro, diranno i metodologisti (dei metodi leggeri), è per questo mettiamo il gruppo di lavoro tutto insieme nello stesso posto: così si crea una sorta di cameratismo. Ma non è così scontato che questa vicinanza, simpatia eccetera debba avvenire per i compagni del gruppo di lavoro solo perché ci hanno messi gli uni vicino agli altri. Le persone che ci sono realmente amiche sono quelle con cui usciamo insieme, mangiamo insieme, magari ci abitiamo insieme. I nostri compagni di lavoro in fondo non sono necessariamente tutto questo.
Essi potrebbero seguire una propria agenda o strategia non proprio benevola nei nostri confronti. Dunque metterci a lavorare insieme gomito a gomito in questo contesto potrebbe essere proprio una pessima idea.

Quindi in generale sembra davvero più opportuno che per proteggere noi e di conseguenza il sistema, questo sistema debba regalarci delle confort zone, anziché togliercele. Dovrebbe consentirci di aver già tutte le informazioni che servono per fare quello che dobbiamo fare.

Serve cioè qualcosa che ti dica “se segui la procedura tutto andrà bene”. Sarà un po’ alienante, ma è pur sempre meglio di una situazione che rischia di essere caotica e schizofrenica per le sue contraddizioni.

Il caso analizzato fino a questo (ipotesi 2) punto partiva dall’ipotesi che il nostro modello di comportamento è egoistico, e che siamo in perenne conflitto tra noi, eccetera eccetera.

La conclusione è che il patto, il “contratto sociale” che protegge noi da tutto noi non può essere un metodo leggero.

Se invece vale l’ipotesi 1 per cui siamo “onesti” (o quanto meno abbiamo buone possibilità di diventarlo) allora l’adozione di un metodo esterno, che sia leggero o meno è quasi superflua (anche se non è irrilevante: alcune pratiche sono in effetti utili, come in relazione alla risoluzione dei problemi per esempio con metodo A3, alla formulazione di checklist, eccetera). Ci fidiamo già gli uni degli altri, non abbiamo bisogno di farci aiutare a “creare un clima di fiducia” perché questo clima c’è già. Conosciamo già le tecniche per scrivere codice che funziona e per manutenerlo. Siamo già convinti, e non dobbiamo “doverlo credere (?)” che i nostri compagni siano meritori e facciano sempre del loro meglio, anche quando sbagliano.

Ma quale delle due ipotesi dovremmo pensare che sia la più verosimile in un caso generale?
Personalmente condivido l’idea che in un certo senso siamo in uno stato conflittuale per la nostra natura, per diversi motivi, per esempio per effetto di alcune irrazionalità connaturate in noi, o per come potrebbe essere modellato un certo tipo di sistema in cui operiamo. Queste irrazionalità però sono a volte presentate in modo esagerato.

Un esperimento mentale per spiegare questo concetto: come programmatore mi può capitare, con il senno di poi, di valutare negativamente una mia scelta tecnica (aver introdotto un design inutilmente complicato, usare troppi parametri a volte inutili, e così via). Nonostante ciò, mi autoassolvo perché “in quel contesto lì per le informazioni che avevo ero giustificato a fare quella scelta”. 
Tuttavia se la mi valutazione avesse riguardato qualche scelta simile fatta da altri, magari sarei stato molto più severo. Questo ipotetico mio comportamento sarebbe da considerare senz’altro ipocrita. Tuttavia qualcuno mi dirà che invece è comprensibile, perché causato da un bias cognitivo, nel caso specifico l’“actor-observer asymmetry bias". Io invece penso questa storia dei bias cognitivi sia troppo comoda da raccontare. Siamo soggetti a bias cognitivi solo se facciamo lavorare troppo i nostri pensieri rapidi, impulsivi, e troppo poco quelli lenti, ponderati. Cerchiamo l'interpretazione più negativa possibile, anziché quella più benevola possibile (che è il Principio di Carità). Quindi se il mio giudizio ingiusto era dovuto ad un bias cognitivo, la causa sarà stata anche la mia pigrizia, la mia impulsività.

Dunque anche se certi nostri tratti bellicosi sono ancestrali, atavici, connaturati, fisiologici e quant’altro, penso comunque che spesso siano superabili sforzandoci un po’ con l’intelletto.

E’ comunque chiaro che nel tradimento rispetto agli interessi comuni certe volte l’irrazionalità non c’entra. Ovvero il tradire risulta essere normale anche per un agente perfettamente razionale. Lo vediamo nel modello di gioco del dilemma del prigioniero. In questo modello è effettivamente razionale tradire. Ma non dobbiamo per forza giocare a quel tipo di gioco, cioè il sistema potrebbe essere anche diverso ed adeguarsi ad un altro tipo modello. Per esempio un sistema potrebbe seguire anche il modello della versione iterata del dilemma stesso, dove il tradimento non è più una scelta razionale vincente. Infatti nella versione iterata le strategie cooperative, anche se non ingenue, sono più competitive, più adatte alla sopravvivenza.

Un sistema in qualche  modo fluido, continuo, iterativo, in effetti è molto più simile alla versione iterata che alla versione a “colpo unico” (“one shot”) del dilemma del prigioniero (è questo è sicuramente un punto, dal lato teorico, positivo dei metodi leggeri).

In definitiva, ci sono casi in cui un metodo collaborativo non può funzionare, per una cospicua presenza di "traditori", "defectors"o "free rider". I cooperatori puri non sopravviverebbero, ed anche i cooperatori non ingenui finirebbero per comportarsi esattamente come i free rider per sopravvivere. In tal caso adottare un metodo che presuppone una attitudine collaborativa è una pessima idea. Rischia di finire come una pantomima, un cargo cult, una pletora di cerimonie stucchevoli.

Se invece siamo già in massima parte cooperatori/collaboratori (non ingenui), allora dovremmo essere in grado di seguire un metodo collaborativo ed anzi potremmo persino darcelo da soli, senza bisogno che ci venga instillato.


nota: per quanto ovvio, il termine "leggero" l'ho usato come sinonimo di "agile". Ho evitato quest'ultimo termine perchè è troppo autopromozionale, sembra positivo solo a pronunciarlo. "leggèro" invece è più neutro. 

Wednesday, July 10, 2019

Fsharp code kata: Prisoner Dilemma

This blog is about the Prisoner Dilemma in F#

(EDIT: something changed  in the code so the description given in this post may be not 100% accurate. Some comments in the source code can give more info about)

(github code: https://github.com/tonyx/PrisonerDilemmaFsharp)

A quick look at the prisoner dilemma description in wikipedia.

This code is about:
defining the possible strategies
defining the player types
creating an iterated prisoner dilemma tournament
playing a tournament.
computing the scores in a tournament.

Let's start with the description and the code:

1) Each move can be: Cooperates, or Defect


2) the result of a single game between two players is this record

Let's also define the mutual score of a jointmove.

3) given a JointMove, we get a score determined by both the players moves:
To determine the JointScore, given a JointMove we have the following function

I want to have a version of the previous function that allows me to "parametrize" the scores, and chack the  P>R>T>S rule at compile time




In the "iterated" version, two players play repeatedly. each player remembers the history of the jointMoves and can use it to decide the next move.

So a player adopts a Strategy, which is a function from jointMoves list to a Move:

type Strategy = JointMove list -> Move

(EDIT: strategy changed ad follows:

type Strategy = Move list -> Move list -≷ Move)

We may also want to label a strategy with a name, so we define a type of record called StrategyInfo:

type StrategyInfo = {Name: string; Strategy:Strategy}

We want to give to each player a name and a StrategyInfo (which means a strategy with a name):
type Player = {Name: string; StrategyInfo: StrategyInfo}

Any game, at a certain state, involves two players, and a list of jointMove that they made:

type Game = { Player1:Player; Player2:Player; JointmoveHistory: JointMove list }

A "tick" is the joint play of both player in a game. The result will be the same game with their joint moves added to the history of moves:




A function for "ticking" a game n time will be useful:


Now, let's try some simple cases, not before defining the naive strategy, the cooperator:

let (cooperatorStrategy:Strategy) =
     fun _ ->
          Cooperate

We want two create a cooperatorstrategyInfo, and two cooperators players, which use the same strategyInfo:


let cooperatorStrategyInfo = {Name="cooperatorStrategy";Strategy=cooperatorStrategy}
let cooperator1 = {Name = "cooperator1";StrategyInfo= cooperatorStrategyInfo}
let cooperator2 = {Name = "cooperator2";StrategyInfo= cooperatorStrategyInfo}

let's define a new game:
let aGame = {Player1=cooperator1;Player2=cooperator2;JointmoveHistory=[]}

let's tick it one time:

game |> tick

the result is a game with a one item in the history of moves.
let't "3 ticks" the game, using the nTicks function:

nTick game 3

the resulting game has a history of moves longest 3.

We can't do so much with a single game.
We need a way to define a tournament, which is based on a list of games, and a number representing the "ticks for game"


(edit July 11 - 2019: in the new version I dropped the tornment type, and always use the games, by playing a game for n "ticks" using the function playGameNTimes)

type Tournment = {Games:Game list; TicksForGame: int}



What the previous code actually means is, described in a procedural way:
for each player, get any player which is different from the current player, and create a game of them. The result will be "flattened" by the List(@) [] operator.
The resulting operation will be the game, and the function will return a structure given by the games and the ticks for each game.
This will ensure that for each pair of players there will be a game with it as the first and second player (and vice-versa).

To play a tournament, we just have to tick each game:
Given a game, we may want to get the total score of the game (given by cumulating all the scores):


For a list of games, we want to get all the players and score for game, and put them in triplets (player1, player2, jointScore):





We want to compute the score in a set of games for a single player.

And we want also the scores for all the players.
(it looks redundant having a way to re-extract players that we already used from the beginning, but for now I found easier to get back players from the games, also because in future "evolutionary" versions of the game players may mutate).


Now suppose that we will start a tournment between four players:
a cooperator, a defector, a random, and a titForTat
I define a strategyInfo for each of them:

    let cooperatorStrategyInfo = {Name="cooperatorStrategy";Strategy=cooperatorStrategy}
    let defectorStrategyInfo = {Name="defectorStrategy"; Strategy=defectorStrategy}
    let randomStrategyInfo = {Name="randomStrategy";Strategy=randomStrategy}
    let titForTatStrategyInfo = {Name="titForTatStrategy";Strategy=titForTatStrategy}

To define a single player, like a cooperator, we may  say:
    let cooperatorPlayer = {Name="cooperator";StrategyInfo=cooperatorStrategyInfo}

But we rather want to have a chunk of cooperators, sharing the same strategy, so we have the following function:





Now suppose we want to make a tornment between 5 cooperators, 5 titForTat, 5 defectors, and 5 randoms:

let cooperatorPlayers = makeNPlayersByStrategyInfo cooperatorStrategyInfo 5
let titForTatPlayers = makeNPlayersByStrategyInfo titForTatStrategyInfo 5
let randomPlayers = makeNPlayersByStrategyInfo randomStrategyInfo 5
let defectorPlayers = makeNPlayersByStrategyInfo defectorStrategyInfo 5

We put all players in a single list:

let allPlayers = cooperatorPlayers@titForTatPlayers@randomPlayers@defectorPlayers

we create a tournment, making all players play against each other, with 10 ticks for game:

let tournment = makeTournment allPlayers 10

we run the tournment:

let playedGames = playTournment tournment

Now we can see all the scores, sorted from the lowest:

sortedPlayersScore playedGames;;

this is the sketch of the result, showing that in this kind of tournament the defector is generally stronger.
This is just a particular case, where the defectors win as long as there are many cooperators to spoil. When there are many defectors (or free riders) they will perform lower because a game between defectors will end up in a lower total outcome, compared to, say cooperator vs cooperator (or titForTat vs titForTat).
Analyzing the prisoner dilemma theory is beyond the goal of this post.

val it : (Player * int) list =
  [({Name = "cooperatorStrategy_4";
     StrategyInfo = {Name = "cooperatorStrategy";
                     Strategy = ;};}, 1208);
   ({Name = "cooperatorStrategy_2";
     StrategyInfo = {Name = "cooperatorStrategy";
                     Strategy = ;};}, 1210);
   ({Name = "cooperatorStrategy_0";
     StrategyInfo = {Name = "cooperatorStrategy";
                     Strategy = ;};}, 1216);
...
                     Strategy = ;};}, 1536);
   ({Name = "defectorStrategy_3";
     StrategyInfo = {Name = "defectorStrategy";
                     Strategy = ;};}, 1540);
   ({Name = "defectorStrategy_4";
     StrategyInfo = {Name = "defectorStrategy";
                     Strategy = ;};}, 1554);
   ({Name = "defectorStrategy_0";
     StrategyInfo = {Name = "defectorStrategy";
                     Strategy = ;};}, 1566);
   ({Name = "defectorStrategy_2";
     StrategyInfo = {Name = "defectorStrategy";
                     Strategy = ;};}, 1568)]


Future development:
- implementing evolution
- implementing real time chart visualization


Sunday, April 14, 2019

A free Orders System in F# (part 1)

I recently added to my github a new open source solution for managing orders in a restaurant.

https://github.com/tonyx/orderssystem


This is a first post about the description of the product:


Main features:

1) managing ingredients, and categories of ingredients
2) managing courses, and categories
3) managing ingredients composing the courses (receipts)
4) collecting orders,
5) defining users roles,
6) managing variations of orders items (in term of add ons or drop off of ingredients)
7) managing price variations related to order items variations
8) printing orders by associating printer for course categories
9) displaying order items
10) managing payment by eventually subdividing the bill
11) print a fiscal cash drawer (by using an external software).



A walkthrough:


1) main menu:




many of those items are visible and usable only by the administrator.















2) manage ingredients:


Clicking on manage ingredients we have get this form to create a new category of ingredients, and create a new one and call it "vegetables".









After creating the new category, I have a button that allows me to select the category itself:



The category is "visible", but I can switch it to "invisible" by clicking the button "modifica visibilita'" (will be translated into "switch visibility).








I click the button of the category, and I can see all the existing items of the category (there is no one, yet), search, or create a new one. I do create a new one.


I am not going through all the options of this form. I just create a new ingredient with default values and call it "green salad".













So now in the ingredients->vegetables page I have this:


I skip all the description of the options related to "prices", "usages", and "load" for now.






Course categories works in similar way, and it is possible to specify the ingredients for each course as well.


Next post will be about collecting orders.
Anyway, I do have some video demo of an earlier version of the product:

https://www.youtube.com/watch?v=-6--mPxDktU






Tuesday, December 11, 2018

Porting a simple toy app to Elmish

In the past I developed a toy app/kata (Animalquiz) for learning purposes. First version was Java, then I ported it to F#.

This post is about making the  F# version run under Elmish.

Roughly speaking, an Emish based application consists in a set of possible messages, a model to represent the current state of the application, and an update function that given a message and a model, returns a new model (and a list of other messages,  but I can skip this part and assume that this list will always be returned as empty, that is ok for my purposes).

My original AnimalQuiz was console based (also with a gtk# interface), and it was based on a sort of model-view-update patten, even if I wasn’t aware of it.

So I expect there will not be so much work to do to put it under Elmish.


First step is creating a project based on the Elmish-Fable template.
According to the documentation that you can find in https://devhub.io/repos/kunjee17-awesome-fable
to install the Fable-Elmish-React template you need the following command:
dotnet new -i "Fable.Template.Elmish.React::*"

To create a new project:
dotnet new fable-elmish-react -n awesome


The template created contains three sample (sub)apps: 
  • The “Home” app which shows us a simple textbook where the content will be coped in a text area (using “onchange” property).
  • The classical counter app called “Counter sample”. 
  • The “About” which just shows some static text (which is just static text).

I want to add the AnimalQuiz as a fourth application, so what I'll do is:
  1. make a clone of one of them, and call the cloned app “AnimalQuiz”, 
  2. make the cloned app accessible from the outer menu.
  3. modify the cloned app, to  behave as the AnimalQuiz app.

The app I clone is the “Home” app, so I just copy the three file of it in a new folder called AnimalQuiz. In each module declaration I'll substitute "AnimalQuiz" to "Home".

I have to add the following rows in the in the project file awesome.fsproj, in that order,  to make sure they will be compiled:
<Compile Include="AnimalQuiz/Types.fs" />
<Compile Include="AnimalQuiz/View.fs" />
<Compile Include="AnimalQuiz/State.fs" />



     
Now the step 2: I want to make extra app reachable by the outer menu, so as follows there are the files that I have to change at it, and how I have to change them:
module App.Types: the message and the model will reference the message and the models of the sub apps:



Module Global (file Global.fs): I extend the Page discriminated union, and the toHash function:




Then I need to change the App.State module (only the row with some animalQuiz string are mine):



Last thing to do is modifying App.View module in two parts.
One is the definition of the menu:


Another one is the definition of the pageHtml internal to the root definition:



This is enough to make the new app visible and selectable from the outer menu.

Now is time to take a look to the actual app, that, until now, is just a copy of Home, but I'm going to change everything there.

The model is the following:




Those data are useful to manage an interaction between the user and the engine, but I am not going to explain all of them, with the exception of the CurrentState, which is of the type State, that describe the different states of the interaction with the user:




What follows are the messages:



The model include also a history of messages. The history of messages is useful because I can do any "replay n steps from the beginning" by applying n times the messages of the history from the initial state using the fold function.

For instance there is an "undo" that applyes the list of the messages from the initial state a nuber of times given by the length of the history minus one:

| (Undo,_) -> 
     let msgHistoryTruncated = model.MessageHistory |> List.take (List.length model.MessageHistory - 1)
     msgHistoryTruncated |> List.fold (fun (acc,_) x -> update x  acc   )  (initState,[])

     
repo is here https://github.com/tonyx/animalquiz-elmish



Wednesday, September 26, 2018

Transforming a nested F# list to Javascript using tail recursion

If I need some javascript in a Suave view, I can include a reference to an external javascript like in the following code:

script ["type","text/javascript"; "src","/externalJavascript.js"] []

Another way to insert javascript code is by adding the code directly by the Raw tag:

script [] [Raw("alert('hello');")]

I can use both way to pass parameters to the external javascript file:

script [] [Raw("var myVar = 123")];
script ["type","text/javascript"; "src","/externalJavascript.js"] []

In this way, the externalJavascript.js may access to the myVar variable as a global variable.

This can be a "hack" to pass parameters to the javascript.

The reason for doing it is being able to make the html page richer, avoiding "round trip" with the server. In this case I wanted to be able to  to add and remove dinamically some element to the options list, on the base of the element selected in another select option list.


However using this way to pass parameters, means generating the javascript code as a string.

An example is if I have a nested list in F#, as follows:

[(1,[(1,2M);(3,4M)]);(11,[(11,22M);(33,44M)] ) ]

and I want to transform in an equivalent javascript map:

new Map([[11, new Map([[11,22],[33,44],])],[1, new Map([[1,2],[3,4],])],]);

From the web page perspective, the key of the map (11) is the element that, when selected in the first select option list, will change the content of the second select option list, populating it with its value, which is a list with two pairs: (11,22), (33,44)

(as you can imagine, such data comes from a database, and is generated by a combination of map operations):
I tried to solve using regular expressions, but the way regular expressions changes from unix (vim) style and the dot.net libraries is annoying for me. So I decided that  a tail recursive function could be cleaner and better, so I come up with the following:

I'm sure there are cleaner ways to enrich the view, for instance using frameworks like Fable and Elmish, but I haven't found yet the time to try to figure out how to integrate them.

So at the moment, the solution is just using F# with Suave.IO (and Postgres), adding some "tricks" if I need to make the page more dynamic on the client side.

EDIT: instead of using a recursive function, I can just use the fold operator:
for instance the first inner function can be rewritten as follows:

let javascriptListPairs l = l |> List.fold (fun acc (x,y)  -> acc + "["+(string)x+","+(string)y+"],") ""





Friday, July 20, 2018

checkboxes with Suave.IO, using dotliquid tamplates



Using checkboxes with Suave.Io

The Suave.IO web library for F# adopts two ways of rendering html.

By using Suave.form/Suave.html the page is represented as a native F# list, which basically consists in html elements, or nodes, and forms which are defined by specific records. Invalid html page is impossible in this way because the syntax check is strict.

Suave.dotliquid instead adopts old fashion html text + some variable substitution at server side.

However, Suve.Form/Suave.html misses support for checkboxes yet.

We can't do the following stuff to render a checkbox form, whereas we can do if we used other supported types for html widget (see https://theimowski.gitbooks.io/suave-music-store/content/en/form_module.html)

Defining the form.

type UserEdit = {
    Enabled: bool
    CanVoidOrder: bool
    CanManageAllorders: bool
    CanChangeThePrices: bool
}


let userEdit: Form =
   Form ( [
            Checkbox ((fun f -> <@ f.Enabled @>), [])
            Checkbox ((fun f -> <@ f.CanVoidOrder @>), [])
            Checkbox ((fun f -> <@ f.CanManageAllorders @>), [])
            Checkbox ((fun f -> <@ f.CanChangeThePrices @>), [])
           ],
         [])

REnd the form in the ui:

renderForm
       { Form = Form.userEdit
         Fieldsets =
             [ { Legend = "Modify user"
                 Fields =
                     [
                       { Label = "enabled"
                         Html = Checkbox (fun f -> <@ f.Enabled @>) ["value", true]  )
                       }                   
                     ]
                     [
                       { Label = "can manage all orders"
                         Html = Checkbox (fun f -> <@ f.CanVoidOrder @>) ["value", true]  )
                       }                   
                     ]
                     [
                       { Label = "can void order"
                         Html = Checkbox (fun f -> <@ f.CanManageAllorders @>)["value", true]  )
                       }                   
                     ]
                     [
                       { Label = "can change the prices"
                         Html = Checkbox (fun f -> <@ f.CanChangeThePrices @>)["value", false]  )
                       }                   
                     ]


                }
             ]
         SubmitText = "modify" }

This is probably how it will be possible in the future, but is not possible yet. bool and chekbox are not supported.

So I needed dotliquid templating to overcome, where any html is valid, because it is actual html plain text code.

A recap of checkboxes in html:



<form method="post">
<input name="myName1" nbsp="" type="checkbox" />myValue1</input>
<input name="myName2" nbsp="" type="checkbox" />myValue2</input>
<input type="submit" update="" />



In posting this form, it evaluates myName1 to myValue1 if checked, and  myValue2 to myValue2  if checked.

So what I we can do to use dotliquid forms for checkboxes is using option types. I don't really care about the value passed, but only if they are passed or not. For that reason option types fit the purpose.

type UserEdit = {
    Enabled: string option
    CanVoidOrder: string option
    CanManageAllorders: string option
    CanChangeThePrices: string option
}

//wa can leave the following empty (no validators an so on)..
let userEdit: Form =
   Form ( [
           ],
         [])

So the code in App.fs would be like:

type modelForLiquid = {name: string} // how to pass parameters to the template, if needed

let manageUser (Db.user) =
choose [
     GET  >=>
          let o = {name = "yourname"}
          DotLiquid.page("template.html") o
 
     POST >=>
          bindToForm Form.userEdit (fun form ->
              let ctx  = db.getContext()
              let isEnabled = form.Enabled.isSome
              let canVoidOrder = form.CanVoidOrder.isSome
              ......
              Db.UpdateUser user.UserId isEnabled canVoidOrder ... ctx

     ]

Something similar should be needed for radiobuttons.

What we need to be sure about is that we use POST rather than GET in the form, and how html pass the parameters. Basically they are a list of name value pairs.
The POST part of our code in the controller (App.fs usually) can handle them in a straightforward way as seen in the code above.

Can be good to know, just in case ;-)




Wednesday, March 22, 2017

criteri di priorità per backlog item, basati su misure di valore e costo


In questo post accenno ad un criterio di ordinamento per priorità di "product backlog item" considerando alcune possibili misure del valore e del costo, e la loro incertezza.

Premessa 

In metodi di organizzazione del lavoro di tipo "leggero", empirico  (definiti "agili" - come Scrum, Xp, Kanban) usati nello sviluppo di prodotti principalmente software, si ha un insieme chiamato "product backlog" costituito da "product backlog item" (p.b.i.) che specificano piccole funzionalità le quali, tutte insieme, una volta realizzate, costituiranno il prodotto intero.

Per fare un esempio, se il prodotto è un un word processor, si può avere tra le sue funzionalità, cioè tra i suoi p.b.i.:
- poter sottolineare,
- "" mettere in grassetto,
- "" creare elenchi numerati,
- "" giustificare il testo in vari modi,
- "" salvare e leggere in vari formati, e così via...

Questi metodi "leggeri" prevedono che il prodotto sia utilizzabile anche in ogni sua versione intermedia, parziale (cioè che implementi un sottoinsieme di p.b.i. rispetto al backlog).
Quindi è importante che i p.b.i. siano il più possibile indipendenti tra loro (non si dà il caso che per lavorare su uno bisogna prima averne completato un altro, anche se in alcuni casi è comunque inevitabile).

Un p.b.i. portato a termine, deve essere effettivamente rilasciabile, funzionante, usabile, testabile, e testato. Il test dovrebbe essere ripetibile in modo automatico, così da poterlo rieseguire rapidamente, per esempio per rilevare eventuali errori di regressione in successivi rilasci (nel caso nuove aggiunte compromettano funzionalità precedenti). Se i test non fossero automatici, sarebbe difficile fare piccoli rilasci per incrementare le funzionalità del prodotto, perché i test di regressione manuali si accumulerebbero, e rallenterebbero il tutto (a meno che non si sia in grado di affidarsi ad altri metodi rapidi per garantire la non regressione, tipo test massivi fatti magari da una certa fetta di utenti).

Un p.b.i. completato si chiama "running tested feature" (r.t.f.),  nel caso di un prodotto software.


Priorità per valore

In genere i p.b.i. su cui lavorare per prima, cioè per i rilasci delle prime iterazioni, sono scelti in base ad un ordine tale che quelli di valore maggiore (e costo minore, vedi sezione successiva) abbiano la priorità.

Il motivo dovrebbe essere ovvio, ma se non lo fosse, una giustificazione è la seguente.

Immaginiamo che si faccia il contrario, cioè che si portino a termine prima i p.b.i. più marginali, ininfluenti.
In tal caso il valore totale erogato nel corso di un certo tempo, e in modo particolare all'inizio del ciclo di vita, sarà minore del valore totale erogabile nello stesso tempo. Allora i finanziatori del progetto potrebbero percepire che questo abbia uno scarso valore nel complesso, e quindi decidere di chiuderlo.

Dunque è meglio selezionare gli item di maggiore valore per prima.

Per "misurare" questo valore occorre fare dei ragionamenti diversi caso per caso.
Faccio un esempio:

Diciamo che il prodotto è un portale, e vogliamo che gli utenti possano interagire se "riconosciuti", per esempio tramite autenticazione da parte di un provider esterno in cui abbiano già un account, che può essere un social network come Google Plus o Facebook.

Più utenti si attirano e più si genera valore (per esempio attraverso l'aumento del numero atteso di click sugli ad pubblicitari).
Inoltre un utente autenticato, quindi "riconosciuto", porta a maggiori probabilità di click sugli ad perché questi sono più mirati.

In una valutazione a grana grossa, si può dire che la scelta che genera più valore è semplicemente quella dell'autenticazione tramite il social che ha un maggior numero di utenti iscritti
Questa valutazione la vedo accettabile  se assumo che:
. la propensione a cliccare un ad pubblicitario da parte di un particolare utente sia indipendente dal tipo di social network in cui abbia un account
. la probabilità di "atterrare" sul nostro portale e decidere di interagirvi sia indipendente dal social network a cui si appartiene.
(se ho motivo di ritenere che queste assunzioni siano lontane dal vero, devo fare un ragionamento più complicato, che include certe correlazioni).

La scelta più razionale è scegliere prima di lavorare sul b.p.i. che ci aspettiamo generi più valore (a parità di costo di implementazione).

Inoltre questa scelta, non solo è preferibile, ma magari genera un tale numero di utenti da rendere praticamente inutile cercarne di altri implementando poi l'autenticazione tramite altri social network (se non esistono altri criteri di "misura del valore" che inducano comunque a farlo, come motivi di equità o raccomandazioni da parte di autorità antitrust etc...).

Come conclusione di questa piccola analisi:
. è utile scegliere prima i p.b.i. che generino un maggior valore (anche rapportato al costo, come dirò dopo)
. serve un criterio per misurare questo valore (che non sempre è economico, o almeno non direttamente)
. il criterio di misura deve esser accurato quanto basta. Per esempio nel caso in questione, non serve sapere quanti utenti ha l'uno o l'altro social network, basta sapere quale dei due ne ha di più
. il modello in base al quale misuro questo valore deve essere semplice, se so che un modello più complicato (che tiene conto di eventuali correlazioni) aggiungerebbe una accuratezza di cui posso fare a meno.

Tener conto delle correlazioni significa assumere che il maggior numero di potenziali click sugli ad lo misuro non solo in base al numero di utenti ma anche alla maggiore o minore propensione a cliccare gli ad dell'uno o dell'altro, ovvero dal tipo di social network da cui provengono. Così la misura sarebbe stata più complicata, ma più accurata.

Non dovrebbe valere solo il beneficio, ma anche il costo nel criterio di scelta della priorità.


Priorità per costo

Per costo si intende sostanzialmente il numero di giornate di lavoro, ovvero il tempo che pensiamo ci vorrà.

Se per me (per il team di lavoro) è più difficile, complicato, lungo implementare l'autenticazione Google Plus rispetto a Facebook, mentre il valore è equivalente, allora è razionale scegliere Facebook (a parità di valore).

Tra l'altro, se scegliamo il p.b.i. "autenticazione tramite Facebook" che è più rapido, allora questo inizierà a produrre valore in tempi più brevi, sarà costato di meno, e forse genererà valore anche di tipo informativo (per esempio consentirà di verificare quanto aumenteranno i click sugli ad, e se varrà la pena cercare di aumentarli, implementando poi anche un altro p.b.i. simile).

Unendo insieme i due ragionamenti fatti, la priorità dipende da un confronto tra i rapporti valore/costo.

In definitiva i criteri razionali saranno del tipo: scegliere A se probabilmente ha un miglior rapporto valore costo rispetto al terminare B.

Ma si tratta di un confronto tra valori ipotetici.
Sappiamo che potrebbe rivelarsi errato (era meglio scegliere B piuttosto che A) ma questo non potremmo mai verificarlo se non, magari, a posteriori. Però è possibile attribuire un grado di confidenza alla valutazione che facciamo.


Stimatori calibrati

Possiamo dare un grado di fiducia nella stima del confronto (maggiore o minore) tra due valori non noti.

Per esempio 50% significa assoluta mancanza di confidenza: esprimersi in merito per noi è come tirare una moneta.
100% significa assoluta certezza.

Uno "stimatore calibrato" è chi sia in grado di dare un grado di fiducia a ciò su cui si esprime (tra due scelte alternative) che corrisponda alla probabilità di avere ragione (usando un criterio di probabilità "soggettivo").

Quindi se lo stimatore calibrato sostiene che ne è sicuro al 60%, allora la probabilità sarà del 60%, o meglio - siccome parliamo di probabilità soggettive - sarà conveniente, rispetto alle conoscenze che ha lo stimatore, una scommessa per cui la vincita corrisponda ad almeno 10/6 della somma giocata. (vedi "gioco equo")

Diventare uno "stimatore calibrato" è una capacità che si può imparare.

In sostanza lo stimatore calibrato non è chi abbia un alto grado di fiducia in una scelta tra due possibilità, ma chi sappia far coincidere tale grado di fiducia con la probabilità di aver ragione (edit: chi, sulla base di criteri razionali dell'agente giocatore, sia disposto a fare una scommessa con ammontare della vincita non inferiore a quella equa rispetto al livello di fiducia espresso).

(per estensione poi il concetto di stimatore calibrato si applica anche alla "stima" di valori puntuali, dove si tratta di individuare "intervalli di confidenza del 90%", ma questo è un approfondimento a parte).

I dubbi su questo eventuale modello decisionale per la priorità, come descritti qui, sono:
- gli esempi presentati sono semplici per motivi di comunicazione, ma certi casi concreti possono essere ben più complicati.
- nell'esempio ho trattato i confronti tra valori e costi separatamente, evitando di mostrare la decisione basata sul confronto dei rapporti tra i due (sempre per evitare di complicare troppo il ragionamento)
- ultimo, ma non per importanza, parliamo di sistemi che reagiscono alle previsioni che lo riguardano: misurare il valore di una cosa come il tempo che ci metterò per fare una cosa, ne altera il valore stesso, e non è detto che sia un bene (stime ottimistiche possono indurre ad una certa "fretta" che poi incide negativamente sulla qualità). 
Questo aspetto in parte è comunque mitigato dal fatto che non si tratta di "previsioni puntuali", ma basate su un confronto, cioè
ho affermato che ci si basa sul fatto che A < B, senza dover dire quanto misura A né quanto misura B in termini numerici di qualsiasi tipo.

Conclusioni


Un modello di scelta razionale basata su "stime calibrate" nel confronto tra p.b.i. può essere in grado di orientare certe scelte di priorità nell'ambito di metodi di sviluppo/lavoro/progetto cosiddetti "agili".


rif. How To Measure Anything - Douglas W. Hubbard
gioco equo: https://it.wikipedia.org/wiki/Gioco_equo