2014年振り返り
少し早いけど、2014年の振り返り。
濃い1年だった。エンジニアとして多くのことを学び、多くのことが今だ学べずに残してしまっている。この1年を誰に感謝するかと問われれば、それはJavaScriptだろう。2月から4月まではサーバ・クライアントどちらもJavaScriptの新規サービスの開発をする機会があり、それが自身にとって得難い経験となった。今まではjQueryでDOM操作をする程度の表層でのみ利用していて気がついていなかったメソッドの意味や、曖昧だった言語の仕様、ソフトウェアに対する要求について考えることができた。必然的にモダンなJavaScript界隈の話を見聞きすることが多くなり、新しい技術やトレンドを追い出すようになった。また、チーム内で教える立場になったこともあり、曖昧な認識では説明できないことが増えた。聞かれたことを夜な夜な学んで翌日しれっと話す、といったことも何度かあったが、未だ充分な役割は果たせていないように思える。
Keep
いわゆるMEANスタックであるとか、WebScoket、WebComponentsなどについて学んだ。モダンなフロントエンド開発や技術については今後も継続して色々挑戦していきたい。NodeやMongoなども。
自分が触ったことのない言語に挑戦した(主にGo, Swift, Rubyなど)。使いこなすレベルにまで至っているものは少ないが、手を動かしたり言語仕様について学んだりすることができた。
多少のアウトプットはできた。何度か発信することができたように思う。同人誌にSocket.IOの記事を書いたりした。
外のライブラリに機能追加pull requestを投げた。Angular.jsのプラグインになかった機能を自分で追加して後日pull request投げた。「機能はOK。ちょっとテスト足りないから追加で書いといたわ」と言われたのが切ない。
Problem
全体的に、テストを書いた方がいい機会で書けなかった。よくある時間がないとかいうアレだったのだけれど、テスト書いておけばエンバグして手戻り、みたいな作業減るよなーという場面を作ってしまった。
インフラに関する知識が足りない。ネットワークやシステム構成の話の基本的な部分から、各種のミドルウェアに対する理解だったり。あとAWSとか全然ついていけてない。
新しい言語やフレームワークを学んでも自分で何か作れるところまでいかなかった。また、設計やデザインパターンについてもっと理解を深めたいが。
依然としてアウトプットが少ない
英語が思ったより学べなかった。夏くらいまでは毎日Podcast聞いたりしていたけど、最近は全く手がついていない。
Try
テストが当たり前の状況にする。そのためにRailsでRSpecを使って、テストの導入からテスト駆動な開発まで自分でやってみる。また、jsでもテストが当たり前で書けるように書ける部分は原則書くようにする。
マスタリングTCP/IPをひと通り読む。AWSで1つのアプリケーションを色々なミドルウェアを使って動かしてみる。herokuとかに色々任せきりにしない。nginx, (apache), mysql, redisなどを1人で色々設定してみる。
自分でライブラリを作って公開してみる。デザパタ本を読みなおしたりDDD本を読んだりしてブログにまとめる。
月1で記事を書く。また、月1で振り返りをして、軌道修正を行う。
課題を課すためにも、できる限り毎日DUOとかやる。
今年読んだ本
Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)
- 作者: 山本陽平
- 出版社/メーカー: 技術評論社
- 発売日: 2010/04/08
- メディア: 単行本(ソフトカバー)
- 購入: 143人 クリック: 4,320回
- この商品を含むブログ (180件) を見る
コーディングを支える技術 ~成り立ちから学ぶプログラミング作法 (WEB+DB PRESS plus)
- 作者: 西尾泰和
- 出版社/メーカー: 技術評論社
- 発売日: 2013/04/24
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (31件) を見る
iOSアプリエンジニア養成読本[クリエイティブな開発のための技術力/デザイン力/マインドを養う! ] (Software Design plus)
- 作者: 高橋俊光,諏訪悠紀,湯村翼,平屋真吾,平井祐樹
- 出版社/メーカー: 技術評論社
- 発売日: 2014/03/20
- メディア: 大型本
- この商品を含むブログ (1件) を見る
開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質
- 作者: Cody Lindley,和田祐一郎
- 出版社/メーカー: オライリージャパン
- 発売日: 2013/06/19
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)
- 作者: Dustin Boswell,Trevor Foucher,須藤功平,角征典
- 出版社/メーカー: オライリージャパン
- 発売日: 2012/06/23
- メディア: 単行本(ソフトカバー)
- 購入: 68人 クリック: 1,802回
- この商品を含むブログ (118件) を見る
- 作者: 川添愛
- 出版社/メーカー: 東京大学出版会
- 発売日: 2013/04/19
- メディア: 単行本
- この商品を含むブログ (9件) を見る
- 作者: 高橋政明
- 出版社/メーカー: 有限会社 快技庵
- 発売日: 2014/09/04
- メディア: Kindle版
- この商品を含むブログを見る
Swiftではじめる iPhoneアプリ開発の教科書 【iOS 8&Xcode 6対応】
- 作者: 森巧尚,まつむらまきお
- 出版社/メーカー: マイナビ
- 発売日: 2014/10/31
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
- 読んでる・途中で止まってる本
シングルページWebアプリケーション ―Node.js、MongoDBを活用したJavaScript SPA
- 作者: Michael S. Mikowski,Josh C. Powell,佐藤直生,木下哲也
- 出版社/メーカー: オライリージャパン
- 発売日: 2014/05/24
- メディア: 大型本
- この商品を含むブログ (1件) を見る
オブジェクト指向入門 第2版 原則・コンセプト (IT Architect’Archive クラシックモダン・コンピューティング)
- 作者: バートランド・メイヤー,酒匂寛
- 出版社/メーカー: 翔泳社
- 発売日: 2007/01/10
- メディア: 単行本(ソフトカバー)
- 購入: 11人 クリック: 307回
- この商品を含むブログ (132件) を見る
- 作者: Eric Evans
- 出版社/メーカー: 翔泳社
- 発売日: 2013/11/20
- メディア: Kindle版
- この商品を含むブログ (2件) を見る
来年もよろしくお願いします。
安全なWebアプリケーションの作り方1
読書会でのメモ
HTTPとセッション, 同一生成元ポリシー
HTTP
- クライアントからサーバへのリクエスト、サーバからクライアントへのレスポンスで構成されるプロトコル
- リクエストラインの構成は以下
- メソッド
- リクエストURL
- プロトコルバージョン
- 実際には
GET /hoge.php HTTP/1.1
といった形式となる - リクエストヘッダにはRefererなどがつく
- Refererはアプリケーションが意図した遷移を経ているかをサーバ側で検証する場合などに用いられるが、改変が容易
- URLにセッションIDなど機密情報が含まれる場合にはセキュリティリスクとなる
- レスポンスメッセージの構成は以下
- ステータスライン
HTTP/1.1 200 OK
- ヘッダ
Date: foo Server: Apache/2.2.14...
- 空行
- 本体
<body>...
- レスポンスヘッダはContent-lengthやContent-Typeなどが代表的
- Content-TypeはMIMEタイプというリソースの種類を指定するhtmlであれば
text/html
, jpg画像であればimage/jpg
, pdf文書であればapplication/pdf
- 特殊記号や日本語などのマルチバイト文字列をURL上に記述する場合はパーセントエンコーディングを行う必要がある
- GET/POSTについて
- GETメソッドを用いる場合は、「リソースに対して副作用を起こさない・機密情報を送信しない・送信するデータ量が少ない」場合に用いるのが望ましい
- Referer経由で情報が漏洩する・アクセスログに記録されるため
- hiddenパラメータは書き換え可能
- HTTPには認識機構が用意されている
- Basic認証
- Digest認証
$user = $_SERVER['PHP_AUTH_USER']; $pass = $_SERVER['PHP_AUTH_PW']; if (!$user || !$pass) { header('HTTP/1.1 401 Unauthorized'); header('WWW-Authenticate: Basic realm="Basic Authentification Sample"'); exit; }
- Basic認証が設定されているサーバから401のレスポンスを受け取ると、ブラウザはBasic認証のidとpassを受け取るダイアログを表示する
- 認証に成功すると、ブラウザはリクエストヘッダにAuthentificationを付与して送信し、ページの閲覧が可能となる
- Cookieとセッション管理
- HTTPはステートレスなプロトコルであるが、クライアント・サーバ間でログイン状態やその他の情報を記憶しておきたい場面が存在する
- 認証状態の管理はセッション管理と呼ばれ、HTTPではブラウザのCookieを用いて実現される
- 有効期限の設定されていないCookieはSessionと呼ばれ、ブラウザが閉じられるまで有効となる
- Cookieは文字列長および利用者による変更が可能なため、Cookieにはセッションidのみ記録し、実際のセッション管理を行う値はサーバ側で保持することが多い
- セッションidに求められる要件は以下
- 第三者がセッションidを推測できない
- 第三者からセッションidを強制されない
- 第三者にセッションidが漏洩しない
- 上記を満たすため、セッションには以下のようなことを考慮する必要がある
- 乱数の質
- ネットワーク的な盗聴の危険性
- XSSからの漏洩
- CookieのDomain属性/Secure属性/HttpOnly属性
- Referer
TemplateMethodパターンの雑感
メモ
- ロジックの手順を定義し、個々のロジックの実装はサブクラスに先送りするパターン
- コード再利用のための基本的な話
- 抽象クラスが定義するのは以下
- フックはクラス内で何もしないか、またはデフォルトの振る舞いを実行する
- サブクラスで適宜オーバーライドもできる
- サブクラスがテンプレートメソッドを変更しないようにfinal修飾子を宣言しておく必要がある
- 「こちらを呼び出さないでください。こちらから呼び出します。」
- スーパークラスが主導権を持ち、必要に応じてサブクラスを呼び出す(実処理を実行する)ように設計するべき
- Storategyパターンと混同しがちだが、Storategyパターンはコンポジションを用いてロジックをカプセル化するのに対して、TemplateMethodパターンは継承を用いてロジックをカプセル化する
- FactoryMethodはTemplateMethodの特化型と言えるかもしれない
- サブクラスがスーパークラスを呼び出すことは許されないのか?
- スーパークラスが定義する抽象メソッドの数が多すぎると実装が超めんどくさいと思うのだが
実例
- JavaのArray.sort()など
- 教科書通りには設計されていないが、「実装をサブクラスに先送りする」という思想が存在する
実装
- 時間がない
Adapterパターンの雑感
メモ
- 既存のクラスがあり、そのインターフェースが使いにくい、求めているインターフェースと異なる場合に適用するとよい
- Adapterパターンによってクライアントが期待するインターフェースに変換することができる
- アダプタの実装は、ターゲットインターフェースの大きさや煩雑さにより必要な作業量が変わる
- コンポジションを使うオブジェクトアダプタと多重継承が前提のクラスアダプタが存在する
- なぜオブジェクトをラップするか
- アダプタは「オブジェクトのインターフェースを変換するために」オブジェクトをラップする
- デコレータは「新しい振る舞いや責任を追加するために」オブジェクトをラップする
- ファサードは「インターフェースの簡素化のために」オブジェクトをラップする
- 複数のインターフェースをラップするのか
- Facadeパターンを使おう。Adapterパターンの目的はインターフェースを「変換」するためである
- システムに古いインターフェースを期待する部分と新しいインターフェースを期待する部分がある
- 双方向アダプタを用いる。アダプタは関連する複数のインターフェースを実装する
実例
- Javaの古いインターフェースであるEnumerationインターフェースを使っているが、新しいインターフェースであるIteratorを使いたい。こういう場合にAdapterクラスを作成しIteratorインターフェースを実装する
- クライアントはIterator型のオブジェクトとしてEnumerationを透過的に呼び出すことができる
実装
- 時間がない
Iteratorパターンの雑感とRubyでの実装
メモ
- Iteratorパターンとは、内部表現を公開することなくアグリゲーションオブジェクトの要素に順次アクセスする方法を示した設計
- Iteratorによる実装を行えば、複数のアグリゲーションオブジェクトの要素を走査する場合に透過的に扱うことができる。これによってその他のメソッドを多態性のある機能として追加できる
- 大事なのは、要素間のトラバースを行う役割をアグリゲーションオブジェクトではなくイテレータに移譲することで、これによりアグリゲーションオブジェクトは反復処理ではなく、本来の役割(オブジェクトのコレクション管理)に専念できるようになる
- 内部イテレータと外部イテレータ - 外部イテレータはクライアント側がnext()を呼び出して、次の要素への処理を決定する
- 上記の多態性のある機能とは、Iteratorを引数に取るメソッドのことである。Iteratorを活用することでコレクションの実装を考えることなく特定の振る舞いを実装できる。以下の様なもの
public void print(Iterator iterator) { while(iterator.hasNext()) { System.out.println(iterator.next()); } }
- アグリゲーションオブジェクトを扱うクライアントは、アグリゲーションオブジェクトの具象クラスではなくインターフェースを参照して各アグリゲーションオブジェクトを利用するようにすると、クライアントと疎結合にできる
- JavaのHashTable等のコレクションをIteratorで扱うとどうなるか
- 順番を担保するものではない
- あくまで「値に対する走査」なので、値を取得してからIteratorを生成する必要がある
- Java.Util.Iteratorインターフェースを用いればよいのか
- ケースバイケース
- ArrayListはデフォルトでサポートされているので不要
- Java.Util.Itreatorインターフェースのremove()どうするの。。。
- 謎い。いみゅーたぼーにしたい場合はどう扱えばいいのか。
Rubyによる実装
# 内部イテレータ # コードブロックの利用によって集約オブジェクトにロジックを伝える # 繰り返し処理の全てが集約オブジェクト内で起こるため、内部イテレータと呼ぶ p '内部イテレータ' array = %w(red blue green) array.each do |val| p val end # 外部イテレータ # 外部機能として渡すため柔軟性に富む # 複数コレクションから一つずつ要素を取り出して並行に処理するようなことも可能 p '外部イテレータ' class ArrayIterator def initialize(array) @array = array @index = 0 end def has_next? @index < @array.length end def item @array[@index] end def next_item value = @array[@index] @index += 1 value end end # 配列を走査する i = ArrayIterator.new(array) while i.has_next? puts("item: #{i.next_item}") end # 文字列を走査する i = ArrayIterator.new('abc') while i.has_next? puts("item: #{i.next_item}") end # 平行させる # こういうのは外部イテレータの方が容易 def merge(array1, array2) merged = [] iterator1 = ArrayIterator.new(array1) iterator2 = ArrayIterator.new(array2) while iterator1.has_next? && iterator2.has_next? if iterator1.item < iterator2.item merged << iterator1.next_item else merged << iterator2.next_item end end set_merged(iterator1, merged) set_merged(iterator2, merged) merged end def set_merged(iterator, merged) while iterator.has_next? merged << iterator.next_item end end array1 = [10, 50, 100] array2 = [15, 45, 95] merged = merge(array1, array2) merged.each do |val| p val end
Flyweightパターンの雑感とJavaおよびcoffeescriptでの実装
復習がてら殴り書きしつつ、Javaとcoffeescriptでの実装を貼っておく
メモ
- GoFが定義したデザインパターンの1つ。同一のインスタンスを複数箇所で利用するときに、1つのインスタンスを再利用することで省リソース化することをねらう
- 共有したいインスタンスFlyweightと、キャッシュを保持しつつ必要に応じてFlyweightインスタンスを生成するFlayweightFactoryが想定される
- Factoryはシングルトンで実装される場面が多く、それによりキャッシュ機構が複数存在してしまうことを防ぐ
- Factoryの振舞いは次の通り
- 利用シーン
- イミュータブルなクラスを複数生成したい場合など
- 注意点
- 一度 FlyweightFactory に保存されたインスタンスは、たとえ不要になった場合でもガベージコレクションされることがないため、場合によっては明示的に FlyweightFactory から削除する必要がある
- Factoryの裏でシングルトンをいくつも存在させたいという場面で、自然と思いついていそうなパターンである。
- プリミティブでないものをキャッシュ機構に載せるということは、参照を保持するということなので、もし参照先で変更が生じた場合、それは参照元にも影響を与える。こう考えるとよくあるバグを生みそうなパターンである。
Javaによる実装
- 素直
package com.sisidovski.flyweight; public class HumanLetter { private String letter; public HumanLetter(String character) { this.letter = character; } public void display() { System.out.println(letter); } } package com.sisidovski.flyweight; import java.util.HashMap; import java.util.Map; public class HumanLetterFactory { private Map<String, HumanLetter> map = new HashMap<String, HumanLetter>(); public static HumanLetterFactory singleton = new HumanLetterFactory(); private HumanLetterFactory(){} public HumanLetterFactory getInstance() { return singleton; } public int countInstance() { return this.map.size(); } public synchronized HumanLetter getHumanLetter(String letter) { HumanLetter humanLetter = map.get(letter); if (humanLetter == null) { humanLetter = new HumanLetter(letter); map.put(letter, humanLetter); } return humanLetter; } } package com.sisidovski.flyweight; public class Test { public static void main(String args[]) { HumanLetterFactory factory = HumanLetterFactory.singleton; factory.getHumanLetter("a").display(); factory.getHumanLetter("b").display(); factory.getHumanLetter("c").display(); factory.getHumanLetter("d").display(); factory.getHumanLetter("e").display(); factory.getHumanLetter("a").display(); factory.getHumanLetter("b").display(); factory.getHumanLetter("c").display(); factory.getHumanLetter("d").display(); factory.getHumanLetter("e").display(); System.out.println(factory.countInstance()); } }
coffeescriptによる実装
- どちらかと言うとsingletonの実装に躓いた
- 生jsでの実装は結構辛そうだが、時間があるときにやってみたい
class FlyWeight constructor: (string) -> @string = string display: -> console.log @string class Factory map = {} instance = null class Private getFlyWeight: (string)-> flyweight = map[string] unless flyweight flyweight = new FlyWeight(string) map[string] = flyweight return flyweight count: -> Object.keys(map).length @get: -> instance ?= new Private() # test factory = Factory.get(); factory.getFlyWeight('a').display() factory.getFlyWeight('b').display() factory.getFlyWeight('c').display() factory.getFlyWeight('d').display() factory.getFlyWeight('e').display() factory.getFlyWeight('a').display() factory.getFlyWeight('b').display() factory.getFlyWeight('c').display() factory.getFlyWeight('d').display() factory.getFlyWeight('e').display() count = factory.count() console.log count
追記
coffeescriptの例でinstance変数の設定が間違っていたので修正した