Qual è il vantaggio del modello senza logica (come i baffi)?

Recentemente, mi sono imbattuto in baffi che si dice sia un modello senza logica .

Tuttavia, non c’è spiegazione del motivo per cui è stato progettato in modalità senza logica. In altre parole, qual è il vantaggio del modello senza logica?

In altre parole, ti impedisce di spararti ai piedi. Nei vecchi giorni JSP, era molto comune avere file JSP cosparsi di codice Java, il che ha reso molto più difficile il refactoring, dal momento che il codice era sparso.

Se si impedisce la logica nei modelli in base alla progettazione (come fa il baffo), si sarà obbligati a mettere la logica altrove, così i modelli finiranno per essere ordinati.

Un altro vantaggio è che sei costretto a pensare in termini di separazione dei dubbi: il tuo controller o codice logico dovrà eseguire il massaggio dei dati prima di inviare i dati all’interfaccia utente. Se in seguito cambi il tuo modello con un altro (diciamo che inizi a utilizzare un diverso motore di template), la transizione sarebbe facile perché hai solo dovuto implementare i dettagli dell’interfaccia utente (dal momento che non c’è logica sul modello, ricorda).

Ho la sensazione di essere quasi solo a mio avviso, ma sono fermamente nel campo opposto. Non credo che il ansible mix di logica aziendale nei tuoi modelli sia una ragione sufficiente per non utilizzare tutta la potenza del tuo linguaggio di programmazione.

La solita argomentazione per i template privi di logica è che se si ha pieno accesso al proprio linguaggio di programmazione si può mescolare una logica che non ha spazio in un modello. Trovo questo simile al ragionamento che dovresti usare un cucchiaio per tagliare la carne perché potresti tagliarti se usi un coltello. Questo è molto vero, eppure sarai molto più produttivo se usi quest’ultimo, anche se con attenzione.

Ad esempio, considera il seguente frammento di modello usando i baffi :

{{name}}: 
    {{#items}}
  • {{.}}
  • {{/items}}

Posso capirlo, ma trovo che il seguente (usando il carattere di sottolineatura ) sia molto più semplice e diretto:

 <%- name %>: 
    <% _.each(items, function(i){ %>
  • <%- i %>
  • <% }); %>

Detto questo, capisco che i modelli senza logica hanno vantaggi (ad esempio, possono essere utilizzati con più linguaggi di programmazione senza modifiche). Penso che questi altri vantaggi siano molto importanti. Semplicemente non penso che la loro natura priva di logica sia una di quelle.

Il baffo è privo di logica?

Non è questo:

 {{#x}} foo {{/x}} {{^x}} bar {{/x}} 

Piuttosto simile a questo?

 if x "foo" else "bar" end 

E non è molto simile alla logica di presentazione (leggi: quasi una definizione di)?

Un modello senza logica è un modello che contiene fori da riempire e non il modo in cui li si riempie. La logica viene posizionata altrove e mappata direttamente sul modello. Questa separazione delle preoccupazioni è l’ideale, perché in tal caso il modello può essere facilmente creato con una logica diversa o persino con un linguaggio di programmazione diverso.

Dal manuale dei baffi :

Lo chiamiamo “logic-less” perché non ci sono istruzioni if, clausole else o loop. Invece ci sono solo tag. Alcuni tag vengono sostituiti con un valore, un po ‘nulla e altri una serie di valori. Questo documento spiega i diversi tipi di tag Moustache.

Rende i tuoi modelli più puliti e ti costringe a mantenere la logica in un posto in cui può essere adeguatamente testata da unità.

Il rovescio della medaglia è che nel disperato tentativo di mantenere la logica aziendale fuori dalla presentazione, si finisce col mettere molta logica di presentazione nel modello. Un esempio comune potrebbe essere che si desidera mettere classi “dispari” e “pari” su righe alternate in una tabella, che potrebbe essere eseguita con un operatore modulo semplice nel modello di vista. Ma se il tuo modello di visualizzazione non ti consente di farlo, allora nei dati del tuo modello non devi solo memorizzare quale riga è pari o dispari, ma a seconda di quanto è limitato il tuo motore di template, potresti anche aver bisogno di inquinare il tuo modello con i nomi delle vere classi CSS. Le viste dovrebbero essere separate dai modelli, a punto intero. Ma i modelli dovrebbero anche essere View agnostic, ed è quello che molti di questi template engine “no-logic” ti fanno dimenticare. La logica va in entrambi i posti, ma devi essere giudizioso su ciò che effettivamente fa la logica per decidere correttamente dove va. È un problema di presentazione o un problema aziendale / dati? Nel tentativo di avere una visione incontaminata al 100%, l’inquinamento finisce in un altro posto meno visibile ma ugualmente inappropriato.

C’è un movimento crescente nella direzione opposta, e si spera che le cose si concentreranno da qualche parte nel terreno di mezzo più ragionevole.

L’argomento migliore che ho trovato per i modelli logicless è che puoi usare gli stessi modelli esatti sia sul client che sul server. Tuttavia non hai davvero bisogno di logica, solo uno che ha il proprio “linguaggio”. Sono d’accordo con le persone che si lamentano che i baffi sono inutilmente limitanti. Grazie, ma sono un ragazzo grande e posso mantenere i miei modelli puliti senza il tuo aiuto.

Un’altra opzione è quella di trovare una syntax per i template che usa un linguaggio supportato sia sul client che sul server, ovvero javascript sul server usando node.js o si può usare un interprete js e json tramite qualcosa come therubyracer.

Quindi potresti usare qualcosa come haml.js che è molto più pulito di tutti gli esempi forniti finora e funziona alla grande.

Questa conversazione sembra quando i monaci del Medioevo discutono sul numero di angeli che possono stare sulla punta di una spilla. In altre parole, comincia a sentirsi religioso, futile e incerto.

Segue mini-rant (sentiti libero di ignorare):

Se non vuoi continuare a leggere .. La mia breve risposta all’argomento sopra è: Non sono d’accordo con i modelli senza logica. Lo considero una forma di programmazione dell’estremismo. 🙂 🙂

Ora il mio rant continua in pieno svolgimento: 🙂

Penso che quando porti molte idee all’estremo, il risultato diventa ridicolo. E a volte (cioè questo argomento) il problema è che portiamo l’idea “sbagliata” all’estremo.

Rimuovere tutta la logica dalla vista è “ridicolo” e l’idea sbagliata.

Fai un passo indietro per un momento.

La domanda che dobbiamo porci è perché rimuovere la logica? Il concetto, ovviamente, è la separazione delle preoccupazioni . Mantenere il processo di visualizzazione separato dalla logica di business ansible. Perché questo? Ci consente di scambiare le visualizzazioni (per piattaforms diverse: mobile, browser, desktop ecc.) E ci consente di scambiare più facilmente il stream di controllo, la sequenza di pagine, le modifiche di convalida, le modifiche del modello, l’accesso di sicurezza ecc. Anche quando la logica è rimosso dalle viste (in particolare le viste Web), rende le viste molto più leggibili e quindi più manutenibili. Lo capisco e sono d’accordo.

Tuttavia l’attenzione prioritaria dovrebbe essere sulla separazione delle preoccupazioni. Viste non logiche al 100%. La logica all’interno delle viste dovrebbe riguardare come rendere il “modello”. Per quanto mi riguarda, la logica nelle visualizzazioni è perfettamente soddisfacente. È ansible avere una logica di visualizzazione che non è logica aziendale.

Sì, nel passato quando scrivevamo pagine JSP, PHP o ASP con poca o nessuna separazione di logica di codice e logica di visualizzazione, il mantenimento di queste web-app era un vero incubo. Credimi, lo so, ho creato e poi mantenuto alcune di queste mostruosità. È stato durante quella fase di manutenzione che ho veramente compreso (visceralmente) l’errore dei modi miei e dei miei colleghi. 🙂 🙂

Così l’editto dall’alto (gli esperti del settore) è diventato, tu devi strutturare le tue app web usando qualcosa come un controller di vista frontale (che viene inviato a gestori o azioni [scegli il tuo framework web]) e le tue visualizzazioni non devono contenere codice . I punti di vista dovevano diventare modelli stupidi.

Quindi sono d’accordo in generale con il sentimento di cui sopra, non per le specificità degli elementi dell’editto, ma piuttosto la motivazione dietro l’editto – che è il desiderio di separare le preoccupazioni tra vista e logica aziendale.

In un progetto in cui sono stato coinvolto, abbiamo cercato di seguire l’idea della vista senza logica fino all’estremo ridicolo. Avevamo un motore di template sviluppato internamente che ci permetteva di eseguire il rendering di oggetti modello in html. Era un semplice sistema basato su token. E ‘stato terribile per una ragione molto semplice. A volte in una vista dovevamo decidere, dovrei mostrare questo piccolo frammento di HTML .. o no .. La decisione è di solito basata su un certo valore nel modello. Quando non hai assolutamente nessuna logica nella vista, come si fa? Beh, non puoi. Ho avuto alcune discussioni importanti con il nostro architetto su questo. Le persone HTML front-end che scrivevano i nostri punti di vista erano completamente ostacolate quando si trovavano di fronte a questo e erano molto stressate perché non potevano raggiungere i loro obiettivi altrimenti semplici. Così ho introdotto il concetto di una semplice istruzione IF all’interno del nostro motore di template. Non posso descriverti il ​​sollievo e la calma che ne è derivata. Il problema è stato risolto con un semplice concetto di IF-Statement nei nostri modelli! All’improvviso il nostro motore dei modelli è diventato buono.

Allora, come siamo entrati in questa situazione sciocca e stressante? Ci siamo concentrati sull’objective sbagliato. Abbiamo seguito la regola, non devi avere alcuna logica nei tuoi punti di vista. Era sbagliato. Penso che la “regola del pollice” dovrebbe essere, minimizzare quella quantità di logica nelle tue visualizzazioni. Perché se non lo fai, potresti inavvertitamente consentire alla logica aziendale di insinuarsi nella vista, il che viola la separazione delle preoccupazioni.

Capisco che quando dichiari che “Non devi avere alcuna logica nelle viste”, diventa facile sapere quando sei un programmatore “buono”. (Se questa è la tua misura di bontà). Ora prova ad implementare un’applicazione web di complessità anche media con la regola precedente. Non è così facile da fare.

Per me, la regola della logica nelle opinioni non è così chiara e francamente è lì che voglio che sia.

Quando vedo un sacco di logica nelle viste, rilevo un odore di codice e cerco di eliminare la maggior parte della logica dai punti di vista – cerco di garantire che la logica aziendale viva altrove – cerco di separare le preoccupazioni. Ma quando inizio a chiacchierare con persone che dicono che dobbiamo rimuovere tutta la logica dalla vista, beh, per me, questo sa solo di fanatismo perché so che puoi finire in situazioni come quelle descritte sopra.

Ho finito con il mio rant. 🙂

Saluti,

David

In una frase: senza logica significa che il motore di template stesso è meno complesso e quindi ha un ingombro minore e ci sono meno modi per comportarsi inaspettatamente.

Anche se la domanda è vecchia e ha risposto, vorrei aggiungere il mio 2 ¢ (che può sembrare uno sproloquio, ma non lo è, riguarda le limitazioni e quando diventano inaccettabili).

L’objective di un modello è quello di eseguire il rendering di qualcosa, non di eseguire la logica di business. Ora c’è una linea sottile tra non essere in grado di fare ciò che è necessario fare in un modello e avere “logica aziendale” al loro interno. Anche se sono stato molto positivo nei confronti di Mustache e ho cercato di usarlo, ho finito per non essere in grado di fare ciò di cui avevo bisogno in casi abbastanza semplici.

Il “massaging” dei dati (per usare le parole nella risposta accettata) può diventare un problema reale – non sono supportati nemmeno i percorsi semplici (cosa che Handlebars.js affronta). Se ho i dati di visualizzazione e ho bisogno di modificare ogni volta che voglio eseguire il rendering di qualcosa perché il mio motore di template è troppo limitante, questo non è utile alla fine. E sconfigge parte della piattaforma: l’indipendenza che i baffi reclamano da sé; Devo duplicare la logica del massaggio ovunque.

Detto questo, dopo un po ‘di frustrazione e dopo aver provato altri template engine, abbiamo finito per creare il nostro (… ancora un altro …), che utilizza una syntax ispirata ai modelli .NET Razor. Viene analizzato e compilato sul server e genera una funzione JS semplice e autonoma (in realtà come modulo RequireJS) che può essere invocata per “eseguire” il modello, restituendo una stringa come risultato. Il campione dato da Brad sarebbe simile a questo quando si utilizza il nostro motore (che personalmente trovo molto superiore in termini di capacità rispetto a Moustache e Underscore):

 @name: 
    @for (items) {
  • @.
  • }

Un’altra limitazione priva di logica ci colpisce quando si chiama in partial con Moustache. Mentre i partial sono supportati da Moustache, non è ansible personalizzare i dati da trasmettere per primi. Quindi, invece di essere in grado di creare un modello modulare e riutilizzare piccoli blocchi, finirò per creare modelli con codice ripetuto.

Lo abbiamo risolto implementando un linguaggio di query ispirato a XPath, che abbiamo chiamato JPath. Fondamentalmente, invece di usare / per attraversare i bambini, utilizziamo i punti e non solo sono supportati stringhe, numeri e valori booleani, ma anche oggetti e matrici (proprio come JSON). Il linguaggio è privo di effetti collaterali (che è un must per i template) ma consente di “massaggiare” i dati secondo necessità, creando nuovi oggetti letterali.

Diciamo che vogliamo eseguire il rendering di una tabella “griglia dati” con intestazioni e collegamenti cusomizable alle azioni sulle righe e aggiungere in seguito righe dinamiche utilizzando jQuery. Le righe quindi devono essere in un parziale se non voglio duplicare il codice. Ed è qui che iniziano i guai se alcune informazioni aggiuntive come le colonne devono essere renderizzate fanno parte del modello viewmodel e lo stesso vale per quelle azioni su ogni riga. Ecco un codice di lavoro effettivo utilizzando il nostro modello e il motore di query:

Modello di tabella:

  @for (columns) {  } @if (actions) {  }  @for (rows) { @partial Row({ row: ., actions: $.actions, columns: $.columns }) } 
@titleActions

Modello di fila:

  @for (var $col in columns) { @row.*[name()=$col.property] } @if (actions) {  @for (actions) {  }  }  

Invocazione dal codice JS:

 var html = table({ columns: [ { title: "Username", property: "username" }, { title: "E-Mail", property: "email" } ], actions: [ { id: "delete", name: "Delete" } ], rows: GetAjaxRows() }) 

Non ha alcuna logica di business, tuttavia è riutilizzabile e configurabile, ed è anche privo di effetti collaterali.

Qui ci sono 3 modi di rendere una lista, con il numero di caratteri. Tutti tranne il primo e il più breve sono in linguaggi che non richiedono la logica.

CoffeeScript (con builder Reactive Coffee DSL) – 37 caratteri

 "#{name}" ul items.map (i) -> li i 

Knockout: 100 caratteri

  

Manubri / baffi – 66 caratteri

 {{name}}: 
    {{#items}}
  • {{.}}
  • {{/items}}

Sottolineatura: 87 caratteri

 <%- name %>: 
    <% _.each(items, function(i){ %>
  • <%- i %>
  • <% }); %>

La promise di modelli privi di logica era, suppongo, che le persone con competenze più ampie sarebbero in grado di gestire modelli privi di logica senza spararsi ai piedi. Tuttavia, ciò che vedi negli esempi precedenti è che quando aggiungi un linguaggio a logica minima al markup basato su stringhe, il risultato è più complesso, non inferiore. Inoltre, sembri un ph della vecchia scuola.

Chiaramente non obietto a mantenere la “logica aziendale” (vasto calcolo) dai modelli. Ma penso che dando loro una pseudo-lingua per la logica di visualizzazione invece di una lingua di prima class, il prezzo è pagato. Non solo più da digitare, ma un mix atroce di cambiamento di contesto, qualcuno deve leggerlo.

In conclusione, non riesco a vedere la logica dei modelli privi di logica, quindi direi che il loro vantaggio è nullo per me, ma rispetto molti che nella comunità lo vedono in modo diverso 🙂

Sono d’accordo con Brad: lo stile di underscore è più facile da capire. Ma devo ammettere che lo zucchero sintattico potrebbe non piacere a tutti. Se _.each è alquanto confuso, puoi usare un ciclo for tradizionale.

  <% for(var i = 0; i < items.length; i++) { %> <%= items[i] %> <% } %> 

È sempre bello se puoi ricorrere a costrutti standard come for o if . Usa solo <% if() %> o <% for() %> mentre Mustache usa un po ‘di neologismo per if-then-else (e confondendo se non hai letto la documentazione):

 {{#x}} foo {{/x}} {{^x}} bar {{/x}} 

Il motore di template è ottimo quando puoi realizzare facilmente modelli annidati (stile di underscore ):

   var tmplFn = function(outerTmpl, innerTmpl) { return function(obj) { return outerTmpl({obj: obj, innerTmpl: innerTmpl}); }; }; var tmpl = tmplFn($('#items-tmpl').html(), $('#item-tmpl').html()); var context = { items: [{name:'A',{name:'B'}}] }; tmpl(context); 

Fondamentalmente si passa il tuo tmpl interiore come una proprietà del tuo contesto. E chiamalo di conseguenza. Dolce 🙂

A proposito, se l’unica cosa che ti interessa è il motore di template, usa l’implementazione del template standalone. Ha solo 900 caratteri quando è ridotto (4 linee lunghe):

https://gist.github.com/marlun78/2701678

I principali vantaggi dell’utilizzo di modelli senza logica sono:

  • Impone rigorosamente la separazione della vista del modello , consulta questo documento per i dettagli (altamente consigliato)
  • Molto facile da capire e da usare , perché non è necessaria alcuna logica di programmazione (e conoscenza!) E la syntax è minima
  • (particolare Moustache) altamente portatile e indipendente dal linguaggio, può essere utilizzato senza modifiche in quasi tutti gli ambienti di programmazione