回答:
つまり、足で自分を撃つことを防ぎます。昔のJSPの時代には、JSPファイルにJavaコードをまき散らすことは非常に一般的でした。コードが分散していたため、リファクタリングがはるかに困難になりました。
テンプレートのロジックを(mustacheのように)設計で防止すると、ロジックを別の場所に配置する必要が生じるため、テンプレートが整理されます。
もう1つの利点は、懸念の分離という観点から考える必要があることです。コントローラーまたはロジックコードは、データをUIに送信する前にデータマッサージを実行する必要があります。後で別のテンプレートに切り替える場合(たとえば、別のテンプレートエンジンの使用を開始するとします)、UIの詳細を実装するだけでよいので、移行は簡単です(テンプレートにロジックがないため、覚えておいてください)。
私は自分はほぼ一人ぼっちだと感じていますが、反対の陣営にしっかりと入っています。テンプレートにビジネスロジックが混在する可能性があるため、プログラミング言語の能力を最大限に活用できないとは思えません。
ロジックなしのテンプレートに対する通常の議論は、プログラミング言語への完全なアクセス権がある場合、テンプレート内に配置されていないロジックが混在する可能性があることです。これは、ナイフを使うと自分で切ることができるので、スプーンを使って肉をスライスするべきだという推論に似ています。これは非常に真実ですが、慎重にではありますが、後者を使用した方がはるかに生産性が高くなります。
たとえば、mustacheを使用した次のテンプレートスニペットを考えてみます。
{{name}}:
<ul>
{{#items}}
<li>{{.}}</li>
{{/items}}
</ul>
私はこれを理解できますが、以下(アンダースコアを使用)の方がはるかに単純で直接的であることがわかります。
<%- name %>:
<ul>
<% _.each(items, function(i){ %>
<li><%- i %></li>
<% }); %>
</ul>
とはいえ、ロジックレステンプレートには利点があることは理解しています(たとえば、テンプレートを変更せずに複数のプログラミング言語で使用できます)。これらの他の利点は非常に重要だと思います。彼らの論理のない性質はそれらの1つだとは思いません。
name
とitems
JavaScriptを含めることができます。
口ひげはロジックレスですか?
これではない:
{{#x}}
foo
{{/x}}
{{^x}}
bar
{{/x}}
これにかなり似ていますか?
if x
"foo"
else
"bar"
end
そして、それはプレゼンテーションロジック(読み:ほとんどの定義)とかなり似ていませんか?
if x > 0 && x < 10
)...したがって、Mustacheをロジックの有無にかかわらず使用することは可能ですが、それはあなた次第です。結局のところ、それは単なるツールです。
ロジックレステンプレートは、埋める方法ではなく、埋めるための穴を含むテンプレートです。ロジックは別の場所に配置され、テンプレートに直接マップされます。テンプレートをさまざまなロジックで、またはさまざまなプログラミング言語で簡単に構築できるため、この懸念の分離は理想的です。
口ひげマニュアルから:
ifステートメント、else句、forループがないため、これを「ロジックレス」と呼びます。代わりに、タグのみがあります。一部のタグは、値で置き換えられるものもあれば、何もないものもあれば、一連の値で置き換えられるものもあります。このドキュメントでは、Mustacheタグのさまざまなタイプについて説明します。
コインの裏側は、ビジネスロジックをプレゼンテーションから遠ざける必死の試みで、モデルに多くのプレゼンテーションロジックを配置することになるということです。一般的な例としては、テーブルの交互の行に「奇数」クラスと「偶数」クラスを配置する場合があります。これは、ビューテンプレートで単純なモジュロ演算子を使用して実行できます。ただし、ビューテンプレートでそれができない場合は、モデルデータで、奇数行または偶数行を格納するだけでなく、テンプレートエンジンの制限に応じて、モデルを汚染する必要がある場合もあります。実際のCSSクラスの名前。ビューはモデルとは別のフルストップでなければなりません。しかし、モデルもビューにとらわれないものである必要があります。そのため、これらの「ロジックなし」のテンプレートエンジンの多くは忘れてしまいます。ロジックは両方の場所に行きます、実際にどこに行くかを正しく決定します。プレゼンテーションの問題ですか、それともビジネス/データの問題ですか?100%自然な見方をするために、汚染は目に見えないが同様に不適切な別の場所に着地するだけです。
他の方向に戻る動きが高まっています。うまくいけば、物事はより合理的な中立のどこかに集中するでしょう。
テンプレートをよりクリーンにし、適切な単体テストが可能な場所にロジックを保持することを強制します。
この会話は、中年の僧侶がピンの先に何人の天使がはまることができるかについて議論するときのように感じます。言い換えれば、それは宗教的で、無益で、誤って焦点を合わせていると感じ始めます。
ミニラントの結果(無視してもかまいません):
読み続けたくない場合..上記のトピックに対する私の短い返答は、次のとおりです。ロジックのないテンプレートには同意しません。私はそれを過激主義のプログラミング形式と考えています。:-) :-)
今私の怒りは本格的に続きます::-)
多くのアイデアを極端にすると、結果はばかげたものになると思います。そして、時々(つまりこのトピック)問題は、「間違った」アイデアを極端にとらえることです。
ビューからすべてのロジックを削除することは「滑稽」であり、間違った考えです。
少し後退してください。
私たちが自問する必要がある質問は、なぜロジックを削除するのですか?コンセプトは明らかに懸念の分離です。ビューの処理は、ビジネスロジックからできるだけ離してください。なぜこれを行うのですか?ビュー(異なるプラットフォーム:モバイル、ブラウザー、デスクトップなど)をスワップアウトすることができ、コントロールフロー、ページシーケンス、検証の変更、モデルの変更、セキュリティアクセスなどをより簡単にスワップアウトできます。ロジックがビュー(特にWebビュー)から削除されると、ビューがはるかに読みやすくなり、保守が容易になります。私はそれを理解し、それに同意します。
ただし、最優先事項は懸念事項の分離です。100%ロジックレスビューではありません。ビュー内のロジックは、「モデル」のレンダリング方法に関連している必要があります。私に関する限り、ビューのロジックは完全に問題ありません。ビジネスロジックではないビューロジックを持つことができます。
はい、コードロジックとビューロジックをほとんどまたはまったく分離せずにJSP、PHP、またはASPページを作成した当時、これらのWebアプリのメンテナンスは絶対的な悪夢でした。私が知っていると信じて、私はこれらの怪物をいくつか作成し、その後維持しました。そのメンテナンスフェーズ中に、私と同僚の方法の誤りを(直観的に)本当に理解しました。:-) :-)
したがって、高(業界専門家)からの命令は、フロントハンドラー(ハンドラーまたはアクションにディスパッチされる[Webフレームワークを選択])のようなものを使用してWebアプリを構築する必要があり、ビューにはコードを含めないでください。ビューは、おかしなテンプレートになるはずでした。
したがって、私は一般に上記の感情に同意します。勅令の項目の詳細ではなく、むしろ勅令の背後にある動機-見解とビジネスロジックの間の懸念の分離への欲求です。
私が関わった1つのプロジェクトで、私たちは論理のないビューのアイデアをとんでもない極端に追い込もうとしました。HTMLでモデルオブジェクトをレンダリングできる独自のテンプレートエンジンがありました。それは単純なトークンベースのシステムでした。非常に単純な理由でひどいものでした。HTMLのこの小さなスニペットを表示する必要があるかどうか、場合によってはビューで決定する必要があります。決定は通常、モデルの値に基づいて行われます。ビューにロジックがない場合、どうすればいいですか?まあ、できません。私はこれについて建築家といくつかの主要な議論をしました。私たちの意見を書いているフロントエンドのHTMLの人々は、これに直面すると完全に窮地に陥り、他の方法では単純な目的を達成できなかったために非常にストレスを受けました。そこで、テンプレートエンジン内に単純なIFステートメントの概念を導入しました。私はあなたに安堵とそれに続いた静けさを説明することはできません。テンプレートのシンプルなIFステートメントコンセプトで問題が解決しました!突然、テンプレートエンジンが正常になりました。
では、どうしてこのばかげたストレスの多い状況に入ったのでしょうか 私たちは間違った目的に焦点を合わせました。私たちはルールに従いました、あなたの見解にロジックがあってはいけません。それは間違っていました。「経験法則」は、ビュー内のロジックの量を最小限に抑える必要があると思います。そうしないと、不注意でビジネスロジックがビューに侵入してしまう可能性があるためです。これは、懸念の分離に違反します。
「ビューにロジックがあってはならない」と宣言すると、「良い」プログラマーであることが簡単にわかるようになります。(それがあなたの良さの尺度である場合)。上記のルールを使用して、中程度の複雑さのWebアプリを実装してみましょう。それほど簡単にはできません。
私にとって、ビューのロジックのルールはそれほど明確ではなく、率直に言って、それが私がなりたい場所です。
ビューに多くのロジックが見られる場合、コードのにおいを検出し、ほとんどのロジックをビューから排除しようとします。ビジネスロジックが他の場所に確実に存在するようにし、懸念事項を分離しようとします。しかし、私がビューからすべてのロジックを削除しなければならないと言う人々とチャットを始めるとき、まあ、私には、あなたが上記のような状況に終わる可能性があることを知っているので、狂信の小片です。
私は怒りで終わりました。:-)
乾杯、
デビッド
論理のないテンプレートについて私が思いついた最良の議論は、クライアントとサーバーの両方でまったく同じテンプレートを使用できることです。ただし、実際にロジックレスである必要はありません。独自の「言語」を持つものだけです。私は口ひげが無意味に制限していると不平を言う人々に同意します。おかげで、私は大きな男の子であり、私はあなたの助けなしで私のテンプレートをきれいに保つことができます。
別のオプションは、クライアントとサーバーの両方でサポートされている言語を使用するテンプレート構文、つまり、サーバー上のjavascriptを検索することです。
次に、これまでに提供されたどの例よりもはるかにクリーンで優れた動作をするhaml.jsのようなものを使用できます。
質問は古くて回答されていますが、2¢を追加したいと思います(これは暴言のように聞こえるかもしれませんが、そうではありません。制限と受け入れられなくなったときについてです)。
テンプレートの目的は、ビジネスロジックを実行することではなく、何かをレンダリングすることです。これで、テンプレートで実行する必要があることを実行できないことと、「ビジネスロジック」を使用することの間に細い線があります。口ひげにとても前向きでそれを使おうとしたが、結局、単純なケースでは必要なことができなくなった。
(受け入れられた回答で単語を使用するために)データの「メッセージング」が実際の問題になる可能性があります-単純なパス(Handlebars.jsがアドレスするもの)もサポートされていません。ビューデータがあり、テンプレートエンジンの制限が多すぎるために何かをレンダリングするたびに微調整する必要がある場合、これは結局役に立ちません。そして、それは口ひげがそれ自身のために主張するプラットフォーム非依存性の一部を打ち負かします。私はマッサージのロジックをどこにでも複製する必要があります。
とはいえ、一部のフラストレーションと他のテンプレートエンジンを試した後、.NET Razorテンプレートに触発された構文を使用する独自の(...もう1つ...)を作成することになりました。これは、サーバーで解析およびコンパイルされ、テンプレートを「実行」するために呼び出すことができる単純な自己完結型JS関数(実際にはRequireJSモジュールとして)を生成し、結果として文字列を返します。私たちのエンジンを使用している場合、ブラッドによって与えられたサンプルは次のようになります(私は、MustacheとUnderscoreの両方と比較して、私は個人的に非常に優れています):
@name:
<ul>
@for (items) {
<li>@.</li>
}
</ul>
Mustacheでパーシャルを呼び出すと、ロジックフリーの別の制限が発生しました。Mustacheはパーシャルをサポートしていますが、最初に渡されるデータをカスタマイズすることはできません。したがって、モジュラーテンプレートを作成して小さなブロックを再利用する代わりに、コードを繰り返してテンプレートを作成することになります。
JPathと呼ばれるXPathに触発されたクエリ言語を実装することで、この問題を解決しました。基本的に、子へのトラバースに/を使用する代わりに、ドットを使用します。文字列、数値、ブールリテラルだけでなく、オブジェクトと配列(JSONのように)もサポートされます。この言語は副作用がありません(テンプレート作成には必須です)が、新しいリテラルオブジェクトを作成することにより、必要に応じてデータを「マッサージ」することができます。
カスタマイズ可能なヘッダーと行のアクションへのリンクを含む「データグリッド」テーブルをレンダリングし、後でjQueryを使用して動的に行を追加するとします。したがって、コードを複製したくない場合は、行をパーシャルにする必要があります。そして、レンダリングされる列などの追加情報がビューモデルの一部であり、各行のそれらのアクションについてもまったく同じである場合に、問題が始まります。テンプレートとクエリエンジンを使用した実際の作業コードを次に示します。
テーブルテンプレート:
<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>
行テンプレート:
<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>
JSコードからの呼び出し:
var html = table({
columns: [
{ title: "Username", property: "username" },
{ title: "E-Mail", property: "email" }
],
actions: [
{ id: "delete", name: "Delete" }
],
rows: GetAjaxRows()
})
ビジネスロジックは含まれていませんが、再利用や構成が可能で、副作用もありません。
row
静的な名前を使用する代わりに、オブジェクトから取得するプロパティ名を動的に指定できます。たとえば$col.property == 'Something'
、これによりのコンテンツが生成されrow.Something
ます。
文字数を含むリストをレンダリングする3つの方法を次に示します。最初のものと最も短いものを除くすべてが、ロジックのないテンプレート言語です。
CoffeeScript(Reactive Coffee builder DSLを使用)-37文字
"#{name}"
ul items.map (i) ->
li i
ノックアウト-100文字
<span data-bind="value: name"/>
<ul data-bind="foreach: items">
<li data-bind="value: i"/>
</ul>
ハンドルバー/口ひげ-66文字
{{name}}:
<ul>
{{#items}}
<li>{{.}}</li>
{{/items}}
</ul>
アンダースコア-87文字
<%- name %>:
<ul>
<% _.each(items, function(i){ %>
<li><%- i %></li>
<% }); %>
</ul>
ロジックなしのテンプレートの約束は、私が思うに、より広いスキルセットを持つ人々は、足を踏み出すことなくロジックなしのテンプレートを管理できるだろうと思います。ただし、上記の例では、最小限の論理言語を文字列ベースのマークアップに追加すると、結果はより複雑ではなく、より複雑になります。また、昔ながらのPHPを実行しているように見えます。
明らかに、「ビジネスロジック」(大規模な計算)をテンプレートから除外することに反対していません。しかし、ファーストクラスの言語ではなく、表示ロジック用の疑似言語を提供することで、代償は払われると思います。タイプするだけでなく、誰かがコンテキストを切り替えるという恐ろしいミックスがそれを読む必要があります。
結論として、私はロジックなしのテンプレートのロジックを見ることができないので、それらの利点は私には無意味だと思いますが、コミュニティの多くがそれを異なって見ることを尊重します:)
私はブラッドに同意しunderscore
ます。スタイルは理解しやすいです。しかし、私は構文糖がみんなに喜ばれないかもしれないことを認めなければなりません。_.each
多少混乱する場合は、従来のfor
ループを使用できます。
<% for(var i = 0; i < items.length; i++) { %>
<%= items[i] %>
<% } %>
for
またはなどの標準的な構成にフォールバックできる場合は、常に便利ですif
。使用する<% if() %>
か<% for() %>
、または少しの間Mustache
、新奇主義を使用しますif-then-else
(ドキュメントを読んでいないと混乱します)。
{{#x}}
foo
{{/x}}
{{^x}}
bar
{{/x}}
テンプレートエンジンは、ネストされたテンプレートを簡単に実現できる場合に最適です(underscore
スタイル)。
<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);
基本的には、内部tmplをコンテキストのプロパティとして渡します。それに応じて呼び出します。甘い:)
ちなみに、テンプレートエンジンだけが必要な場合は、スタンドアロンテンプレートの実装を使用してください。それは唯一の900文字(4長い行)縮小さとき: