Be Brave

Un altro episodio della serie “cose che solo io trovo utili”

http://playersgonnaplay.it/be-brave-in-ruby-land

Conosco almeno un altro sviluppatore che lo avrebbe trovato utile HINT
HINT

:high-five:

2015-08-06 12:14 GMT+02:00 Elia S. [email protected]:

Fino a poco tempo fa lavoravo su una code base Rails 3 composta per un
terzo di rescue nil, perché il capo si lamentava che c’erano troppi
errori… una tortura.
Insomma, questa è roba da professionisti, i niubbi non provino a rifarla
a casa! :slight_smile:

Inviato da iPhone

Più che da professionisti, è una cosa da fuori di testa xD fin quando si
scherza si scherza, ma exceptions as control flow… brividi!

Il giorno gio 6 ago 2015 14:05 Luca P. [email protected]
ha
scritto:

Mi permetto di correggere, perché qui stiamo parlato di missed exception
control to keep the flow ◕ ◡ ◔

Giusto, ascrivibili al gruppo “usare le eccezioni per far altro che non
sia
gestire eccezioni”

Il giorno gio 6 ago 2015 14:14 Elia S. [email protected] ha scritto:

class NilClass
def method_missing(*)
self
end
end

Ecco, monkey patch di questo tipo mi fanno davvero paura :smiley:
Preferisco un approccio meno invasivo :slight_smile:

2015-08-06 14:26 GMT+02:00 Elia S. [email protected]:

Mah, sono abbastanza serio :slight_smile:
Il caso d’uso è ben circoscritto e sarei ben lieto di usare soluzioni
altrettanto concise anche se ad ora non ne vedo.
La try chain è scomoda e poco leggibile quando si gestiscono accessi ad
Hash:

params.try(:[], :profile).try(:[], :resume).try(:tempfile).try(:path)

Così come la boolean chain:

if params[:profile] && params[:profile][:resume] &&
params[:profile][:resume].try(:tempfile).try(:path)

Come affronteresti questo specifico caso?

@luca: da maneggiare con attenzione, ovviamente :slight_smile: Un uso ad-minchiam è
potenzialmente letale.

2015-08-06 14:10 GMT+02:00 Maurizio De Santis
[email protected]:

Ok, allora rispondo seriamente :slight_smile:

Usare le eccezioni per controllare il flusso è un noto antipattern:

Ho avuto a che fare con questo tipo di approccio con un collega a cui
piaceva, e l’aveva usato un bel po’ in giro nel codice di un progetto.
Dopo
averne parlato siamo giunti alla conclusione che crea più problemi che
altro, per i seguenti motivi:

  • viola il principio di minima sorpresa: le eccezioni sono fatte per
    gestire errori, non per gestire un flusso previsto
  • la logica ha la priorità sulla concisione: se del codice richiede
    della
    complessità logica in sé, non puoi sacrificarla per amor di concisione
  • ti perdi le eccezioni rescuate: questo è un grande problema, perché se
    la
    parte di codice wrappata genera un’eccezione che non pensavi potesse
    spuntare fuori te la perdi, non viene loggata e cominciano a verificarsi
    i
    tanto classici quanto temuti fenomeni paranormali informatici

Inoltre, nel codice postato usi rescue Exception, che rescua anche da
eccezioni di sistema:

Nel caso da te citato userei una delle soluzioni che hai scritto, magari
estraendola a metodo privato. Sarà meno elegante, ma è più logica e
manutenibile.

Il giorno gio 6 ago 2015 14:29 maurizio de magnis <
[email protected]> ha scritto:

+1 per StandardError al posto di Error (ho aggiornato il post) e +1
anche
per il fatto di non usare le eccezioni come strumento di gestione del
flusso di codice.

Ora, nel caso menzionato gestisco solo questi fallimenti:

  • NoMethodError: undefined method `[]’ for nil:NilClass
  • NoMethodError: undefined method `XXX’ for “YYY”:String

L’obiettivo che mi sono posto, limitando volontariamente lo scope di
Brave.be, è ottenere una syntactic sugar per recuperare un valore
nestato
in una struttura dati. Di fatto, a parte l’essere più o meno bello da
vedere, non comporta le stesse sorprese della magia nera da
Metaprogrammazione.

2015-08-06 15:13 GMT+02:00 Maurizio De Santis
[email protected]:

FY(possible?)I: Tom Stuart - Refactoring Ruby with Monads - YouTube


:: Andrea P.
:: email: [email protected]
:: mobile: +44 747 3090534

On 6 August 2015 at 14:13:46, Maurizio De Santis
([email protected]) wrote:

Ok, allora rispondo seriamente :slight_smile:

Usare le eccezioni per controllare il flusso è un noto antipattern:

Ho avuto a che fare con questo tipo di approccio con un collega a cui
piaceva, e l’aveva usato un bel po’ in giro nel codice di un progetto.
Dopo
averne parlato siamo giunti alla conclusione che crea più problemi che
altro, per i seguenti motivi:

  • viola il principio di minima sorpresa: le eccezioni sono fatte per
    gestire errori, non per gestire un flusso previsto
  • la logica ha la priorità sulla concisione: se del codice richiede
    della
    complessità logica in sé, non puoi sacrificarla per amor di concisione
  • ti perdi le eccezioni rescuate: questo è un grande problema, perché se
    la
    parte di codice wrappata genera un’eccezione che non pensavi potesse
    spuntare fuori te la perdi, non viene loggata e cominciano a verificarsi
    i
    tanto classici quanto temuti fenomeni paranormali informatici

Inoltre, nel codice postato usi rescue Exception, che rescua anche da
eccezioni di sistema:

Nel caso da te citato userei una delle soluzioni che hai scritto, magari
estraendola a metodo privato. Sarà meno elegante, ma è più logica e
manutenibile.

Il giorno gio 6 ago 2015 14:29 maurizio de magnis <
[email protected]> ha scritto:

params.try(:[], :profile).try(:[], :resume).try(:tempfile).try(:path)
potenzialmente letale.

casa! :slight_smile:

Conosco almeno un altro sviluppatore che lo avrebbe trovato utile

Maurizio ಠ_ಠ My profile

Ml mailing list

[email protected]
[email protected]
http://lists.ruby-it.org/mailman/listinfo/ml


Ml mailing list
[email protected]
http://lists.ruby-it.org/mailman/listinfo/ml

Ecco, questa è una soluzione molto, molto elegante :slight_smile:
Nonostante non sia un patito di method_missing, lo preferisco ad un
begin/rescue
+1

2015-08-06 15:26 GMT+02:00 Andrea P. [email protected]:

La mancanza di Optional/Maybe nel 2015 in un linguaggio come Ruby è
piuttosto preoccupante.

2015-08-06 15:59 GMT+02:00 maurizio de magnis
[email protected]:

@maurizio: Revolution! XD

ecco il repository con l’implementazione di Tom S. delle monad
Optional, Many ed Eventually:

2015-08-06 16:09 GMT+02:00 Maurizio De Santis
[email protected]:

O se vuoi solo un wrapper per quei due casi… fai un wrapper!

comunque +1 per Tom S.

PS. il tuo post oramai è una wiki :stuck_out_tongue:

Comics time: The Philosophy of the Science of Poker - Existential Comics

Il giorno gio 6 ago 2015 16:03 Stefano P.
[email protected]
ha scritto:

Piccola nota: dovrei convertire params in una OpenStruct (o similare)
per
poter gestire la chain tramite Optional.

2015-08-06 16:59 GMT+02:00 Elia S. [email protected]:

O se vuoi solo un wrapper per quei due casi… fai un wrapper!

Mmh, espandi un po’. Cosa intendi?

comunque +1 per Tom S.

Già, tanta roba. :slight_smile:

PS. il tuo post oramai è una wiki :stuck_out_tongue:

ghgh, lo prendo come un complimento :slight_smile:

class InfiniteHash
def initialize(hash = nil)
@hash = hash
end

def value
@hash
end

def [] key
value = @hash[key]
return Value.new(value) unless value.nil? or value.is_a?(Hash)
InfiniteHash.new(value)
end

class Value < Struct.new(:value)
def [] key
self
end
end
end

hash = {a: 1, b: {c: 2}}
p InfiniteHash.new(hash)[:a].value
p InfiniteHash.new(hash)[:b][:c].value
p InfiniteHash.new(hash)[:b][:c][:d][:e][:f].value

>> 1

>> 2

>> 2

Ma tutto sommato mi sa che una specializzazione di quello che fa TS