astamuse Lab

astamuse Labとは、アスタミューゼのエンジニアとデザイナーのブログです。アスタミューゼの事業・サービスを支えている知識と舞台裏の今を発信しています。

そろそろネタがないのでテストに関しての雑談です

どうもえいやです。

最近の業務ではオンプレサーバからのGCP移行とか、負荷試験の対応とか、JVMのチューニングとか、観葉植物の手入れとか色々あるんですが、その辺は当たり前にやることをやってるだけで、ネタにできるほどのことも、書く時間もないので、今回はとてもいい加減な感じでテストの話をしようと思います。

雑談とか、日記とかポエムとかそういう類のものです。コード例もありません。内容の推敲も、事実の確認もないです。

普段ふわっと思ってることを書きます。

「テストは重要」と分かっている人は、それ以上の内容はないので読む必要はありません。最後の1行まで飛ばしてください。

以下、いつもの通りですが、なにもかもがいい加減なので、可能な限りスルーしてください。

さて、「テストを書きましょう」と、プロジェクトで話が出るとき、一体いつのフェーズからそれを言い出して、書き始めるのはいつなのか。また、言い出した理由はなんでしょうか。

もちろん、プロジェクト、チームによって違います。

弊社で僕が担当しているプロジェクト(のサーバサイド限定)で言えば、まず言い出す時期について、多くの場合かなり遅めの段階で出ます。

モノが出来上がって、リリースして、稼働して、バグがちらほら出始めてから、くらいですかね。言い始めるのは僕で、言わないと永遠にテストが書かれることはないでしょう。言っても書かれるとは限らないけど。

ただし、その時点までにテストが全くないわけではなく、実装者が不安を感じるシーンではテストが書かれている部分もあります。その前提として、プロジェクトのコードが書かれ始める前に、テストフレームワークの選定や、多少個々人の趣味によりますが、テストの手法の検討も大体済んでいます(いるよね?)。

テストの話をすると、かなりガミガミ言ってくる人も多いので、TDDでやらなきゃとかテストファースト当然とか思う人も多いと思います。それらの手法にメリットがあることも事実で、デメリットなどない、と豪語する人もいるでしょう。

では、「テストを書きましょう」と本格的な指示が出るのが遅いことを以て、このプロジェクトはダメなプロジェクトでしょうか。

そのこと判断するまえに、「テストを書きましょう」と言い出す理由について考えてみましょう。

もちろん、限られたリソースを割いて「テストを書きましょう」というからには、テストの効果に期待しているわけです。

テストの効果は一般的に言われていることでは、1)「バグを検出し、品質を高める」ということが主なところでしょう。テストを実行可能なコードとしておくことで、変更都度の確認も楽にできます。

さらに、BDD形式のテストコードについてよく言われることでですが、2)「仕様のコード化」という効果もあります。仕様書やコメントは簡単に嘘をつきますが、実行可能な形式のテストコードは、少なくとも動作については嘘をつきません。

それに加えて、これは一般的にどう言われているのかわかりませんが、個人的には実装者に対しての3)「実装コードへの理解度を高める」学習効果もテストを書く上での重要な効果だと考えています。

この学習効果には、実装者が頭の中やサンドボックス、実コードへの試しの実装など、実装の途中で大体行っているような「一旦書いてみる」コードの正確度を高め。試行錯誤の回数を減らし、ひいては生産性を向上させる効果があります。

また、学習効果は品質にも影響があると想定されますが、学習進度が高い実装者であってもバグを組み込むことが往々にして存在するという経験則から、学習効果と品質の相関はこの際無視します。

学習効果の性質として、学習効果による生産性の向上は、あるプロジェクトの中で必要十分となる内容に限定すると、一定で頭打ちになります。

翻って、上述のテストの時期が遅いプロジェクトにおいて、1~3の効果がどれほど期待できるのかについて考えることで「テストを書きましょう」の指示が遅すぎるのかを判断してみましょう。

情報の後出しになりますが、このプロジェクトの性質として、次のようなことが言えます。

  • 品質と密接な関係があるプログラムの複雑度について、初期リリース時点では可能な限り低く抑えた設計を行っている。仕様が複雑であっても、サーバサイドのプログラムの複雑度に寄与しない。
  • リリース初期段階では、仮に停止していたとしても、売り上げ的な意味での機会損失につながらず、利用者もほとんどいない非クリティカルなサービス。かつ、全て自社サービス。
  • 仕様について、リリース後に見直されることがなく消失したり、同じ名前で呼ぶ全く違う存在になったりすることがほとんど。
  • 十分に学習済みのフレームワークを用いて、学習済みの手法を用いて、学習済みのチームメンバーのみで初期リリースまで行う。

以上の点で、

  • 1)について、高品質がまるで求められてない。
  • 2)について、リリース初期段階の仕様を見直すことはほどんどない。
  • 3)について、メンバーの学習進度は頭打ちになっているため、テストコードによる学習が生産性の向上につながりにくい。

のがプロジェクトの初期の段階です。なので、この段階でリソースを割いてテストを積極的に記述しようという号令をしたところで効果が低いのです。こういうプロジェクト、わりとどこにでもあるんじゃないでしょうか。

もちろん、利用者が増えることでプロジェクトが長期化したり仕様が安定化してきたりしてきて、コードに手を入れる必要が出てきたりすれば、要所から順にテストが導入されていきます(理想的には)。

利用者が存在しない限りバグが見つかることはほぼないので、前述の「バグがちらほら」がその合図だったりします。また、この時点以降でテストの保証するコードの範囲がある一定を下回ると、プロジェクトは紛れもなくダメになります(現に下回ってしまうことも常態化しているんだけど)。

以上の点を踏まえて、このプロジェクトはダメなプロジェクトでしょうか。ということを判断すると、たぶん「どちらとも言えない」か「どちらとも言える」ということだと思います。

個人的には、後からテストによって保証されたであろう品質や仕様のコード化がリカバリされる仕組みがない限りはダメだろうなぁと思っています。

ダメじゃない、と言いそうな感じで話を進めてきてなんですが、まぁダメですね。

単純にリソースの増加と無駄なリソースの投資を削減することなどが必要なんですが、まともなやる気に溢れるテストエンジニアかクオリティエンジニアの出現が求められます。

そういうわけで、プロジェクト進行と品質設計がちゃんとできるエンジニアを募集しています。

astamuse.comのcssが崩壊した日(2017/07/14改訂)

2017/07/14更新

主に「抽象的な」と言っている箇所の削除・修正を行いました。

前々回くらいに「cssアーキテクチャのtips」とか偉そうなブログ書いた者ですが、 今回自分のcssを崩壊させてしまいました。まったく笑えない、由々しき事態です。

失敗事例をこういうとこで書くべきなのか悩みましたが、反省と自責の意味を込めて書かせていただきます。

astamuse.comのcssアーキテクチャ

2013年に大幅リニューアルしたastamuse.comのcssアーキテクチャは6つの層で成り立っています。

f:id:astamuse:20170704201421p:plain

※この「widgets」という層ですが、atomicデザインでいう「modules」のようなもので、オレオレ概念です。こいつが後々首絞めます。

例としてデザインを見ていきます。

f:id:astamuse:20170704200020p:plain

このデザインをastamuse.comのcssアーキテクチャで分解していくと、下記のようになります。

f:id:astamuse:20170704200023p:plain

componentsのラベル・ボタン・widgetsの見出し・リストらを、modulesで実装してます。

何ら違和感はないように思えますよね。

少なくとも、このcssアーキテクチャで2013年~2017年まで維持できたという点では「間違いではなかった」はずです。

何が起こったか

本年度より、徐々にastamuse.comのモバイル対応を行っております。

【注釈】astamuse.comの「モバイル対応」方針について

astamuse.comはAsta4Dを使っており、特定のUIをモバイル用UIでオーバーライドすることも容易にできますので、モバイル用cssで「モバイル対応」に取り組んでいます。

.wdg-list-vline は横並びli間に「|」を装飾するwidgets。 f:id:astamuse:20170704200023p:plain

だがしかし!

f:id:astamuse:20170704200025p:plain

モバイルだと上記のようなデザインになり、「vline」という単語が意味不明になってしまいました。utilitiesも同じような事態(.line-bottom, .al-center, etc.. )に・・・。

最悪です。抽象的な概念を取り入れすぎた結果がこれです。

[改訂]「構造と見た目の分離」というcssの基本を軽視した結果がこれです。

反省と今後に向けて

今回反省すべきは

  • astamuse.comプロジェクト(サイトデザイン・制作メンバー含め)に適したアーキテクチャではなく、自分が好きなアーキテクチャを選択してしまったこと
  • 抽象的なclass名をhtmlに書きすぎたこと
  • [改訂] 「構造と見た目の分離」を軽視したこと

の2点です。

このアーキテクチャは、widjets,modulesによって新規・追加コンテンツを作るスピードは確かに上がるのですが、

[改訂]この方法は直感的にwidjets,modulesを組み合わせていくことができるので、新規・追加コンテンツを作るスピードは確かに上がるのですが、

中長期で見たときのスピード(削除・リデザイン)を考えると、本プロジェクトには向いてませんでした。


今後に向けてですが、下図のようなアーキテクチャでリデザインしていこうと思います。 各pageの独立性を持たせており、今度のコンテンツ拡充・削除・変更にも耐えていける設計になるはずです。 (Enduring CSSに近しい思想があるかもしれません。)

f:id:astamuse:20170704213009p:plain

完了時期がいつになるかまだスケジュールをたててませんが、近いうちにまたここで発表できればなと思います。

最後になりますが、astamuse.comの大規模リファクタリングを一緒にやっていただける方や、私のcssうんちく話を聞いてくれる方を切に、切にお待ちしております。

Apache Zeppelin と Spark2 on YARN の連携

こんにちは、データ周りを担当してる朴です。

今日はのデータ分析、可視化ツールで注目されているApache ZeppelinとSparkの連携およびZeppelinのマルチユーザー環境の設定について共有したいと思います。

簡単な紹介

簡単にApache zeppelinの紹介をしますと、Apache zeppelinはwebベースのデータ分析、データ可視化をインタラクティブにできるNotebook系のオープンソースです。
似たようなプロジェクトとしてはJupyter Notebookがあります。

主な特徴としては以下のとおりです。

  • サポートしているバックエンドが豊富
    • ほぼすべてのHadoop エコシステム,JDBCで接続できるRDBをサポート
    • 言語もR,Python,Sql,Scalaなどデータ分析で流行ってる言語はほぼサポート
  • Pluggableなパッケージ
    • 0.7から追加されたHelium機能でサードパーティー制のグラフプラグイン、データインターフェースを追加できる
  • データ分析結果を保存共有できる
    • BIツールとしても使える

Sparkとの連携

Apache zeppelinは様々なデータソースをサポートしてますが、中でもSparkと連携するのが最もベーシックな使い方です。 今回はSpark2.1@CDH5.7.xと連携することを試したいと思います。

  • インストール

公式サイトから2017年6月28日時点での最新バージョン(0.7.2)を落としてくるかソースからコンパイルすることも可能です。

$ wget http://ftp.jaist.ac.jp/pub/apache/zeppelin/zeppelin-0.7.2/zeppelin-0.7.2-bin-all.tgz
$ tar -xvf zeppelin-0.7.2-bin-all.tgz


  • Spark@CDH接続設定

zeppelin_home/confで以下の設定ファイルをコピー

$ cp zeppelin-site.xml.template zeppelin-site.xml
$ cp zeppelin-env.sh.template zeppelin-env.sh

zeppelin-env.shに以下の環境変数を設定

export SPARK_HOME=/opt/cloudera/parcels/SPARK2-2.1.0.cloudera1-1.cdh5.7.0.p0.120904/lib/spark2 // 実際のSparkのホームディレクトリを設定
export SPARK_APP_NAME=zeppelin // これは設定しなくても動く
export HADOOP_CONF_DIR=/etc/hadoop/conf
export MASTER=yarn // sparkをyarnで動かす場合


  • Zeppelinを起動する

zeppelin_home/binで以下のコマンドを叩く

./zeppelin-daemon.sh start

ブラウザでhttp://ホスト名:8080入力して、以下の画面が出ればOK f:id:astamuse:20170622150516p:plain

  • interpreterの設定:Spark

Zeppelinではinterpreterを経由して色んなバックエンドに接続してます。
SparkをYarnで動かすためには以下の設定が必要となります。

右上のanonymousをクリックし、intepreterをクリックします。 f:id:astamuse:20170623163356p:plain

interpreterからsparkを検索して、出てきたsparkのinterpreter画面でmasterにyarnを設定する

f:id:astamuse:20170622152830p:plain

これでSparkをYarn上動かせるようになりました。

  • 軽く動作確認

Zeppelinのホーム画面に戻り、NotebookメニューからCreate new noteを選択して新しいnotebookを作成します。 Default Interpreterはsparkを選びます。

以下のコードを入力して、実行します。

sc.version
res1: String = 2.1.0.cloudera1

sc.master
res1: String = yarn

Spark 2.1がYarnで動いてることを確認しました。

マルチユーザー環境にするには(Multi-user Support)

apache zeppelinは0.6まではマルチユーザー環境のサポートが不十分だったようですが、0.7になってから一気にマルチユーザー関連の機能をいくつかリリースしてありますので、その辺の設定方法を共有したいと思います。
詳細は以下リリースノートのMultiuser Supportをご覧ください。
https://zeppelin.apache.org/releases/zeppelin-release-0.7.0.html

  • ユーザ認証を有効に

デフォルトだとanonymousでログインできますが、これだとzeppelin画面に接続できるすべての人が勝手にnotebookを通して、大切なサーバーリソースを使えてしまうので、あまり望ましくありません。 anonymousログインをfalseにすることでユーザごとのID/PWでログインさせます。 zeppelin_home/conf/zeppelin-site.xmlの以下の2つをtrue -> falseにします。

<property>
  <name>zeppelin.anonymous.allowed</name>
  <value>true</value>
  <description>Anonymous user allowed by default</description>
</property>

<property>
  <name>zeppelin.notebook.public</name>
  <value>true</value>
  <description>Make notebook public by default when created, private otherwise</description>
</property>

zeppelin_home/conf/shiro.ini.templateをshiro.iniにコピーします。

$ cp shiro.ini.template shiro.ini

※ZeppelinはApache shiroを使ってユーザ認証を実現しています。https://zeppelin.apache.org/docs/0.7.0/security/shiroauthentication.html

shiro.iniの中身をのぞいてみるとデフォルトで以下のユーザが設定されていることが分かります。

admin = password1, admin
user1 = password2, role1, role2
user2 = password3, role3
user3 = password4, role2

※id = password, roleのフォーマットで設定されてます。
roleも設定できるので、柔軟な権限設定が出来そうです。

zeppelin再起動します

$ ./zeppelin-daemon.sh restart

再びzeppelin home画面に入るとanynomous代わりにloginボタンが表示されます。
これでnotebookをユーザごとに作成・管理できるようになりました。

user1とuser2でそれぞれログインしてnotebook作ってお互いに相手が作ったnotebookがメニューから見えないことを確認できればOKです。

  • Spark applicationをユーザごとに実行する

上の設定までだとuserは分かれていてもsparkのapplicationは一つを共有することになります。
spark applicationをユーザごとに作成するにはspark interpreterのOptionを
The interpreter will be instantiated Per User in isolated per userに変更する必要があります。

f:id:astamuse:20170622175609p:plain f:id:astamuse:20170622175621p:plain f:id:astamuse:20170622175634p:plain

上記設定をsaveしてrestartすれば反映されます。

user1のapplicationIdを確認

sc.applicationId
res1: String = application_1498098397540_0004

user2のapplicationIdを確認

sc.applicationId
res1: String = application_1498098397540_0005

それぞれ異なるIDが出たので、違うアプリケーションとして動くことが分かります。

以上で、マルチユーザー環境のの設定も完了したので、チームでNotebookを使って作業を進めることができます。

Copyright © astamuse company, ltd. all rights reserved.