ハウテレビジョン開発者ブログスマートフォン用の表示で見るハウテレビジョン開発者ブログ『外資就活ドットコム』を日夜開発している技術陣がプログラミングネタ・業務改善ネタ・よしなしごとについて記していきます。pathのためにgithubアカウントを短くしたymgytです。ハウテレビジョンでは2018年5月15日にiOSアプリ外資就活ドットコムのリニューアル版をリリースいたしました。Service(ESC)とGoを中心に作りました。本blogではその際にハマったところや意識したところを述べていきたいと思います。Events)RDSElasticache(redis)TerraformAWSリソースの作成はterraformを利用しました。terraformはvagrant,packer等を提供しているHashiCorpが作成したGo製のCLIツールです。APIを叩くことになりますが、この際の適用scriptは自分でつくる必要があります。リソースへの変更を表現したデータを一度作成して、内容を確認した後にこれを適用する必要があります。実行すればよいだけなのがすごく良かったです。どんな設定fileでもそうですが、再利用性を考えた場合や後の変更箇所は変数化されていていき、結果変数の数が増えていきます。templateを設けてtemplateを細分化して対応したりして対応していました。terraform.tfvarsfileを作成して変数を明示的に管理できる仕組みが用意されており、templateと変数の分離/管理が行いやすかったです。terraformはAWSに特化したツールではないので、Cloudformationで利用できる組み込み関数(GetAZs)やConditionといったものは利用できません。各リソースのパラメータについての説明はterraform上のdocumentは説明が簡素なので、場合によってはCloudformationのdocumentを参照する必要がでてきます。Go製CLIツール最後は個人的な好みになりますが、terraformがGoで書かれているので+5億点でした。等が利用されており、読んでいてとても勉強になります。Fargateの対応予定がアナウンスされましたが構築中の時期ではFargateはap-northeast-1では未対応でしたので、通常のEC2で作成しました。Instanceの集合をClusterという概念で捉え、CPU使用率やメモリ使用率といったリソースの使用状況もCluster単位で把握できる仕組みを提供してくれています。Instanceを意識せざるをえない場面もあります。Instanceの作成とかわりません。/etc/ecs/ecs.configに従って機能するので、起動時に必要なパラメータを設定します。Instance群を捉えられるようになります。InstanceとしてAPIのパラメータやdocument上で扱われます。Serviceは最初はわかりづらい概念ですが、私はコンテナ群とロードバランサーを紐付ける概念上のモデルと捉えています。ServiceのパラメータでlaunchType(FARGATE,EC2)を設定したり、taskDefinition(docker-componse.yml)やコンテナ数(task数)を設定します。叩くとdeployが走ります。groupに登録してくれます。Instanceのリソースを有効に使い切れます。Container(80)というイメージです。ecs-cliはaws-cliとは別にawsによって管理されており、こちらもGo製です。typeをEC2に設定している場合,autoscalingさせるには2つの設定が必要です。InstanceのCPU/メモリの合計なので、これを超えてtaskを配置するためのClusterのautoscalingがそれぞれ必要になります。alarmを作成して、metricの閾値に応じてactionを実行する形でautoscalingさせるよう設定しました。alarmを設定しなくてはならず、問題がないのもかかわらずalarmが発火してしまうので、他のalarm運用と衝突してしまいかねないので、なにかいい方法がないか探しているところでもあります。alarmを作成して、scalingさせていきます。InstanceのAutoscaleと変わらないかと思います。ここでCluster側が一切ECSを意識しなくてよいことによる問題が生じます。inする際に当該Instaceで起動しているContainerに関知しないことです。in時にhookを設定し、gracefulな終了処理を行います。Lambda処理の概要としては、Autoscaleのscalein時のHookにSNS通知を設定し、Lambdaを起動します。APIを利用してDrainingに変更します。APIを呼び出します。LambdaはGoで実装しました。Instanceから所属しているClusterを取得する必要があります。dataのparseという2つのアプローチでClusterNameを取得しようとしています。lambda.Start(app.HandleEvent)}Goのlambdaはbuildしたbinaryをzip化してS3に設置するだけなのでシンプルです。terraform側ではbucket/keyとversionIDを指定しています。廃棄容易性を意識してすばやくshutdownできる必要があります。利用したpackage主に以下のpackageを利用しましたhttps://github.com/gin-gonic/ginhttps://github.com/jinzhu/gormhttps://github.com/uber-go/zapginhttp関連のhandlingはginを利用しました、requestをparseしてjsonを返すsimpleなAPIなので特に問題なく利用できまし。URLのroutingにはhttprouter(https://github.com/julienschmidt/httprouter)が利用されているので,URLが特殊な場合は事前に対応できるか確認が必要です。validate処理にはvalidator(https://github.com/go-playground/validator)を利用してvalidate処理を行いましたgormDB処理にはgorm(https://github.com/jinzhu/gorm)を利用しました。Builder的に利用しました。document(http://gorm.io/docs/)が充実しており、とても利用しやすかったです。subqueryが必要な場合は明示的にsubqueryを生成する必要があるので、裏側でとんでもないSQLが生成されるといったこともなく、過度な抽象化は行わない方針で進めました。以外に決定版が存在していないと思っており,皆様がloggingをどのように行っているか気になっているところです。今回は構造化されたloggingを行いたかったのでuber社が公開しているzap(https://github.com/uber-go/zap)を利用しました。layout今回の一番の悩みどころがpackageのlayout(directory構成)でした。Goの場合Webframeworkといった形で構成から命名規則まで統一的に管理するより各component単位でpackageを組み合わせ、できるだけ小さく保っていくアプローチがマッチしていると感じています。Architectureの考えにのっとり,domain層(業務logic),httpに関連するcontroller層,データのCRUDを担当するrepository層の分離を意識したpackage構成にしました。Design(https://www.amazon.co.jp/dp/B075LRM681)や各種blog等を読ませていただき悪戦苦闘している状態です。Go(https://www.amazon.co.jp/12-Factor-Applications-Docker-English-ebook/dp/B075HWVLMC)が参考になりました。コードベースgithubを利用しているので、ここは特に意識しませんでした。依存関係Goのpackage管理にはdepを利用しました。設定は設定fileを用意することはせず、すべて環境変数から渡すようにしました。そのため設定値を管理するためにviper(https://github.com/spf13/viper)を利用したりはせず、直接環境変数を読んで構造体にbindするシンプルなものにしました。SecretsManager上に保持するようにしました。architectureにそっていれば自然と外部サービスへの依存はinterfaceとして切り出されているはずなので、特に意識することなく環境変数を通じた切り替えができました。実行この箇所は自分の理解が曖昧なのですが、リリースを一意に識別し、ロールバックする点については、ECRを通じたimage管理で実現できていると思っています。Serverだったので特に意識せずにstatelessかつshared-nothingが実現できたのではないでしょうか。bindingまで完結されるで特に意識しませんでした。理解が曖昧ですが、share-nothingが満足されていれば、自然と満たせると考えております。serverをshutdownする処理を加えました。autoscalingの中でappの内容をできるだけ意識したくないので、起動/終了処理が数秒で完了することは運用面からとても重要な性質だと実感しています。非同期で処理するジョブを抱え込んだりして、すぐに終了できなくなった場合は黄色信号で、Queue等を通じて処理を分散させる必要があります。appを読む前はログといえばログファイルに書き込んでローテションさせるものと思っており、app側が出力ストリームより向こう側を意識してはいけないという主張は極端だなと感じていました。ところが実際にapp側はSTDOUTに書き込むだけにすることで、logging関連処理をappから切り離し、ローテション処理やストレージ管理といった依存性もなくすことができました。ログ管理については後述します。管理プロセスこの考えは徹底できておらず、今後の改善が望まれる箇所です。定期実行が必要な処理はlambda等に切り出し、DBや外部サービスの管理は別途オーケストレーションツール(chef,ansible)で行っています。いうシンプルな構成をとりました。definition(docker-componse.yml)で制御しています。以下のようにlogging.dirverとしてfluentdを指定しています。Server同様、ECSで管理しています。logがどのように利用されるかはlogging処理作成時点ではわかっていない/運用次第で変化しうる箇所なので、いったんaggreageする層が必要だと考えています。ListenerのprotocolをTCPにする関係で動的ポートの設定ができず、1Host-1Taskなってしまっている点です。この点は今後の改善点ですが現状ではfluend側の機能で吸収しきれています。Serviceのひとつであるbigqueryがlogの最終的な格納先です。bigquery自体は既存システムが利用していた関係で採用されていますが、logを構造化して出力したい理由のひとつでした。いうのも、bigqueryは事前に定義されたschemaをもつので、loggingもアドホックにせず決められたkeyを出力する必要があったからです。plugin(https://github.com/kaizenplatform/fluent-plugin-bigquery)を利用してinsertしました。SQLが使えるのがとてもありがたいです。Mackerelはsimpleで使いやすくUIも洗練されていて,とてもすばらしいサービスだと思います。(もちろん(CLI)https://mackerel.io/ja/docs/entry/advanced/cli)ただし、リクエスト間隔は1分で固定なので注意が必要です。InstanceのMetricはECSを通じて収集しているので、mackerel-agent(https://github.com/mackerelio/mackerel-agent)は利用していないのですが、Go製でServerのMetricとはどうやって収集するのか興味があるので、ソースを読んで勉強させてもらいたいと思っています。AlarmをECSの各種Metricに設定し,SNS経由でpagerdutyに集約するようにしています。Eventで定期実行しています。filterを作成し、シンプルにlog中のerrorを拾ってMetricに変換しています。subscriptionを設定し、lambdaを呼び出しています。APIを呼び出しています。appに従うようにしておくと、アプリをコンテナ化して運用しやすいGoは楽しいお知らせハウテレビジョンでは、エンジニアを募集しています。AWS,Go,Dockerで一緒にシステムを作っていきませんか。NINJANINJAを防ぐにはどうするかおわりにはじめにこんにちは!世界で挑戦したいと思う学生に向けた就活支援プラットフォーム、外資就活ドットコムの開発チームです。Nativeでリニューアルの上リリースしました!(パチパチ)さて、このアプリは募集情報や体験記、コミュニティなど、比較的件数が多いリストを表示させる箇所がいくつかあります。いったリストも業界などのカテゴリやタグでのタブ切り替え表示やソート順などでの切り替え表示をさせています。遅延の少ない切り替えといったことが必要になってきます。それを実現するまでにどのような構成で作っていったか、また想定外のハードルも乗り越える必要があったのでそこで得た知見をシェアできればと思います。本題に入る前に主要なライブラリ構成を書いておきます。(使い方はreact-routerに似ている)styled-components:セマンティックにCSS設計ができるNativeBase:UIコンポーネント補助またこのようなディレクトリ構成になっています。企業名や体験記の種別で絞り込んだり、人気順などでソートすることも出来ます。実装上で気をつけているポイントさて、つらつらと書いていくと長くなってしまうので、気をつけたポイントを列挙していこうと思います。データの管理リストの内容とフォロー状態などのstateは分けるリスト取得時にフォロー状態も合わせて取得できるようなAPIにしていますが、それをreduxのstateに保管するときは内容とフォロー状態(KeyValue)、またページング(KeyValue)に分けて保管しています。することでフォローのコンポーネントがそのリストアイテム以外にある場合でも瞬時に状態を共有でき、変わった場合それぞれのコンポーネントで再レンダリングを走らせることが可能になります。下記のように、内容とページングはカテゴリ(タブ)ごと、またソート順ごとに保管するためそこまではObject(連想配列)で保管するのに対し、フォロー状態はアイテムのKeyValueなので単純な配列で保管しています。これはそうすることで単純なソート切り替え時に(すでに取得済みの場合)通信が走らずにパッと切り替えられるようにすることを目指しました。ページングも合わせて保管することでエッジケースの齟齬がないようにしています。Nativeではいかに再レンダリングを走らせないようにし、端末に負担をかけさせないようにするかが重要になります。そのためコンポーネントは(ユーザーがフォローを行うなど)頻繁に表示が変わりうるものとそうでないものは分けています。することでメモリ使用量の増大や突然アプリが落ちる事態を防いでいます。ちなみにここ、結論だけ見るとあっさりですがたどり着くまでは試行錯誤の連続でした。タブ切り替え時の挙動がモタっとしてしまいます。体験も大きく変わってしまうことがよくあるので気をつけましょう。リスト取得処理も合わせて行なっていたのですが、そうすると描画までもたついてしまうんですね。状態の変更を検知し、リスト取得処理を走らせるようにしました。これによりレンダリングはそこまで遅延せずに済むようになっています。17以降削除されてしまうという移り変わりの早さが良くも悪くもすごいですね。ソート順を保管し、各ソート順のページ状態も保管するも遅延の少ない切り替えに貢献しています。NINJA上で書いた実装上の気をつけるポイントをしなくても、社内でNINJAと呼ばれているレンダリングの不正が起こります。開発スタートした当初はリストで11番目のアイテムを表示させようとしただけでリスト全体がぐしゃっと重なった表示(隠れ身の術)になるなど、常にリスト周りは暗雲が立ち込めていました。タブもうまくデータ管理しておかないとタブが左右に高速回転しだす(分身の術)など、憎めないヤツです(笑)一番悩まされたのは下部メニューを切り替えるとたまーに真っ白になるケースでした。これはとあるウルトラCを使っているのですが、気になる方はぜひオフィスに遊びに来てください♪NINJAを防ぐにはどうするか一番疑った方が良いのは、意図せず複数のAPI取得が走っていないか、またニアリーイコールですが意図せぬ挙動が走っていないかです。いつ走っているか常にデバックしないとですね。それでもダメな場合はreactやredux、redux-saga公式のdocsとにらめっこしましょう。ほとんどの場合はなんとかなります。Nativeをこれからも使用していく予定です。(もっと大規模になるとAirbnbのように別の形をトライするかもしれませんが。Nativeにおいても既存のiPhone/Android開発の知見は必要な部分も多いので、そういう方で新しい技術にもトライしてみたい方など絶賛募集中です。ReactとかVueとかAngularとか触ってはいるけどまだアプリに手を出していない方も絶賛募集中です!ぜひぜひオフィスに遊びに来てくださいー!ご連絡はこちらよりお待ちしております。弊社サービスも日頃からお世話になっている、AWSとGCP。この両者が大規模なカンファレンスを東京で行うということで、参加してきました。Nextに2日間参加しましたので、ざっくりとしたレポートを掲載します。個々の発表には触れず、全体的な感想のみ記載します。基調講演があり、導入事例紹介や各サービスの紹介が行われるセッションがパラレルで開催される、という点は同じです。Summitでは豊富なセッションがあり、実に様々な機能・事例の紹介がありました。参加者も多く、広い会場が埋まっており勢いを感じました。Dayに大別されて会場が分かれており、専門や興味に応じた参加が可能でした。Day」として全てサーバーレスに関する発表がなされるという思い切った構成でした。Summitと同じような構成が取られ、発表内容も親しいものでした。規模は比較すると小さく、セッション数も少ないため、興味に合うものが見当たらないことも発生しがちだったかと思います。GCPが生まれた経緯を踏まえてか、一部セッションでGoogle社内システムの説明があり興味深かったです。API互換などに代表されるように、オープンであることを押し出しており、ロックインを自ら放棄する姿勢が素敵です。参加したセッションによりどうしても偏りがでますが、キーワードとして「マイクロサービス」が挙げられるかと思います。単純なサーバーはパブリッククラウドへの移行が順調に進んでおり、更に各サービスを利用させ、新サービスをクラウド上で構築させる段階に入っているのかな、と感じました。上記を踏まえ、発表内容は以下の2つに大別できるかと思います。各種サービスの利用促進1は、引き続きオンプレで運用しているサービスをクラウド上に移行してもらうためのものです。2は、AI系サービスの新規利用やマイクロサービス化など、今まで各自が実装していた機能を提供することで、利用量を増やすためのものです。これはロックインにも繋がります。この区分で言うと、1より2の発表が多く見え、何となく時代の流れを感じました。Summitの企業ブースは、配っているグッズを貰うと手持ちの二次元コードをスキャンされ、後ほどメールが届くという効率的なシステムでした。アンケートに答えると公式グッズがもらえます。何がもらえるかは行ってのお楽しみ。まとめAWS、GCP共に次々と公式サービス・関連サービスが追加され、開発者にとっては便利な世の中になっています。低コストで高度な機能が実現できるため、これを使わない手はないでしょう。どのような機能が実現できるかのイメージを掴むため、このような公式のイベントに参加してみてはいかがでしょうか。おまけハウテレビジョンでは、AWSやGCPの好きな仲間を募集しています。dayとして、業務と直接関係しない技術を学んでみたり、今まであまり触れてこなかった領域を調べたりしています。APIを使ったサービスのプロトタイプを作ってみました。音声処理が必要なWebサービスは限られますが、作ってみると意外に簡単で楽しいので、空いた時間に何か作ってみてはいかがでしょうか。弊社エンジニアの中で、noisliというWebサービスがにわかに流行りだしました。https://www.noisli.com/これが何かというと、「幾つかの環境音をミキシングし、好きなノイズを作って垂れ流せる」というサービスです。似たようなサービスは幾つかありますが、作った環境音を簡単に共有出来る点が楽しいです。各人が好き勝手に作った環境音がSlackで共有されていたのですが、「これは良い」「これは無い」という評価がある程度偏っており、ノイズにも良し悪しがあることが分かりました。APIを使って、作ったノイズの評価をリアルタイムで閲覧できるようなサービスを作ってみます。ここではプロトタイプとして、実運用で考慮すべき諸々は省いています。API、4はmaterial-ui、5はfirebaseがそれぞれ主なトピックです。環境構築まずはサービスを作成できる環境を整えます。今回はホビーなプロジェクトですので、以下のコマンドで最小限のReactアプリの土台を作ります。APIはMDNにドキュメントがありますので、まずそちらを読み進めてゆきます。contextやBufferなどの基本概念に軽く触れた後は、サンプルコードを見つつ動かしてみます。こちらのコードを利用し、ランダムなノイズを生成し2秒間流してみます。source.start();}createBufferで2秒間分のバッファを作り、そこにランダムな値を放り込んでゆきます。作ったバッファは出力にAudioContext.destinationを繋ぎます。これでページをロード(正確にはDOMをマウント)した際にノイズが流れるようになりました。音量調整このままでは音が大きいので、全体の音量を調整してみます。GainNodeをsoruceとdestinationの間に挟み、加工するイメージです。buffer;source.connect(gainNode);gainNode.connect(audioCtx.destination);source.start();これで小さな音量で再生することができました。valueは環境にあわせて設定してください。ファイルを再生するずっとランダムなノイズを聞いていいると精神が疲弊してきますので、環境音を再生させてみます。利用するとファイルからの非同期読み込みが行えます。いずれかを用いて行えます。今回はXHRでリソースを取得します。それをXHRで取得してオーディオバッファに渡し、以前と同じ流れで再生をさせます。再生部分はplayという関数にまとめています。付けるだけでループ再生してくれます。source.start();}再生・停止できるようにする現在はロード時に強制的に再生するようにしていますが、これをボタンで再生・停止できるようにしてみます。必要な処理として、以下が挙げられます。読み込んだオーディオデータを保存して再利用する再生・停止を切り替える処理を作るボタンを用意しonClickで切り替える今回は再生位置は関係ない(再生する度最初から始まる)ので、再生位置の保存などは必要ありませんでした。オーディオデータを雑にthisに保存するよう変更します。});};...次に、再生ボタンが押されたら、保存済みデータでsourceを作成する処理を作ります。source;}また、停止する処理も作成します。}}これらを切り替えて表示にも反映されるよう、toggle関数を作ってonClick時に発火するようにします。);}完成です!実際に切り替わるかを試してみてください。今までは単一のサウンドファイルを再生してきましたが、複数のサウンドを読み込み、合成して出力してみます。グラフなので、ノードとエッジを増やすだけで同じように処理出来る気がしますね。複数ファイルの読み込みまずはオーディオデータ読み込みを複数ファイルに対応します。ファイル名を指定してXHRの結果をキャッシュする処理を括りだし、それをファイル名のループで呼び出します。'wav'));}これで、複数のオーディオファイルデータを簡単に読み込めるようになりました。サウンドの合成DTMをやったことがある方には馴染みのある現象かと思いますが、複数の音源から好き勝手に音をだすと、一定のレベルを超えた所で音がビリビリに割れてしまいます。そんな時はコンプレッサーと呼ばれるものを挟み、大きな音を絞って調整します。いうものが用意されており、同じような処理が可能です。https://developer.mozilla.org/en-US/docs/Web/API/DynamicsCompressorNodeそのため、作成するグラフは、「複数のsource」→「コンプレッサー」→「全体のゲイン(音量)調整」→「出力」という流れになります。実装としては、まず汎用的な処理にするため、sourceを作成する以下の処理を関数として括りだします。source;}その後、複数のsourceをまとめて作成・connect・startさせる処理を記述します。}}個々の音源の音量を調整する個々の音源のバランスを調整するため、それぞれのsourceにもGainNodeをくっつけます。});これで、0.3という固定値を持ったGainNodeを各ソースに紐付けることができました。後ほど、ここは調整されたパラメータがやってくる予定です。この段階で、スライダーで全体のゲインを変えられるようにしました(ソースは省略しますが)。1000]などにしておき、Gainに渡す際は1/1000すると細かく調整できて便利です。UIを作るさて、このセクションは一休みとして、主にUIを作ります。リストなどの表示をするのに、通常のulやliをそのまま使うと少し不格好です。頑張ってCSSを当てても良いですが、ここではMaterial-UIを入れて表示を整えてみます。今回はSlider、Table、TextField、Buttonの3つのみで事足りました。React”だった文字なども変えておきます。結果、以下のような表示になりました。手抜き感はありますが、最低限使えるものにしています。投票ボタンがキモですが、この段階ではとりあえず置いているだけで、クリックしても何も起きません。投票結果を保存して共有するために、サーバーとDBが必要です。ここではFirebaseの無料プランを使って、お手軽に開発をしてゆきます。Firebaseの初期化は、コンソールからプロジェクトを作って初期化コードを埋め込むだけの簡単設計です。https://console.firebase.google.com/?hl=jaただし、今回はReactから使うため、NPMとして使います。-SDBへの保存そのままではDBに書き込むのにログインが必要なため、とりあえず全開放のルールを設定します。FirebaseコンソールのDatabase以下、ルールタブから設定できます。}}もちろん、プロトタイプ以外では、しっかりとルールを設定しましょう。全ての情報を誰でも閲覧・編集できてしまうため極めて危険です。パラメータとそれに応じた評価を格納すれば良いので、以下のような形式で保存してみます。8認証が無いためシンプルです。itemの変更を検知するので、ユーザー数が増えそうならもう少し工夫をする必要がありますが、今回はプロトタイプなので手を抜いています。実際にデータが入ると以下のようになります。DBにノイズのデータを書き込むユーザーが好きなパラメーターを投稿できるようにします。このように適当なフォームを作り、入力を受け取れるようにします。“CREATE”ボタンが押されたら、フォームの値を取得し、合計が1.0の時のみデータベースに送信します。});}送信処理は親から渡されており、子コンポーネントはそれにパラメーターを渡して発火するだけです。送信処理はこれだけです。});};DBからノイズのパラメータを取得する上記のような処理でデータが詰められてゆきますので、適切に取得する必要があります。firebaseではDB上のパスを指定し、継続的に変更を検知することができます。値を検知するには以下のようにコールバックを指定します。})})orderByXXXで特定の値によりソートをすることができます。indexやlimitなどを考慮する必要がありますが、今回はプロトタイプなので大量のデータを受け取るのも許容してしまいます。評価を書き込む評価を変更する箇所ではトランザクション処理にして、複数人が同時に評価してもデータが破損しないようにします。value;});デプロイするさて、一応機能ができた所で、デプロイして使ってもらいます。Firebaseのホスティング機能、create-react-appのbuild機能により、以下のように簡単にデプロイすることができます。deploydatabase.rulesができた場合は、以前ルールを書き換えた場合と同様に書き換えておきます。APIを使い、ちょっとしたサービスのプロトタイプを作ってみました。create-react-appなどのテンプレート、material-ui、そしてFirebaseを使うとこのようなサービスが簡単に組み立てられますので、プロトタイピングにはオススメです。dayとして、業務と直接関係しない技術を学んでみたり、今まであまり触れてこなかった領域を調べたりしています。Dataflowに入門し、簡単なデータの分析コードを組み、動かしてみました。簡単に強力な並列処理が出来るので、ログの分析などで活用できそうです。Cloudで提供されているデータ処理用のプラットフォームです。2017/04現在、JavaとPythonのクライアントが提供されております(Pythonはβ版)。「便利だよ!」という話はよく訊くのですが、実際に使ってみたことはなかったため、これを機に入門してみます。できたこと基本的なDataflowの使い方、そのコンセプトを把握しました。簡単なデータ処理として、「Trump氏のツイート」を対象に「1週間ごとのつぶやき数」を集計、ただし「RTは除く」、という3つの条件でカウントをしました。進めかた利用方法をまとめてくれている有用なブログ記事もありますが、変化が激しいのとまとまった時間があるため、下記のGoogle公式のドキュメントを使って入門してみます。https://cloud.google.com/dataflow/docs/また、せっかくですので、Pythonのクライアントライブラリを使って進めます。やったことクイックスタートhttps://cloud.google.com/dataflow/docs/quickstarts/quickstart-pythonセットアップまずは新規プロジェクトを作り、APIを有効にします。コマンドのインストール、認証などは事前に済ませているものとします。Storageにバケットを作成します。現状Pythonのバージョンは2.7のみ使えますので、pyenvで固定しておきます。必要なコマンドはpipになっているため、簡単にインストールできます。ローカルでの実行、リモートでの実行のそれぞれが載っているので、両方試しておくと無難です。公式ドキュメントどおりリモート実行を下記コマンドで行うとエラーが出ます(2017/04現在)。$BUCKET/outputエラーメッセージはこの通り。書き換えて実行します。正常に実行されると5分ほどかかり、操作が完了します。ステップごとに実行している様子はGCP上で確認できます。https://d2mxuefqeaa7sj.cloudfront.net/s_8ACB1D17AA95783CAEC7C335CBA2166A66ED243120AE0FF2F7C766C37CADD651_1492145861146_+2017-04-14+13.56.03.pngStorageに結果が出力されていることも確認しておくと安心です。パイプラインについてサンプルが実行できたので、次にコンセプトを学んでゆきました。公式ドキュメントが充実していますので、重要な所を拾い読みすると捗ります。書かれており、分岐やループが出来ることが併せて述べられています。beam)は関数型言語で書くような感覚で記述すれば良いことがわかります。実際サンプルで挙げられているコードも、以下のようにmapやflatMapなどをメソッドチェーン的に呼び出しており、見慣れた形になっています。beam.io.WriteToText(my_options.output))サンプルを実行するとまたしてもエラーが出ます。以下のように修正します。pipeline_options.view_as(MyOptions)実行してみると、前回と同様の結果が得られました。実践https://cloud.google.com/dataflow/pipelines/constructing-your-pipelineパイプラインのコンセプトをほんのりと理解したので、その周辺の理解を深めるため、実際にデータ処理を行ってみます。今回は簡単なデータ処理として、「Trump氏のツイート」を対象に「1週間ごとのつぶやき数」を集計、ただし「RTは除く」、という3つの条件でカウントをします。ちなみに、以下が対象の「本物」なTrump氏のTwitterです。https://twitter.com/realDonaldTrumpデータとしてツイートの一覧が必要なので、tweepyでさっくりと取得しました。全ツイートは制限により取れないため、直近の約3000ツイート程度です。毎回リモートで実行するのは時間がかかるので、ローカルでパイプライン処理を実行させます。指定するだけでローカル実行されます。処理がすぐ返ってくるので「実行されてない?」と思ってしまいますが、バックグラウンドで動いています。すると結果が同じように出力されます。パイプラインの組み立て目的の処理を実現するため、今回は以下の流れで処理をしてゆきます。count)結果を出力するでは、パイプラインのステップを順番に見てゆきます。beam.io.ReadFromText(my_options.input)RTのツイートを除外これはフィルタリングするだけで事足りそうです。入っていれば除外とします。いうプロセッサがあるので、これをありがたく利用します。x)各行のタイムスタンプを設定するBigQueryやStorageなどからではない、テキストから読み込んだファイルなどは、全ての行が共通のタイムスタンプを持っています。データとして持っているものを自動で認識してくれる訳ではありませんので、自分で設定してあげる必要があります。https://cloud.google.com/dataflow/model/windowing#TimeStampingJavaではParDoという変換が用意されていますが、PythonではさらにMapとFlatmapが用意されています。使って出力をすれば良さそうです。区切られたTSV形式になっているので、日時と内容を分離します。https://t.co/ZtC14AJ0xs次に、タイムスタンプが日付形式になっているので、Unixタイムスタンプに変換します。返してあげれば、DoFnの完成です。グローバルに読み込むと、各関数が別のマシンで実行された際にimportがされておらずエラーになってしまいます。https://cloud.google.com/dataflow/faq#nameerror-作ったクラスはParDoで適用すればOKです。beam.ParDo(ExtractUserAndTimestampDoFn())ウィンドウで区切るタイムスタンプを一定の区間で区切るものとして、ウィンドウという仕組みがあります。https://cloud.google.com/dataflow/model/windowingデータ集計ではよく出てくる方法ですので、標準で用意されていて便利です。いう関数を利用します。これも公式ドキュメントには無いので、Githubのサンプルから漁ると見つかります。いう形に変換し、groupByが出来るようにします。これは以下のようなクラスを作り、いつも通りにParDoで適用します。beam.ParDo(WithWindow())カウントと出力これは標準で提供されているプロセッサを適用させれば完了です。beam.io.WriteToText(my_options.output))処理のまとめ処理部分のソースは以下のようになりました。beam.io.WriteToText(my_options.output))各ステップでやることがはっきりしているので、分かりやすいですね。実行してみると、以下のような出力が得られました。38)もちろん、数の代わりに平均を出したり、ひと月あたりに変換したり、ということがすぐできます。いうファイル名で保存したとします。このまま意気揚々とリモートで実行をするとコケてしまいます。これは、例えばdatetimeなど、グローバルでimportしているパッケージをParDoなどで使用しているためです。ParDo内で実行された関数は、並列に別のマシンで実行されるため、importしていない事になってしまいます。オプションを利用します。他は同じように、リモートで実行するよう指示を出します。--save_main_sessionしばらくすると、ローカルで実行したものと同じ結果が出力されました!まとめDataflowに入門し、軽いデータ処理が行えるようになりました。並列性の高い処理が簡潔に記述して実行できるため、特に大規模なデータを扱う際には重宝しそうです。軽い気持ちでPythonクライアントを使うと辛いことになるということがわかりました。ドキュメントが充実していないのはしょうがないにしても、重要な機能であるストリーミング実行がJavaでしか対応していないなど、まだまだ未対応なので使う際は強い意思を持ってご利用ください。ドキュメントがおかしい時はフィードバックを送ってみましょう。上記で問題になっていた箇所には既にフィードバックを送っているので、もしかしたら直っているかもしれません。dayとして、業務と直接関係しない技術を学んでみたり、今まであまり触れてこなかった領域を調べたりしています。今回は複数人で集まってRustのチュートリアルを読み進め、実際に簡単なコードを組み、動かしてみました。結果として、今から入門するのに向いた言語で、特に今まであまり多くの言語を触ったことのない方にお勧めできる、ということが分かりました。Rust?Rustでは、通常のWebアプリケーション開発ではあまり気にすることのない、低レベルな処理を学べます。いわゆる関数型言語の特徴を取り入れているためそのパラダイムを学んだり、静的型付けに慣れることができます。C++やHaskellといった言語を触ったことのある人にはお馴染みですが、RubyやPythonしか触ったことがないというメンバーもいますので、これを気にまとめて学んでしまおうという寸法です。利点をまとめると以下になります。メモリの状態を意識できるようになる静的型付けに親しめる様々なパラダイムに触れることができる(特に関数型)WebAssemblyで使えるかもしれない最近の話題についていけるこのように多くの利点がある便利な言語ですので、Rustを選択しました。一部リファレンス)を読んだ過程と、入門をおすすめする理由を記載してゆきます。やったことRustの公式チュートリアルを読み進め、実際にサンプルを動かしたり、改変したりしました。読んで進めてゆきました。ガベージコレクタ無しで実現するとのことで、肝になるメモリ管理をどうするのか、幾つか推測が話されました。組み込み環境が利用目的に入っているためか、対応プラットフォーム一覧がとても充実しています。簡単に導入ができました。World!単純なプログラムですが、なかなか重要な情報が詰まっていました。println!は関数ではなくマクロだということや、インデント・スペースの規約がさらりと述べられていたりします。コンパイラの説明も、Rubyなどの動的言語しか触ったことがない人のため懇切丁寧に書かれており、入門に向いています。続いて、ビルドツールであるCargoの説明が入ります。いった便利なコマンドが紹介されました。便利さに慣れてしまった我々も安心の親切設計です。ディレクトリの中を覗いてみましたが、ディレクトリ名を見ただけでそれがどのようなものか分かる、綺麗な構造になっていました。「インクリメンタルビルドをする」などの後々説明が入る特徴もディレクトリ名を見るだけでおおよそ推測でき、ツールへの安心感が芽生えました。数あてゲームのチュートリアルライブラリの読み込みや変数束縛やimmutabilityなどの説明が入り、いよいよコーディングに入ります。紹介されているのはおおよそ他の言語でおなじみな機能ですが、懇切丁寧に説明されているので初見でも理解が進みます。一部、パターンマッチや所有権の話も出てきますので、関数型やC++に触ったことが無いと少し理解が大変でした。所有権はサンプルコードを書き換えて、内部の仕組みを推測しながら進めました。traitや所有権の詳細ページで出てきて氷解しますので、とりあえず先に進むことをおすすめします。基本的な所を見てゆき、読み終わった後は簡単なプログラム(FizzBuzzなど)を各自作成しました。いじってみた中で、以下のコードが生まれました。後々ドキュメントを読み進めてゆくと出てくるのかと思いますが、挙動が面白かったです。error!実際に動かすとコンパイルエラーが出るので、そのメッセージを見ると原因が分かります。チュートリアルの後ここからは、各機能の詳細ページです。Ownership」まで読み進めました。Ownershipのページは今までの謎が解ける感覚がありますので、Rustの入門としては外せないページでした。メモリ管理関連のページは3つに分かれており、残り2つも読むことが強く推奨されています。次回は続きから読み進めたいところです。言語周辺で良いと思ったところチュートリアルを終えて、言語の周辺で良いと思った点をまとめます。便利なビルドツールが用意されているディレクトリ構造が分かりやすい新規プロジェクト用のコマンドが用意されている「言語の強力さ」「開始のお手軽さ」「ドキュメントの丁寧さ」を兼ね揃えており、これから学習するのに向いている言語だと感じました。新しい言語を使うのに際し、リファレンス的にドキュメントを参照して学習を進めることもありますが、今回はドキュメントに沿って進めたため以下のような感想が挙がりました。“新しい言語を学習する際に、チュートリアルを丁寧になぞるという事をあまりしないので、よい経験になった。複数人で読み合わせすることにより、理解があいまいな箇所、解説の意味・意図を勘違いしてしまうことを防げたと思う。男性)一方で、全員で同じドキュメントを読み進めたのみでしたので、以下の改善案も挙がっています。“皆で同じことをやるのも良いが、アウトプットが似たり寄ったりになってしまうので、次はもくもくタイムと簡単な発表の時間を設けても良いかもしれない。男性)そのため、ある程度の時間を確保し、自習や好きなものを作ってみる時間を取るのが良さそうです。時間を見積もるのは難しいですが、お題を先に決めておいて、それをどのように実装したか、発表とレビューを行うのも良いと思いました。同じようにドキュメントを読まれる際は、是非参考にしていただければと思います。まとめ今回はRustのチュートリアルを利用し、入門してみました。今までRailsやJSだけ書いてきた、という方にもお勧めな入門しやすい言語だと思います。他の言語を学んでみたい場合のご参考になれば幸いです。おまけハウテレビジョンでは、プログラミング言語の好きな仲間を募集しています。dayとして、業務と直接関係しない技術を学んでみたり、今まであまり触れてこなかった領域を調べたりしています。最先端の研究を知るのに、カンファレンスの論文を読むのは有効な手段です。役立つことは多くないですが、理論を応用できたり、今後どんな技術が出てくるのかを知ることができます。Engineering)の論文をざっくり読んでゆきます。2017の論文を読みます。やって読むの?と思いますが、Preprintsとして事前に論文を公開してくれている場合があるので、それを利用します。公式Twitterによると、おおよそ66%の論文がpreprintsとして集まっているようです。https://twitter.com/ICSEconf/status/841892455809187840preprintsはこちらに掲載されていますので、原文を読みたい方はこちらから辿ってください。Gall(南京大学・ロンドン大学・チューリッヒ大学)概要の大雑把な訳:APIドキュメントは開発者にとって最も重要なドキュメントだが、よくソースコードとずれが生じており、開発の効率や品質に関わる問題になっている。本論文では、ソースコード理解と自然言語処理を利用し、自動でこのずれを検出する方法を提案している。手法としては、引数の制約(NonNull、型など)と吐く可能性のある例外に関するAPIドキュメントの記述を利用する。この内容を用いて、制約ソルバを使ってずれを検出する。APIの中から1146個のずれを検出した。プレシジョンは81.6%、リコールは82.0%となり、実際に使えることを示した。ドキュメントとずれている状態はよく直面する。早く普及して解消されて欲しい。ドキュメント中に「ずれてますよ」というマークがあるだけでも便利そう。ハルビン工程大学)概要の大雑把な訳:開発者はどんどんAPIチュートリアルに頼るようになっている。不慣れなAPIの中からチュートリアルのコード片を探すのは未だに困難である。既存手法では、大量にコーパスを手動で作る必要があり、悩まされていた。本論文では、FRAPT(APIをページランクとトピックによりコード片をリコメンドする)というアプローチを取り、自動で行えるようにしている。FRAPTでは、APIに関連するチュートリアルとなるコード片を決定する上で生じる2つの課題に挑戦している。1つ目は、「代名詞と変数の解像度問題」として、チュートリアルとなるコード片の中からAPIを特定し、抽象的な代名詞と変数をAPI名や即した文脈に置き換える、という問題。2つ目は、「説明にならないコード片の検出問題」として、不要なコード片を除去するフィルターを作成する問題。これらの問題を解決し、トピックモデルとページランクアルゴリズムの両方を適用することで相関係数の算出と関連するコード片の集約ができた。オープンなデータに対して本手法を適用し、既存手法に比べF値で8.77%→12.32%に精度が向上した。加えて、本手法の核となるコンポーネントの効率性も検証した。既存手法でも同様かもしれないが、「開発者はAPIドキュメントのチュートリアルに頼っている」という切り口が良い。チュートリアルはAPIの習熟に大きく関わる要因なので、こちらも実務に直接関わってきそうな内容。Pradel(ダルムシュタット工科大学、シカゴ大学)概要の大雑把な訳:並列プログラムを書くのは難しく、困難な問題を隠してくれているスレッドセーフなクラスに頼ることが多い。これらのクラスのテストは並列プログラムの正確性を担保する上で極めて重要な問題である。テストの見逃しを減らすため、自動生成した並列テストを作成することは効果的な手法である。ランダムに作成する既存手法があるが、これは計算コストが高い解析に依存していたり、特定のバグに依存していたりする(アトミック性など)。本論文では、CovConというカバレッジでガイドしてテストを作成する手法を提案する。2つのメソッドをペアにして、それらがどれくらい並列に実行されたかを計測し、その頻度に着目する。本手法では特定のバグのパターンに依存するものではなく、あらゆる並列実行時のバグを検出できる可能性がある。計算コストが高くなく、短時間で多くのテストを生成することが出来る。本論文ではCovConを18個のスレッドセーフなJavaのクラスに適用し、17のバグを見つけた。既存の5つの手法に比べ、CovConは短時間でかつより多くのバグを見つけた。詳細には、38/47のケースでより早くバグを見つけ、22/47のケースでは4倍近い速度で検出をした。手法としてはシンプルに見えるが、検出精度も速度も大きく向上しているらしく意外性がある。スレッドセーフなクラスには多くの人が頼っていると思うので、その裏側で日々研究がされているのを見ると面白い。Wang(バージニア工科大学、南カリフォルニア大学)概要の大雑把な訳:競合状態はWebアプリケーションでよく発生するが、原因を突き止めるのが難しく、修復するのも難しい。positive)」が大量に出る。ニセの検出とは、bogus(実際にはまず起こらない)、benign(エラーを引き起こさない)の両方を示す。手動でこれらの検出結果を調べることは大変で間違えやすいため、これらの検出結果を提示することは非生産的である。本論文ではプラットフォームに囚われない、決定性の実行に基づいた手法により、実際に起こり有害な競合状態を特定する。手法としては、競合するイベントのペアを2つの異なった順番で実行し、プログラムの状態に及ぼす影響を評価する。(1)両方のイベント実行が実行完了すること、(2)それぞれが異なった状態を生み出すこと、という両方の条件を満たすものと定義する。Fortune500の企業で使われている大規模で実際に使われているWebサイトに対して本手法を適用し、既存の手法を大きく上回る効果を示した。概要だけでは詳細は分からないが、実際にかけてみやすい類のツールなので、公開されていたら類似ツールも含めて試してみよう。Sen(オーフス大学、米サムスン研究所、ノースイースタン大学、カリフォルニア大学バークレー校)概要の大雑把な訳:モダンなWebアプリはイベントドリブンで書かれており、イベントハンドラが非同期にユーザーやシステムのイベントを処理する。このスタイルでは、非決定性が致命的なエラーを生じさせうる。近年の研究ではイベント競合とその分類(有害かそうでないか)にフォーカスをしている。ソースコードをこれらの競合が起こらないようにするのは難しく間違えやすいため、よくない実行をさせない方が望ましい。本論文では、JavaScriptで書かれたWebアプリケーションで発生するイベント競合を自動修正する手法を提案する。この手法では、イベントを後で実行させたり破棄して競合を回避する、というポリシーを適用するため、イベントコントローラーを用意しブラウザ内のイベントハンドラのスケジューリングを制限する。本手法はEventRaceCommanderというツールにし、Fortune500の中で大きな20のWebアプリケーションに対して適用し、100以上のイベント競合を検出した。アプリケーションに依存しない修正ポリシーは、パフォーマンスやユーザー体験を大きく損なうこと無く十分にイベント競合を解消したが、特定の修正ポリシーを定めた方が望ましい場合もある。1つ前の論文とは別のアプローチで競合状態に挑んでいる。スケジューリングの方法がかなり複雑になりそう。実行時に発生させないようイベント自体をずらすのは面白いが、逆に分かりにくいバグの原因が増えてしまいそう。Sen(カリフォルニア大学)概要の大雑把な訳:トラバーサル(機械的に一部・全部のデータを辿る処理)はデータ構造に対する最も基礎的な処理である。本論文ではTRAVIOLIという動的解析でトラバーサルを検知するツールを提案する。ここでは、ループや再帰の中にある、配列やリスト・木などのトラバーサルを正確に検出することを可能にする、非環(acyclic)な実行コンテキストを導入する。本論文では、「どのようにTRAVIOLIの実行結果をデータ構造のトラバーサルの可視化に利用するか」「パフォーマンスの劣化はどの程度か」「無駄なトラバーサルによる性能劣化の検出をどうするか」について説明する。実際に使われている5つのJavaScriptのプログラムに適用し、誤検出は4%以下だった。結果は概要にはない)。D3とexpressに性能劣化を検出した。概要を読む限り、動的解析だとどうしても誤検出が増えそうだが、どのようにして減らしているのかは読み込まないと分からなさそう。Rosenblum(ウーロンゴン大学、ロンドン大学、シドニー工科大学、シンガポール国立大学)概要の大雑把な訳:ソフトウェアシステム、特にサービスは実行時のパフォーマンスが要求される。パフォーマンスが落ちている場合、再設定によって対策をする。その対策が反映されるまでしばらくラグがある。そのため、現在のシステムを受動的に監視することは勿論大事だが、将来のパフォーマンスを予測することも大事である。連続時間マルコフ連鎖(CTMC)は時間を区切ったパフォーマンスのメトリクスを算出するのに適している(例えば、ある将来の時間でパフォーマンスの劣化がどれくらい起こりうるかを求める)。CTMCを活かす上で課題となるのが、遷移率などのモデルパラメーターを実行中に計測すること。これらのパラメーターはシステムや環境によって頻繁に更新されるため、正確な値を与えるのが困難である。本論文では、既存のCTMCモデルを、遷移率として不正確で区間の中での予測値を許容するよう拡張したProEvaというフレームワークを作った。ProEvaは不正確なモデルの出力として、漸近的な式と境界を計算することをコアな手法としている。精度とオーバーヘッドについても触れている。数値予測の理論的な論文なので、読むのは骨が折れそう。サービス監視系のツール開発に特に役立つ内容に見える。Dovom(コンコルディア大学)概要の大雑把な訳:ラムダ式はJava8で関数型プログラミングをサポートするため導入され、関数を引数として渡すことで「動作のパラメーター化」を実現した。既存のコードクローンは異なった動作をするものが大部分(Type2、Type3に分類されるもの)である。筆者らの知る限りでは、これらのコードクローンをラムダ式を用いて共通化する研究は無かった。本論文では、ふるまいの違うコードクローンを、ラムダ式を用いてリファクタリングできるかを調べる手法を提案する。大規模なコードクローンのデータセットに対し適用し、適用可能性と、リファクタリングに使われたラムダ式の特徴を示している。結果、他の手法ではリファクタリングできなかった多くのクローンに対して、ラムダ式を使ってリファクタリングができた。普段からよくこの手のリファクタリングはするものの、そういえば研究されてるという話を聞かなかった。いい所を突いた感じがある。リファクタリング提案機能が備わっているIDEが増えているが、この機能が搭載されれば開発の強力なサポートになるのでは。Lab)概要の大雑把な訳:ログのスニペット(Log.infoやSystem.out.printlnなど)は開発者がソフトウェアに埋め込む。ログの中で出力している変数が無くなったり、NPEになったり)。加えて、パフォーマンスが落ちたり、ディスクI/Oが増えたりする問題もある。最近の研究では、効果的なロギング方法がしっかりと定められたコーディングガイドラインは無いとされている。ロギングに関する先行研究の多くは、「どこに」「何を」ログを取るか、に主に取り組んでおり、「どのように」ログを取るか(ロギングコードの開発・保守性)に取り組んだ研究は非常に少ない。本論文では、ロギングのアンチパターンを特徴づけ、及び検出を行い、「どのように」ログを取るかの問題に取り組む。ロギングコードの大部分は対象となるコードの進化に伴い変化してゆき、残りはアンチパターンの解消のために修正される。本研究では、3つのよくメンテナンスされているOSS(ActiveMQ、Hadoop、Maven)に対し352個のロギングコードに対する変更をチェックした。その結果、6つのアンチパターンが見つかった。この発見の有用性を示すため、これらのアンチパターンの検知をするLCAnalyzerというツールに実装した。LCAnalyzerを使った実験では、リコールが95%、プレシジョンが60%でアンチパターンを発見し、未知のアンチパターンの発見にも使えることを示した。フィードバックを得るため、64の代表的な検出結果を10個のOSSで修正して送った所、46個(72%)が(この時点で)マージされた。普段開発する中で、たしかにロギング処理はとっ散らかりがち。level」など、よくやってしまうものが多い。たかがログのコードと侮らず、ちゃんとメンテナンスしてゆくことが必要だと考えると、アンチパターンという分かりやすい形でまとめてくれているのはとても有用だと思う。まとめまだまだ面白そうな論文がありますが、ここで一旦終わります。ソフトウェア工学という分野の特性か、上記9つの中でも実用的な内容が多く、実際に使われるイメージが持てるものが多かったです。上記概要で気になった論文があれば原文を読んでみてください。残りの論文もタイトルを眺めて、面白そうなものを探すと良いかと思います。おまけハウテレビジョンでは、論文の好きな仲間を募集しています。はてなブログPro『外資就活ドットコム』の開発チームです。技術ネタ・プログラミングネタ等々書いていきます。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。