Danzare sulla tastiera

Parecchi anni fa ero un fan di Resharper, ricordo ancora alcuni degli shortcut che usavo e penso agli incredibili livelli di produttività che ti permetteva di raggiungere con Visual Studio. E’ stato allora che ho iniziato ad amare l’uso della tastiera e ho capito che il mouse e’ uno strumento utile ma lento e scomodo. Da alcuni anni tutti in CodicePlastico si sono dotati di tastiere meccaniche, siamo partiti con le DAS e gli switch CherryMx Brown leggeri e silenziosi, poi alcuni di noi sono passati alle tastiere Filco e ai Blue switch molto più “clicky” e piacevoli. All’inizio non ci credevo ma l’uso di una tastiera meccanica, oltre che comoda facilita la scrittura veloce e l’uso della tastiera e gli switch meccanici hanno un feedback più preciso, una corsa della giusta lunghezza e una curva di risposta ideale per chi usa tanto la tastiera.

Qualche anno fa nelle community degli sviluppatori si e’ parlato parecchio di questo articolo in cui l’autore spiega come ricostruire (almeno virtualmente) la gloriosa Space cadet keyboard

Ma questo e’ stato solo l’inizio e un mondo si e’ aperto. Il layout delle tastiere qwerty non e’ l’ideale per scrivere, si sa ma siamo ormai abituati ad usarlo. Quello che pero’ stanca di piu’ e’ dover continuamente spostare le dita dalle lettere per arrivare ai tasti modificatori (CTRL-SHIFT-ALT-CMD). Alcuni amici mi hanno fatto conoscere l’esistenza di una famiglia di tastiere che hanno un firmware open source e quindi permettono una completa customizzazione dei tasti modificando il firmware e flashando il chip della tastiera. Il firmware in questione e’ il QMK

Cosi, incuriosito da questa novità (almeno per me), mi sono comprato una Whitefox, una piccola tastiera 65%, molto elegante e completamente Open source (per i maker: su Github si trovano gli schemi elettrici della board oltre ai disegni tecnici del case e le istruzioni di montaggio). La Whitefox inutile dirlo utilizza il firmware QMK.

Con questa tastiera abbinata al firmware e’ possibile rimappare i tasti ma soprattutto assegnare allo stesso tasto diverse funzioni a seconda di come viene premuto. Ad esempio nel mio caso specifico il tasto S emette una S se premuto normalmente ma diventa SHIFT se tenuto premuto. Quindi la combinazione S+P stampa una P maiuscola.

L’obbiettivo del remapping dei tasti e’ quello di spostare i tasti più utilizzati vicino alla home row. (La home row e’ la fila di tasti ASDF….) La prima modifica che ho fatto e’ stata di spostare i tasti freccia nei pressi della home row. I tasti freccia sono tra i più utilizzati, li usiamo per spostarci tra le linee di codice, per selezionare il testo, per navigare tra le cartelle e aprire i file, quindi averli addirittura fuori dalla tastiera e’ davvero scomodo e poco produttivo. Per cui ho modificato il firmware per avere i tasti I-J-K-L come tasti freccia uniti ad un modificatore che li attivava. Dove mettere il modificatore? Anch’esso l’ho voluto sulla home row per cui ho usato il tasto A. Come dicevo prima e’ possibile far si che il tasto A si comporti come A se premuto da solo, e si comporti da modificatore se premuto insieme ad un altro tasto. Quindi A+ J e’ la freccia sinistra, A + K e; la freccia in basso , ecc…

Questa e’ stata la prima modifica effettuata su consiglio dell’amico Arialdo. Devo ammettere che e’ stato illuminante, mai avrei pensato di poterli usare fin da subito. Ma abbiamo appena incominciato, appena ci si abitua viene a mancare un altro set di tasti modificatori: i classici SHIFT, ALT, CMD (o CTRL). Le frecce come detto prima spesso si usano insieme a SHIFT per poter selezionare del testo, ad ALT per avanzare di una parola alla volta o a CMD per andare ad inizio/fine riga e avere i tasti freccia a portata di mano ma i modificatori lontano e’ vantaggioso solo a meta’. Quindi il remapping successivo e’ stato di portare tutti i modificatori sulla home row. Per cui S = SHIFT, D = ALT, F = CMD e per simmetria J = CMD, K = ALT, L = SHIFT. Questo si puo’ fare grazie alla modifica del firmware QMK, usando i tasti sulla home row come modificatori temporanei. L’ultimo piccolo hack riguarda il dimenticato tasto Caps-lock (chi lo usa??). Anche lui e’ tornato doppiamente utile, premuto da solo e’ ESC, se tenuto premuto diventa CTRL. Questo e’ lo stato attuale della mia nuova piccola tastiera, sicuramente andrò avanti con altre modifiche volte a massimizzare l’efficenza riducendo gli spostamenti.

Un post molto nerd, per non dimenticarci che siamo nerd.

Teams x Progetti

CodicePlastico è una software house nel classico senso del termine: il suo unico scopo di business è soddisfare i bisogni dei suoi clienti mediante programmi scritti ad-hoc. Non rivendiamo, customizziamo, modifichiamo software fatto da altri ma scriviamo sempre tutto da zero. Oggi siamo in 15 persone, 14 sviluppatori e una persona che si occupa della parte amministrativa/gestionale/organizzativa dell’azienda. Queste 15 persone seguono diversi progetti. I progetti arrivano, iniziano, qualche volta finiscono molte volte continuano per anni e la cosa più difficile per noi è ottimizzare lo scheduling delle persone sopratutto per progetti che sono nella fase di coda lunga (principali sviluppi terminati e attività manutenzione, correzione e piccole aggiunte in corso) Fino ad oggi abbiamo fatto in modo che ogni progetto sia assegnato ad un microteam di 2-4 persone e che queste persone seguissero più di un progetto per contemporaneamente, tipicamente un progetto principale e uno o due progetti secondari su cui fare piccole manutenzioni. Questo meccanismo crea incroci difficili da sbrogliare soprattutto quando i numeri crescono. Capita che i team si “rubino” le persone a vicenda per poter terminare il progetto o effettuare un veloce intervento.

Uno dei modelli ideali, raccontato anche da alcuni coach è quello in cui tutti possono lavorare su tutti i progetti cosi da poter modulare l’effort a seconda delle esigenze. Ma anche questo, con i nostri numeri, diventa molto difficile, soprattutto per progetti grossi con una lunga storia. Se poi aggiungiamo il fatto che abbiamo in produzione diversi stack tecnologici le cose sono ancora più complesse.

Un’idea ci è venuta ripercorrendo la storia di codiceplastico e ricordando quando questo per noi non era un problema. Era il periodo in cui eravamo 5-6 persone, tutte commitate su tutti i progetti (che al tempo non erano molti come oggi) e tutti in grado di intervenire in caso di necessita’.

Ci abbiamo pensato, abbiamo valutato varianti e il modello che si sta concretizzando è quello in cui tutti possono lavorare su tutto ma su una scala ridotta. Stiamo cioè provando a creare tante (tre?) piccole CodicePlastico che siano autonome, per buona parte isolate dalle altre e responsabili di un sottoinsieme (proprio) dei progetti di tutta l’azienda. In questo modo ogni unita’ potrà seguire un piccolo set di progetti e su quelli avrà tutta l’autonomia necessaria, tutti i membri dell’unita’ saranno in grado di metterci le mani sia come per lo sviluppo che per la manutenzione.

L’idea ci piace e sembra, in linea teorica, funzionare correttamente. L’unico drawback che stiamo vedendo e’ il fatto che con il tempo potrebbero crearsi dei silos isolati che non comunicano tra loro essendo di fatto piccole aziende separate. Per far fronte a questo ipotetico problema abbiamo pensato di predisporre un programma di rotazione delle persone: una volta ogni tanto (stiamo ancora cercando di capire qual e’ l’intervallo di tempo giusto) una persona si sposta da una unita’ ad un’altra in modo che nel giro di 12-18 mesi tutti siano in un nuovo team.

Questo e’ l’ennesimo esperimento che stiamo conducendo per provare a diventare ancora migliori di quanto siamo oggi.

Remotizziamoci!

Il 2018 è stato per CodicePlastico un anno in cui sono maturatemolte nuove idee, mi piacerebbe raccontarle sia per riuscire a ripercorrerle e metabolizzarle sia per condividerle con la speranza che possano servire anche ad altre aziende o professionisti.

Uno degli obbiettivi che avevamo fissato a gennaio 2018 era trovare un nuovo ufficio più grande e spazioso per tutti. Fino ad allora eravamo stati all’interno del CSMT, un consorzio di aziende dell’innovazione bresciana, ma gli spazi disponibili non erano sufficienti a contenere 15-20 persone quindi o ci splittavamo in più uffici oppure dovevamo cambiare. L’idea di cambiare ci piaceva e a metà anno abbiamo iniziato la ricerca affidandoci ad “esperti” agenti immobiliari. Oggi, un anno dopo, siamo ancora qui!

Cosa è successo nel frattempo? Trovare un ufficio che ospiti 15-20 persone è una soluzione valida ma non è definitiva, chi può dire se tra 5 anni sarà sufficiente o sarà troppo piccolo ( o troppo grande)? Un nuovo ufficio implica grosse nuove spese: trasloco, adeguamento, nuovo canone d’affitto, attivazione dei contratti. Cercare un nuovo ufficio è dispendioso in termini di tempo ed è dannatamente noioso avere a che fare con gli agenti immobiliari.

Fatte queste considerazioni verso la fine dell’anno ci siamo detti: e se rimanessimo qui? Basterebbe far si che tutti possano lavorare da casa e che l’ufficio diventi un’opzione da usare solo qualche volta alla settimana. Nessuno avrà più la sua scrivania e le postazioni saranno libere. L’idea ci è piaciuta, ne abbiamo parlato con i colleghi e anche loro hanno apprezzato la possibilità. Ma, come Jacopo insegna, prima di effettuare una cambiamento vanno fatti degli esperimenti per validare l’idea. A novembre abbiamo istituito il remote-day: il giovedì tutto il team di CodicePlastico lavora da remoto. Ci serviva per capire se l’idea poteva funzionare o se c’erano delle grosse inefficienze da colmare che impedissero l’idea di remotizzarci quasi completamente.

Oggi, qualche mese dopo l’esperimento possiamo dire di essere soddisfatti, per molti di noi l’opzione remoto è diventata una buona abitudine e ci prendiamo sempre un paio di giorni per lavorare da casa. Sicuramente abbiamo ancora qualche dettaglio da migliorare ma tutto il team ne è consapevole e tutti sono committed per risolversi e proporre miglioramenti. Abbiamo anche deciso di riorganizzare l’ufficio per renderlo adatto al lavoro da remoto e al fatto che non avremo una postazione fissa per tutti.

Fp-ts validation spiegata bene

In CodicePlastico stiamo studiando la programmazione funzionale, abbiamo fatto un corso con Matteo Baglini (che consiglio a tutti) e in questi giorni stiamo provando a fare un po’ di refactoring verso il paradigma funzionale. Naturalmente i dubbi vengono, e ieri ho scritto una mail a Matteo per chiedere aiuto su una parte di codice dedicata alla validazione. La mail di risposta e’ stata talmente dettagliata che ho pensato fosse uno spreco tenerla solo per me, così (con l’autorizzazione di matteo) la pubblico qui:

[ema] Ciao Matteo, nell’addentrarmi nella programmazione funzionale in Typescript usando questa libreria https://github.com/gcanti/fp-ts mi sono imbattuto in questo meccanismo di validazione che non capisco completamente e mi sembra molto complesso. L’esempio particolare a cui mi riferisco e’ questo: https://github.com/gcanti/fp-ts/blob/master/docs/Validation.md


Ciao Ema,

Personalmente direi articolato non complesso. Più avanti mi spiego.

[ema] Perche’ si deve creare una funzione curried per costruire la Person?

In generale per costruire Person ti serve una funzione, questo banalmente perchè sei in fp e in fp tutto si fa con le funzioni. Le strutture dati algebriche (Person è un product type) non fanno niente se non immagazzinare dati. Le funzioni permettono la costruzione e/o manipolazione di questi dati. Ambienti come haskell e scala (con le case class) ti offrono out-of-box la funzione di costruzione. Typescript no, prima sfiga.

[ema] Allora perchè curried?

Questo accade perchè Applicative serva a comporre una funzione con effetti (le funzioni di validazione) + una funzione senza effetti con due parametri (la funzione di creazione di person). Nel mondo fp ovvero haskell una funzione con due paramentri (a, b) => c è di fatto (grazie a curry) 2 funzioni da 1 parametro a => b => c. Molto probabilmente Fp-Ts ha scelto di seguire più da vicino lo stile haskell, seconda sfiga. In scala gli autori di librerie tendono ad evitare il currying perchè non è naturale nel linguaggio.

Detto questo, perchè validatePerson nell’esempio di Fp-Ts è così complessa? Perchè ti mostra a basso livello come si compone una funzione con effetto con una funzione senza effetti con due parametri (curried).

Dissezioniamo questo mostro:

A.ap(validateName(input['name']).map(person), validateAge(input['age']))

la funzione ap è fatta così:

readonly ap: <A, B>(fab: HKT<F, (a: A) => B>, fa: HKT<F, A>) => HKT<F, B>

in scala

def ap: [A, B](fab: F[A => B], fa: F[A]): F[B]

in poche parole

  1. accetta fab: una funzione da A=>B wrappata in un effetto F aka F[A => B]
  2. accetta fa: un valore A wrappato in un effetto aka F[A]
  3. restutisce un F[B]

invocando le singole validazioni ottengo

const nameResult: Validation<NonEmptyArray<string>, string> = validateName(input['name'])
const ageResult: Validation<NonEmptyArray<string>, number> = validateAge(input['age'])  

A.ap(nameResult.map(person), ageResult)  

ora concentriamoci qui

nameResult.map(person) 

passando alla map (che accetta in ingresso una funzione con 1 parametro) il curried constructor ottengo

const nameResultBindend: Validation<NonEmptyArray<string>, number => Person> = nameResult.map(person)

dai! non ci credo! ho una funzione wrappata in un effetto sta a vedere che ora posso chiamare ap! ;-)

A.ap(nameResultBindend, ageResult)

applicando più volte la stessa tecnica (ap + map) posso comporre funzioni con 3/4/5/N parametri. Ripeto è un dettaglio low level, importante, ma low level.

Durante il corso per non andare così low level abbiamo usato la map2/map3/etc oppure la mapN. Prendiamo la map2, in scala la sua firma è:

def map2[A, B, Z](fa: F[A], fb: F[B])(f: (A, B) => Z): F[Z]

il suo scopo è quello di valutare in maniera indipendente 2 effetti (fa e fb), passare i risultati alla funzione f e liftare quanto prodotto (Z) nel solito effetto (F). Questo ci permetteva di fare una roba tipo

case class Person(name:String, age:Int)
def makePerson(name:String, age:Int):ValidationResult[Person] = 
   Applicative[ValidationResult].map2(validateName(name), validateAge(age))(Person.apply)

Quindi se vuoi usare questo tipo di combinatori (a più alto livello) devi cercarli in fp-ts. Ho fatto un giro e controllando la definizione di Applicative (https://github.com/gcanti/fp-ts/blob/master/docs/Apply.md) non ho trovato map2 ma una cosa equivalente liftA2: Lift a function of two arguments to a function which accepts and returns values wrapped with the type constructor F

ovvero data la funzione f: (A, B) => Z passandola a liftA2 otteniamo una funzione g: (F[A], F[B]) => F[Z].

nel mondo curry andiamo da f: A => B => Z a g: F[A] => F[B] => F[Z]

in pratica prendiamo una funzione senza effetti (f) e la trasformiamo in una che funziona allo stesso modo ma effectful.

Se caliamo liftA2 nell’esempio di validation di Fp-Ts dobbiamo prima di tutto prendere il curried constructor

const person = (name: string) => (age: number): Person => ({ name, age })

e liftarlo con liftA2 (non conosco typescript e fp-ts quindi vado un po’ di pseudo codice)

const A = getApplicative(getSemigroup<string>())
const personLiftata = liftA2(A)(person)

ed in fine validationPerson invocherà la versione liftata

function validatePerson(input: Record<string, string>): Validation<NonEmptyArray<string>, Person> {
  return personLiftata(validateName(input['name']), validateAge(input['age']))
}

sintetizzando prendiamo una funzione

string => number => Person

e “senza fare niente” la facciamo operare in un contesto di validazione

Validation<NonEmptyArray<string>, string> => Validation<NonEmptyArray<string>, number> => Validation<NonEmptyArray<string>, Person>

E qui sta la figata, ipotizziamo che validateName e validateAge siano implementate server side, quindi la validazione diventa asyn con i Task (sempre di Fp-Ts). Come cambia il tutto? La contruction function non cambia, non dipende da effetti.

Le validateName e validateAge le riscriviamo.

function validateName(input: string): Task<string> ...
function validateAge(input: string): Task<number>  ...

La definizione della personLiftata non cambia.

Mentre validatePerson cambia solo come tipo di ritorno

function validatePerson(input: Record<string, string>): Task<Person> {
  return personLiftata(validateName(input['name']), validateAge(input['age']))
}

Il tutto accade perchè prendiamo la solita

string => number => Person

e “senza fare niente” la facciamo operare in un contesto di HTTP async

Task<string> => Task<number> => Task<Person>

Forte, no?

[ema] E se avesse 20 campi?

Hai un problema di design! :-) Detto questo, esistono tante liftA con il numero di parametri

fp-ts arriva al max a liftA4. haskell arriva al max fino a liftA3 in scala arriviamo a map22 (siamo troppo avanti :-) scherzi a parte sono 22 perchè in java possiamo definire metodi fino ad un massimo di 22 parametri).

Quindi se cambiano i requisiti ed a Person viene aggiunto un campo “email” da validare dobbiamo:

  1. aggiungere il campo sul product type
  2. aggiungere il parametro curried alla constructor funcion
  3. definire eventuali nuovi validatori
  4. usare liftA3 invece di liftA2
  5. usare il terzo validatore in validatePerson

Meccanico e dal punto 2 in poi guidato dal compilatore, per questo lo vedo articolato, ma non complesso. Una volta conosciute bene le astazioni. :-)

Nel nostro caso le validazioni sono N e sullo stesso campo devo poter fare piu’ validazioni (ad. es. la stringa e’ una data e la data e’ maggiore di oggi).

ti fai una funzione di validazione da stringa a data poi una da data a data in pratica ti fai le singole “check” slegati da cosa andrai a creare

function validateNotEmpty(input: string): Validation<NonEmptyArray<string>, string>
function validateGtToday(input: date): Validation<NonEmptyArray<string>, date>  

dopo la validatione della data per la solution da stringa a data è solo la composizione dei check (faccio ancora un typescript “a braccio”)

function validateDate(input: string): Validation<NonEmptyArray<string>, date> 
              validateNotEmpty.flatMap(validateGtToday)

flatMap, aka composizione monadica, perchè prima devi poter passare da stringa a data e solo se riesci devi vedere se la data è maggiore di oggi, altrimenti non fare niente.

[ema] E in uscita vogliamo:

export type SelectedSolution = {
  from: Station,
  to: Station,
  outbound: TrainDateTime,
}
export type TrainDateTime = {
  date: Date,
  time: Time
}

la validazione della TrainDateTime è una composizione applicativa di validateDate e validateTime (che non ho implemetato…)

function validateTrainDateTime(input: Record<string, string>): Validation<NonEmptyArray<string>, TrainDateTime> 
    createTrainDateTimeLiftata(validateDate(input['date']), validateTime(input['time']))

idem per Station e SelectedSolution, comporre le altre funzioni (che erano a sua volta composte da altre funzioni)

function validateStation(input: string): Validation<NonEmptyArray<string>, Station>
    validateNotEmpty(input).map(createStation)

function validateSelectedSolution(input: Record<string, string>): Validation<NonEmptyArray<string>, SelectedSolution>  
    createSelectedSolutionLiftata(validateStation(input['from']),  validateStation(input['to']), validateTrainDateTime(input))  

:-)

Arcade in Codiceplastico

In CodicePlastico abbiamo sempre cercato modi per creare un ambiente piacevole in cui passare la giornata lavorativa. Sappiamo benissimo che il nostro lavoro di programmatori ha parecchi aspetti negativi legati principalmente al poco movimento e al prolungarsi delle ore passate a concentrarsi su un problema. Per questo, senza imporre regole o obblighi, nel tempo ci siamo inventati strumenti e metodi per migliorare la situazione. Abbiamo iniziato anni fa con le freccette, “sport” al quale ci dedichiamo giornalmente con sfide all’ultimo 20 triplo! Da un annetto circa abbiamo introdotto anche l’acquisto aziendale di frutta (esistono fruttivendoli che vendono su internet!) e non ci facciamo mai mancare un po’ di frutta di stagione da consumare durante i meeting interni o durante le pause. Ma la grande novita’ di questi gioni e’ lui:

Eccolo

Ci siamo regalati un cabinato brandizzato CodicePlastico per staccare la mente dal codice e ritornare ai tempi delle scuole medie con i videogiochi del passato.

Insomma le giornate lavorative sono diventate piu’ divertenti e tra un test verde e uno rosso abbiamo tempo per qualche sfida!