AngularJSの背景を調査してみた

きっかけは、AngularJSの存在を知り、そうすると芋づる式に知らない単語がたくさん出てきて
そもそもJSってなに?なにが目的で生まれて、他のフレームワークと何が違うの?JS使うには他に何が必要なの?
・・・整理したい!!!! ということから調査結果をoutputしようと思う。

JSの変遷

CommonJS、ES6、Node.js、Webpack、Browserify...etc JSの勉強してると、登場する単語が多すぎて、どうも全体像がつかめない。 そして勉強していくにつれて、「これ前提知らないと分からないっしょ...」みたいなことが多数出てきたので、その前提を色々とまとめてみることにした。

JavaScriptが辿った変遷

JavaScriptの歴史をざっくりまとめたよ!

Angularの変遷

AngularJS

  • 2012年6月にリリース
  • 周辺ツールが多い!(Gulp, Bower, Grunt)とか。でもここら辺の勢いは最近あまりないし、独特の書き方がほかに応用できない。

※ Gulp,Grunt・・・タスクランナー(実際にブラウザで使えるまでの諸々の作業を自動化してくれるツール)
 bower・・・パッケージのバージョン管理

Angular2

  • 2016年9月16日にリリース
  • 周辺ツールはAngularCLIが使えればOK。
  • 1→2で結構文法が変わって、互換性もない(重要)

AngularCLI・・・公式コマンドラインツール

Angular4

  • 2017年3月にリリース
  • 周辺ツールはAngularCLIを使えばOK、今後半年ごとにメジャーアップデートされるときにも一緒に進化してくれる予定。
  • 2→4で文法が少し変わった。でも互換性あり! 参考書にAnguar2のやつを使っていてもとりあえずは大丈夫

Angular5

  • 2017年11月にリリース
  • 次バージョンとなるAngular 5のテーマの1つはシンプリシティ。 その1つは、Angularアプリケーションのコンパイルをよりシンプルにする。JITコンパイラだけでなくAHTコンパイラ(A head of time:事前コンパイラ)を採用したが、この2つがあると混乱することもある。今後はAHTコンパイラをデフォルトにすることでビルドの手順を一本化し、余計な作業を減らしていくつもりだ。
  • もう1つはスピードとサイズへの注力。MaterialやIonicを利用したときなどでも最適に扱えるようにする。
  • 最後の1つは、スムーズなアップデートだ。バージョン4のときにもこれを約束したが、将来のバージョンに渡ってもすすめていく。

ところでAngularJSからAngular2になって何が変わったの?

AngularJSはいいjsフレームワークだったが、問題点整理をすると「重い」とか「記述ルールがややこしい」とかいろいろでてきたらしく、「それだったら、その問題点をがさっと整理し直して後継バージョンを出すぞ!」と気合の入った当プロジェクト。 気合が入りすぎて、互換性はほとんどない。 関連記事はこちら。

AngularJS と Angular2 の連携:シームレスなアップグレードの方法について

AngularJSで書いた資産をAngular2で使うのは無理だろうけど、Angular2は便利だから、混在させることができるよ!と書いている。

しかし、AngularJSと比べて「処理速度は3〜5倍」「inputとoutputに分かれて書きやすくなった」「TypeScriptを推奨しているので、コードの保守性が圧倒的に優れてる(どっちかというとTypeScriptの成果ですが)」などなどあるので、これからjsフレームワークの採用を決めるなら有力候補の一角になるだろう。

ところでAngular2からAngular4になって何が変わったの?

  • 色々なコンパイルをするタイミングを変えたので、アップロードされるファイルサイズが小さくなった(30%~50%減)
  • タグがタグに変更(互換性あり)
  • コンポーネントをもう少し細分化
  • @angular/animationってのが追加された、アニメーション使っていた人は注意。使い方は変わっていない
  • AngularCLIのインストールが変更(重要)

JSフレームワークの独自進化について考える

1. jsが有効化されているのが当たり前の時代になった
2. W3Cの拡張空間を仮想DOMによってjsフレームワークが作ろうとしている

の二点が結構はっきりしてきたように感じる。

「jsが無効化されてても操作できるようにしなさい」というのは一時代前のお作法だった。 しかし、ガラケーが減り、スマホが当たり前になって、IEのシェアが落ちていく中で、この作法は当たり前ではなくなり、「jsは有効化されてて当たり前」に入ったからこそ、jsフレームワークでviewを構築するような時代に入ったことを感じる。 今では、「jsが有効化されているのが当たり前の時代になった」ことを多くのエンジニアが実感しているであろう。

もうひとつの「W3Cの拡張空間を仮想DOMによってjsフレームワークが作ろうとしている」はかなり大切な局面だと思っていて、ブラウザ間差異はjsフレームワークで吸収する前提のもと、これからもどんどんとjsフレームワークが独自進化を遂げていくのではないか。 つまり、jsフレームワークが進化していくことにより、W3Cで勧告されるような機能を意識しなくても使用しなくてもよくなるとなるというのは、大きな時代の変化ではないか。 この変化を象徴しているのが、まさにAngular1からAngular2への変化かと思っている。

調査メモ

JSについて

JavaScript界隈の流行の変遷を調査する時は「npm trends」がオススメ ⇒トレンド系を調査するのは何が良いのか?

フロントエンド+JavaScriptの歴史(1) #JavaScript

Angularについて

AngularJSをこれからはじめてみようかな?という人のための記事まとめ

AngularJSとAngular2の比較から、jsフレームワークの独自進化を考える

下記についてまとめるのも楽しいかも。 (詳細や他との比較は次回記載)

Node.js Bower Typings Gulp

フレームワーク構築入門研修の参加報告

はじめに

研修に参加してきたので、忘れないように自分用にoutputしておく。

カリキュラム内容

コース概要

JavaによるWebアプリケーションアーキテクチャを設計する際によく利用されるデザインパターンについて学習し、その実装方法について学習していきます。 講義で採り上げるパターンはシステム開発でよく利用されるMV*やIoC、サービスクラス、DAOなどです。本コースで学んだアーキテクチャに関する知識は既存のフレームワークを理解するのにも役立つ知識ですので、アーキテクチャ設計を一から行わない方にもお勧めのコースになっています。

学習目標

  • レイヤ化されたWebアプリケーションの構成を理解する
  • 学習した各パターンの意義と使いどころを理解する
  • Webアプリケーションのアーキテクチャを構築する際の選択肢を持つ

学習内容

  1. フレームワークとは

    • Inversion of Control
  2. プレゼンテーションレイヤに関するパターン

    • MV*
  3. ドメインレイヤに関するパターン

    • サービスクラス
  4. データソースレイヤに関するパターン

    • DAOパターン
  5. Javaによるフレームワークの実装1

  6. Javaによるフレームワークの実装2

    • 依存性の解決(ファクトリー、DI、AOPの実装)
    • 汎用的なDAOの実装

1. 基本の考え方(デザインパターン

デザインパターンとは、オブジェクト思考に基づいて経験則から得られた、プログラミングにおける優良なパターンのこと。 GoF本では23個が提示されている。

参考:デザインパターン

その中で、代表的な4つについて学習した。

①Template Methodパターン

目的:具体的な処理をサブクラスに任せる

スーパークラスでは処理の順番だけが決められ、サブクラスでは具体的な処理が実装されている。
 ※スーパークラスにテンプレートを記載する、という意味合いからメソッド名が付けられた。

②Factory Methodパターン

目的:インスタンス作成をサブクラスに任せる

抽象度を高めることで、可用性を高めることができる。 しかし、ファクトリを指定する手段を別途考えなくてはならない。 →DIで解決する。

③Singletonパターン

目的:たった1つのインスタンス

<他の言語の例>
scalaだと、 「object ○○」でシングルトンとして使用可能。
⇨自分たちで作成しようとしないこと

④Strategyパターン

目的:アルゴリズムカプセル化と入れ替え

Strategyとは処理内容(=戦略)の意味。

2. プレゼンテーションレイヤに関するパターン

MVC(Model-View-Controller)

MVCとは、ユーザインターフェースの動作を3つの明確な役割へ分割するアーキテクチャパターン

  • View・・・プレゼンテーションレイヤ(変わりやすい)
  • Controller・・・プレゼンテーションレイヤ(変わりやすい)
  • Model・・・ドメインレイヤ、データソースレイヤ(変わりにくい)

その他、MVP、MVVM、MVWなど多数あるが、どの機能をどこに実装するかは設計者によって様々である。 ただ1つ言えるのは、変わりやすいものと変わりにくいもので分けている、ということだ。 例)Angularでは、MVW(W:Whatever)を使用している。

<参考>
参考ではあるが、インタラクティブさや使いやすさ向上などのために、JSが多様化されたものが増えてきた。その例がGoogleマップである。
DOM操作を使用し、ページ全体ではなくその一部分を細く書き換えるような動作を行うものだ。これらの構造を作成するためのフレームワークとしてBackbone.jsやAngular.jsが挙げられる。
これらはサーバ上の動作処理と同じかそれ以上をクライアント側でも複雑な処理を記述する必要がある。 そのため、サーバ側でもクライアント側でもMVCモデルを使用することで。複雑さへの対応を取ることが求められつつある。
しかしそれだとクライアントもサーバもModelが配置され、冗長的なので、サーバ側もJSで作成しようという動きが出てきた。その中で出てきたのがサーバサイドJSとしてのnode.jsである。

※これについては後日調べてoutput

Front Controller

Front Controllerとは、すべてのリクエストを受け付けるコントローラを1つだけ用意するアーキテクチャパターン

例えば、設計上の課題として共通の処理だけど本質的ではない部分(前処理や後処理)を各サーブレットに実装しなければならない場合に、これらの部分を個別にサーブレット内に実装するのは明らかに無駄が多い。このような共通処理を実装するにはどうすればよいかの解決策として、Front Controllerパターンがある。
その際、Front Controllerにはアクションクラスにリクエストを振り分ける何らかのルールを与える必要がある。その設定方法としては、設定ファイルを用意したり、ロジックとしてif-else文で作り込んだり、アノテーションによって記述したり、などの方法がある。
設定ファイルにリクエストとActionの関係が書かれていくとxmlが大きくなる「xml地獄」が起こる。そのため、xmlを小さくしようというのがトレンドである。

※設定ファイルのトレンドについては次の機会に調べてoutput

Template View

HTMLページに特殊なタグを埋め込むことで、動的な情報を表示するテンプレートとする。(要はJSPのこと)

問題点に対して純粋な(特殊なタグを全く入れない)HTMLをテンプレートとして使用するプロダクトも存在している。(例:Thymeleaf)

※これについては後日調べてoutput

3.ドメインレイヤに関するパターン

サービスレイヤ

プレゼンテーションレイヤとの境界に位置し、ドメインレイヤに対する処理を受け付ける役割。 導入を検討するのは、複数のDBテーブルを使ってのトランザクション処理が必要な場合など。

トランザクションスクリプト

実際にビジネスにおいて行われる手続きをそのままプログラムロジックとして記述するパターン

ドメインモデル

その業務(ドメイン)における処理内容と処理するデータを一体化させたモデル

トランザクションスクリプトドメインモデルのどちらを使用するかは、システムの難易度によって変わる。JavaによるWebアプリケーションはトランザクションスクリプトを使うことが多い。
なぜトランザクションスクリプトが多く使われるのかというと、トランザクションスクリプトは昔ながらの手続き指向に近いからだ。そのため、DB内のデータも素直に処理することができる。またドメインモデルだと、ドメインモデルとDBテーブル間で、モデルの表現の違いを変換する何らかの仕組み(※1)が必要だからだ。

※1 OR Mapper(Object RDB)

ドメインモデルによるシステム開発は、ドメイン駆動設計がある。 顧客と対話しながら、業務領域(ドメイン)を表すモデルを中心としてシステムを構築していく考え方のことだ。
 例)顧客が本当に欲しかったもの(風刺画)

DI(Dependency Injection)

オブジェクトの注入のこと。
近年多くの業務システムは多層的な構造になっており、コンポーネントが他のコンポーネントに数珠つなぎのように依存した構成になっている。 これではコンポーネント単独ではテストできないし、再利用性も低い。→品質向上と開発の効率化が行いにくい

もっと依存性を低くしようということより、生まれた。

AOP(Aspect Oriented Programming)

アスペクト指向プログラミング
重複・横断的な処理を画一的に外部から介入し処理を行う。(処理そのものを介入する。)

例)ログ出力、トランザクション制御、セキュリティ、例外ハンドリング

4. データソースレイヤに関するパターン

Data Access Object(DAO)

DBアクセスをビジネスロジックから切り離す

Data Transfer Objet(DTO)

データを保持し他レイヤに運搬することを目的とするオブジェクト

O/Rマッピング

メモリ内のオブジェクトとRDBテーブルを相互に変換する仕組み

例)OR Mapper(Object RDB)

  • Hibernate・・・難易度高め。独自のHQLを使用。
  • mybatis・・・簡易的。SQLを重視したい場合に人気。
  • JPAJava Persistence API)・・・背後にHibernateが実装してあり、使いやすくするためにIFを定めている
  • Doma・・・Hibernateやmybatisのいいとこどり。seasarのサポートは切れているが、依存していないので使用可能。おすすめ。

※ Domaについては今後調査する

5. フレームワーク構築時に使用するJavaテクニック

Javaリフレクション

アノテーション

SwiftのOptional型を勉強してみた

Optional型とは

  • Optional型 : nilが入るのを許す
  • 非Optional型 : nilが入るのを許さない

Optional型の宣言方法

var a: Int? // Optional型
var b: Int  // 非Optional型

var c: String! // Optional型
var d: String  // 非Optional型

Optional型とImplicitly Unwrapped Optional型

宣言方法 型の実体 アンラップ時の操作
Optional型 var a: T? Optional\ 明示的な操作が必要
Implicitly Unwrapped Optional型 var a: T! ImplicitlyUnwrappedOptional\ 不要(暗黙的にアンラップされる

ラップ(wrap)とアンラップ(unwrap)

Optional型(Optional\型)の変数のことを「ラップされている」と言う。
Optional型(Optional\型)からT型の変数を取り出すことを、「アンラップする」と言う。

Optional型の変数をアンラップする方法

1. Forced Unwrapping(!使用)

以下のように、!を使ってアンラップすることを「Forced Unwrapping」と言う。

class Dog {
    func bark() -> String {
        return "Wan!"
    }
}
var d: Dog? = Dog() // Optional型
print(d!.bark()) // -> Wan!

2. Optional Chaining(?使用)

以下のように、!ではなく?を使ってアンラップすることを「Optional Chaining」と言う。

class Dog {
    func bark() -> String {
        return "Wan!"
    }
}
var d: Dog? = Dog() // Optional型
print(d?.bark()) // -> Wan!

3. Optional Binding(if let, guard let使用)

if文やguard文の条件式で宣言され、Optional型の変数を代入された変数は、非Optional型になる。これを「Optional Binding」と言う。

class Dog {
    func bark() -> String {
        return "Wan!"
    }
}
var d: Dog? = Dog() // Optional型

// if letでアンラップ
if let unwrappedDog2 = wrappedDog {
    print(unwrappedDog2.bark()) // -> Wan!
}

// guard letでアンラップ
guard let unwrappedDog2 = wrappedDog else{
        return
    }
    print(unwrappedDog2.bark()) // -> Wan! 
}

<参考>guard文を使用する目的

  • 条件に合わない場合に処理を抜けるコードをシンプルに記述することができる。
  • guard文ではelseブロックを抜けたあとでも変数を利用できる。
    if文の場合は、if-elseブロックを抜けると条件式で代入した変数は使えなくなる。

guard文の使い方

4. Implicitly Unwrapped Optional型(暗黙的アンラップ)

Optional型ではなく、Implicitly Unwrapped Optional型を使うと、暗黙的にアンラップすることができる。変数をImplicitly Unwrapped Optional型で宣言する際には、?ではなく、!を使う。

class Dog {
    func bark() -> String {
        return "Wan!"
    }
}
// 「?」ではなく、「!」を使って宣言する
var d: Dog! = Dog() // Implicitly Unwrapped Optional型

// アンラップ操作は不要(暗黙的にアンラップされる)
print(d.bark()) // -> Wan!

nilに対して、アンラップをした場合の挙動

Optional型の場合

アンラップの方法 結果
Forced Unwrappingの場合(!を使う方法) ランタイムエラーが発生する
Optional Chainingの場合(?を使う方法) nilが返ってくる
class Dog {
    func bark() -> String {
        return "Wan!"
    }
}
var d: Dog? = nil // Optional型

// Forced Unwrappingの場合(!を使う場合)
print(d!.bark()) // ランタイムエラーが発生する: fatal error: Can't unwrap Optional.None

// Optional Chainingの場合(?を使う場合)
print(d?.bark()) // -> nil

Implicitly Unwrapped Optional型の場合

アンラップの方法 結果
暗黙的にアンラップされる ランタイムエラーが発生する
class Dog {
    func bark() -> String {
        return "Wan!"
    }
}
var d: Dog! = nil // Implicitly Unwrapped Optional型
print(d.bark()) // ランタイムエラーが発生する: fatal error: Can't unwrap Optional.None   

演算子を用いたアンラップ

nil結合演算子

??という演算子を使うと、オプショナル型がnilでなければその値を、nilの場合は指定した値を与えることができる。

var a: Int?
let b = a ?? 10 // aはnilなので、10が代入される

var s: String? = "Hello"
println(s ?? "Bye") //  sはnilでないので、その値(Hello)が出力される

nil合体演算子

以下のように、通常のif-let文や三項演算子より手軽に記述することができる。

通常のif-let文

var opv: String? = nil
let S = "なにか"
if let o = opv {
    print(o)
} else {
    print(S)
}

三項演算子

print((opv != nil) ? opv! : S)

nil合体演算子

print(opv ?? S)

nil合体演算子2つ以上に重ねることができる

let x: Int? = nil, y: Int? = nil, z: Int? = 3
let val = x ?? y ?? z ?? 0
print(val)

ハマったポイント

データクラス

//Infoクラス
class Info {
    var price:Int?
    var reqDnb:RegDnb?
}
//Infoに含まれる電文クラス
class RegDnb {
    var cardNum:Int?
}

失敗例
データのクラスにnilが入っていたら、データに値を入れてもnilとなってしまう。

let info = Info()
//info.reqDnb.cardNum = 12 // -> reqDnbをアンラップしろと怒られる
info.reqDnb?.cardNum = 12
print(info.reqDnb?.cardNum) // -> nil(理由:reqDnbがnilとなるから)

//アンラップ処理
if let unwrapCardNum = info.reqDnb?.cardNum {
    print(unwrapCardNum)
} else {
    print("nilです") // -> nilです
}

成功例
直属のデータクラスをインスタンス化し、値を挿入した。

let reqDnb = RegDnb() // -> ReqDnb

reqDnb.cardNum = 12
print(reqDnb.cardNum) // -> Optional(12)

//アンラップ処理
if let unwrapCardNum = reqDnb.cardNum {
    print(unwrapCardNum) // -> 12
} else {
    print("nilです")
}

応用編

SwiftのOptional型を極める