カテゴリー: programming

ES2015+Flowなlambda関数をApexで管理する

ES2015 + 型チェッカー flow で書かれた AWS Lambda 関数を Apex で管理する方法について、つらつらとメモ。この記事は @nagisio 先生のご指導のおかげで成立しています(謝辞)。

  • キーワード
    • AWS Lambda
    • yarn
    • ES2015
    • flow
    • Apex

記事読むの面倒くさいので、動くリポジトリよこせという方はここをcloneすべし(動かしてから理解する方が楽なのですよねー :wakaru:)

ES2015 + flow + Apex の環境構築

yarn の導入

導入はかんたん。

  1. npm initpackage.json を作る
  2. npm install yarn --dev で yarn を導入する
    • global に入れたい方はどうぞ

package.json はきっとこんな感じになっているのではなかろうか

ESS2015 + flow の環境構築

まずは必要なものを片っ端からいれていく

次に .babelrc を次のようにする

node_modules/flow-bin/cli.js init でflow の設定ファイル .flowconfig を作り、以下のような感じにする

もう多分この時点で ES2015 + flow のコードが書けるので適当に src/hello/index.js に適当なコードを書いてみよう

続いてトランスパイルして functions 下に成果物を出力してみよう

成果物は次のようになっているだろう

良い感じにハローワークに行きたいくなる良いラムダ関数ですね。さて、ここまできたらあとは Apex を導入して AWS にデプロイするだけです。

ちょっとその前に、トランスパイルするコマンドが長ったらしくてだるいのでエイリアスを張っておきましょう。package.json の script の部分をちょちょいといじるといい感じに npm run build で諸々実行できます。

Apex の導入

今回 AWS Lambda 関数の管理には Apex をつかいます。Apexの挙動は非常に単純で project.json に指定されたリソースやタイムアウト時間、IAMロールの設定で、functions直下にある各ディレクトリをそれぞれラムダ関数とみなし、デプロイしてくれます。

導入はかんたん

project.json をイカのよう設定すればよいでゲソ(各自IAMロールは適切なものを指定してください)

apex deploy でデプロイできます。apex invoke hello で実行できます。

良い

ESLint の導入(お好みで)

ESLintを入れたい方は適当に必要そうなやつをどうぞ(適当)

.eslint を適当に書く

deploy 前に uglify の処理を入れる

lambda の起動時間は多分デプロイされる成果物のサイズが小さい方がはやいので、uglifyをかけたほうがよさそう。packaage.jsonを書き換えればいい感じに実現可。

npm run build:prod で functions 下にできる成果物を確認してみるとちゃんとできてるか確認出来る。

ステージ管理

このあたりの対応が一番筋がよさそう👉 Lambda with Apex: 環境変数で環境別にLambda環境を整える

おわりに

ES2015 + flow + Apex で快適な AWS Lambda ライフを!

RxJava本がなかなかよさそうな内容だった件について

おととい発売された RxJava リアクティブプログラミング、 Amazon から背表紙が裂けた悲しい状態で到着し商品交換依頼を Amazon に出しつつ、本をナナメ読みしてたら休日が終わってしまった今日この頃、みなさまいかがお過ごしでしょうか。

 さて、本の内容がなかなか良い内容な雰囲気だったので軽く感想とともにアフィリエイトリンクを貼ってみんなにふんでもらって金儲けがしたいなぁとか思ったので、感想文を書きました。

 あ、あと私そんなに Rx サイコーみたいな人間ではないので… 念のため。(とはいえ iOS アプリ開発では RxSwift が一番よさそうっぽい気がする)

第1章の素晴らしいボリューム感

 Rx 系のライブラリというと、まずリアクティブプログラミングとは何かについて、オタクは嬉しそうに早口で語り始めます。だいたい領域外の人間の理解なんて御構い無しの言説を垂れ流してくる方が多いですよね。この本の第1章では、初見の方に必要のない部分についてはどんどん後回しにして、押さえるべきキーワードをピンポイントで押さえてあり、かつ実際に動くコードを提示した簡潔で適切な例示により基本的なライブラリのふるまいなどがわかりやすくまとまっています。RxJava 1系と2系の根本的な違いについては、普段 RxJava を使ってない(RxSwiftを使ってます)自分にはなるほどなぁと思わせてくれる内容でした。Reactive StreamsやRxJavaの基本的な仕組みについてもわかりやすいシーケンス図とコード、解説があってよかった。その後は実際に RxJava を使ったコードとそのふるまいの解説が載っていて、基本的にRx系ライブラリは「まず使ってみてふるまいを見てから理解したほうが学習しやすい」と思っている自分の考え方にマッチしていてよかった。1章読んで、写経すればだいたいみんなライブラリ使えるようになるのでは…?(ホントか?) Rx系の経験がないかたでも 3時間あれば読んでコード動かせるボリューム感だと思いますのでトライしてみてください。

Observable についてきちんと説明がある

Rx の柱の一つである Observable の背後に潜む、push 型 Observer パターンについてしっかりと解説されていて、とてもわかりやすい。私もむかしこのあたりのことについて記事にまとめたり、発表したりしました(唐突なリンク)。

また非同期処理の部分のスケジューラまわりについては Java でどうなっているのか気になっていたので、簡潔にまとまってて、とてもありがたかった。

第4章オペレーターまわりはだいたい知ってるのでまあ読まなくていっかみたいな雰囲気でいま5章を読んでる。Rx系のライブラリをこれから使おうという方は公式のチュートリアルとか見つつ、Qiitaの適当な記事みるくらいならこの本が良いのではとか思ってたりします。

現場からは以上です。


ちなみに自分は基本的に RxJava は触ったことありませんが、悲しいことに Swift という大変すぐれている言語を書いている今日この頃ですので RxSwift はそこそこ触っているほうだし、ソースコードも8割くらい読んだりしてます。なので、ライブラリ自体はほぼ触っていない RxJava 本とはいえ、スラスラ読めました(だいたい知ってる内容だった)。

serf を試す

  • serf で /etc/hosts とか config の更新とかをクラスタ全台にサクッと反映させたい
  • でも serf そのものがよくわからんのでまずは hello, world から
  • 資料は https://www.serf.io/intro/getting-started/install.html

  • ご覧のように、全台に簡単に通知を飛ばせる
  • この通知をフックして、更新をするシェルスクリプトを仕込めば /etc/hosts の更新や config の更新がお手軽にできる気がする

そこで以下のような簡単なスクリプトを用意(node01, node02に配置)

一旦各マシンで serf を落とし、イベントハンドラを指定して再起動

これは良さそうだ。実践編として /etc/hosts や config 系の反映についてどうすれば良いか気が向いたら書きます。

iOSアプリ開発基礎ハンズオン

この資料はラビットハウス社内で開催される、iOSアプリ開発未経験者向けのハンズオン会向けに作成されたものです。このハンズオンを一通り行うことにより、iOS開発において以下のことができるようになります。

  • 基本的なUIKitコンポーネントの利用
    • UILabel: テキストの表示
    • UIButton: ボタンの表示
    • UIBarButtonItem: バーボタンの表示
    • UITextField: テキストフィールドの表示
    • UITableView: テーブルの表示
    • UITableViewCell: テーブルセルのカスタマイズ
    • StoryboardとAuto Layoutの利用: UIをデザインベースで構成する仕組み
    • プッシュ遷移とモーダル遷移: iOSの大きな2つの画面遷移パターンへの理解

お品書き

0. はじめに

 iOSアプリ開発自体は技術的にはそれほど難しくないため、他の分野のエンジニアに開発に関わってもらえるようにハンズオン会を開催しました。また、場合によっては、簡単なプログラミングができるアプリディレクターやデザイナーにも理解出来るようになるべく平易な内容とするように心がけました。 if, else などのキーワードや変数、関数などについてざっくりと理解していて、簡単な関数を実装できれば、この資料を見ながらきっと誰でもアプリ開発ができると思います。

 2時間でTODOアプリを作るところをゴールとして進めていきますが、プログラミングに慣れている方であれば1時間で終わってしまう内容かもしれません。しかしながら、iOSアプリ開発のフローは一通り体験でき、Googleで検索をしながらアプリ開発を進めていけるレベルには達するのではないかと思います。また、このハンズオンで実装を進めていくアプリのソースコードは https://github.com/53ningen/iOSHandsOn に置いてありますので、困ったときは参照してみると良いかもしれません。

それでは、iOSアプリ開発の世界に飛び込んでいきましょう。

1. 環境構築

このハンズオンを進める上で必要な Xcode 8.2 の実行環境を構築します

1.1 Xcode 8.2 の導入

 Xcode 8.2 を含めた過去のバージョンの Xcode は以下の URL からダウンロードすることができます。ダウンロード、およびインストールにはかなりの時間がかかりますので、時間に余裕のあるときにやることを強くお勧めします。

https://developer.apple.com/download/more/

1.2 .gitignore

自分がよくつかってる .gitignore は以下のような感じです

2. プロジェクトの作成、 Hello, world とその周辺

 ここでは実際に開発を進めるためのプロジェクトを作成し、簡単な文字を表示させるところまでを行います。

2.1 プロジェクトの作成

Xcode を起動し、 Create a new Xcode project を選択してください。

xcode

続いて Single View Application を選択してください。

ChooseATemplateForYourNewProject

 ProductName として、とりあえず今回のハンズオンでは iOSHandsOn を指定しておきましょう。また、Organization Name は適当に、Organization Id についてはサービスのドメイン名や、github の id を指定することが多いかもしれません。

 このあたりの指定については実際にプロダクトを AppStore へリリースするなどの際に重要になってきますが、今回のハンズオンアプリではとりあえずの値を指定しておけば良いでしょう。また、後から変更することも可能ですので、必要であればそのときに直せば良いと思います。

ChooseOptionsForYourNewProject

 以上をすすめると最後にプロジェクトを保存するパスを指定するダイアログが出てきますので、お好きな場所に保存すると良いでしょう。これでひとまず iOS アプリ開発のためのひな形を作成することができました。この状態で Command + R (アプリ実行へのショートカットキー) を押すと、iOSシミュレーターが立ち上がり、真っ白な画面が表示されると思います。

2.2 Hello, world

続いて簡単なサンプルとして画面に文字を表示させてみましょう。目標とするイメージは下図のようなものです。

 早速 Main.storyboard を選択し、右下にあるパネルからラベル(UILabel)を選択して上図のような画面を作ってみてください。ラベルに表示される文字はラベルをダブルクリックすると編集できるようになります。作業が終わったら再びシミュレーターで実行してみてください。きっとストーリーボードに入力した文字どおりの表示が出ているかと思います。しかしながら、このままでは画面回転をするときっとレイアウトが崩れてしまうでしょう。試しに Command + → キーを押して画面を回転させてみてください。

 画面が回転した場合でも上下中央位置に表示させたい場合にはConstraints(制約)を指定してあげる必要があります。ラベルを選択したあと、ストーリーボード編集画面右下のボタンを押し、下図のような設定にチェックを入れ Add 2 Constraints ボタンを押してください。それぞれ Horizontally in Container は水平方向中央揃え、Vertically in Container は上下方向中央揃えの意味となります。最後に右下5つアイコンがならんでいる部分の一番左、更新マークのボタンを押すと、追加された制約がストーリーボードに反映されます。

 この状態で再びシミュレーターを立ち上げ画面を回転させてみてください。きっと画面がどのような方向を向いていてもラベルは画面上下中央位置に表示されたのではないでしょうか。もしストーリーボードを使わずコードでUIを構成する際も同じような形で Constrain を指示してあげないと、画面回転時や異なる縦横比のデバイスでの表示がおかしくなることがありますので、デバッグ時に画面を回転させながらデザインが崩れないかをチェックしてみてください。

まとめ
* 開発中はこまめに画面回転を試し、制約のつけ忘れなどミスがないかを確認しながらすすめる

2.3 ボタンを押したら文字がかわる機能をつける

 画面にただ単に Hello, world と表示されているだけではつまらないので、ボタンを設置して、押したときの時刻が表示される機能を搭載してみましょう。まずはストーリーボードに対して下図のようにボタンを追加してください。

 続いてXcodeの右上にある ボタン(真ん中)を押してみてください。ストーリーボードとソースコードの2画面表示になったかと思います。この状態でラベルを選択したのち control キーを押しながらソースコードの適当な位置にドラッグすると下図のようなダイアログが出てくるでしょう。

 Name に label と入力し Enter を押すと @IBOutlet weak var label: UILabel! というコードが追加されると思います。これはストーリーボード上にあるラベルをコードから操作できるようにリンクしてあげたと思っていただければ大体良いと思います。ボタンに関しても同様に操作を行うと @IBOutlet weak var button: UIButton! というコードが追加されるでしょう。

 続いて、ボタンを押したときのイベント処理を書いてみましょう。 ViewController.swift を開いて、次のようなメソッドを追加してください。

 最後にボタンのタップイベント発生時にこのメソッドを呼び出すように設定するコードを追加します。

 これでボタンが .touchUpInside、つまりタップして指を離した瞬間に、先ほど定義したメソッドを呼び出すという紐付けができました。早速シミュレーターで動かして試してみてください。おそらく、ボタンを押すと現在時刻が表示されるようになったのではないでしょうか?

 ついでに、同じ仕組みを異なる方法で実装しておきましょう。一旦ストーリーボードのボタンを control キーを押しながらクリックして、New Referencing Outlet に紐付いているものを削除し、もう一度 control キーを押しながらソースコードへドラッグします。その際に下記のように ConnectionAction に変更します。この場合 Name の欄にはボタンの名前ではなく action の名前を指定することになるので buttonOnTouchUpInside など適当な名前を指定してあげてください。すると今度はメソッド定義が生成されたのではないでしょうか。この手法ではこうして生成されたメソッド内に、ボタンが押されたときの挙動を定義していくことになります。

さきほどと同じ内容を実現しようとすると最終的にコードは次のようになるかと思います。

 実装が終わったらシミュレーターで実行してちゃんと動作するかを確認してください。これで iOS で UI を構成する最も基本的なUI部品である UILabelUIButton の使い方の雰囲気は理解できたのではないでしょうか。

まとめ
* ボタンのイベント処理には @IBOutlet を使う方法と UIButton.addTarget を使う方法がある

2.4 トラブルシューティング

 この先ますます複雑なことをやるとしばしば謎のエラーがでて、うまくシミュレーターで実行できない場合がでてくるかと思います。そんな際は command + shift + alt + K キーを押して、ビルドした成果物をディレクトリごと消すということを試してみてください(mvn clean的なものになります)。また Xcode がおかしな挙動を見せてくることがしばしばありますが、たいてい再起動すれば治るかと思います。

 何か問題が生じた場合は無理に頑張ろうとせず、まず上記の2点を試してみるということを忘れずに、寛容な心で開発を進める必要があります。

3. 2種類の画面遷移

 1画面だけで構成されるアプリはほとんどなく、プロダクトとして出すものは、ほとんどの場合画面遷移が発生します。iOSの画面遷移には主に次の2つのパターンが存在します。

  1. モーダル遷移(下からビューが飛び出してくる、閉じるボタンでビューを閉じる)
  2. プッシュ遷移(右方向にビューがスタックする、スワイプで戻れる)

 iOSヒューマンインターフェースガイドラインにこの2つの遷移の使い分けの思想について書かれているので、Apple 信者の方々は是非そちらをごらんください。そうでない場合には普段のiOSアプリの利用の仕方に照らし合わせて適切な方を選んでいくと良いでしょう。例えばコンテンツの構造として 「漫画アプリ」 ⊃ 「漫画作品」 ⊃ 「漫画エピソード」 という図式が成り立つのであれば、きっと漫画アプリトップから作品への遷移と作品からエピソードへの遷移はプッシュ遷移が適しているはずです。また、この間の任意の場所でログインさせるというアクションをユーザーにさせたい場合はモーダル遷移でログイン画面をユーザーに提示し、ログインが完了したらその画面を閉じてあげると良いでしょう。

 余談になりますが、近年はデバイス自体が大型化してきており、モーダル遷移時の「閉じる」ボタンの位置が左上にあると手の大きさ的に届きにくい位置になるため、モーダルで出すビューの画面デザインをする際にこのあたりのことを気をつけると良いと思います(※ 個人の感想です)。前話が長くなってきたのでこのあたりにして、早速それぞれの遷移を実装してみましょう。

3.1 プッシュ遷移の実装

 プッシュ遷移をするためには現在の ViewControllerUINavigationController に属している必要があります(正確にいうと UINavigationControllerchildViewControllers の要素である必要ということ)。こんなこと言葉で言われてもわからないと思うので、早速作業をしながら理解していきましょう。

 ここではボタンを押すとプッシュ遷移をする仕組みを実装していきたいので、その準備段階として Main.storyboard でいままで「時刻を表示」となっていた部分を「遷移する」というテキストに変えてみましょう。続いて、ViewControllerを選択し、右カラムのメニュー Identity -> Storyboard ID の部分に Main というテキストを入力しましょう。

 そして「上部メニュー:Editor」→「Embed in」→「Navigation Controller」を選択してください。すると Navigation Controller とかかれたよく分からない画面が出現したと思います。と、同時にさきほどまでのビューの上部にも謎の灰色のスペースが生じてしまいました。とりあえず起動して動作確認してみましょう。

 上図のような状態になっているのではないでしょうか。さて、ここからプッシュ遷移を実装をしていきます。新しい画面を作るのは一旦後回しにして、まずは同じ画面に遷移するコードを書き足してみましょう。そのためにボタンのタップイベント処理のメソッド内を次のように書き換えます。

 この状態でシミュレーターで実行すると、ボタンを押したときにきちんとプッシュ遷移できるようになっているのではないでしょうか? またスワイプや左上の < ボタンで前の画面に戻れるようになっていると思います。

まとめ
* プッシュ遷移には navigationController?.pushViewController を使う

3.1.1 (プログラマ向けトピック) UINavigationController のふるまい

 UINavigationController の振る舞いについてちょっとだけ見ておきましょう。冒頭で UINavigationController は UIViewController をスタックしていくことが役割だと言いました。その様子を実際に見るためにページ遷移が終わった瞬間(viewDidAppear)に navigationControllerchildViewControllers をログ出力するコードを ViewController に仕込みます。

この状態でシミュレーター実行をし、遷移をしたり戻りながら、ログ出力を観察してみましょう。

きちんとスタック構造になっていることがわかるかと思います。

3.1.2 (プログラマ向けトピック) Storyboard と 型

 静的型付け言語になれたプログラマであれば、ViewController を取得するときのコードについて文字列で指定しているあたりに恐怖心を覚える方もいるのではないでしょうか? 実際この部分の指定を間違えると、静的チェックが走らず実行時にアプリがクラッシュします。

 この部分に対する対応策は各自で取らざるを得ないのが現状で、例えば次のようなやり方をしている人が多いです。

  1. 動作確認を徹底することによる対応(筋肉系)
  2. ViewController を生成するファクトリを作り、そのファクトリのすべてのメソッドについてテストを書き、確実にインスタンスが得られることを保証する
  3. ViewControllerStoryboard ID(または Storyboard のファイル名) の命名規則を定める、ViewController の型を受け取り、そのインスタンスを生成するファクトリメソッドを用意し、アプリ内ではそれを通してインスタンスを得る

 3. については具体的には、MainViewController に対する Storyboard の名前は必ず MainViewController にするという規則を設け、次のように ViewController の型名を取得して上記のようなことを実現するという手法になります。命名をミスれば安全でもなんでもない手法ですが、StoryboardやViewControllerの名前を変更することはまれであるため、手軽な方法ではないかと考えています。

3.1.3 (プログラマ向けトピック) Storyboard ID を使わず Storyboard に紐づくViewController を取得する

以下のようなコードで可能です。口頭で説明いたします。

3.1.4 プッシュ遷移画面から戻るボタンの実装

 プッシュ遷移をしたあとにスワイプで前の画面に戻れますが、ある条件のときに強制的に前の画面に戻したいことがあるかと思います。ここでは、ボタンを押すと前の画面に戻る機能を実装してみましょう。まずはおなじみ Main.storyboard を次のような状態に改変しましょう。またトラブル防止のため、各UIButton を control + クリックし Outlet を一旦クリアにしましょう。

 続いて、ストーリーボード上のボタンとコードを結びつける作業をもう一度やりましょう。その作業が終わったら、まず「プッシュ遷移する」ボタンについて以前やったとおりに addTarget を利用してプッシュ遷移の実装を行ってください。これがおわるとコードは以下のような状態になっているかと思います。

 つづいてポップボタンについてですが、こちらについては最初の画面では戻り先が存在しないのでボタンを無効化しておくのが親切だと思います。そのためにビューが読み込みされた時点(viewDidLoad)で navigationController!.childViewControllers.count (スタックされているViewControllerの数) が 1 より大きかったら有効にしてあげる処理を記述します。

 また、プッシュ遷移から戻る処理は navigationController?.popViewController(animated: true) という命令を呼び出してあげれば実現できるため、この処理とボタンのタップイベントを addTarget で紐付けましょう。

 シミュレーターで実行すれば期待したとおりの動作になっているのではないでしょうか。

まとめ
* プッシュ遷移からもどるときには navigationController?.popViewController を使う

3.2 モーダル遷移

 同様のノリでモーダル遷移についても実装していきましょう。モーダル遷移については UINavigationController うんぬんは一切関係なく、どのビューからもこの遷移が使えます。いつもどおり Main.storyboard に「モーダル遷移する」ボタンを、これまでの流れと同じ手順で一つ増やし、右上にモーダル画面を閉じるボタンを設置しましょう。イメージは下図のとおりです。

 例によって最初の画面では戻り先の画面が存在しないので、右上の × ボタンを無効化したくなります。モーダル遷移からの戻り先があるかどうかの判定には presentingViewController が使えます。これの中身が空っぽだった場合、戻り先がないということになります。諸々の実装は以下の通りになります。

まとめ
* モーダル遷移には present を使う
* モーダル遷移後の画面から元の画面に戻るには dismiss を使う
* モーダル遷移の戻り先の VC は presentingViewController に格納されている

4 TODO管理アプリの作成

 UITableView(テーブルビュー)はiOSアプリでしばしば見かけるUIコンポーネントのひとつです。たとえば標準のメールアプリや設定画面などに使われています。さて、ここからは簡単なTODOリスト管理アプリを作っていきましょう。TODOリストの表示にはテーブルビューが適していると思いますので、さっそく実装方法を見ていきましょう。

4.1 新しい画面の作成

 Storyboard に新たな ViewController を追加するほうほうもありますが、ここでは新しいストーリーボードと新しいViewControllerファイルを追加しましょう。TODOMainViewController.storyboardTODOMainViewController.swift を作成して以下のように画面を構成して、遷移できる状態まで持って行ってください。

 TODOMainViewController.swift のソースコードは以下のような状態になっていると良いかと思います。

これでTODO機能を実装する下地が整いました。

4.2 テーブルビューを組み込んでみる

 テーブルビューを組み込んでみましょう。TODOMainViewController.storyboardTableViewを追加して適切な constrain を設定しましょう。左・右・下方向への制約は constrain to margins のチェックボックスを外す必要がある点に注意してください。またViewController自体について Under Top Bars のチェックボックスをオフにしてください。TableViewのStyleは Grouped を選択します。

 つづいて TableView をコードに紐付ける作業を行ったあと、以下のようにコードを記述してください。tableView.dataSource はテーブルのデータを供給するための設定でここには、UITableViewDataSource プロトコルを満たす全てのインスタンスを指定することができます。また、tableView.delegate はテーブルのふるまいを指定するための設定でここには UITableViewDelegate プロトコルを満たす全てのインスタンスを指定することができます。

 
 ここで罠になるのが tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) です。ここに 0 を指定するとなぜかテーブルビュー上部に大きな余白ができます。なので、雑に対応したければ、0.1などの小さな値を指定するとよいでしょう。厳密にやりたければここに任意の数字を指定して、tableView自体を上方向にその任意の数字分ずらしてあげれば良いと思います(ホントか)。

4.3 テーブルビューのセルをスワイプできるアレ

テーブルビューのセルをスワイプできるアレを実現したいときには以下のようなコードを extension TODOMainViewController: UITableViewDelegate に追加します。

4.4 テーブルビューセルの表示を作る

 画面を構成する部品を作るには Storyboard ではなく、 xib というファイルを作ったほうが良いことが多いです(※あまりこだわりはないし、宗教的な問題だと思うので思想の強い方はブコメとかで暴れていただければ)。さっそくタスク名を表示するだけのセルを作ってみましょう。iOSHandsOn 直下に TODOMainViewTableCell.xibTODOMainViewTableCell.swift というファイルを作り、xibにViewを紐付けてください。このあとの作業はストーリーボードでやったときと一緒なので、同じノリでやって下図のような状態にしてみてください(だんだん説明が雑になってきた)。

4.5 「タスクを追加するテキストフィールド」を上部に適当に作る

もうだいたい絵を見れば実装する方法わかってきましたよね? TODOMainViewController.storyboard を以下の状態に変更して、コードベースとの紐付けもよしなにやってください(雑)。

4.6 TODOデータの入力・保存・削除の仕組みをひと通り実装する

 TODOデータを保存する仕組みとしてとりあえず、文字列のリスト([String], Array<String>) を使いましょう。注意して欲しいのは、この実装ではTODO管理機能のモーダルを dismiss するとすべてのデータが水の泡になるという点です。ちゃんとデータを保持するためのほうほうは後ほどご紹介しますが、基本的にはここで完成させたものに少し手をいれて、iOSデバイス内のファイルに保存するという形になりますので大筋の流れは同じです。というわけで、まず TODOMainViewController に以下のコードを追加しましょう。

 また、表示させるセルの数はタスクの数と同じにしたいので tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) を変更する必要があります。セルにはタスク名を表示させたいので tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) にも手を入れます

4.6.1 タスクの削除

 削除については対象のセルのインデックスと変数 tasks のインデックスが一致しているので、変数からタスクを削除してテーブルの再描画命令を呼び出してあげればよいので簡単です。削除はセルをスワイプすると出てくるボタンで実現するので、tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) に手を入れます。

シミュレータで実行すると、もうタスク削除機能がうまく動作していることがわかるのではないでしょうか?

4.6.2 タスクの追加

 テキストフィールドに文字を入力して、エンターを押した瞬間にタスクが追加されるという仕様を実装に落とし込みましょう。テキストフィールドの振る舞いは UITextFieldDelegate プロトコルを実装したクラスのインスタンスを指定することができます。

また普通のアプリだとキーボードで文字入力中にテキストフィールド以外の適当な部分をタップすると、キーボードを閉じて入力を中断することができます。その振る舞いを実装するには次のようなコードを追記すればよいと思います。

 まあこのままじゃテーブルビュー領域をタップした時にキーボードを閉じないんですけどね…。

4.6.3 ローカルへのデータ保存

あとで書く

4.7 テーブルビューのよくある実装

 テーブルビューを実装するときによく使われるのが「引っ張って更新」と「セルの逐次読み込み」なので、それぞれどのように実装されているのかを軽くおさらいしておきます。

4.7.1 引っ張って更新の実装

説明あとで書く

さりげなく非同期処理の導入をしてしまった

4.7.2 ページネーションの実装

あとで書く

5. CocoaPods の導入

 iOS開発にはしばしば依存ライブラリ管理ツールとして CocoaPods が利用されています。これは node における npm や Java における maven などのようなものです。CocoaPods は Ruby で作られていて、Mac には標準で Ruby の実行環境が入っていますが CocoaPods の最新バージョンは古い Mac に標準で入っている Ruby では動作しない可能性があります。

 そこでまず Ruby のバージョン管理ツール rbenv を導入しましょう。続いて Ruby のライブラリ管理ツールである bundler を導入し、それを利用して CocoaPods を導入します。よく分からないと思った方は、とりあえずおまじないだと思って以下のコマンドを実行していってみてください。余談ですがチーム開発においては、手元の環境で CocoaPods が正常に動くとしても新しいメンバーが開発に加わりやすいように rbenv を導入しておくと何かとスムーズで良いと思います。1

5.1 rbenv を使った Ruby 2.3.3 の導入

 rbenv とは、複数のRubyバージョンを切り替えることができるツールになります。マシンによっては OS X 標準で入っている Ruby のバージョンが古く、iOSアプリ開発によく使われる Ruby のライブラリ(gem)がうまく利用できない場合があるため、rbenv を利用して特定環境かにおけるつまづきどころをなくす意図があります。

5.2 bundler と CocoaPods の導入

プロジェクトルートに Gemfile を以下のように追加して rbenv exec bundle install を実行してください

続いて rbenv exec bundle exec pod initPodfile が生成されるので、いい感じに依存を指定して、 rbenv exec bundle exec pod install すれば良いと思います。

6. 追加課題

  • データ構造の定義(リスト/遅延リスト/スタック/キュー)
    • ユニットテストを書く
  • 電卓アプリの作成
    • その1: ボタンベースのiOS標準の電卓を目標に進める
    • その2: テキストフィールドベースでユーザーに数式を入力させ、計算結果を表示するアプリ
  • 本格的な TODO アプリを作成してください
    • タスクをどういった形で持てば拡張性を維持できる?
    • タスクがマイルストンやタグといったものに紐づくときにはどうすればよい?
    • データやロジックと UI がなるべくひっつかないようにするためにはどうしたらよい?
  • 株価/天気アプリの作成

時間が余ったら

  • URLSession を使った HTTP 通信
  • DispatchQueue を使った非同期処理
  • RxSwift を用いた非同期処理

などを試してみてください。


  1. rbenv を利用した開発フローに載せてくださった @koki_cheese さん、ありがとうございます 

UnicodeScalar とは?

docs: https://developer.apple.com/reference/swift/unicodescalar

The UnicodeScalar type, representing a single Unicode scalar value, is the element type of a string’s unicodeScalars collection.

UnicodeScalar は Unicodeスカラ値を表す値

UnicodeScalar から String への変換

ansible のソースコードを実行する

ansible のソースコードを直接実行したい

  • 頻繁にバージョンを切り替えたり、なんなり色々したい

誤り検出についての整理

誤り制御について頭の中を整理〜。誤り制御の方法は以下の二つ。

  1. 誤り検出 により再送
  2. 誤り訂正 により自己修復

参考資料

誤り検出: パリティチェック

  • 誤り検出用のパリティビットを付加してデータの整合性を検査する方法
    • 偶数パリティ: データの和が偶数になるようにパリティビットを付加する
    • 奇数パリティ: データの和が奇数になるようにパリティビットを付加する

例えば、7bitデータを送出する場合に偶数パリティを採用するとすれば以下のように、パリティビットを付加すればよい

[0,0,0,0,0,0,0] [0] ← パリティビット
[0,1,0,0,0,0,0] [1]
[0,1,1,0,1,0,0] [1]

VRC(Vertical Redundancy Check) – 垂直パリティ

  • キャラクタ単位でパリティチェックを行う

偶数パリティの場合8bit目をパリティビットとすれば次のような感じ

LRC(Longitudinal Redundancy Check) -水平パリティ

  • 伝送した文字列の終端に Block Check Character(BCC) と呼ばれる誤り検出のためのキャラクタを付加する
  • 伝送した各ビットの正当性を確認することによりキャラクタ単位ではなく文字列全体のなかに誤りがあることを検査することができる

偶数パリティの場合以下のような具合で

群係数チェック

  • 水平方向の和の下2桁を取り、下位ビットのチェックビットとする

偶数パリティであれば以下のような具合

CRC(Cyclic Redundancy Check) – 巡回冗長検査

  • バースト誤りを検出できるのが特長的
  • 書いてる途中で飽きた(続き暇なときにまとめる)

play 2.5 のアレコレ

playがいろいろと変わっているので、いろいろと走り書き

logback.xml を使え

  • WARN がうるさい
  • logback.xml という名前でとりあえず次のようなファイルを作っとけばOK
  • https://www.playframework.com/documentation/2.5.x/SettingsLogger

GlobalSettings それ死んだよ

  • ドキュメント曰く、ライフサイクル系は Guice の eagerSingleton に便乗して実現するっぽい
  • JDBCConnectionPoolまわりなんかもここで Application が Inject されることを期待して、記述すればよいっぽさ
  • https://www.playframework.com/documentation/2.5.x/ScalaDependencyInjection#Stopping/cleaning-up

sbt 0.13.12 から build.sbt 使え

  • https://github.com/sbt/sbt/pull/2530
  • nrhd…

Apache Bench

使う機会があったのでサクッとメモ

導入

使い方

terraform を使ったAWS構成管理 ハンズオン

terrafrom は、インフラの構築や設定などをコードで表現して管理できるようにするツールです。AWS や Azure、 Heroku など様々な環境に対応しています。

この資料はラビットハウス社内で開催される、 AWS リソースを terrform で管理するためのハンズオン向けに作成した資料になります。AWS 構成管理をコードで管理したいなどと思っている方のなかにも、こういったツールが面倒臭そうだとか、すぐ使えなくなってしまいそうだとお思いの方が多いかと思いますが、 terraform の挙動はとてもシンプルで学習コストはものすごい低いツールです。また AWS 構成をコード化することでより深く AWS について理解することできる側面もあると考えています。

是非この機会に terraform に入門してみませんか…? この記事の通りにコマンドを入力していけば、きっとあなたも1時間もしないうちに terraform を使いこなせるようになっているでしょう。

1. 環境構築

このハンズオンでは terraform v0.7.4 を前提として話を進めます

Mac の場合

Windows の場合

https://www.terraform.io/downloads.html

AWS 側の準備

あらかじめterraformで用いるIAMユーザーを作成しておきましょう

  1. IAM ユーザー管理ページにアクセス
  2. 新規ユーザーの作成
  3. 必要なポリシーのアタッチ
  4. access_key, secret_key の作成

2. S3 bucket を管理する

まずは S3 bucket を作ったり変更したり壊したりして遊んでみましょう。下準備として、適当な作業用ディレクトリを作成してください。次に AWS リソースにアクセスするための設定を書きます。

2-1. S3 bucket を作る

早速 S3 bucket を作ってみましょう。次のようなファイルを作成してください。ただし bucket の名称はグローバルで一意になるように定めてください。

以上のようなファイルを作ったら、terraform validate で正しい .tf ファイルを記述できているかを確認してみましょう。きっと上記の通りに書けば問題なくコマンドが通ると思います。

つづいて terraform plan コマンドで、これからどのようなことが実行されるのかを確認します。この操作は常に安全で、AWSに対して情報の読みとり操作しか行われません。

+ aws_s3_bucket.terraform_tutorial とあるように S3 の bucket が作成されることが確認出来たので terraform apply コマンドで実際に実行してみましょう。

無事、成功したようですので、とりあえず aws cli から s3 bucket が本当に存在するのか確認してみましょう。

ちゃんと s3.tf ファイルで指定した com.github.53ningen.terraform.tutorial という名前の bucket ができていることがわかります。さて、terraform apply が無事に成功したあとには terraform.tfstate というファイルができていると思います。

このファイルの中身はリモート(今の場合AWS)の状態を保存するファイルになります。この中にはアクセスキーやシークレットキーがふくまれているため、git 管理対象外にしておきましょう。このファイルの管理についてはのちほど 「remote state の管理」の節でご説明します。とりあえず以下のような .gitignore ファイルを追加しておきましょう。

2-2. S3 bucket の状態を変更する

さきほど作った S3 bucket はバージョニングが有効になっていますが、これを無効にしてみましょう。s3.tf を次のように修正します。

続いて terraform validate コマンドで tf ファイルのシンタックスを検証し、 terraform plan で AWS リソースに対してどうのような変更が行われるか確認しましょう。

Plan: 0 to add, 1 to change, 0 to destroy. とあるので、既存の S3 は削除されず、表示されたパラメータのみが変更されることがわかります。確認をしたら apply をすれば S3 の状態の変更は完了です。

2-3. S3 bucket を破棄する

さて、いままでチュートリアルとして S3 bucket を作成してきましたが、不要なので削除しておきましょう。terraform destroy コマンドを使えば OK ですが、この操作もやはり実行する前に確認しておきたいものです。そんな場合はまず terraform plan --destroy を実行してみましょう。これで terraform destroy 時の実行計画を見ることができます。

実行計画に問題がなさそうであれば、terraform destroy を実行してみましょう。

terraform destroy を実行すると本当にリソースを削除して良いのか聞かれます。yes と入力すると、ここまでに作った S3 bucket は削除されます。

2-4. tf ファイルをフォーマットする

terrform fmt でファイルをフォーマットできます

2-5. terraform 基本コマンドのまとめ

以上で terraform の基本的な 5 コマンドは理解できたかと思います。まとめると以下のようになります。

  • terraform validate: .tf ファイルのシンタックスを検証する
  • terraform plan: terraform がこれから行う実行計画を表示する。--destroy オプションで destroy 時の実行計画を表示できる。
  • terraform apply: plan を実行する。
  • terraform destroy: terraform で作ったリソースを破棄する
  • terraform fmt: tfファイルをフォーマットする

基本的には apply の前にかならず plan で実行計画を確認することを徹底してください。 destroy は実際にはほとんど使うことはないと思います。また、terraform.tfstate を git で管理したり、他人の目に触れるような状態にすることをお忘れなく。

3. remote state を管理する

terraform.tfstate ファイルはリモートの状態を管理するファイルです。apply が成功すると、どのようなリソースがどのようなパラメータで作成されたのかを細かく記録しています。

tfstate ファイルを誤って削除すると terraform はリモートにリソースが存在しないと認識して、tf ファイルに定義された構成を新規作成しようとしてしまいます。しがって何らかの形で、このファイルを管理する必要があるのですが、秘匿情報が多分に含まれているため単純に git で管理するわけにはいきません。

管理する方法は何通りかあるのですが、ここでは private な S3 bucket を使ってこのファイルを管理する方法をご紹介します。

3-1. tfsate管理用 S3 bucket の作成

S3 bucket の作成は前節でやったのでもうきっと理解できていると思います。復習がてらやってみましょう。remote_state.tf という名前で次のようなファイルを作ってみましょう。

terraform plan で実行計画を確認したのち、terraform apply で bucket を作成します。terraform 公式ドキュメントによると versioning を有効にすることが推奨されています。

3-2. tfstate管理設定を行う

無事 S3 bucket が作成されたら terraform remote config コマンドを使って tfstate ファイルの管理設定を行います。次のコマンドの bucketaccess_key などは自分のものに適宜変更してください。

ここで key というのは S3 上でどのような名前で tfstate ファイルを管理するかという指定になります。今コマンドが無事通るとカレントディレクトリにあった terraform.tfstate はきっと .terraform 下に移動するかと思います。

3-3. remote に tfstate を push する

さて、管理設定が無事おわったら S3 に tfstate ファイルを転送しておきましょう。

リモートへの terraform apply を行った場合は必ず terraform remote push を行いましょう。

3-4. remote から tfstate を pull する

普通にいかのような感じになります。複数人での開発で、他人が apply したあとの remote state を反映させたい場合などに使います。

4. より高度なリソース定義を行う

4-1. 変数を用いる

aws の access_keysecret_keyvariable.tf に直接書き込んでいますが、変数という機能を使えば、実行時に指定することができます。

このようにした上で、terraform plan を実行すると各パラメータとしてどの値をとるかを対話式に尋ねられます。

また、次のように変数のデフォルト値を指定しておくこともできます。

4-2. 環境変数を用いる

CLIから access_keysecret_key を毎回指定するのも面倒なので、環境変数を用いると楽そうです。terraform では TF_VAR_ というプレフィックスがついた環境変数を .tf ファイルの中で用いることができます。さっそく、これを用いて access_key, secret_key を環境変数から取ってくるように変更しましょう。

続いて variable.tf を以下のように変更しましょう

terraform plan を変数指定なしで利用できるようになっていれば、無事環境変数の利用ができているということになります。

4-3. 依存管理のあるリソース定義を行う

より複雑なリソースを構成するときには、リソース同士に依存関係が生じます。たとえば terraform で作成した IAM ユーザーにポリシーをアタッチしたいときに、リソース間に依存が生じていると思います。

いま、 IAM ユーザー cocoa さんを作成し IAMReadOnlyAccess ポリシーをアタッチしたいとします。その場合の .tf ファイルは以下のように記述すればOKです。

terraform plan を実行すると依存関係が解決されていることがわかるでしょう。

4-4. 設定ファイルを使う

複雑なリソースを管理するときには設定だけをまとめた設定ファイルが使えると便利そうです。 terraform には設定ファイルを使う仕組みも備わっています。今回は AWS のリージョン指定を設定ファイルに切り出しましょう。variable.tfregion 変数から default 値を削除してください。

そして config.tfvars という名前で次のように設定を記述しましょう。

あとは terraform planterraform apply 時に設定ファイルを指定してあげればOKです。設定ファイルの指定は -var-file= オプションを使います。

4-5. 出力を行う

terrform apply 後に作成されたリソースのARNが知りたい場合などは output という機能を使うとよいでしょう。たとえば先ほど作成した cocoa ユーザーのARNを出力させるには次のようにすれば OK です。

terraform plan, terraform apply を実行してみましょう

しっかりと ARN が出力されていることが確認できます。

5. モジュールと複数のステージへの対応

terraform はカレントディレクトリに置かれている .tf ファイルを実行するというとても単純なふるまいを持っています。しかし複数ディレクトリに構造化してファイルを保存したい場合や、複数のステージを作るためにパラメータだけ変えて呼び出したいなどさまざまに理由により、異なるディレクトリ下にあるものを呼び出したいことがあるでしょう。そのときに使えるのが、モジュールという機能です。

5-1. モジュールの利用の基礎

モジュールを試すためにまずは以下のようなディレクトリ構造を作りましょう。

modules に それぞれのリソースを定義していくことになります。今回はサンプルとして dev/prod 向きそれぞれの S3 bucket を作ってみましょう。まずは modules/s3/s3.tf の中身から。

続いて dev/modules.tf, prod/modules.tf というファイルにそれぞれ、modules/s3 以下のファイルを取り込んで実行するコードを書いてみましょう。modules という新たな構文を利用します。

最後に、dev/variable.tf, prod/variable.tf に対して、AWS を操作する設定値などを記述します。

これで準備が整いました。dev ディレクトリ下から実行すると dev 環境向けの構成、prod ディレクトリ下から実行すると prod 環境向けの構成を管理することができます。 dev 環境向けのリソースを実際に作ってみましょう。 dev ディレクトリに移動して、terraform get を実行して依存モジュールのコードを取り込みを前もってやっておく以外は、いままでと基本的には同じ操作で OK です。

5-2. 複数ステージへモジュールを用いたの対応例

このようなモジュールの機能を用いて dev や production など複数のステージ向けにデプロイできるように更生する場合、ディレクトリ構造として特に決まっているものはないのですが、優れたものとして以下のような形があるので、参考にしながら進めると良いと思います。

6. 既存のAWSリソースを terraform で管理する

6-1. terraforming の導入

terraforming は既存のAWSリソースにアクセスしてterraformのコードを生成してくれたり、tfstateを生成してくれたりするツールです。導入は Gemfile に次のように書いて、bundle install すればOKです。

6-2. 既存の IAM user を terraform で管理する

AWSアカウントを持っているほぼ全ての人は、すでに IAM user などのリソースを持っていると思います。従って、まずここを terraform で管理する形にしましょう。次のようにすると現在のIAM userリソースに応じたHCLが出力されます。

これをファイルに書き出しましょう。

またリモートの状態を手元の .tfstate ファイルに反映させるなければ、terraform はリソースを新規に作成しようとしてしまいます。そのために以下のようにしておきましょう。

terraforming iamu --tfstate --profile default --merge=.terraform/terraform.tfstate

出力をみて問題なさそうであれば、このコマンドに --overwrite オプションを付加して反映させます。こののちに terraform plan をして差分がでなければ、晴れて IAM user の管理を terraform に移行できたことになります。

terraform plan 時にもしも、 destroy されるリソースが表示されたとしたら、既存のリソースやシステムが破壊される可能性がありますので、特に慎重に操作してください。また、IAM policy などについては JSON の改行位置やインデントなどが差分として出やすいので、悩んだときはそのあたりが既存のポリシー設定と食い違っていないか確認することをお勧めします。

さて、terraforming はよく使われるほとんどの AWS リソースに対応しているため、まずはこれを使ってできるところまで terraform に移行すると良いでしょう。v0.7.0 では以下のようなものに対応しています。

6-3. terraform のコードを管理するリポジトリを作成する

個人アカウントのaws構成をopenなgithub repositoryに配置するのは、はばかられるので code commit リポジトリを作成しておくと良いでしょう。

code commit 上に作成したレポジトリにアクセスするためポリシーのアタッチ、ならびに公開鍵登録も terraform を使って行うことができます。

この状態で terraform plan, terraform apply をしてみます

すると以上のように作成された ssh_public_key_id が出力されるので、あとはこいつを ~/.ssh/config に反映させれば手元のマシンから作成した code commit レポジトリに疎通がとれるようになります。

6-4. terraform import

T.B.D

7. 構成管理方法の整理

7-1. 個人開発の場合

個人のAWSリソースを管理する場合は大きく分けて次の2つの方法があるかと思います

  • .tfstate ごと git で管理して、 code commit にぶちこむ
  • .tfstate は S3 で管理、コードは code commit で管理

7-2. チーム開発の場合

  • .tfstate はセキュリティ上の理由から S3 で管理することが望ましい
  • .tfstate やアクセスキーなどを含むものをコミットせず、GitHub Enterprise, code commit, GitHub private repository に push する