Niedawno natknąłem się na wąsy, które rzekomo są szablonem pozbawionym logiki .
Jednak nie ma żadnego wyjaśnienia, dlaczego jest zaprojektowany w sposób pozbawiony logiki. Innymi słowy, jaka jest zaleta szablonu bez logiki?
Niedawno natknąłem się na wąsy, które rzekomo są szablonem pozbawionym logiki .
Jednak nie ma żadnego wyjaśnienia, dlaczego jest zaprojektowany w sposób pozbawiony logiki. Innymi słowy, jaka jest zaleta szablonu bez logiki?
Odpowiedzi:
Innymi słowy, zapobiega to strzeleniu sobie w stopę. W dawnych czasach JSP bardzo często zdarzało się, że pliki JSP były posypane kodem Javy, co znacznie utrudniało refaktoryzację, ponieważ kod był rozproszony.
Jeśli zapobiegniesz logice w szablonach przez projekt (tak jak robią to wąsy), będziesz zobowiązany do umieszczenia logiki w innym miejscu, aby Twoje szablony były uporządkowane.
Kolejną zaletą jest to, że jesteś zmuszony myśleć w kategoriach oddzielenia obaw: twój kontroler lub kod logiczny będzie musiał wykonać masowanie danych przed wysłaniem danych do interfejsu użytkownika. Jeśli później zmienisz szablon na inny (powiedzmy, że zaczniesz używać innego silnika szablonów), przejście będzie łatwe, ponieważ musisz tylko zaimplementować szczegóły interfejsu użytkownika (ponieważ w szablonie nie ma logiki, pamiętaj).
Mam wrażenie, że moim zdaniem jestem prawie sam, ale stanowczo jestem w przeciwnym obozie. Nie wierzę, że możliwe mieszanie logiki biznesowej w twoich szablonach jest wystarczającym powodem, aby nie wykorzystywać pełnej mocy twojego języka programowania.
Zwykłym argumentem przemawiającym za szablonami bez logiki jest to, że jeśli masz pełny dostęp do swojego języka programowania, możesz mieszać logikę, która nie ma miejsca w szablonie. Uważam, że jest to podobne do rozumowania, że do krojenia mięsa należy używać łyżki, ponieważ można skaleczyć się nożem. To bardzo prawda, ale będziesz o wiele bardziej produktywny, jeśli użyjesz tego drugiego, choć ostrożnie.
Weźmy na przykład pod uwagę następujący fragment szablonu wykorzystujący wąsy :
{{name}}:
<ul>
{{#items}}
<li>{{.}}</li>
{{/items}}
</ul>
Rozumiem to, ale uważam, że następujące elementy ( podkreślenie ) są znacznie prostsze i bardziej bezpośrednie:
<%- name %>:
<ul>
<% _.each(items, function(i){ %>
<li><%- i %></li>
<% }); %>
</ul>
Biorąc to pod uwagę, rozumiem, że szablony bez logiki mają zalety (na przykład mogą być używane z wieloma językami programowania bez zmian). Myślę, że te inne zalety są bardzo ważne. Po prostu nie sądzę, że ich pozbawiona logiki natura jest jedną z nich.
name
i items
może zawierać JavaScript.
Wąsy są pozbawione logiki?
Czy to nie jest:
{{#x}}
foo
{{/x}}
{{^x}}
bar
{{/x}}
Całkiem podobny do tego?
if x
"foo"
else
"bar"
end
I czy nie jest to całkiem podobne do (czytaj: prawie definicji) logiki prezentacji?
if x > 0 && x < 10
) ... Tak więc, chociaż możliwe jest użycie Wąsów z logiką lub bez, to zależy od Ciebie. W końcu to tylko narzędzie.
Szablon pozbawiony logiki to szablon zawierający dziury do wypełnienia, a nie sposób ich wypełnienia. Logika jest umieszczana w innym miejscu i odwzorowywana bezpośrednio na szablon. To oddzielenie obaw jest idealne, ponieważ wtedy szablon można łatwo zbudować z inną logiką, a nawet z innym językiem programowania.
Nazywamy to „bez logiki”, ponieważ nie ma instrukcji if, klauzul else ani pętli for. Zamiast tego są tylko tagi. Niektóre tagi są zastępowane wartością, inne niczym, a inne serią wartości. W tym dokumencie wyjaśniono różne typy tagów Mustache.
Drugą stroną medalu jest to, że w desperackiej próbie utrzymania logiki biznesowej poza prezentacją, w końcu umieszczasz w modelu dużo logiki prezentacji. Typowym przykładem może być to, że chcesz umieścić „nieparzyste” i „parzyste” klasy w naprzemiennych wierszach tabeli, co można zrobić za pomocą prostego operatora modulo w szablonie widoku. Ale jeśli twój szablon widoku nie pozwala ci tego zrobić, to w danych modelu musisz nie tylko zapisać, który wiersz jest nieparzysty lub parzysty, ale w zależności od tego, jak ograniczony jest twój silnik szablonu, może być nawet konieczne zanieczyszczenie modelu z nazwami aktualnych klas CSS. Widoki powinny być oddzielone od modeli, kropka. Ale modele powinny być również niezależne od widoku i właśnie o tym zapomina wiele z tych silników szablonów „bez logiki”. Logika działa w obu miejscach,faktycznie robi, aby prawidłowo zdecydować, dokąd zmierza. Czy chodzi o prezentację, czy o biznes / dane? Chcąc mieć w 100% nieskazitelny widok, zanieczyszczenie ląduje w innym mniej widocznym, ale równie nieodpowiednim miejscu.
Istnieje rosnący ruch z powrotem w innym kierunku i miejmy nadzieję , że sprawy skupią się gdzieś na bardziej rozsądnym poziomie pośrednim.
Sprawia, że szablony są bardziej przejrzyste i zmusza do zachowania logiki w miejscu, w którym można ją odpowiednio przetestować jednostkowo.
Ta rozmowa sprawia wrażenie, jakby średniowieczni mnisi zastanawiali się, ile aniołów zmieści się na końcu szpilki. Innymi słowy, zaczyna wydawać się religijny, daremny i nieprawidłowo skoncentrowany.
Następuje mini-rant (nie krępuj się zignorować):
Jeśli nie chcesz kontynuować czytania… Moja krótka odpowiedź na powyższy temat brzmi: Nie zgadzam się z szablonami pozbawionymi logiki. Myślę o tym jako o programowej formie ekstremizmu. :-) :-)
Teraz mój rant trwa pełną parą: :-)
Myślę, że kiedy doprowadzasz wiele pomysłów do skrajności, wynik staje się absurdalny. Czasami (np. W tym temacie) problemem jest to, że doprowadzamy „zły” pomysł do skrajności.
Usunięcie całej logiki z tego widoku jest „niedorzeczne” i jest złym pomysłem.
Cofnij się na chwilę.
Pytanie, które musimy sobie zadać, brzmi: po co usuwać logikę? Koncepcja polega oczywiście na rozdzieleniu obaw . Zachowaj jak najbardziej oddzielne przetwarzanie widoku od logiki biznesowej. Czemu to robić? Pozwala nam na wymianę widoków (dla różnych platform: mobilna, przeglądarka, komputer stacjonarny itp.) I pozwala nam łatwiej zamieniać przepływ kontroli, kolejność stron, zmiany walidacji, zmiany modelu, dostęp bezpieczeństwa itp. Również wtedy, gdy logika jest usunięte z widoków (zwłaszcza widoków internetowych), sprawia, że widoki są znacznie bardziej czytelne, a zatem łatwiejsze w utrzymaniu. Rozumiem i zgadzam się z tym.
Jednak nadrzędny nacisk powinien być położony na oddzielenie obaw. Nie w 100% pozbawione logiki widoki. Logika w widokach powinna odnosić się do sposobu renderowania „modelu”. Jeśli o mnie chodzi, logika w widokach jest w porządku. Możesz mieć logikę widoku, która nie jest logiką biznesową.
Tak, w czasach, gdy pisaliśmy strony JSP, PHP lub ASP z niewielką lub żadną separacją logiki kodu i logiki widoku, utrzymanie tych aplikacji internetowych było absolutnym koszmarem. Uwierz mi, wiem, stworzyłem i utrzymywałem niektóre z tych potworności. To właśnie podczas tej fazy utrzymania naprawdę zrozumiałem (wewnętrznie) błąd mojego i moich kolegów. :-) :-)
Tak więc edykt z góry (eksperci z branży) stał się, musisz tworzyć strukturę swoich aplikacji internetowych za pomocą czegoś w rodzaju kontrolera widoku z przodu (który jest wysyłany do programów obsługi lub działań [wybierz strukturę sieciową]), a widoki nie mogą zawierać kodu . Widoki miały stać się głupimi szablonami.
Generalnie zgadzam się więc z powyższym sentymentem, nie ze względu na specyfikę treści edyktu, ale raczej z motywacji, która za nim stoi - jaką jest chęć rozdzielenia obaw na pogląd i logikę biznesową.
W jednym projekcie, w którym byłem zaangażowany, staraliśmy się podążać za koncepcją poglądów pozbawionych logiki do absurdalnej skrajności. Mieliśmy własny silnik szablonów, który pozwolił nam renderować obiekty modelu w html. Był to prosty system oparty na tokenach. To było straszne z jednego bardzo prostego powodu. Czasami musieliśmy zdecydować, czy powinienem wyświetlić ten mały fragment HTML… czy nie… Decyzja jest zwykle oparta na jakiejś wartości w modelu. Kiedy nie masz absolutnie żadnej logiki w widoku, jak to robisz? Nie możesz. Odbyłem w tej sprawie poważne spory z naszym architektem. Ludzie z front-endu HTML piszący nasze widoki byli kompletnie sparaliżowani, kiedy mieli do czynienia z tym i byli bardzo zestresowani, ponieważ nie mogli osiągnąć swoich skądinąd prostych celów. Dlatego wprowadziłem koncepcję prostej instrukcji IF w naszym silniku szablonów. Nie potrafię opisać ci ulgi i spokoju, które nastąpiły. Problem został rozwiązany za pomocą prostej koncepcji instrukcji IF w naszych szablonach! Nagle nasz silnik szablonów stał się dobry.
Jak więc znaleźliśmy się w tej głupiej, stresującej sytuacji? Skupiliśmy się na złym celu. Postępowaliśmy zgodnie z zasadą, że nie możesz mieć logiki w swoich poglądach. To było złe. Myślę, że „praktyczną zasadą” powinno być zminimalizowanie tej logiki w swoich poglądach. Bo jeśli tego nie zrobisz, możesz niechcący pozwolić logice biznesowej wkradać się do widoku - co narusza rozdzielenie obaw.
Rozumiem, że kiedy deklarujesz, że „nie możesz mieć logiki w widokach”, łatwo jest rozpoznać, kiedy jesteś „dobrym” programistą. (Jeśli to jest twoja miara dobroci). Teraz spróbuj zaimplementować aplikację internetową o nawet średniej złożoności, stosując powyższą regułę. Nie jest to takie łatwe.
Dla mnie reguła logiki w poglądach nie jest tak jednoznaczna i szczerze mówiąc, tak właśnie chcę.
Kiedy widzę dużo logiki w widokach, wykrywam zapach kodu i staram się wyeliminować większość logiki z widoków - staram się, aby logika biznesowa znajdowała się gdzie indziej - staram się oddzielić obawy. Ale kiedy zaczynam rozmawiać z ludźmi, którzy mówią, że musimy usunąć wszelką logikę z widoku, cóż, dla mnie, to po prostu trąci fanatyzmem, ponieważ wiem, że możesz skończyć w sytuacjach takich, jak opisałem powyżej.
Skończyłem z rantem. :-)
Twoje zdrowie,
David
Najlepszym argumentem, jaki wymyśliłem dla szablonów bez logicznych, jest to, że możesz używać dokładnie tych samych szablonów zarówno na kliencie, jak i na serwerze. Jednak tak naprawdę nie potrzebujesz bez logiki, wystarczy taki, który ma swój własny „język”. Zgadzam się z ludźmi, którzy narzekają, że wąsy bezcelowo ograniczają. Dzięki, ale jestem dużym chłopcem i mogę utrzymać moje szablony w czystości bez Twojej pomocy.
Inną opcją jest po prostu znalezienie składni szablonów, która używa języka, który jest obsługiwany zarówno na kliencie, jak i na serwerze, a mianowicie javascript na serwerze za pomocą node.js lub możesz użyć interpretera js i json przez coś takiego jak therubyracer.
Wtedy możesz użyć czegoś takiego jak haml.js, który jest znacznie czystszy niż którykolwiek z dotychczas dostarczonych przykładów i działa świetnie.
Jednym zdaniem: bez logiki oznacza, że sam silnik szablonów jest mniej złożony i dlatego zajmuje mniej miejsca i istnieje mniej sposobów, aby zachowywał się nieoczekiwanie.
Mimo że pytanie jest stare i na które udzielono odpowiedzi, chciałbym dodać moje 2 centy (co może brzmieć jak tyrada, ale tak nie jest, dotyczy ograniczeń i kiedy stają się nie do przyjęcia).
Celem szablonu jest renderowanie czegoś, a nie wykonywanie logiki biznesowej. Teraz jest cienka granica między niemożnością zrobienia tego, co trzeba zrobić w szablonie, a posiadaniem w nich „logiki biznesowej”. Mimo że byłem bardzo pozytywnie nastawiony do Mustache i próbowałem go używać, w dość prostych przypadkach nie byłem w stanie zrobić tego, czego potrzebowałem.
„Masowanie” danych (aby użyć słów w zaakceptowanej odpowiedzi) może stać się prawdziwym problemem - nie są obsługiwane nawet proste ścieżki (coś, co adresuje Handlebars.js). Jeśli mam widok danych i muszę to poprawić za każdym razem, gdy chcę coś renderować, ponieważ mój silnik szablonów jest zbyt ograniczony, ostatecznie nie jest to pomocne. I pokonuje część niezależności platformy, którą wąsy domagają się dla siebie; Muszę wszędzie powielać logikę masowania.
To powiedziawszy, po pewnej frustracji i po wypróbowaniu innych silników szablonów, w końcu stworzyliśmy własny (... jeszcze inny ...), który wykorzystuje składnię inspirowaną szablonami .NET Razor. Jest analizowany i kompilowany na serwerze i generuje prostą, niezależną funkcję JS (właściwie jako moduł RequireJS), którą można wywołać w celu „wykonania” szablonu, zwracając w rezultacie ciąg znaków. Próbka podana przez brada wyglądałaby tak podczas korzystania z naszego silnika (który osobiście uważam za znacznie lepszy w porównaniu z Mustache i Underscore):
@name:
<ul>
@for (items) {
<li>@.</li>
}
</ul>
Kolejne ograniczenie pozbawione logiki dotknęło nas, gdy wywołujemy podszewki z Mustache. Chociaż częściowe są obsługiwane przez Mustache, nie ma możliwości dostosowania danych, które mają być przekazane jako pierwsze. Więc zamiast być w stanie stworzyć modułowy szablon i ponownie wykorzystać małe bloki, skończę z tworzeniem szablonów z powtórzonym kodem.
Rozwiązaliśmy ten problem, wprowadzając język zapytań inspirowany XPath, który nazwaliśmy JPath. Zasadniczo zamiast używać / do przechodzenia do dzieci używamy kropek, a obsługiwane są nie tylko ciągi, liczby i literały boolowskie, ale także obiekty i tablice (tak jak JSON). Język jest wolny od efektów ubocznych (co jest konieczne przy tworzeniu szablonów), ale umożliwia „masowanie” danych w razie potrzeby poprzez tworzenie nowych obiektów literału.
Powiedzmy, że chcemy wyrenderować tabelę „siatki danych” z dostosowywanymi nagłówkami i linkami do działań w wierszach, a później dynamicznie dodawać wiersze za pomocą jQuery. Dlatego wiersze muszą być w części, jeśli nie chcę powielać kodu. I tutaj zaczyna się problem, jeśli dodatkowe informacje, takie jak kolumny, które mają być renderowane, są częścią modelu widoku i są takie same dla tych działań w każdym wierszu. Oto trochę działającego kodu używającego naszego szablonu i silnika zapytań:
Szablon tabeli:
<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>
Szablon wiersza:
<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>
Wywołanie z kodu JS:
var html = table({
columns: [
{ title: "Username", property: "username" },
{ title: "E-Mail", property: "email" }
],
actions: [
{ id: "delete", name: "Delete" }
],
rows: GetAjaxRows()
})
Nie ma w sobie żadnej logiki biznesowej, ale można go wielokrotnie używać i konfigurować, a także nie ma skutków ubocznych.
row
obiektu, zamiast używać nazw statycznych. Np. Jeśli $col.property == 'Something'
to dałoby zawartość row.Something
.
Oto 3 sposoby renderowania listy z liczbą znaków. Wszystkie, z wyjątkiem pierwszego i najkrótszego, są w językach pozbawionych logiki szablonów.
CoffeeScript (z konstruktorem Reactive Coffee DSL) - 37 znaków
"#{name}"
ul items.map (i) ->
li i
Knockout - 100 znaków
<span data-bind="value: name"/>
<ul data-bind="foreach: items">
<li data-bind="value: i"/>
</ul>
Kierownica / Wąsy - 66 znaków
{{name}}:
<ul>
{{#items}}
<li>{{.}}</li>
{{/items}}
</ul>
Podkreślenie - 87 znaków
<%- name %>:
<ul>
<% _.each(items, function(i){ %>
<li><%- i %></li>
<% }); %>
</ul>
Obietnica szablonów pozbawionych logiki była, jak przypuszczam, taka, że ludzie z szerszymi umiejętnościami byliby w stanie zarządzać szablonami pozbawionymi logiki bez strzelania sobie w stopę. Jednak w powyższych przykładach widać, że po dodaniu języka logiki minimalnej do znaczników opartych na ciągach wynik jest bardziej złożony, a nie mniej. Poza tym wyglądasz, jakbyś robił oldschoolowe PHP.
Oczywiście nie sprzeciwiam się utrzymywaniu „logiki biznesowej” (obszernych obliczeń) poza szablonami. Ale myślę, że dając im pseudo-język do logiki wyświetlania zamiast języka pierwszej klasy, cena jest płacona. Nie tylko więcej do pisania, ale ohydna mieszanka przełączania kontekstów, które ktoś musi przeczytać.
Podsumowując, nie widzę logiki szablonów pozbawionych logiki, więc powiedziałbym, że ich przewaga jest dla mnie zerowa, ale szanuję, że wielu członków społeczności widzi to inaczej :)
Główne zalety korzystania z szablonów bez logiki to:
Zgadzam się z Bradem: underscore
styl jest łatwiejszy do zrozumienia. Ale muszę przyznać, że cukier syntaktyczny może nie wszystkim zadowolić. Jeśli _.each
jest nieco mylące, można użyć tradycyjnej for
pętli.
<% for(var i = 0; i < items.length; i++) { %>
<%= items[i] %>
<% } %>
Zawsze dobrze jest, jeśli możesz wrócić do standardowych konstrukcji, takich jak for
lub if
. Po prostu użyj <% if() %>
lub <% for() %>
podczas Mustache
używania nieco neologizmu dla if-then-else
(i mylące, jeśli nie przeczytałeś dokumentacji):
{{#x}}
foo
{{/x}}
{{^x}}
bar
{{/x}}
Silnik szablonów jest świetny, gdy można łatwo uzyskać zagnieżdżone szablony ( underscore
styl):
<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);
Zasadniczo przekazujesz swoje wewnętrzne tmpl jako właściwość swojego kontekstu. I nazwij to odpowiednio. Słodkie :)
Nawiasem mówiąc, jeśli jedyne, co Cię interesuje, to silnik szablonów, użyj samodzielnej implementacji szablonu. Po zminimalizowaniu ma tylko 900 znaków (4 długie linie):