Yearly Archives: 2017

2017-12-11

Java 9 ModularityでJigsawを学ぶ

GMOアドマーケティングのT.Nです。

今年の9月にJava9が正式にリリースされました。
弊社ではまだJava8を使用していますが、
Java9へのアップグレードに備え、勉強しているところです。

Java9の変更点はいくつかありますが、
最大の変更点とも言えるJigsawについて、以下の本を読んで学んでいます。

本を読んで学んだことなどを、数回に分けてブログに書く予定です。
今回は、Jigsawの概要について書きます。

Jigsawとは

Project Jigsawという、Javaのプラットフォームをモジュールに分割するプロジェクトのことです。
Java9でJDKがモジュールに分割され、
モジュールを使ったアプリケーションの設計が可能になりました。

モジュールとは

他のモジュールとの依存関係や公開範囲が明確な、
適切にカプセル化されたソースコードの集まりです。

モジュール化のメリット

  • 外部に公開するもの、公開しないものを明確にできる。
  • クラス同士が予期せぬ依存関係を持つことを防ぐことができる。
  • 実行時にクラスパスが存在しないことで起きるエラーを防ぐことができる。
  • 攻撃にさらされる部分を減らすことができる。(リフレクションによるアクセスも制限できる。)
  • 必要なモジュールが明確なので、JVM起動時に必要とするモジュールの最適化ができる。

モジュールの定義

公開するパッケージや依存するモジュールは、module-info.javaに記述します。
module-info.javaは、モジュールごとに定義します。

以下はJava9で追加されたjshellのmodule-info.javaです。
(jshellというのは、コマンドラインでJavaの処理を実行できる機能です。
コマンドラインでjshellと入力することで起動できます。)

module-info.javaには以下のように依存関係が定義されています。

module-info.javaの記述方法

requires

依存するモジュールを定義できます。

exports

公開するパッケージを定義できます。
(privateなフィールド、メソッドなどのリフレクションは許可しません。)

opens

実行時にリフレクションによる参照を許可するパッケージを定義できます。
opensに指定したパッケージは、コンパイル時には参照することができません。

provides, uses

ServiceLoaderを用いた依存関係を定義できます。
モジュールを利用する側では、
供給側のインターフェースの情報のみを持っていれば、実装クラスの処理を実行することができます。
利用する側には実装クラスの情報がないので、
供給側では実装クラスを柔軟に変更することが可能になります。

Annotations

モジュールには、@Deprecatedなどのアノテーションをつけることもできます。

ClasspathとModule Path

Java9以前では、classpathを参照して、JVMがクラスをロードしていましたが、
Java9からは、module pathが使用されるようになりました。
Java9でもclasspathは存在しますが、モジュールからはclasspathを参照することができません。
モジュール化されていないクラスからは、
classpathを通して今までと同じようにクラスを参照できます。

Automatic ModulesとUnnamed Module

モジュールからは、classpathを参照することができないので、
モジュールからモジュール化されていない既存のJARファイルなどを参照する場合は、
Automatic Modulesという仕組みを使用する必要があります。
コンパイル時にオプションで指定することで、
モジュール化されていないJARファイルなどをモジュールとして扱うことができ、
モジュールから参照することができます。

Automatic Modulesは、モジュールであるため、classpathを参照することができませんが、
classpath上のクラスは、Unnamed Moduleとして扱われ、module pathからも参照できるので、
モジュール化されていないクラスも参照することができます。

Moduleクラスについて

Java9でjava.langにModuleというクラスが追加されました。
Moduleクラスには、addExports、addOpens、addReadsのようなメソッドがあり、
実行時にモジュールを操作して、依存関係を変更することができます。

これらのメソッドを使用して、
本来は公開されるべきではないモジュールに対する参照を得ることなどができそうですが、
実際にはできないようになっています。

これらのメソッドには、
@CallerSensitiveというアノテーションが付与されており、
メソッド内で呼び出し元が適切であるかのチェックが行われています。
変更対象のモジュール内のクラスから実行された場合のみ、変更を行うことができます。

最後に

今回はJava 9 Modularityを読んで学んだことをまとめました。
途中までしか読んでいないので、簡単な内容のみになりましたが、
今後読み進めていく中で学んだことを、弊社でのモジュール化対応に活かし、
次回はそちらの内容についても書けたら良いと考えています。

2017-12-07

SparkのWebUIでモニタリング

皆さん

こんにちは、GMOアドマーケティングのS.Rです。

SparkのProgramを開発する上で、Performanceの改良やInstanceの設定のTuningはかなり重要です。

これらのチューニングはSparkのWebUIを使えばかなり簡単に制御できます。

そこで、今回はSparkのWebUIを皆さんへ紹介致します。

※この記事を理解するには、Spark、Hadoop、Linuxのshellコマンドの基本知識が必要です。

1 Sparkとは?

Sparkの概要は以下のWikipediaの記事を参考にして下さい。

Apache Sparkはオープンソースのクラスタコンピューティングフレームワークである。カリフォルニア大学バークレー校のAMPLabで開発されたコードが、管理元のApacheソフトウェア財団に寄贈された。Sparkのインタフェースを使うと、暗黙のデータ並列性と耐故障性を備えたクラスタ全体をプログラミングできる(Apache Spark、2014年5月30日、ウィキペディア日本語版、https://ja.wikipedia.org/wiki/Apache_Spark)

 

2 Sparkのインストール:

  1. Sparkの公式ダウンロードサイトで任意のバージョンをダウンロードします。
    今回は例として最新のSpark2.2.0、Pre-bulit版をダウンロードしました。
  2. Sparkのモードを選びます。Sparkには3つの起動モードがあります。
    1. WorkerNodeがない状態で起動します(Standalone Deploy Mode)。
      今回は例としてこのモードで説明します。
    2. Yarnで起動します。YARN(Yet Another Resource Negotiator )は、Hadoopクラスタのリソース管理、ジョブスケジューリングを担当するモジュールです(YARN、2014年5月30日、ウィキペディア日本語版、https://ja.wikipedia.org/wiki/Apache_Hadoop#Yet_Another_Resource_Negotiator_.28YARN.29)
    3. Mesosで起動します。Mesosはカリフォルニア大学バークレー校の研究機関AMPLabのプロジェクトによって開発されたクラスタのリソース管理のモジュールです(Mesos, 30 October 2017, Wikipedia, https://en.wikipedia.org/wiki/Apache_Mesos)
  3. SparkのShellを起動します。Sparkは四種類のShell(Scala, Java, Python, R )を実行できます。
    今回は例としてScalaのShellを起動します。起動するコメントは下記です:

SparkのShellを起動すると下記の画面を確認することが出来ます:

図1:Sparkの起動画面

3 WebUIへアクセス:

今回は二つモード(StandaloneとDataproc)でSparkのWebUIをアクセスする方法を紹介します。

  1. Standalone:
    例としてStandaloneモードでSparkの公式サイトに記載されているLinearRegressionのSampleCodeを実行します。SampleCodeやデータはSpark公式のGithub(Source CodeData)からDownloadしてください。今回はWebUIを確認しやすくするために、ソースコードの最後に下記の”halting”のコードを追加します。

    操作の手順は以下の通りです:

    1. Sparkをインストールします。
    2. LinearRegressionのSampleCodeをsubmitします。
    3. SampleCodeが動作しているときにBrowserへMaster NodeのIPやPortを入力してWebUIへアクセスします(Standaloneの場合はhttp://127.0.0.1:4040/jobs/を入力します)。
      WebUIのアクセスに成功すると図2のような画面を確認することが出来ます。
      WebUIの各部については第3章で詳しく説明します。

      図2:StandaloneのWebUI

     

  2. Google Cloud Dataproc:
    今回はGoogle社により提供されている Spark / Hadoop のマネージドサービスであるDataprocのWebUIにアクセスする方法を紹介します。

    1. Google SDKを設定します。設定方法はGoogle Cloudの公式サイトを参考にしてください。
    2. DataprocのInstanceを立ち上げます。使うCommandは下記の通りです。
    3. Step2で作ったDataprocのInstanceのMasterNodeと連携するSSH tunnelを作ります。
      使うCommandは下記の通りです。

      Commandの詳細の説明はGoogle Cloudの公式サイトを参考にしてください。
    4.  Sparkのapplicationをsubmitします。今回は例としてLinearRegressionのSampleCodeをsubmitします。使うCommandは下記の通りです。
    5. Terminal(Mac, Linux)やCommand Line(Window)でChromeを起動します。
      使うCommandは下記の通りです。

      各OSでのChromeのDefault Pathは表1の通りです。

      表1:ChromeのDefault  Path

      Operating System Default  Path of Google Chrome
      Mac OS X /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome
      Linux /usr/bin/google-chrome
      Windows C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
    6. 起動したChromeでhttp://[MasterNodeのInstance名]:8088へアクセスします。
      アクセスすると、DataprocのWebUIを確認することができます(図3)。
      DataprocのWebUIの項目「TrackingUI」から「History」をクリックすることで、図3の様なSparkのWebUIに遷移できます。

      図3:DataprocのWebUI

4 WebUIの説明
SparkのWebUI には6つのTabがあります。

  1. Jobs:
    Tab JobでJobのListが確認できます(図4)。
    JobのDescriptionをクリックすることでさらに詳細のJobを確認することができます。
    今回は例としてJob 5(count at LinearRegression.scala:696)をクリックしてみます。
    図4はJob 5の詳細画面です。

    図4:Job の詳細

    Jobの詳細画面にはstageが並んでいます。気になるstageのDescription項目をクリックするとさらに詳細な情報を確認することができます(図5)。

    図5:Stage の詳細

  2. Stages
    Tab Stagesで全てのStagesのListが確認できます。気になるStagesをクリックすることで、そのStageの詳細を確認することができます(図6)。

    図6:Tab Stages

  3. Storage
    Storageで当InstanceのStorageの状況を確認できます。今回のSample CodeではRDDの詳細はないのでStorgeの詳細画面はBlankになりました(図7)。

    図7:Stage の詳細

  4. Executors
    Executorsで当Executorsの詳細状況を確認できます(図8)。

    図8:Executors の詳細

  5. SQL
    SQLでSubmitしたCodeで実行されたSQLの詳細状況を確認できます(図9)。
    気になるStepのDescriptionをクリックして当Stepの詳細情報を確認できます。
    今回は例としてID: 1(first at LinearRegression.scala:198)をクリックしてみました。
    図10はクリック後の遷移画面です。

    図9:SQLの詳細

     

    図10:SQLの詳細状況

5 まとめ

今回はSparkのWebUIについて紹介しました。いかがだったでしょうか。
私は以前、大規模なデータのSparkのProgramを開発していたときに一番悩んだのは、メモリ不足によるエラーを解決することでした。
現在はSparkのWebUI を利用することでProgramの各部分の処理時間、メモリの使用量などの状況を全て確認できるようになりました。
これにより、Programのエラー解決がスムーズになるので、皆さん興味があればSparkのProgramを開発する時にぜひ試してください。

2017-11-29

PhpStorm(Intellij IDEA)のプラグイン作ってみる

GMOアドマーケティングのSSP開発チームのT.Kです。
コードレビューで処理を追いかける際にPhpStormを良く使いますが
ビューからコントローラへのジャンプが出来ず、不便に感じていました。
既存のプラグインで対応できるかもしれませんが、ブログの執筆を兼ねて
ビューから呼び出しコントローラを検索するプラグインを作ってみます。

環境構築
プラグインの開発はJavaとIntelliJ IDEAを使う必要があるので、公式からDLしてインストールします。

プロジェクトを作成
IntelliJ IDEAを起動したら、下記の手順でプロジェクトを作成します。

  • [File] -> [New] -> [Project] でプロジェクト作成画面を開く
  • [IntelliJ Platform Plugin] を選択して [Next] をクリック
    リストに[IntelliJ Platform Plugin]が無い場合は
    [File] -> [Settings] -> [Plugins] から [Plugin DevKit] を有効にしてください
  • [Project name] を入力して [Finish] をクリック

plugin.xmlを編集
プラグインの基本情報や依存関係などの設定ファイルです。
初期状態ではPHPStormで動作しないので、下記行のコメントを外します。

アクションを作成する
プロジェクトツリーのsrcディレクトリを右クリックして
[New] -> [Plugin DevKit] -> [Action] でアクション作成画面を開きます。

[Action ID] [Class Name] [Name] を入力します。

アクションの種類が大量にあり、全体を把握するには無理がありました。
今回はコンテキストメニューに追加したいので [PopupMenu] で検索し
[Groups] から [EditorPopupMenu(Editor Popup Menu)]
[Actions] から [EditorPopupMenu1(Editor Popup Menu Actions(1))] を選択しました。

[OK] をクリックするとクラスファイルが作成されます。
plugin.xmlを見ると <actions> に作成したアクションの情報が追加されています。

コードを書く
作成されたクラスファイル内のactionPerformedに処理を実装します。

動かしてみる
[Run] -> [Debug Plugin] から実行すると、 IntelliJ IDEA が別プロセスで起動します。

jarファイルの作成
[Build] -> [Prepare Plugin Module ‘<module name>’ for Deployment] で jar ファイルを作成します。

PhpStormにインストール
[File] -> [Settings] -> [Plugins] -> [Install plugin from disk] から作成した jarファイルをインストール
PhpStormを再起動すると反映されます。

PhpStormで動作確認
コンテキストメニューを開くと作成したプラグインの項目が追加されています。

実行すると検索結果が表示され、コントローラへのジャンプが楽になりました。

まとめ
Java初心者で最初は不安でしたが
IDEの補助と公開されているコードを参考に、最低限の機能は実装できました。
検索オプションでまだ不明な箇所があるので、引き続き調査&改良していきたいです。

2017-11-27

Go言語でGoogle Cloud StorageへのUploadとBigQueryで集計

GMOアドマーケティングに中途入社してまもないy.yです。

11/5(日)のGo Conferenceの内容についてまとめようと思っていたのですが

補欠からくり上がれなかったので今回はGo言語を使って

Google Cloud Storageへのアップロードをし、BigQueryでの集計手順について記載します。

 

本題に入る前にGo言語を選んだ理由

マスコットキャラクターのGopherくんが可愛かった 😀

Gopherくんはホリネズミという動物がモチーフらしいです。

どうでしょう?世界のミッキー○ウス並みにGopherくん可愛くないですか??

引用元:Gopherくん入門

@tentenのGopher by tenntenn CC BY 3.0

 

公式のGopherくんはきも可愛いですね 😀

引用元:The Go Blog

The Go Blog by Google CC BY 3.0

Gopherくんについて詳しく知りたい方は Gopherくん入門 へ!

 

Gopherくんが可愛いから選んだというのは冗談で

実際は下記の2点でGo言語を選択しました。

  1. いくつかの言語でパフォーマンスを計測した結果、Go言語のパフォーマンスが一番良かった。
  2. 並列処理でログをparseするのにGo言語が簡単だった。

 

ここから本題の手順を記載いたします。

  • 認証

 

  • Google Cloud Storageへのアップロード

ContentType 型:String

ContentTypeを指定します。

ChunkSize 型:Int

指定したサイズを上限にオブジェクトを分割してアップロードする指定。

1回のリクエストでアップしたい場合はCunkSizeを指定。

上限を指定しない場合は0または無指定。

オプションの詳細はこちら

容量の大きいObjectをUploadする際はネットワークに影響しないように制限した方がいいかもしれないですね。

 

  • BigQueryへLoad

AllowJaggedRows 型:bool

不正なレコードがあった場合、NULLとして扱うかエラーとして扱うかを選択します。

MaxBadRecords 型:Int

不正なレコード数を許容するレコード数を指定します。

Compression 型:String

Google Cloud StorageにuploadされたLoadするObjectの圧縮タイプを指定します。

FileDelimiter 型:String

Loadされるファイルのdelimiterを指定します。

オプションの詳細はこちら

圧縮されたファイルをLoadをする場合はCompression、CSV形式ではないファイルをLoadする場合はFileDelimiterを指定しましょう。

 

  • BigQueryで集計

UseLegacySQL 型:bool

オプションの詳細はこちら

LegacySQLを使用する場合はUseLegacySQLをtrueにしましょう。

 

ここまででGoogle Cloud Storageへのアップロード、BigQueryでの集計手順は終わりです。

どういったオプションがあるのか確認するのに時間が多少かかりましたが

アップロード、集計までの処理はサクッと簡単に書くことができました。

Go言語に関してまだまだ初心者なのでまずは中級者を目指したいと思います。

以上、Google Cloud Storageのアップロードから BigQueryでの集計の手順でした。

 

エンジニア採用

弊社は、広告をより便利な物にしていく事を一緒に目指してくれるエンジニアを募集しています。

エンジニア採用 | GMOアドパートナーズ株式会社

GMOアドパートナーズグループのエンジニア採用サイトです。

 

2017-11-20

軽量アプリケーションサーバ NGINX Unitを触ってみる

こんにちは、GMOソリューションパートナー媒体開発本部のN.Sです。

先日NGINX社より軽量アプリケーションサーバNGINX Unitのベータ版リリースがありました。
各言語毎のアプリケーションサーバ運用を一本化出来るメリットがありそうですが、
今後の選択肢として、導入の手間、操作感、パフォーマンスはどうなの?という事で簡単に触ってみました。

NGINX Unitとは?

  • https://www.nginx.com/products/nginx-unit/
  • 2017.9.7に発表されたばかりのNGINX社製 軽量アプリケーションサーバ。
  • 2017.9.28現在でv0.1ベータ版、特徴は主に以下です。
    • RESTful APIやJSON経由でサービス無停止でリアルタイムに設定変更が出来る
    • 複数言語に対応(PHP, Python, Go対応、今後Java, Ruby, Node.jsにも対応予定
    • 将来的に既存の商用NGINX + NGINX Unit にGUI管理機能のNGINX Controllerを加えて統合プラットフォームを作る構想がある
      https://oss.sios.com/nginx-ch/nginxconf2017

 

CentOS7コンテナにNGINX Unitをインストールしてみる

NGINX Unit導入の前提環境は以下です。

  • Linux2.6以上
  • Python 2.6, 2.7, 3
  • PHP 5系、7系
  • Go 1.6以上

今回はテスト環境として以下を使用しました。

  • Dockerコンテナ環境構築
  • ホストOSは、ローカルPCにVagrant+ VirtualBoxで構築したCentOS7.4
  • コンテナ環境はCentOS 7.4.1708/Linux3.10.0 + NGINX Unit 0.1 + PHP5.4.45

今回行う導入・設定を実施済のDockerコンテナ環境は以下です。
とりあえず環境を見たい方はこちらをご覧ください。
※実行手順はリンク先の「起動方法」参照

https://hub.docker.com/r/oshou/docker-centos7-unit/

1. CentOS7コンテナ起動、コンソールログイン

管理者モードでCentOSプレーンのコンテナ起動起動、NGINX Unitで動かすサンプルアプリケーション用にport8300を通しておきます。

2. NGINX Unit用レポジトリ作成

CentOS7 or Ubuntu16.04TLSはunitインストールパッケージが提供されているので、今回はそちらを使います。

3. NGINX Unitインストール

4. 設定用ツール インストール

Unitデーモンの設定は、UNIXドメインソケットへのリクエストにより行うので、
curl(v7.40以上)をインストールします。
※v7.40以上でないとドメインソケット対応オプション –unix-socketが使えません。
CentOS7では以下手順で別途レポジトリを定義してインストールしました。
https://www.rootlinks.net/2017/09/21/update-curl-7-29-to-7-55-on-centos-7-with-city-fan-repo/

5. NGINX Unitデーモンの起動

デーモンの起動を確認します。
unitdは管理用のTCPポート等は存在せず、UNIXドメインソケット通信により設定を行います。

Unitの初期設定をしてみる

1. 設定用jsonファイルの作成

listeners(待機するTCPポート設定)とapplications(遷移先のアプリケーション設定)は必須なのでそれぞれ以下要領で指定します。
詳しいパラメータは下記を参照下さい。
https://unit.nginx.org/docs-configuration.html#listener-and-application-objects

2. 設定用jsonファイルをunitデーモンに投入

リクエストメソッド、設定用jsonファイル、socketファイル、配置先URLをそれぞれ指定してリクエストを行います。
socketファイルはデフォルトだと/var/run/control.unit.sockです。

設定は以上です!簡単ですね。
注意点としては以下です。

  • curlがv7.40以上になっている事(–unix-socketオプション指定でエラーが発生しない事)
  • socketファイルのパスが正しく指定されている事(デフォルトだと/run/control.unit.sock)
  • HTTPメソッドが正しく設定されている事

3. 設定反映の確認

それでは正しく動作しているか確認してみましょう。
設定内容は設定先URLにGETリクエストを送ることで確認できます。

反映直後から指定したTCPポートでリッスンされる事が確認出来ました。

DocumentRootの場所にphpinfo()表示用スクリプトを配置してみます。
http://[Docker親ホストIP]:8300/[スクリプト名]にアクセスして正しく表示された事が確認できました。

ちなみに複数サーバ設定時はlisteners, applicationsでそれぞれ並列表記します。
一覧性があり見やすいですね

一部設定を動的変更する場合はパラメータに対応した特定URLにPUTリクエストを送ります。
例えばworkersを20->30に変更する場合は、
http://localhostの/applications/sample_php/workers宛に更新データを-dオプションで送るだけで即反映されます。

 

簡易的なベンチマークを行ってみる

それではNGINXサーバ連携で置換え検討機会の多そうなphp-fpmと比較してみましょう。
テスト環境は以下です。

テスト環境

  •  比較環境
  • アプリケーションサーバは基本デフォルト設定、worker数MAX値だけ10で統一
  • サンプルスクリプトは以下
  • Apache Benchで計測
  • 以下で計測(同時接続数100、総リクエスト数10000、keepaliveを使用しない)

テスト結果

APサーバ スループット(req/s) 平均レスポンスタイム(ms/req) エラー率(%)
NGINX Unit 423.12 2.363 0
php-fpm 571.13 1.751 0

不本意ながらphp-fpmの方が早い!という結果が出てしまいました、、、
実施後の所感としては以下でした。

  • 同一ホストでコンテナ環境もミドル部分以外は統一しているため、他影響ではなくアプリサーバ側の性能差が取れていそう
  • ps aux等で見るとNGINX Unitは子プロセスのメモリ効率が悪い印象を受けた。RSS=実際に使用した物理メモリ がphp-fpmの約4倍だった。
    • php-fpm側が5.94MB、NGINX Unit側が26.04MB程度
  • php-fpmのpm.start-serverにあたるものが無いため初回コストがかかっている
  • 他Go、Python言語等でも性能差比較してみたい

まとめ

  • CentOS7、Ubuntu向けにパッケージ提供されているので導入は簡単、CentOS6系等は公式手順でソースインストールが必要
  • 比較的軽量でサクサク動く印象だが、本検証ではphp-fpmには及ばずでした。
    他言語でも比較して傾向を見たい所ですが、PHPに関してはメモリ効率部分で今後に期待したい所でした。
  • JSONベースの設定が使いやすい。
    一覧性が高く、config.jsonだけ抑えておけばOKな手軽さが良い。動的設定変更も可能。
    ただし、初回起動時に設定用JSONファイルを都度PUTリクエストする必要があるので注意
  • モニタリング、権限管理機能等は今後登場予定のNGINX Controller側で実装される(?)
    • https://oss.sios.com/nginx-ch/nginxconf2017
  • 複数言語でアプリケーションサーバを一本化、という事が出来そうですが、
    ベータ版という事であまり詳細なパラメータはまだ公開されていない模様。
    php-fpmで言う pm.start-server(初回起動時のワーカー数)やpm.max_requests (メモリリーク対応)、slowlog(スローログ取得)等にあたるものが今後出てくると嬉しい。

2017-11-16

TerraformでGCP環境を構築してみる

はじめまして。GMOアドマーケティングでインフラを担当しているa.sです。
今回はTerraformを用いて、GCP上に検証環境を構築する機会がありましたので、構築に伴う一連の作業をご紹介します。


構築内容


既存のオンプレミス環境から接続可能なKVSサーバ環境を構築します。
目的として、オンプレミス環境上に構築しているKVSサーバを物理的にスケールする作業のコストを
クラウド化することで下げたいというものです。

以下のような構成になります。


  • KVSサーバはGCPで提供されているCentOS7のイメージを使用して構築します。
  • オンプレミス環境とGCP環境の通信はVyOSとGCP上のVPN Gatewayで暗号化して行います。
  • KVSへの接続は内部ロードバランサを介して各KVSサーバにバランシングする設計としています。
  • Terraformのtfstateファイルの管理はGCS(Google Cloud Storage)上で行います。
  • Terraformで作成したインスタンスのミドルウェア等の管理は踏み台サーバ(bastion Server)上からansibleで行います(本ブログでは触れません)。

残念ながら、VPN環境は現時点では構築できていないため、その他のGCPリソースをTerraform化したもののご紹介となります。


Terraformを使用する事前準備


予め用意しておくもの

  • TerraformとCloud SDKをインストール可能な環境
    弊社ではCentOS7の環境で実施します。
  • GCPのプロジェクト
    GCPの環境を構築するためにGCP上でプロジェクトを作成しておきます。
  • 作成したGCPのプロジェクトでAPIを有効化
    こちらを参考に、作成したGCPプロジェクトで「Google Compute Engine API」を有効化しておきます。

Google Cloud Console上からTerraform用のサービスアカウントを作成する

TerraformとCloud SDKのAPI認証用にGoogle Cloud Console上からサービスアカウントを作成します。

1.Google Cloud Consoleログイン後、画面左側から「IAM & admin」を選択し、「Service accounts」を選択します。

2.遷移した画面上部にある「CREATE SERVICE ACCOUNT」を選択します。

3.「Service account name」に適当な名前を入力し、「Role」部で必要な権限を選択します。
今回はGCE(Google Compute Engine)及びGCSを操作するために、
「Compute Admin (beta)」及び「Storage Admin」を付与します。


鍵が必要になるので、json形式の鍵を選択して、「CREATE」を選択します。
この鍵は再ダウンロードが出来ないので、大切に保管します。
※鍵の再設定は可能なので、万が一鍵を紛失した際は再設定を行います。

何かと使えるのでGCP用のCloud SDKのインストールと認証
※本ブログではGoogle Cloud Storageのbucket作成にしか使いません

Terraform実行サーバでCloud SDKのインストール及び、認証作業を実施します。

公式ドキュメントの「yum(Red Hat と CentOS)」部を参考にしています。

1.リポジトリを登録します

2.yumでCloud SDKをインストールします

3.Cloud SDK及びTerraformを操作するユーザにスイッチし(任意)、作成したサービスアカウントのjsonを設置します

4.Cloud SDKで作成したサービスアカウント及びGCPのプロジェクトを認証します

5.認証した情報を確認します。

tfstateファイルをGoogle Cloud Storage上で管理するため、保存するためのバケットを作成する

Terraformはデフォルトだと「terraform.tfstate」という名前のファイルで管理対象のインフラの状態を保存しています。
Terraformはこのファイルに基づいて、インフラの構成の変更などを検知し、必要に応じてリソースの作成や削除、変更などを行っています。
チームでTerraformを運用する場合、各々でtfstateファイルの状態が異なると矛盾が生じてしまうため、今回の場合はGCS上にtfstateファイルを保持することで情報の一貫性を保ちます。

Cloud SDKインストール時に併せてインストールされるgsutilコマンドを用いてGCS上にtfstateファイルを保存しておくためのバケットを作成します。

gsutilコマンドの各オプションの意味は以下の通りです。

  • mb
    バケットを作成します
  • -p 
    作成するバケットの対象プロジェクト名を指定します
  • -c
    作成するストレージクラスを指定します
  • -l
    バケットロケーションを指定します
  • gs://example_tf-state-prod/
    「gs://バケット名/」として作成するバケットを指定します

Terraformのインストール

Terraformのインストールを行います。
今回はTerraform実行ユーザの「~/terraform」以下にインストールします。

インストール後、以下コマンドでバージョンが確認できればインストールに成功しています。


Terraformのコードを書く


Terraformの実行環境が整ったところで、ここからは実際にTerraformのコードを書いていきます。
Terraform構成の構文はHashiCorp Configuration Language、HCLという言語で記述します。
「*.tf」という拡張子を持つファイルにコードを書くことで、Terraformがそれをテンプレートとして自動的に認識します。

Terraform用に適当なディレクトリを作成して、その中に設定ファイルを作成していきます。
今回作成する「*.tf」ファイルの構成は以下の通りです。今回は分かりやすくするために各機能ごとにファイルを分けました。

以下からは個別に設定ファイルと、設定内容の詳細を記載します。

provider.tf

接続するプロバイダー(今回はGCP)を設定します。

  • provider
    接続先を設定します。今回はgoogleとなります
  • credentials
    認証情報を設定します。作成したサービスアカウントから発行されたjsonのkeyのパスを指定します
  • project
    対象のプロジェクトを設定します
  • region
    対象のリージョンを設定します

backend.tf

tfstateファイルをGCS上で管理するための設定です。

  • backend
    対象のバックエンドサービス(gcs)を指定します
  • bucket
    作成したバケットを指定します
  • path
    対象のtfstateファイルのパスを指定します
  • credentials
    認証情報を指定します。作成したサービスアカウントから発行されたjsonのkeyのパスを指定します

variables.tf

各設定ファイル内で使用する変数を設定します。
変数は “${var.変数名}” の形で使用します。

  • variable “region”
    「asia-northeast1」を変数”region”に登録します
  • variable “region_zone”
    「asia-northeast1-a」を変数”region_zone”に登録します
  • variable “bastion_ssh_keys”
    “bastion_ssh_keys”という変数に「exampleadmin」ユーザと、そのユーザ用の公開鍵(ssh-rsa 〜)を登録しています。
    ここで登録したユーザはsudo権限が与えられた状態でサーバに設定され、併せて公開鍵を登録しているので秘密鍵ログインが可能になります
  • variable “kvs_ssh_keys”
    「variable “bastion_ssh_keys”」と同様です

network.tf

カスタムVPCネットワークを設定します。

  • resource “google_compute_network” “example”
    ネットワークリソースを作成します
    name
    ネットワークの一意の名前を設定します。ここでは「example」としています
  • resource “google_compute_subnetwork” “subnet1”
    サブネットワークリソースを作成します
    ・name
    サブネットワークの一意の名前を設定します。ここでは「subnet1」としています
    ・ip_cidr_range
    作成するネットワークレンジを設定します。ここでは「192.168.10.0/24」を設定しています
    ・network
    このサブネットワークが属する親ネットワークを設定します。ここでは直前で作成した「example」ネットワークを設定しています
    ※「${google_compute_network.example.name}」とは、「google_compute_network」というリソースの中の「example」というリソースの中の「name」に当たるものという意味で、ここでは
    「resource “google_compute_network” “example”」内で設定されている「name = “example”」を指定しているということになります。
    ・description
    このサブネットワークの説明となります
    ・region
    このサブネットワークが属するリージョンを設定します

bastion.tf

GCEでbastion Serverを構築するための設定です。

  • resource “google_compute_address” “bastion01”
    bastion Serverに割り当てる静的グローバルIPアドレスリソースを設定します
    name
    一意の「bastion01」というリソース名を設定します
    region
    静的グローバルIPアドレスリソースを作成するリージョンを設定します。
  •  resource “google_compute_instance” “bastion01”
    作成するGCEインスタンスリソースの情報を設定します
    name
    一意の「bastion01」というリソース名を設定します
    machine_type
    作成するインスタンスのマシンタイプを設定します
    zone
    インスタンスを作成するゾーンを設定します
    tags
    インスタンスに付与するタグのリストを設定します
    boot_disk
    インスタンス作成に使用するOSイメージを設定します
    metadata_startup_script
    サーバ起動時に流すコマンドを設定できます
    ここではSSHのポートを10022で使用できるようにし、GCPのCentOS7のイメージはデフォルトUTCなためJSTに変更しています
    network_interface
    インスタンスに接続するネットワークを設定します
    ここではnetwork.tfで作成したネットワークからの静的プライベートIPを割り振り、
    「resource “google_compute_address” “bastion01” 」で作成した静的グローバルIPを割り振ります。
    metadata
    ここではSSH用の公開鍵を登録しています。個別にインスタンスに公開鍵を登録するため「block-project-ssh-keys」を有効化します。「sshKeys」には変数で登録した公開鍵を指定します

kvs.tf

GCEで3台のKVS Serverを構築するための設定です。3台とも同スペックで構築するためリソース名に変数を使って一つの設定で3台分のインスタンスを作成することも出来るのですが、このように1台1台個別に設定しないと後述の「instancegroupes.tf」で設定するインスタンスグループに登録できなかったためこのような記述となりました
静的グローバルIPアドレスリソースの設定が無いことを除いて、こちらの説明は「bastion.tf」と重複するため割愛します

firewall.tf

ファイアウォールルールを設定します。項目が多いためそれぞれピックアップして説明します。
「xxx.xxx.xxx.xxx/xx」となっている箇所は弊社固定IPになります。

  • resource “google_compute_firewall” “allow-icmp”
    「example」ネットワーク内の「bastion」タグが付いたリソースに対してソースIPからicmpを許可しています
  • resource “google_compute_firewall” “allow-tcp-10022”
    「example」ネットワーク内の「bastion」タグが付いたリソースに対してソースIPから10022番ポートを許可しています
  • resource “google_compute_firewall” “allow-tcp-8091”
    「example」ネットワーク内の「kvs」タグが付いたリソースに対してソースIPから8091番ポートを許可しています
  • resource “google_compute_firewall” “allow-internal”
    「example」ネットワーク内の「server」タグが付いたリソースに対してソースIPから全ての通信を許可しています
  • resource “google_compute_firewall” “allow-internal-lb”
  • resource “google_compute_firewall” “allow-health-check”
    これらの設定は内部ロードバランサ及びヘルスチェックのアクセスを、「example」ネットワーク内の「kvs」タグが付いたリソースに対して許可しています。内部ロードバランサからのアクセスを許可する設定は公式ドキュメントを参考にしています

instancegroupes.tf

内部ロードバランサから各インスタンスにバランシングさせるためには、対象のインスタンスをインスタンスグループとして登録する必要があります。今回は非マネージドインスタンスグループとして作成します。インスタンスグループに関して詳しくは公式ドキュメントをご参照下さい。

  • resource “google_compute_instance_group” “kvs-group”
    インスタンスグループを作成します。
    ・name
    インスタンスグループの名前を設定します
    ・description
    作成するインスタンスグループの説明です
    ・zone
    インスタンスグループを作成するゾーンを指定します
    ・instances
    インスタンスグループに登録するインスタンスを指定します
    今回はkvs.tfで作成するインスタンスを指定しますが、他のケースで使用する場合にも基本的には以下の形で指定の形で問題ないと思います
    ${google_compute_instance.インスタンス名.self_link}
    ※self_linkとは、作成されたリソースのURIを示します。基本的にTerraform側でGCP側から動的に取得してくれます。

internallb.tf

内部ロードバランサの設定を行います。ここでは実際の内部ロードバランサの設定とともに、ヘルスチェックと転送ルールも併せて設定しています。

  • resource “google_compute_health_check” “kvs-health-check”
    内部ロードバランサが使用するヘルスチェックリソースを設定します
    ・name
    ヘルスチェックリソースの一意の名前を設定します
    check_interval_sec
    ヘルスチェックの間隔を設定します
    timeout_sec
    接続失敗を判断するまでの秒数を設定します
    tcp_health_check
    ヘルスチェック接続先のポートを設定します
  • resource “google_compute_region_backend_service” “kvs-int-lb”
    内部ロードバランサを設定します
    name
    バックエンドサービスの名前を設定します
    protocol
    使用するプロトコルを設定します。ここではTCPを指定しています
    health_checks
    使用するヘルスチェックリソースを設定します。ここでは先程設定した「kvs-health-check」を指定しています
    timeout_sec
    接続要求が失敗したと判断するまで待機する時間を設定します
    session_affinity
    使用するアフィニティ機能を設定します。詳細はTerraformの公式ドキュメントと、GCPの公式ドキュメントを参照して下さい
    region
    バックエンドが存在するリージョンを設定します。ここでは「variables.tf」で設定した変数を利用しています
    backend
    作成する内部ロードバランサを利用するインスタンスグループを設定します
  • resource “google_compute_forwarding_rule” “kvs-int-lb-forwarding-rule”
    内部ロードバランサが利用する転送ルールを設定します
    name
    転送リソースの一意の名前を設定します
    load_balancing_scheme
    使用するロードバランシングのタイプを設定します。今回は内部ロードバランサなので「INTERNAL」を指定しています
    ports
    内部ロードバランサに使用するポートを設定します。このポート宛のパケットが、この転送ルールで指定したバックエンドサービス(kvs-int-lb)に転送されます
    region
    転送ルールを使用するリソースが存在するリージョンを設定します
    network
    負荷分散対象のネットワークを設定します。ここでは「network.tf」で作成した「example」ネットワークを指定します
    subnetwork
    負荷分散対象のサブネットワークを設定します。ここでは「network.tf」で作成した「subnet1」ネットワークを指定します
    backend_service
    転送ルールに一致したパケットの転送先のバックエンドサービスを設定します。ここでは先程作成した「kvs-int-lb」を指定します
    ip_address
    パケットを最初に受信する静的IPを設定します。この場合だとクライアント側からは「192.168.10.100:11210」宛にKVS用のパケットを送信することになります。

ここまででTerraformのコードの準備が出来ました。


Terraformの実行


コードの準備ができたら、実際にTerrafomを実行してGCP上にリソースを構築します。

コードの検証
先ずは 「terraform validate」コマンドを使用して作成したコードの構文チェックを行います。

実行した結果、何も表示されなければ構文に問題はありません。
エラーが出た場合はその内容に沿ってコードの修正を行う必要があります。

実行計画
構文に問題がなければ、次に「terraform plan」コマンドを実行してGCP上のリソースにどのような変更を加えるか、実行計画を確認します。このコマンドを実施しても実際のGCPリソースに変更は加えられません。

実行した内容を確認し、実際にコードの内容通りに変更が加えられるかどうかなどをチェックします。

適用
実行計画に問題がなければ、「terraform apply」コマンドを使用して実際にコードをGCPリソースに適用します。

実行した内容を確認し、エラーなどが出ていなければGCP上にリソースが作成されているはずです。
後は実際にGoogle Cloud Console上や、「terraform show」コマンドなどでリソースの情報を確認してみましょう。

 


Terraformで作成したリソースの削除


Terraformで作成したリソースを全て削除する場合は以下の通り実行します

リソースの削除計画の確認
先ず「terraform plan -destroy」コマンドを使用してどのリソースを削除するのかを確認しておきます。このコマンドを実施しても実際のGCPリソースに変更は加えられません。

実行した内容を確認し、削除対象に問題がないことを確認します。

リソースの削除
terraform destroy」コマンドを使用して実際に削除処理を行います。実行後確認プロンプトが出てくるはずなので、「yes」を入力して実行を進めます。

実行した内容を確認し、エラーが出ていないことと、対象リソースが削除されていることを確認します。
また、Google Cloud Console上でも同様にリソースが削除されていることを確認できると思います。

まとめ

今回はGCP上のリソースをTerraformで作成する場合の一連の作業と、各設定ファイルの詳細、リソースを削除するまでをご紹介しました。
Terraformはまだ検証のみの使用であるため、ご紹介できた機能はごく一部だと思いますが、同じようにGCPリソースをTerraformで管理を始めたような方に少しでもご参考になれば幸いです。

2017-11-14

GitHubのWebhook活用

2017年7月からGMOアドマーケティングのSSP開発チームにJoinしたK.Mです。
先日、試用期間も無事終え落ち着きました。
GMOアドパートナーズグループには、住宅補助手当という
オフィスビル近隣に住んでいる人が対象となる福利厚生があるので、
そろそろオフィスビル近くに引越かと考えています。

早速本題です。

Webhookってなに?

Webhookとは特定の条件を満たした際に他のアプリケーション/URLへリクエストする仕組みとなります。
SSP開発チームでは今回紹介するGitHubの他にSlackのWebhookも活用しています。

活用事例

SSP開発チームはGitHubのレビュー機能を利用したGitHubフローで開発しています。
Pull Request = レビュー依頼ではないため、レビュー依頼はラベル機能を利用していますが、
レビューNGとなった場合、主に3つ問題がありました。

  • Pull Requestの一覧上のレビュー結果が見辛い
  • ラベルが放置され、レビュー依頼中なのか、修正中なのかの判断がつかない
  • ラベルが放置されガチだったため、”[WIP]”とタイトルに付けるPRが散見された

上記のような問題を抱えていたため、
GitHubのWebhookを利用し、レビュー結果を元にラベルの張替を実現しました。
ラベル張替をWebhookに任せる事で、以下のメリットがありました。

  • ラベルがついていない = 開発/修正中
  • ラベルがついている = レビュー依頼中/レビュー完了
  • “[WIP]”が消えました

実装コード例

Webhook設定

去年の10月に追加されたPullRequestReviewEventを利用します。
まず、GitHub側のWebhook設定を行います。
Webhookを適用したいリポジトリのページから Settings > Webhooks と遷移し、 Add webhook から新規にWebhookを追加します。
今回は Let me select individual events. を選択し、 Pull request review のみにチェックを入れます。

Access Token取得

ラベル張替用のAccess Tokenを生成します。
アカウント情報の Settings > Developer settings > Personal access tokens にアクセスし、 Generate new token から新規にトークンを発行します。
利用しているリポジトリに応じ public_reporepo にチェックを入れます。

リクエスト先の設定例

SSP開発チームではPHP、JavaScript、Ruby、Goで開発を行っていますが、
今回はPHPでの実装例となります。

GitHubのdeveloperガイドに記載ありますが、GitHubからみたPull Requestはissueと大差ありません。

Labels, assignees, and milestones

その事を踏まえた上で、下記実装を行いました。

まとめ

ラベルの張替は対応時間としては微々たるものですが、日々の業務で開発者全員にちょっとした気遣いを強いるものでした。
そのちょっとした気遣いを自動化する事で意識せずに済むようになったためチーム内で好評でした。

リクルーティング

GMOアドマーケティングではBigQuery、機械学習など新しい技術に興味のあるエンジニアに限らず、
開発効率の向上に積極的なエンジニアを募集しています。

エンジニア採用 | GMOアドパートナーズ株式会社

GMOアドパートナーズグループのエンジニア採用サイトです。

 

2017-11-09

機械学習入門者がKerasでマルチレイヤーパーセプトロンのサンプルを読む

こんにちは。
GMOアドマーケティング、機械学習入門者のT.Mです。

はじめに

ゼロから作るDeep Learningを読み終え、
実際に何か作るにあたって何をしたらよいか調べていたところ
ニューラルネットワークのライブラリであるKerasを知り触ってみました。
いきなりKerasのサンプルソースを見てもさっぱり分からなかったので、
ゼロから作るDeep Learningで学習した内容とKerasドキュメントを参照しながら
見ていきたいと思います。

Kerasについて

Kerasについては公式ドキュメントを参照ください。
TensorFlow上で動く、ニューラルネットワークをより簡単に書けるようにした
ライブラリという認識です。

サンプルソース

Keras公式のサンプルソースから、
ゼロから作るDeep Learningでも5章までガッツリと書かれていたMLP(マルチレイヤーパーセプトロン)のサンプルを見ていきます。

サンプルソースを読む

サンプルソースから引用しながら見ていきます。
Kerasのライセンス表記です。

Copyright (c) 2015, François Chollet.
Copyright (c) 2015, Google, Inc.
Copyright (c) 2017, Microsoft, Inc.
Copyright (c) 2015 – 2017, the respective contributors.
Released under the MIT license
https://github.com/fchollet/keras/blob/master/LICENSE

最初の部分ですが、MNISTのデータをロードし、ニューラルネットワークに取り込めるようにデータを変換しています。

どのようなニューラルネットワークなのかを定義しています。
Sequentialモデルはニューラルネットワークの各層を順番につなげたモデルを表します。
add()で層を追加していきます。
https://keras.io/ja/getting-started/sequential-model-guide/

最初の層として追加しています。
どんな層かというと、Dense()で定義されています。
このDenseは、全結合ニューラルネットワークになります。
この1行だけで1つのニューラルネットワークを表しています。
https://keras.io/ja/layers/core/#dense
Kerasのソースの方にも、
https://github.com/fchollet/keras/blob/master/keras/layers/core.py#L729
Just your regular densely-connected NN layer.
とあり、
Dense implements the operation:
output = activation(dot(input, kernel) + bias)
と、ゼロから作るDeep Learningにも出てきたA・W+Bというニューラルネットワークになります。

このDenseの引数を見ると、下記の通りになっています。

  • units・・・出力の数
  • activation・・・活性化関数。reluを指定しています。
    https://keras.io/ja/activations/#relu
    活性化関数については、この記事も参照ください。
  • input_shape・・・最初の層のときにだけ指定します。入力層の形を指定します。MNISTで扱う28×28=784のデータのことを表しています。

ドロップアウトの層になります。
ドロップアウトは、ゼロから作るDeep Learningの6章にも出てきました。
過学習を避けるために出力結果を間引くようになります。
引数はレートを指定します。

第2層目のニューラルネットワークです。
出力の次元数は512、活性化関数は前回と同じくreluです。

またドロップアウトを指定しています。

最後に出力層として、次元数10(0〜9の数字なので)、活性化関数はSoftmaxを指定しています。
ここまでがSequentialモデルで定義したニューラルネットワークになります。

次に、compileメソッドは訓練の定義をします。
https://keras.io/ja/models/sequential/#compile

  • loss・・・損失関数を指定します。ここでは、categorical_crossentropyが指定されています。
    MNISTのような多クラス分類では、categorical_crossentropyを使用します。
  • optimizer・・・最適化アルゴリズムを指定します。RMSpropを指定しています。
    https://keras.io/ja/optimizers/#rmsprop
    ゼロから作るDeep Learningには出てこない最適化アルゴリズムです。
    書籍で出てきた内容としては、SGD、Adagrad、Adamがあります。
  • metrics・・・評価関数を指定します。通常はmetrics=[‘accuracy’]を指定するとのこと。
    https://keras.io/ja/metrics/

fitは、ニューラルネットワークの訓練を行います。
https://keras.io/ja/models/sequential/#fit

  • 第1引数、第2引数・・・入力データとなります。
  • batch_size・・・バッチサイズを指定します。
  • epochs・・・訓練を行う回数を指定します。
  • verbose・・・指定する数値により実行ログの出す内容が変わります。
  • validation_data・・・評価用のデータを指定します。
  • 戻り値・・・訓練の損失値と評価関数値が返ってきます。

evaluateは、損失値を計算します。
https://keras.io/ja/models/sequential/#evaluate

  • 第1引数、第2引数・・・評価用の入力データを指定します。
  • verbose・・・進行状況の表示を指定します。0は出しません。
  • 戻り値・・・テストデータの損失値を返します。

まとめ

いかがだったでしょうか?
最初はどこから手を付けたらよいか分かりませんでしたが、
ゼロから作るDeep Learningで学習した知識をベースに
Kerasのドキュメントを参照することでほんの少し読めるようになったと思います。
次は自分でニューラルネットワークを作っていきたいです。

2017-11-02

あなたが選ぶなら、どのエンジニアの職種?

GMOアドマーケティングのKMです。気が付けば、IT業界20年です(笑)
エンジニアの人は自分の得意分野って把握している?キャリアプランは?
エンジニアを目指す人や理解したい人も参考になればと思い職種について書きます。

IT(Information Technology: 情報技術)エンジニアも様々な職種があり、
GMOインターネットグループでも、大きく分けて下記5つがあります。
http://recruit.gmo.jp/engineer/guide/

🙂 アプリケーションエンジニア
😎 インフラエンジニア
😐 データベースエンジニア
😮 スマホアプリエンジニア
😛 フロントエンドエンジニア

メガネしてチェックのシャツ来ているイメージですが、
27職種に細かく分けて求人している会社もあり、
職種や適性については実は様々なんです。

今回は、大きく分けた上記5職種について説明しますが、
非エンジニアの方は、スマホを使っている気持ちで、
下記を読んで頂けるとイメージが湧くと思います。

■職種

・アプリケーションエンジニア 🙂 
→アプリケーションとは、コンピュータで、使用者の業務に応じて作成したプログラムを意味するので、使用者の目的や要件を汲み取って、利用シーン、利用される為の運用まで考えて、理想的に自動で動く仕組み(システム)を作るエンジニア。
★適性は、人がやる仕事を自動化したいとか、物作りや部品化が好きな方、
システムが直近から中長期に使われて、ビジネスと共に成長していくイメージを行う事が好きな方。

♥ 嬉しい事:世の中に広く使われる事。
× 悲しい事:作った物が使われず、無駄になる事。
○【トリセツ】:良い企画を出して優先順位を間違えないであげましょう。

・インフラエンジニア 😎 
→システムが動作する為のネットワークやハードウェア(機器)の環境構築及び
通信やシステムの正常稼働を監視する設定などを行うエンジニア。
★適性は、新しい機器の操作や、システムが稼働する構成を考える事が好きな方。
システムが稼働するベースとなる機器を設定するので慎重な面もあるとベスト。

♥ 嬉しい事:アプリケーションエンジニアと連携して開発したり、原因を特定しづらい、トラブルシューティングで問題を見つけた時。
× 悲しい事:障害を未然に防ぐ、あまり表に出ないので評価されない事もある。
○【トリセツ】:機器の故障、障害など昼夜問わず発生するので、消防士にように守ってくれる事、理解して感謝しましょう。

・データベースエンジニア 😐 
→大量データを高速に集計したり、最適化の為の分析を行うエンジニア。
★適性は、整理整頓好きで、合理的な効率化が好きなタイプ。

♥ 嬉しい事:求める結果が、効率良く検索でき早く返却される事。
× 悲しい事:検索結果が要求された速度で得られない事。
○【トリセツ】:F1のように限界まで効率化に対する意識や、お願いしたデータを素早く抽出してくれたり、意味を持たないデータを、価値ある法則を導き出す事ができるので、尊敬してあげましょう。

・スマホアプリエンジニア 😮 
→ブラウザで見るサイトではなく、専用のiPhone/Androidアプリを作る
エンジニア。
★適性は、ゲームなどアプリでしか実現できない事や利便性に関心があり、
その為なら、新しい言語を習得する事を苦にしないタイプ。

♥ 嬉しい事:Webでは実現できない高度な機能を開発し、世の中に広く使われる事。
× 悲しい事:制約が多く、実現したい事が実現できない。
○【トリセツ】:むしろ複雑な事を相談して、頼りにしましょう。きっと解決してくれます。

・フロントエンドエンジニア 😛 
→ユーザーへ見せる画面表示を担当するエンジニア。
★適性は、他人に対する見え方、見せ方に関心があり、
ユーザーに気持ち良く使ってもらう為に導線に配慮したり、
工業デザインを意識して画面が考えられるタイプ。

♥ 嬉しい事:自分が作った機能がサクサクと動いて、意図通りユーザーが使ってくれる事。
× 悲しい事:画面でJavaScriptエラーが発生し、うまく動かない時。
○【トリセツ】:目的を明確に伝えて、きっと素敵なインターフェースを一緒に考えてくれる筈。

ITは情報技術なので、情報の伝達や連携という意味でコミュニケーションやチームワークが必要な一方、自動車作りのように、電力供給からネジ作り等の専門性も必要で職種が分かれています。
上記で隣接する職種は関連する事が多いので、2つ以上の職種を兼任しているエンジニアもいますし、上3つの職種の知識が多い人を、バックエンドエンジニアと総称する事もあります。

システムは、VR、ロボット、自動運転、IoT等、社会のニーズが常に発生していますが、どれも上記、職種のエンジニアが活躍しているので、どの職種を選択するかは、適性や好みと、仕事の「イメージが湧くか 」で良い思います。海外のエンジニアは殆どが理系のようですが、日本でもその傾向はありまして、仕事内容から内向的な方がスティーブ・ジョブズのようにいい物を作る印象です。

最後に
弊社は、現在、広告をより便利な物にしていく事を、一緒に目指してくれるエンジニアを募集しています。
https://www.wantedly.com/companies/gmo-am/projects

尚、どの職種も、以下のような工程がありますので、次回説明したいと思います。
「要件定義」、「設計」、「開発」、「テスト」、「稼働」、「運用」

2017-10-11

コードレビューを怖がっていた新卒エンジニアが始めた対策

この記事の概要


  • 新卒エンジニアのY.Oの自己紹介
  • 入社後苦労した事
  • コードレビューとは何か
  • コードレビューの回数を減らすために行っている対策。

ご挨拶


こんにちは! TAXELチームに配属された新卒エンジニアのY.Oです!
今回は、私が入社してから味わったコーディングの苦労とその対策について、というテーマの記事です。
が、その前にちょっとだけ、私の自己紹介をさせてください。

私は現在、TAXELというレコメンドエンジンの開発を行っています。
レコメンドエンジンとは何か簡単に説明すると、
「この記事を見た人にはこの記事もオススメです」 といった機能を提供する仕組みです。
私はそんなTAXELの管理画面をRuby on Railsを使って改善するお仕事をしています。

今でこそ、会社に入ってエンジニアとしてお仕事をさせて頂いていますが、
入社まではあまり開発作業をした事はありませんでした。

大学時代にやった事と言えば…

  • プログラミングの授業の受講
  • 後輩へのプログラミング指導
  • 研究の一環としてのプラグインの開発
  • 長期休暇中のスマホアプリ開発(ダウンロード3桁レベルの小規模なもの)
  • アドパートナーズのインターンシップ(内定承諾後の半年程度)

といった内容で、プログラミングの授業でS評価は貰えるものの、
開発の経験が浅いことに加えて、集団開発の経験も無いため、
入社してからは苦労の連続でした。

入社して苦労した事


いざ入社してみると…

  • Gitむずかしい…リポジトリとかブランチとか何が何やら分からない…
  • Ruby on Railsってなんかスゴイけど勝手にやってくれ過ぎ?!
  • 「とにかく動いて自分が読めりゃいいんだよ!」なコーディングをしてきたツケが!
  • アドテクの講義、概要を追っていくので精一杯…
  • 設計内容をまとめた仕様書…他の人が読んで解るように書く…って言われても、
    一体どこまで書けばいいんだろう…?
  • プロダクトが複雑すぎて仕様や使い方が覚えきれない!
    影響範囲の検討なんてひたすらコードを読んで紐解かないと分からない!
  • サーバー関係触ったこと無いんだけれど…
    踏み台サーバーを経由してSSHでログインするって何のこと?
  • コードレビューこわい
  • etc…

とまぁ、当然の事ながら分からない/出来ない事だらけでした。
中でも特に怖かったのが、コードレビューという作業です。

コードレビューってなんぞや?


コードレビューとは、作ったコードを別の人に見てもらい、
おかしなところが無いか確認する作業の事です。
(学生の方は、論文査読のソースコード版、と考えると分かりやすいかもしれません)

個人での開発や学校の授業では意識する事は少ないかと思いますが、
仕事としてコーディングをする際は、可読性が高く安定して動くコードを書かなければなりません。
そこで、コードレビューを通じて、より良いコードがプロダクトに追加されていく仕組みにしている…とのことです。

このコードレビュー、独学でプログラミングをやってきた私にとっては鬼門で、
かなりの回数の指摘を受けてしまっています。

いまパッと思い出せるだけでも…

  • Returnの直前で条件式使ってBoolean返すなら、その条件式を返却した方がいいですよ!
  • ネストが深すぎますよ!
  • 関数の中身は直ってるけど、コメントが前のままだよね!
  • この仕様だと、~の処理の時に問題が起こるよ!
  • 関数名が処理内容を適切に表現してないよ!
  • etc…

などなど…シンプルなものだけを例として挙げましたが、
実際は他にも大量に指摘され何度も何度も再レビューをする事になってしまいました。

レビューをして頂ける事はとてもありがたい事なのですが、何度も繰り返していると、
次の失敗が怖くなったり、レビュアーへの申し訳無さでいっぱいになったり…
徐々にレビューへの苦手意識が芽生えるようになりました。

対策


とはいえ、苦手だからといって逃げる訳にも行きません。
先輩からのアドバイスや書籍/ネットで調べた情報を元に、徐々に対策をするようにしています。
同じような立場の人に少しでも役立てられたらと思い、私がやってきた対策を書いていこうと思います。

1. 指摘された点はちゃんとメモを取ろう!

エンジニアに限らず誰もがやる事だと思いますが、何より重要な事だと思います。
レビューの際どの箇所で指摘を受け、その理由が何だったかを記録する事で、
後で見返せるだけでなく、書くことで記憶にも残りやすくなります。

私の場合は、会社で扱っているWikiの自分のページの中に、
指摘された内容と、その時の修正前/修正後のコードをまとめ、
以降のレビュー前に確認する自分だけのチェックリストのようなものを作っています。

2. コーディングの参考になる本を読んで勉強しよう!

私は個人で開発を行う際、自分さえ分かれば大丈夫というコードを書いてきた為、
チームの誰にとっても理解しやすいコードを書く習慣が身に付いていませんでした。

そんな状態ではいくら自分の頭で考えたところで、良いコードを考えつく訳もありません。
そのため本を通して先人の方のやり方を参考にし、コーディングスキルやチーム開発における重要な考え方を学びました。

参考になった本をいくつか、ここで紹介させて頂きます。

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

(引用元:O’Reilly Japan「リーダブルコード――より良いコードを書くためのシンプルで実践的なテクニック」https://www.oreilly.co.jp/books/9784873115658/”)

読みやすいコードを書くためのテクニックを凝縮した本になります。
既にチーム開発を体験している方は当然の事ながら、
私のような独学でやってきたプログラマーにもオススメな書籍になっています。

理解しやすいコードとはどんなものなのか?といった内容から、
名前の付け方のコツやコメントに書くべき内容などの、
実際に理解しやすいコードを書くために必要な技術や知識が山ほど書いてあります。

言語に依らず、どんなエンジニアにとっても必要な考え方が学べますので、
エンジニアになってまず何を読めば良いか分からない、
という方はとりあえずコレを読んでおけば良いのではと思います。

プログラマが知るべき97のこと

テスト

(引用元:O’Reilly Japan「プログラマが知るべき97のこと」https://www.oreilly.co.jp/books/9784873114798/”)

こちらは、技術というよりもプログラマとしての考え方を学べる書籍となっています。

(実は こちら で全て無料で公開されています。)

まだまだ経験不足で理解できない内容もありましたが、
今でも必要性が理解できて、記憶に残るエッセイも数多くありました。

ネットから無料で読むことも出来るので、通勤時などに少しづつ読み進めています。

3. 静的コード解析ツールで、目視では見逃しがちなミスを捕まえよう!

自分ではとても気をつけているつもりでも、小さなミスを0にするのは中々難しいものでした。
最終的には正しい書き方を覚え、ミス無く書けるようにする…というのがベストだとは思うのですが、
慣れるまでの間、何度も何度もミスを重ねてしまうのは悲しいので、
静的コード解析ツールを導入しました。

静的コード解析ツールというのは、コードを実行せずにコード中の悪い点を見つけてくれるツールです。

例えば、下記のような規約違反だらけのコードがあったとすると、

このように問題点を指摘してくれるツールです。

静的コード解析ツール以外にも、規約に沿った形に自動整形してくれるプラグインや、
過去のGitのCommitと現在のコードを比較するプラグインなど、
業務の効率化が図れるツールは積極的に導入するようにしています。

4. コードにコメントを書き、自分もメンバーも分かりやすいコードに!

コメントが必要な全てのコードにコメントが書かれていれば良いのですが、必ずしもそうではありません。
TAXELのコードの中にも、名前やコードだけでは意図が掴みづらいにも関わらず、
コメントが書いていないコードが多々ありました。

その為、コードを読んだ後は理解した内容をコメントで残すようにしています。
当然の事ながらコメントを書くべきではない箇所もありますので、
その点は気を付けなければなりませんが、
自分やチームの助けになるだけでなく、コメントにまとめる事で理解が進むように感じています。

5. キレイなコードを読み、参考にしよう!

成長する為には、上手い人のやり方を真似するのが近道である場合が多いと思うので、
一度キレイなコードを読もうと考えました。

TAXELのコードも、私から見ればキレイなコードではありますが、
それ以上にキレイなコードを見てコーディングの参考にする為に、
オープンソースのコードを読んでみる事にしました。

先輩にオススメを聞いたところMastodonが良いと聞きコードを読んでみたのですが、
とてもシンプルで読みやすく書かれており、キレイなコードを書く上での勉強になりました。

まとめ


今回の記事では、私が入社後体験した苦労や、その中でも最も苦しかったコードレビューへの自分なりの対策を書かせて頂きました。
私なりの対策ですのでより良い方法もあるかと思いますが、ほんの少しでも参考になったら嬉しいです。

上記の対策をしても尚、まだまだレビューを通すのに時間が掛かる毎日ですが、
一日でも早く成長してコードレビューやその他業務をミス無くこなせるように頑張ります!