ガジェット通信

見たことのないものを見に行こう

AngularJSプロジェクトを保守しやすくするためにやっておくべき5つのこと

DATE:
  • ガジェット通信を≫

こんにちは、フロントエンドエンジニアのいなばです。
ここ最近案件でAngularJSに関わるエンジニアが若干名増えたので、社内共有も兼ねてAngularJSを保守しやすい状態に保つためにやっておくべきだと思うことを思いつく限りまとめておきたいと思います。

1. プロジェクトのファイル構成を決める

これは別にAngularJSに限った話ではないですが、まず一番最初に決めなくてはいけないことですね。
AngularJSに限らずある程度規模が大きくなる&運用をするのであれば、構成ははじめにきちんと考えて設計するべきだと思います。
ある程度規模が大きくなる場合、app.jsにすべてを記述したり、controller.jsみたいなファイルにcontrollerの処理をずらずらと記述したりしていくと、開発が進むにつれエディタをスクロールする量が増えていき、保守がとてもつらい感じになります。

例:controller.jsにずらずら書く
angular.module(‘controller’,[])
.controller(‘hogeCtrl’, [
function(){}
]).
.controller(‘fooCtrl’, [
function(){}
]).

// 省略

.controller(‘barCtrl’, [
function(){}
]);

ディレクトリ構成をどうするかはプロジェクトにもよると思いますが、ひな形の自動生成はYeomanで行えるようにして、1ファイルに1モジュールとするのが望ましいです。
Yeomanを使うことにより、ファイルの設置場所やファイル名のモジュール名といった表記揺れなどから守られやすくなります。

Yeoman
http://yeoman.io/

generator-angular
https://github.com/yeoman/generator-angular

AngularJSのディレクトリ構成に関しては、過去に弊社エンジニアのびすけくんが勉強会で登壇をしています。

参考:Angular.jsのディレクトリ構成のベストプラクティスを探る
http://qiita.com/n0bisuke/items/6a79d3ee63020f771260

ディレクトリ構成のパターンを紹介してくれているので参考になりますね。
悲惨なことになる前に、最初にきちんと構成を決めましょう。

ちなみに弊社のとある案件は現在このような構成になっています。
※ざっくりです

app/
├ app.js
├ common.js
├ components/
 │ └ hoge/
 │   └ hogeCtrl.js
 │   └ hoge.html
├ directives/
 │ └ hoge/
 │   └ hoge.js
 │   └ hoge.html
├ services/
 │ └ HogeService.js
 │ └ model/
 │   └ HogeModel.js
 └ test/
  └ components/
└ hoge/
└ hogeCtrlSpec.js
  └ directives/
└ hogeSpec.js
  └ services/
└ HogeServiceSpec.js
└model
└ HogeModelSpec.js

2. $rootScopeは極力使わない

グローバル変数は極力減らしたほうが良いのと同じ理屈です。
$rootScopeにプロパティは原則生やしません。
複数人で開発する場合、$rootScopeを多用してしまうとプロパティ名のバッティングなどで思わぬバグを出すリスクも高くなります。
また、$rootScopeは根幹にいて常にダーティチェックが走るので、パフォーマンスを下げる要因にもなります。

ただし、アプリケーション全体でイベントを監視したい場合には、$rootScopeにイベントを設定します。

例:$rootScopeに設定しているイベント

$rootScope.$on(‘$viewContentLoaded’, function () {});
$rootScope.$on(‘$stateChangeStart’, function() {});
$rootScope.$on(‘$stateChangeSuccess’, function() {});

3. $broadcastと $emitを使わない

現在自分が携わっている案件では、最初に$broadcastと$emitは使わないというルールを決められていました。$broadcastと$emitをあちこちで使ってイベントが飛び交っていくようになると、つながりも適用範囲もわかりづらくなり、処理を追えなくなって破綻してしまうからです。

実際半年ほど開発と運用をしていますが、$broadcast, $emitを禁止して困ったことはありません。代わりにController間で状態や値を共有したい場合は、Serviceで仲介するようにしています。

Angular JS で複数のコントローラ間でモデル(状態や値)を共有する方法 3 種類
http://qiita.com/sunny4381/items/aeae1e154346b5cf6009

4. Controller As記法を使う

Controller As記法を使うべき理由はこちらになります

参考:Digging into Angular’s “Controller as” syntax
http://toddmotto.com/digging-into-angulars-controller-as-syntax/

参考記事ではコントローラーを入れ子にして、それぞれのコントローラーで同じ名前のプロパティを参照した場合の例について解説がされています。

AngularJSではコントローラーを入れ子にした場合に、子コントローラーは親コントローラーのscopeを参照することができますが、階層が深くなると

データがどこから来たのかわかりずらくなる
スコープの値の変更が想定していないところに影響する

というデメリットがあります。

Controller As記法であれば、そのプロパティがどのコントローラーに属しているのかが一目でわかるようになり、意図しないバグを防ぎやすくなります。

日本語で書かれた記事もありますのでこちらもどうぞ。

参考:
AngularJSの$scopeをController As で置き換えるべき理由
http://qiita.com/Quramy/items/e55ba394031794236fc9

5. UIコンポーネントはディレクティブ化する

特にJSの処理がないUIコンポーネントでもどんどんディレクティブ化しています。
ディレクティブにするメリットには、

viewのHTMLが簡略化されてスッキリする
ディレクティブのHTMLテンプレート一箇所を直せばすべてに修正を反映できる

などがあります。

ディレクティブはOOCSS(オブジェクト指向CSS)な設計と相性がよいなと思っていて、ディレクティブ名とcssクラス名を同じ名前にしておくことで、CSSのクラス名のバッティングが回避しやすいです。
さらにこのパターンの利点としてHTMLの記述があちこちに散らないので、コンポーネントの設計が変わってもディレクティブのテンプレートのHTML一箇所だけを修正するだけで済むので改修に強くなります。

ただし、それぞれが好き勝手にオレオレ実装をしていってしまうとかえって破綻する危険性もあります。
事前にルールを決める&ドキュメントを用意するなどしましょう。

angular.module(‘directives’).directive(‘btn’, [
function(){
return {
template: function(element, attrs){
var type = attrs.type || ‘default';
return ‘<a href="{{::href}}" class="btn btn-{{::type}}" ng-transclude></a>';
},
restrict: ‘AE’,
transclude: true,
scope: {
type: ‘@’,
href: ‘@’
}
}
}
])

使用例
<btn href="#" type="default">default</btn>

 

展開後
<btn href="#" type="default" class="ng-isolate-scope">
<a href="#" class="btn btn-default" ng-transclude="">
<span class="ng-scope">default</span>
</a>
</btn>

まとめ

いかがでしたでしょうか?
AngularJSをプロジェクトに導入する際の参考になりましたら幸いです。

カテゴリー : 生活・趣味 タグ :
LIGの記事一覧をみる ▶
  • 誤字を発見した方はこちらからご連絡ください。
  • ガジェット通信編集部への情報提供はこちらから
  • 記事内の筆者見解は明示のない限りガジェット通信を代表するものではありません。