Persistence

技術メモなど

vim環境の更新など

ちょっとしたテキストファイル(jsonなど)の編集にいちいちVSCodeを起動するのがだるくなってきたので、vimでサクッとできるように環境を整えることにした。

環境はMacOSです。

neovimから本家のvim

vimはneovimの2.xがインストールされてたんだけど、neovimの活動状況があまり活発でないように見えたので本家のvimに変更した。

$ brew uninstall neovim
$ brew install vim

本家のvimのインストールの際に --with-lua をつけると入力補完の機能が使えるようになるという記事を見たんだけど、いまは --with-lua オプションはなく、標準でインストールされた。

neobundleからdein.vim

neobundleの公式にdein.vimへの移行が推奨されていたので、dein.vimに移行した。

インストール手順はこのあたり。

https://github.com/Shougo/dein.vim#unixlinux-or-mac-os-x

$ curl https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.sh > installer.sh
$ sh ./installer.sh ~/.cache/dein

neobundleでインストールしていたパッケージは、call dein#add('リポジトリ名など') と書く。

  " Add or remove your plugins here like this:
  call dein#add('Shougo/neosnippet.vim')
  call dein#add('Shougo/neosnippet-snippets')
  " ディレクトリツリー
  call dein#add('scrooloose/nerdtree')
  " マルチカーソル
  call dein#add('terryma/vim-multiple-cursors')

そして、vimを起動して :call dein#install() を実行するとパッケージがインストールされる。 以下のように起動時にインストールチェックをするようにしても良い。

if dein#check_install()
  call dein#install()
endif

nerdtree

vimIDEのようなファイルツリーを表示してくれるパッケージ。 操作方法を覚えるのは結構大変だけど慣れるしかない。 キーマップは以下を設定した。

" Toggle NERDTree
map <C-t> :NERDTreeToggle<CR>
" move left Tab
"map <C-[> gT " 有効にすると起動時に置換モードになってしまう
" move right Tab
map <C-]> gt

ところがコメントにもある通り、 map <C-[> gT を設定すると起動時に置換モードになるという事象に遭遇し未解決状態。個人的にタブの切替は [] 以外に使いたくないので解決したい。

vim-multiple-cursors

マルチカーソル機能を提供してくれるパッケージ。 これを使う以前にvimのVisualモードなどを使いこなす必要があり、全く速度が出ない。

Insertモードでdeleteキーが効かない問題

ずっと前からおかしいなと思いつつ放置していたが、vim-multiple-cursorsを使いこなすためにも必要なので調べてみたら一瞬で解決した。

vimで文字が削除出来ないと思ったらバックスペースが効かなくなった - Qiita

gitのcommitコメントを書くときとかもdeleteキーが効かなくて煩わしかったので解決できてよかった。

fish shellでnodeのcompletionエラーが出る問題

vimとは関係ないけど気になっていたので直した。

症状

$ node [ここでTabキーを入力] __fish_not_contains_opt: Unknown option --version
__fish_not_contains_opt: Unknown option --version
__fish_not_contains_opt: Unknown option --version
__fish_not_contains_opt: Unknown option --eval

調べたらだいたいすぐ解決方法は見つかった。

https://fishshell.com/docs/current/commands.html#fish_update_completions

$ fish_update_completions

これだけ。fish shellは ~/.config/fish/completions/ にcompletionファイルを配置するようになっている。 fish_update_completions コマンドは、それを最新にするコマンド。要するにcompletionファイルが古かっただけだった。このコマンドは定期的に実行するように仕組み化しておきたい。自動で差分更新してくれればいいんだけどな。

dotfile

ほとんどいじってないけどdotfileはこちらに公開しています。

GitHub - bisque33/dotfiles

GraphQLキャッチアップ

最近、AWS AppSyncやReactをさわり始めた。AppSyncはまだまだ十分ではないものの、近い将来、APIサーバは必要なくなるという可能性を感じた。API Gateway + Lambdaのときも感じたけど、その時はRESTful脳だったから正直サーバレスにしたところで楽にはならなそうと思ったけど、AppSyncの場合はそれよりもずっと可能性が高そうに感じた。ということでGraphQL界隈を少しだけ探索してみた。ほんの少しだけなのにこんだけたくさん出て、サーバサイドエンジニアとしてはこりゃもうReactなんてやってる場合じゃないわ。

リンクメモ

GRANDstack

GraphQL, React, Apollo, Neo4j Database の頭文字を取ってGRAND stack。 AWSだったらAppSync + Neptuneか。

GRANDstack Starter

サンプルアプリケーションを動画で詳しく説明してくれている。 Neo4jはWeb上のサンドボックスで、アプリケーションの実行はZEITというPaasで行っている。

2018ワールドカップのGraphQL APIを作りました | POSTD

GRAND stack で作られたサンプルの紹介。スキーマ設計の参考になります。

prisma/graphql-playground

GraphiQLの進化版。デスクトップアプリになっている。

serverless/serverless-graphql

AWSで実現するGraphQLアプリケーションのサンプル。 AppSync版とAPI Gateway + Lambda版がある。

GraphCMS

GraphQLを使ったBaas。Typeスキーマを定義するだけでMutationなどは自動生成される。CMSとしてはデータ管理のほか、AssetsやWebhookなどもあり、なかなか良くできている。

GitHub GraphQL API v4 | GitHub Developer Guide

Githubが提供しているGraphQLのドキュメント。 GraphQLの設計の参考になりそう。

サンプル

graphql-playground に Example として紹介されているものたち。

https://graphql-pokemon.now.sh/

ポケモンのデータベース。

https://api.graph.cool/simple/v1/cixne4sn40c7m0122h8fabni1

Instagramっぽいもの。

https://api.graph.cool/simple/v1/cixos23120m0n0173veiiwrjr

映画のデータベース。

オブジェクト指向設計やプログラミング言語の歴史とこれからについて

はじめに

クソコードを生成して迷惑をかけた気がするので、オブジェクト指向設計について学び直すことにした。今振り返ると、当時の自分はオブジェクト指向設計を全く理解せずにコードを書いていた。極端に言ってしまうと、構造化プログラミングにクラスと継承を付け足したもの、といえば伝わるだろうか。

それでもなぜか自分はプログラミングちょっとデキると思っていた。なぜか。まず第一に、コードの綺麗さにはそれなりに自身があった。「リーダブルコード」などを読んで自分なりにきれいに書くように努めていたからだ。第二に、いくつかのWebApplicationフレームワークを使ってプロダクションコードを書いた経験があったからだ。第三に、ドメイン駆動開発(DDD)やソフトウェアアーキテクチャについても学んできたからだ。(ただ今思うと、概念的にわからないことが多くて上滑りしていた気がする)

しかし今回のクソコードはWebApplicationフレームワークRuby on Rails)の土台の上に、かなりの業務ロジックを追加したもので、それらは全くオブジェクト指向設計の要素や原則を無視したもので、残念ながら変更に脆くとても保守性の悪いものだった。(以前、こんな記事を書いているのにもかかわらず、使わずに時間が立ってしまうと全く忘れてしまうという、悲しいことだ)

更に悪いことに、メタプログラミングを多用し、設計ではなく力技で実装を進めてしまった。弱い人間が強い力を手にすると自滅するというセオリーをここまで身をもって体験するとは、自分でも苦笑してしまう。なお、この記事ではメタプログラミングの失敗についてはこれ以上は触れないことにする。

動的型付け言語は保守性が悪い?

少し本題とは逸れるが、はじめにこの疑問についてケリを付けたかった。職場には比較的、静的型付け言語の支持者が多く、動的型付け言語はプロダクションコードとしても使われて入るものの市民権を得られていない雰囲気があった。そんな中でも自分は割と動的型付け言語肯定派(というか適材適所派)で、よほど特殊な要件がない限りはどちらのタイプの言語でも置き換え可能と思っていた。

でも実際のところ、クソコードを書いてしまったわけだし、動的型付け言語でどうやって保守性の高いコードを書くことができるのかを知りたくなった。そこでまず読んだのが「オブジェクト指向設計実践ガイド」だ。オブジェクト指向設計の本の中では比較的新しいし(それでもオリジナルが発行されたのは2012年)、サンプルはすべてRubyで書かれているのでここに求めている答えがある気がした。

とても良本だった。オブジェクト指向設計の本質や、SOLIDの原則(なんとなく知っていたけどオブジェクト指向設計の話だと思っていなかった。)などが詳しく解説されていて、自分の無知を思い知った。オブジェクト指向設計の本質は「要求の変更」に対して「依存関係」を管理することで変更可能なアプリケーションを構築するということだ。そのために、オブジェクト同士がメッセージを通じて協調し合うことで動作する。これがオブジェクト指向プログラミングだ。また変更可能性を高めるために、カプセル化・継承・委譲・ポリモーフィズムなどの機能が提供され、SOLIDの原則やデザインパターンといった設計原則を用いることでさらにそれを高めていくことができる。

しかし、ダックタイピングの章を読んだところで、どうしても動的型付け言語の怖さを克服することができなかった。結局、動的型付け言語で型(やインターフェイス)が動的に決まることについては、「テストで文書化して保証する」「型宣言がなくてもコンテキストがわかるように設計する」のだが、これらをプロジェクトのメンバー全員が達成することはコスト的にもスキル的にもハードルが高いと感じたからだ。静的型付け言語の本質は「設計が型で表されているから保守性が高い」なんだと思う。(まだうまく言語化できない)

静的 vs 動的 vs ???

では2000年台に入り、その当時、Javaや.Netなどの静的型付け言語があったにもかかわらず、動的型付け言語が流行したのはなぜか。一つは、それらの静的型付け言語がまだ発展途上であったこと。もう一つは、動的型付け言語のフレームワークが台頭し生産性が向上したから。それらが重なってPHPRubyなどの動的型付け言語が使われるようになった。しかし、2010年台は静的型付け言語が進化し生産性が向上し、また保守性を取り戻すべく静的型付け言語が再び流行りだすことになる。また、2018年現在は、静的と動的の両方を併せ持つ言語)が開発されていたり、動的型付け言語であるPythonに型アノテーションを導入する動きなども見られるが、どこまで実用的かはまだわからない。

UMLはなぜ廃れたのか

また脇道に逸れるが、「オブジェクト指向設計実践ガイド」の中でオブジェクト同士のメッセージのやり取りを表すためにシーケンス図が用いられていた。シーケンス図といえばシステム同士のAPIコールを表すことにしか使ったことがなかったので、そもそもUMLオブジェクト指向設計を図示するためのツールだということを知らなかった。そこで、UMLを学べばオブジェクト指向設計をもっと知ることができるのではと思い、マーチン・ファウラー先生の著書「UMLモデリングのエッセンス第3版」を読んだ。

UML モデリングのエッセンス 第3版 (Object Oriented SELECTION)

UML モデリングのエッセンス 第3版 (Object Oriented SELECTION)

この本では最初の2つの章で、UMLの使い方と、UML開発プロセスに適応する方法について書かれている。というのも、UMLの標準化団体は、UMLを厳密化しUMLからプログラムを生成できるようにするために、UMLをどんどん複雑な仕様にしていった。しかし設計からコードを生成するということは、コードと同じレベルの設計書を書くということなので、コードを書いたほうが遥かに楽ということは想像できるだろう。また、開発プロセスについてもウォーターフォール開発ではなくアジャイル開発が主流になり、設計書を書くという行為自体が無駄という風潮が高まり、UMLは姿を消していった。

しかし、本書はそういった厳密なUMLの使い方ではなく、スケッチとして、コミュニケーションツールとしての使い方を推奨している。特に知っておいたほうがいいと思ったのは3章から5章までに書かれているクラス図とシーケンス図だ。クラス図を知っておけばオブジェクト指向設計をする上で必要な継承・集約・コンポジット・依存関係などをすばやく組み立てることができる。また、シーケンス図を知っておけば「オブジェクト指向設計実践ガイド」でも使われているようにカプセル化やSOLIDの原則に違反している箇所に気づきやすくなるため有効だと思う。その他、有用そうなものは、上流工程としてユースケース、詳細設計として状態マシン図くらいだ。

プログラミング言語パラダイム

最後にパラダイムについて少しだけ触れて終わりにする。様々なパラダイムがこれまでの歴史上発明されたにもかかわらず、オブジェクト指向設計は20年以上に渡り第一線のプログラミングパラダイムとして使用されている。しかしここ数年の動きとしては、リアクティブプログラミングや関数型プログラミングにも注目が集まっており、それぞれの特性を理解した上で次に乗る船を決めたい。手始めに「関数型リアクティブプログラミング」などを読んでみたいと思っている。

まとめ

オブジェクト指向言語を使うのなら、オブジェクト指向設計はちゃんと学んだほうがいい。オブジェクト指向設計に関する定番的な本は2000年代前半までに書かれたものが多く、いまさら結構な金額の本を読むのは抵抗があると思うが、逆に考えると定番さえ読めば特に重要な先人の知恵をストレートに得ることができるので楽なのかもしれない。

2017年のふりかえり

総括

2017年の主なトピックとしては、プライベートでは「第一子が魔の二歳児に突入(とっても可愛いけど)」と「東京から札幌への引っ越し」、仕事では「入社以来関わってきた案件から別の案件への異動」「リモートワーク」などがありました。そんな中で色々な出会いや経験があり、今までにないほどの「価値観の変化」や「視野の広がり」を感じ、人としての成長を感じました。また、自分の思考が分かるようになりコントロールできるようになることで、精神的な安定を得られた気がします。エンジニアとしては、昨年はチームメンバーに多くのことを教わりながら仕事を進めていましたが、今年は昨年の経験を活かして能動的に動けていたと思います。技術スタックとしては相変わらずの何でも屋で、そのお陰か、特に「わからないことを調べる力」や「問題を嗅ぎ分ける感覚」などが付いてきた気がいしていて、エンジニアとして人並なレベルにはなってきているのではないかと思います。

個別

仕事

仕事でやりたかったことは、部内のインフラ周り(デプロイフロー、インフラ構成、ログ、監視、など)を標準化することでした。これは部門長の理解を得られたし賛同してくれるメンバーも居たのですが、リソース不足(つまりそこまで優先度が高くなかった)により実現できませんでした。では何をやっていたかというと、前半は昨年から継続しているモバイルアプリのサーバサイドの保守&追加開発を、後半は新規プロジェクトのサーバサイドの開発をやっていました。前半の案件については、おおよそ自分が居なくても問題ない状況になっていたので、このままこの案件に居続けるより別の案件に移ったほうが部全体の利益になるだろうと思い、追加開発も半ばでしたが無理を言って移らせてもらいました。後半の案件では部内の技術リーダーをはじめとするメンバーから多くの刺激や学びを得て、また自分の得意とするところではそれなりの価値を出せて本当にいいチームワークで働くことができたと思いました。

技術

メインは昨年から引き続き、AWSRuby(RoR)でした。今年はこれに加え、Node.jsを仕事でガッツリ使えたことも大きいです。今まで個人プロダクトでは結構使っていましたが、仕事で使えたことで自信になりました。他にもGoでOSSを作ったりしました。また、一番大きな変化はDockerをプロダクション環境で使うことが当たり前になったことです。これによって、上で述べたデプロイフローやインフラ構成あたりの課題は軽減されてきたように思います。

リモートワーク

6月に東京から札幌に引っ越し、リモートワークになりました。これまで東京にいたときも、東京以外のメンバーと仕事をしていたのでリモートワークには変わりないのですが、多数側か少数側かでは環境が大きく違います。特にリモートミーティング時は伝わってくる情報が対面しているよりかなり減ります。1:1ならまだ良いのですが、N:1になるとNが増えるほど顕著になります。これを解決するには全員が同じ環境、つまり全員がオンライン状態にならないと解決しないと思ってるんですが、いまのところNの数が少ない&チームメンバーもかなり意識してくれているのでそんなに支障なく仕事はできています。

育成

自分ともう一人(サーバサイドの知識が殆ど無いiOSエンジニア)の2人でチームを組んでサーバサイドアプリケーションを開発する機会がありました。自分がリードする立場だったので、本当はいろんなことを教えたかったのですが、困ったことに自分はまともに教えを受けた(前職や学生時代なども含め)経験がなく、どのように教えたら良いかわからなかったのが課題でした。年齢的にも立場的にも、「教える」という機会が今後増えそうな気がするのでどうにかしたいところです。

セルフコントロール

メンタル面については仕事以外の部分で、登壇を引き受けたけど価値のある内容が考えられず、メンタルが崩れ結果登壇をお断りして迷惑をかけたことが反省としてあります。あと時間管理については子どもや家庭で忙しいことを理由にさぼってたのですが、「ドラクエ11」を発売から4日でクリアできたり、「リネレボ2」を一週間ひたすらやった(そして止めた)ところ、考えが改まり「スキマ時間ならいくらでも作れる」ということがわかりました。

価値観

自分は「空気を読む」というのが嫌いで、空気を読まず(時には読めず)、結果相手のことを考えず一方的な主張ばかりになっていたことに気づきました。忖度(※2017年の流行語)はいらないけど、相手の立場を考えることがコミュニケーションには重要だなあとこの年になって感じました。それから、人との距離を詰めるのが上手い人の共通点を見つけたり、毒づく人の気持ちがわかったり、人に期待しても幸せになれないって改めて感じたり、いままでは自分が受けた言葉や感情をそのまま受けることしかできなかったけど、受けたもの客観的に観察できるようになった気がする。あと、人生使える時間は少ないから無駄なことはできないって思ってなんにもできてなかったけど、短いからこそ一つずつを全力でやったほうがいい。無駄なことはない。

ブラウザから直接S3にファイルをアップロードする方法

ブラウザからS3にファイルをアップロードする場合、S3のアクセスキーやシークレットキーを隠ぺいするためにブラウザ→サーバ→S3というようにサーバを経由してアップロードする事を考えますが、サーバを経由せずに直接S3にアップロードする方法がありました。

元の情報はこのページです。

devcenter.heroku.com

概要

何が行われているかというと、

  • ブラウザがサーバに対してS3のシグネチャ付きのURLを要求します。
  • サーバはS3に対してSDKシグネチャ付きのURLを要求します。
  • サーバはブラウザにS3から返されたシグネチャ付きのURLを返します。
  • ブラウザはアップロードしたいファイルを受け取ったURLにPUTします。

シグネチャ付きのURLにはアクセスキーが含まれますがシークレットキーは含まれないので、一応安全ではあります(ただあまり見せたくはないですが)。またこの方法をを取ることで、通信は2往復になりますがブラウザからサーバへファイルを送る必要がないので通信量・通信時間は少なくなります。

注意点

1つは情報元のページにもありますが、S3の『CORSの設定』で送信元Origin(ドメイン)からのPUTを許可しておくということです。この設定がない場合、403エラーで"No 'Access-Control-Allow-Origin' header is present on the requested resource."が返されます。

もう1つは、情報元のページに無いのですが、aws-sdkのconfig設定にregionとsignatureVersionの設定が必要でした。この設定がない場合は、403エラーで"SignatureDoesNotMatch"が返されます。一応PRを送ってGitHubのソースにはmergeされています。(と書いた後にもう一度再現させてみようと思ってsignatureVersionの設定を削除してリクエストしたらエラーにならずにできました。謎です。)

問題点

1つはやはり上にも書きましたが、アクセスキーが見えてしまうということです。アクセスキーとシークレットキーがセットでないと何もできないですが、重要なシステムではオススメできません。

もう一つは、ファイルに何か加工(例えば画像をリサイズするなど)したい場合、S3にアップロードした後で行うことになります。システムによってはアップロード後に非同期で加工でも問題ないかもしれませんが、DollFaceDetectorの場合はアップロード後すぐにAPIにファイルのURLを渡すので、先にリサイズなどの加工をする必要がありました。

顔認識APIについて調べました

Doll Face Detectorを開発するにあたり、顔認識&機械学習APIについて調べたことを書いていきます。

APIの選定条件

まず最低限必要な機能として、「静止画から顔を検出する」「登録した顔のデータから近いものを検索する」の2点が必要です。さらに、個人的なサービスなのでお金は掛けたくないので、 無料枠がどれだけあるかも重要なポイントです。あとは、「顔認識の精度」「機能の充実度」なども評価のポイントに成ります。

候補となったAPI

いくつか試したAPIを紹介します。

日本国内のサービス: PUX

pds.polestars.jp

まず日本国内のサービスで探すと、これくらしか見つかりませんでした。無料枠は月5000リクエスト、登録顔数10なので、本当に評価版として使える範囲の数になっています。提供されているAPIの機能自体も最低限という感じです。

項目 評価
無料枠の多さ
機能の充実度
顔認識の精度 ?(詳しく検証していない)

Microsoft機械学習サービス: Project Oxford

Microsoft Project Oxford Home

最近ベータ版が開始されたサービスで、一時話題になったHow Old do I Look?もこのプロジェクトの内の1つであるFaceAPIsのデモサイトです。現在ベータ版なので無料版しかないのですが、無料版は15アクセス/分という制限があります。まあそこまでアクセスはいかないだろうと思って、これを使うつもりで開発を始めたのですが、いざ作り始めると1回の処理で数回リクエストする必要があり、リクエストを減らすために自前のデータベースでAPI側のデータをキャッシュしたりしてるうちに、今度はAPIそのものが不安定になってきて(デモサイトでも同じ症状が出てました)、ベータ版の時点では実用に耐えないなということでやめました。

一応、APIアクセスについてはモジュール化して作っていたので、npmに公開しています。

www.npmjs.com

項目 評価
無料枠の多さ
機能の充実度
顔認識の精度

全部無料のサービス: Face++

www.faceplusplus.com

中国のサービスで全部無料・制限なし(相当なアクセス数になってくると要相談とありますが)って、ちょっと信頼できるのか心配だったんですが、背に腹は変えられぬってことでこれを使いました。

登録すると最初はDeveloperモードとなり顔登録数が100までという制限がありましたが、サービスURLを公開した後でProductionモードにアップグレードするリクエストを送ると、2〜3日でなんの通知もなくProductionモードに変更されていました。

また機能的にもかなり充実していて、データはすべてFace++側で管理することができます。データそのものはAPIで取得できるので、定期的に全件取得しておけば万が一サービスがなくなっても他のサービスに移行することはできるかなと思っています。

モジュールも準備できしだいアップ予定。

項目 評価
無料枠の多さ
機能の充実度
顔認識の精度

その他

他にもたくさんの同種のサービスがありました。APIを探すのにとても役に立つのがMashapeというサイトです。

www.mashape.com

ここに顔認識系の有名どころのサービスがまとめられています。

Popular Face Detection/Recognition APIs from Mashape

これらひと通りデモを試してみましたが、認識できる精度についてはほぼすべて同じでした。唯一ちょっと違ったのがMicrosoftのサービスです。ただ、どちらが優れているというわけではなく、どちらも認識できる画像/できない画像がありました。ちなみにこれはドール画像の話で、人間の顔認識に関してはどちらもかなりの精度で認識されます。

DollFaceDetectorというサービスを作りました。

概要

このサービスは、顔認識&機械学習を使ってドール画像からそのドールの顔の型番を判定するサービスです。学習すればするほど精度が上がる(想定)なので、興味がある方はぜひ使ってみてください。

f:id:bisque3311:20150609011143j:plain

http://doll-face-detector.herokuapp.com/

開発背景

アイディア自体はかなり前からあったものですが、当時はまだ使えるAPIがなく、専門知識もないので自前で作るなんて途方も無いので、アイディア自体を寝かせておきました。最近になってまたAPIを捜してみたらかなりたくさんあって、これならできそうということで開発をはじめました。

あと、技術的に色々と使ってみたいものがあってその練習課題という意味もありました。構成としてはMEANスタック+Heroku(ホスティングのみ)+AWS(S3, dynamodb, lambda)あたりを使っています。次回以降の記事で、色々と得た知識を書いていこうと思います。