Recentemente, mi sono imbattuto in baffi che si afferma essere un modello senza logica .
Tuttavia, non si spiega perché sia stato progettato in modo senza logica. In altre parole, qual è il vantaggio del modello senza logica?
Recentemente, mi sono imbattuto in baffi che si afferma essere un modello senza logica .
Tuttavia, non si spiega perché sia stato progettato in modo senza logica. In altre parole, qual è il vantaggio del modello senza logica?
Risposte:
In altre parole, ti impedisce di spararti ai piedi. Ai vecchi tempi di JSP, era molto comune avere file JSP cosparsi di codice Java, il che rendeva il refactoring molto più difficile, dal momento che il codice era sparso.
Se previeni la logica nei modelli in base alla progettazione (come fanno i baffi), sarai obbligato a mettere la logica altrove, quindi i tuoi modelli finiranno per essere ordinati.
Un altro vantaggio è che sei costretto a pensare in termini di separazione delle preoccupazioni: 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 (supponiamo che inizi a utilizzare un motore di modelli diverso), la transizione sarebbe facile perché dovevi solo implementare i dettagli dell'interfaccia utente (poiché non c'è logica sul modello, ricorda).
Ho la sensazione di essere quasi solo secondo me, ma sono fermamente nel campo opposto. Non credo che la possibile combinazione di logica aziendale nei tuoi modelli sia una ragione sufficiente per non utilizzare tutta la potenza del tuo linguaggio di programmazione.
Il solito argomento per i modelli senza logica è che se hai pieno accesso al tuo linguaggio di programmazione potresti mescolare una logica che non ha posto in un modello. Lo trovo simile al ragionamento secondo cui dovresti usare un cucchiaio per affettare 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 utilizzando baffi :
{{name}}:
<ul>
{{#items}}
<li>{{.}}</li>
{{/items}}
</ul>
Posso capirlo, ma trovo che quanto segue (usando il carattere di sottolineatura ) sia molto più semplice e diretto:
<%- name %>:
<ul>
<% _.each(items, function(i){ %>
<li><%- i %></li>
<% }); %>
</ul>
Detto questo, capisco che i modelli senza logica hanno dei vantaggi (ad esempio, possono essere utilizzati con più linguaggi di programmazione senza modifiche). Penso che questi altri vantaggi siano molto importanti. Semplicemente non credo che la loro natura priva di logica sia una di queste.
name
e items
potrebbe contenere JavaScript.
Moustache è senza logica?
Non è questo:
{{#x}}
foo
{{/x}}
{{^x}}
bar
{{/x}}
Abbastanza simile a questo?
if x
"foo"
else
"bar"
end
E non è che abbastanza simile a (leggi: quasi una definizione di) logica di presentazione?
if x > 0 && x < 10
) ... Quindi, mentre è possibile usare Moustache con o senza logica, dipende da te. Dopotutto, è solo uno strumento.
Un modello senza logica è un modello che contiene dei buchi da riempire e non il modo in cui vengono riempiti. La logica viene posizionata altrove e mappata direttamente al modello. Questa separazione delle preoccupazioni è ideale perché quindi il modello può essere facilmente costruito con una logica diversa, o anche con un linguaggio di programmazione diverso.
Dal manuale dei baffi :
Lo chiamiamo "senza logica" perché non ci sono istruzioni if, clausole else o cicli for. Invece ci sono solo tag. Alcuni tag vengono sostituiti con un valore, altri niente e altri una serie di valori. Questo documento spiega i diversi tipi di tag Moustache.
Il rovescio della medaglia è che nel disperato tentativo di mantenere la logica di business fuori dalla presentazione, si finisce per inserire molta logica di presentazione nel modello. Un esempio comune potrebbe essere quello di voler inserire classi "dispari" e "pari" su righe alternate in una tabella, operazione che potrebbe essere eseguita con un semplice operatore modulo nel modello di visualizzazione. 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 modello, potresti persino dover inquinare il tuo modello con i nomi delle classi CSS effettive. Le viste dovrebbero essere separate dai modelli, punto. Ma i modelli dovrebbero anche essere indipendenti dalla vista, ed è questo che molti di questi motori di modelli "senza logica" ti fanno dimenticare. La logica va in entrambi i posti,in realtà fa per decidere correttamente dove va. È un problema di presentazione o un problema aziendale / dati? Nel tentativo di avere una vista incontaminata al 100%, l'inquinamento atterra in un altro luogo meno visibile ma ugualmente inappropriato.
C'è un crescente movimento di ritorno nella direzione opposta, e si spera che le cose si concentreranno da qualche parte nella più ragionevole via di mezzo.
Rende i tuoi modelli più puliti e ti costringe a mantenere la logica in un luogo in cui può essere adeguatamente testata.
Questa conversazione sembra come quando i monaci del Medioevo discutevano su quanti angeli possono stare all'estremità di uno spillo. In altre parole, inizia a sentirsi religioso, futile e focalizzato in modo errato.
Segue un mini-rant (sentiti libero di ignorare):
Se non vuoi continuare a leggere ... La mia breve risposta all'argomento precedente è: non sono d'accordo con i modelli senza logica. Lo considero una forma di programmazione dell'estremismo. :-) :-)
Ora il mio sproloquio continua a pieno ritmo: :-)
Penso che quando si portano 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 . Mantieni l'elaborazione della vista il più separata possibile dalla logica aziendale. Perché fare questo? Ci consente di scambiare le visualizzazioni (per diverse piattaforme: mobile, browser, desktop ecc.) E ci consente di scambiare più facilmente il flusso di controllo, la sequenza di pagine, le modifiche di convalida, le modifiche al modello, l'accesso di sicurezza ecc. Anche quando la logica è rimosso dalle visualizzazioni (soprattutto visualizzazioni web), rende le visualizzazioni molto più leggibili e quindi più manutenibili. Lo capisco e sono d'accordo con quello.
Tuttavia, l'attenzione principale dovrebbe essere sulla separazione delle preoccupazioni. Non visualizzazioni senza logica al 100%. La logica all'interno delle viste dovrebbe riguardare come rendere il "modello". Per quanto mi riguarda, la logica nelle viste va benissimo. È possibile avere una logica di visualizzazione che non sia logica di business.
Sì, ai tempi in cui scrivevamo pagine JSP, PHP o ASP con poca o nessuna separazione tra logica del codice e logica di visualizzazione, la manutenzione 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 mantenimento che ho veramente capito (visceralmente) l'errore dei modi miei e dei miei colleghi. :-) :-)
Quindi l'editto dall'alto (gli esperti del settore) è diventato, devi strutturare le tue app web usando qualcosa come un controller di vista frontale (che viene inviato ai gestori o alle azioni [scegli il tuo framework web]) e le tue opinioni non devono contenere codice . I punti di vista dovevano diventare modelli stupidi.
Quindi concordo in generale con il sentimento di cui sopra, non per le specificità degli articoli dell'editto, ma piuttosto per 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 di una visione senza logica fino all'estremo ridicolo. Avevamo un motore di modelli sviluppato internamente che ci avrebbe permesso di rendere gli oggetti del modello in html. Era un semplice sistema basato su token. È stato terribile per una ragione molto semplice. A volte in una vista dovevamo decidere, se visualizzare questo piccolo frammento di HTML .. o no .. La decisione è solitamente basata su un valore nel modello. Quando non hai assolutamente alcuna logica nella vista, come lo fai? Beh, non puoi. Ho avuto alcune discussioni importanti con il nostro architetto su questo. Le persone HTML front-end che scrivevano le nostre opinioni erano completamente ostacolate quando si trovavano di fronte a questo ed erano molto stressate perché non potevano raggiungere i loro obiettivi altrimenti semplici. Quindi ho introdotto il concetto di una semplice istruzione IF all'interno del nostro motore di modelli. Non posso descriverti il sollievo e la calma che ne seguirono. Il problema è stato risolto con un semplice concetto di istruzione IF nei nostri modelli! All'improvviso il nostro motore di creazione dei modelli è diventato buono.
Allora come siamo finiti in questa situazione stressante sciocca? Ci siamo concentrati sull'obiettivo sbagliato. Abbiamo seguito la regola, non devi avere alcuna logica nelle tue opinioni. Quello era sbagliato. Penso che la "regola pratica" dovrebbe essere, ridurre al minimo quella quantità di logica nelle tue opinioni. 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 logica nelle viste", diventa facile sapere quando sei un "buon" programmatore. (Se questa è la tua misura di bontà). Ora prova a implementare un'app Web di complessità anche media con la regola precedente. Non è così facile.
Per me, la regola della logica nelle visualizzazioni non è così chiara e francamente è lì che voglio che sia.
Quando vedo molta logica nelle viste, rilevo un odore di codice e cerco di eliminare la maggior parte della logica dalle viste - cerco di assicurarmi che la logica aziendale risieda altrove - cerco di separare le preoccupazioni. Ma quando comincio a chattare con persone che dicono che dobbiamo rimuovere ogni logica dalla vista, beh, per me, che sa solo di fanatismo, come so che puoi finire in situazioni come ho descritto sopra.
Ho finito con il mio sproloquio. :-)
Saluti,
David
Il miglior argomento che ho escogitato per i modelli senza logica è che puoi utilizzare gli stessi identici modelli sia sul client che sul server. Tuttavia non hai davvero bisogno di logica, solo una che ha il proprio "linguaggio". Sono d'accordo con le persone che si lamentano del fatto che i baffi limitano inutilmente. Grazie, ma sono un ragazzo grande e posso tenere puliti i miei modelli senza il tuo aiuto.
Un'altra opzione è trovare solo una sintassi di template che utilizzi un linguaggio supportato sia sul client che sul server, vale a dire javascript sul server utilizzando node.js oppure puoi utilizzare 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.
In una frase: Logic-less significa che il motore del modello stesso è meno complesso e quindi ha un footprint inferiore e ci sono meno modi per comportarsi in modo imprevisto.
Anche se la domanda è vecchia e ha una risposta, vorrei aggiungere il mio 2 ¢ (che può sembrare uno sproloquio, ma non lo è, si tratta di limitazioni e quando diventano inaccettabili).
L'obiettivo di un modello è eseguire il rendering di qualcosa, non eseguire la logica aziendale. Ora c'è una linea sottile tra non essere in grado di fare ciò che è necessario fare in un modello e avere "logica di business" in essi. Anche se ero molto positivo nei confronti di Moustache e ho provato a usarlo, alla fine non sono stato in grado di fare ciò di cui avevo bisogno in casi piuttosto semplici.
Il "massaggiare" dei dati (per usare le parole nella risposta accettata) può diventare un vero problema - non sono supportati nemmeno semplici percorsi (cosa a cui si rivolge Handlebars.js). Se ho i dati di visualizzazione e ho bisogno di modificarli ogni volta che voglio eseguire il rendering di qualcosa perché il mio motore di modelli è troppo limitante, questo non è utile alla fine. E sconfigge parte dell'indipendenza dalla piattaforma che i baffi rivendicano per sé; Devo duplicare ovunque la logica del massaggio.
Detto questo, dopo un po 'di frustrazione e dopo aver provato altri motori di modelli, abbiamo finito per creare il nostro (... ancora un altro ...), che utilizza una sintassi ispirata ai modelli .NET Razor. Viene analizzato e compilato sul server e genera una semplice funzione JS autonoma (in realtà come modulo RequireJS) che può essere invocata per "eseguire" il modello, restituendo una stringa come risultato. Il campione fornito da Brad sarebbe simile a questo quando si utilizza il nostro motore (che personalmente trovo di gran lunga superiore prontamente rispetto sia a Moustache che a Underscore):
@name:
<ul>
@for (items) {
<li>@.</li>
}
</ul>
Un'altra limitazione priva di logica ci ha colpito quando si chiamano parziali con Moustache. Sebbene i parziali siano supportati da Moustache, non è possibile 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 al loro interno.
Lo abbiamo risolto implementando un linguaggio di query ispirato a XPath, che abbiamo chiamato JPath. Fondamentalmente, invece di usare / per attraversare i bambini usiamo punti, e non solo stringhe, numeri e valori letterali booleani sono supportati ma anche oggetti e array (proprio come JSON). Il linguaggio è privo di effetti collaterali (che è un must per la creazione di modelli) ma consente di "massaggiare" i dati secondo necessità creando nuovi oggetti letterali.
Supponiamo di voler eseguire il rendering di una tabella "griglia di dati" con intestazioni personalizzabili e collegamenti ad azioni sulle righe, e successivamente aggiungere righe dinamicamente utilizzando jQuery. Le righe quindi devono essere in un parziale se non voglio duplicare il codice. Ed è qui che inizia il problema se alcune informazioni aggiuntive come quali colonne devono essere visualizzate fanno parte del viewmodel, e lo stesso per quelle azioni su ogni riga. Ecco un po 'di codice funzionante utilizzando il nostro modello e motore di query:
Modello di tabella:
<table>
<thead>
<tr>
@for (columns) {
<th>@title</th>
}
@if (actions) {
<th>Actions</th>
}
</tr>
</thead>
<tbody>
@for (rows) {
@partial Row({ row: ., actions: $.actions, columns: $.columns })
}
</tbody>
</table>
Modello riga:
<tr id="@(row.id)">
@for (var $col in columns) {
<td>@row.*[name()=$col.property]</td>
}
@if (actions) {
<td>
@for (actions) {
<button class="btn @(id)" value="@(id)">@(name)...</button>
}
</td>
}
</tr>
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 contiene alcuna logica di business, tuttavia è riutilizzabile e configurabile ed è anche privo di effetti collaterali.
row
dall'oggetto, invece di usare nomi statici. Ad esempio, se $col.property == 'Something'
questo restituisse il contenuto di row.Something
.
Ecco 3 modi per visualizzare un elenco, con il conteggio dei caratteri. Tutti tranne il primo e il più breve sono in linguaggi di template privi di logica.
CoffeeScript (con DSL Reactive Coffee builder) - 37 caratteri
"#{name}"
ul items.map (i) ->
li i
Knockout - 100 caratteri
<span data-bind="value: name"/>
<ul data-bind="foreach: items">
<li data-bind="value: i"/>
</ul>
Manubrio / Moustache - 66 caratteri
{{name}}:
<ul>
{{#items}}
<li>{{.}}</li>
{{/items}}
</ul>
Sottolineato: 87 caratteri
<%- name %>:
<ul>
<% _.each(items, function(i){ %>
<li><%- i %></li>
<% }); %>
</ul>
La promessa di modelli senza logica era, suppongo, che le persone con competenze più ampie sarebbero state in grado di gestire modelli senza logica senza spararsi sul piede. Tuttavia, quello che vedi negli esempi precedenti è che quando aggiungi un linguaggio a logica minimale al markup basato su stringhe, il risultato è più complesso, non meno. Inoltre, sembra che tu stia usando PHP della vecchia scuola.
Chiaramente non mi oppongo a mantenere la "logica di business" (calcoli estesi) fuori dai modelli. Ma penso che dando loro uno pseudo-linguaggio per la logica di visualizzazione invece di un linguaggio di prima classe, il prezzo venga pagato. Non solo più da scrivere, ma un atroce mix di cambio di contesto che qualcuno ha bisogno di leggerlo.
In conclusione, non riesco a vedere la logica dei modelli senza logica, quindi direi che il loro vantaggio è nullo per me, ma rispetto che molti nella comunità lo vedano in modo diverso :)
I principali vantaggi dell'utilizzo di modelli senza logica sono:
Sono d'accordo con Brad: lo underscore
stile è più facile da capire. Ma devo ammettere che lo zucchero sintattico potrebbe non piacere a tutti. Se _.each
è un po 'confuso, puoi usare un for
ciclo tradizionale .
<% for(var i = 0; i < items.length; i++) { %>
<%= items[i] %>
<% } %>
È sempre bello poter eseguire il fallback a costrutti standard come for
o if
. Usa <% if() %>
o <% for() %>
mentre Mustache
usi un po 'il neologismo per if-then-else
(e confuso se non hai letto la documentazione):
{{#x}}
foo
{{/x}}
{{^x}}
bar
{{/x}}
Il motore dei modelli è ottimo quando puoi ottenere facilmente modelli nidificati ( underscore
stile):
<script id="items-tmpl" type="text/template">
<ul>
<% for(var i = 0; i < obj.items.length; i++) { %>
<%= innerTmpl(obj.items[i]) %>
<% } %>
</ul>
</script>
<script id="item-tmpl" type="text/template">
<li>
<%= name %>
</li>
</script>
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 passi 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 del modello, usa l'implementazione del modello autonomo. Sono solo 900 caratteri se minimizzati (4 righe lunghe):