astamuse Lab

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

アスタミューゼ開発部の新人育成の話

こんにちはnishikawaです。今年度もあと少しで終了です。花粉が辛い今日この頃ですが、巷では新年度に向けて色んな仕事が舞い込んできているのではないでしょうか。

さて、新年度といえば学生が社会人になる時期でもあります。新しい環境下で始まる社会人生活に緊張や不安を抱いている新社会人も中には居ることでしょう。

一方、採用側の企業はというと、こちらも色々と緊張していると思います。「えっ?採用側も緊張するの?」と思うかもしれないですが、『新人が会社になじむにはどうしたらいいのか』『研修はうまく行くのか』等々、心配事は尽きません。nishikawaの上司は新しい人が入る度に最初のコミュニケーションをどうしようか凄く考えています。それは周りにいる同僚も同様で新人の方が初めて出社した日はオフィスにいつも以上の緊張感があります。

そんなアスタミューゼの開発部ですが、今年はIT業界での業務経験がない方が入社されました。その方は大学も文系卒でプログラミングとは無縁の経歴だったため、新人を教育するにあたり、研修内容をどうしたらいのかというところが部の一番の悩みでした。

そこで、私が提案させていただいたのがジャストシステムさんの開発の方が利用されているJava100本ノックというドキュメントです。これは、Javaを利用する上で必要となる知識や、よく利用するライブラリ、フレームワークについて学習するために作られた問題集です。

Java 100本ノック: https://github.com/JustSystems/java-100practices

この問題集、GitHubに公開されており、初歩的なJavaの操作から言語仕様、コアAPI、ライブラリ、フレームワークととにかく基本を意識した問題が多いのが特徴です。

この問題集を今回弊社では試用期間中に最低2巡することを目標にカリキュラムを組み現在実施中です。

今回は弊社でやっているJava 100本ノックの進め方を記載したいと思います。

  • 1巡目 (現在実施中)
    • とにかく問題を流しでやってみる。分からなかったらすぐ解答・解説を読む
    • 問題文、解答・解説を読んでも分からないところ、それ以外の箇所での分からないところはOJT指導者に質問する
  • 2巡目
    • 1巡目で得た知識を踏まえて問題を解く
    • コーディング規約を意識する
    • テストを書く

1巡目

1巡目はとにかく全体を俯瞰させるためにとにかく問題をやらせています。少し考えて何も閃かなかったらすぐに解答と解説を読むことを推奨し、その上で分からないことを些細なことでも質問させています。

プログラミング経験がないということなので、ターミナルの使い方やbashの話などJavaには全く関係ないことについても質問を受け付け、それに対して実例も見せながら解説しています。1日に解説している時間は2〜3時間程度で、その時間で収まるように新人の方には質問の要点を絞らせ、まとめさせることを強く意識させています。

1巡目のねらいは、Javaの全体像の把握と問題・課題の深掘りによる問題解決能力の育成があります。問題を解いてJavaを理解することは重要ですが、それよりも何が分からないのか、分からないのは何が問題になっているからなのかの把握と追求が一番重要だと考えております。

2巡目

1巡目を踏まえて、今度はJavaを集中して体得するのがねらいです。そのため、2巡目では問題文が求めていることを精査し、それを実現するための手法を考えることに重きを置いています。また、2巡目ではすべてのコードに対してテストコードを書いてもらおうかと考えています。

Java 100本ノックをやってみての感想

1ヶ月間、Java 100本ノックを新人にやらせてみて振り返ってみると色んなものが見えてきました。

良かった点

  • Java のコーディングの仕方、機能の使い方が分かる
  • 業務上では使わない機能も問題に取り上げられている
  • ちゃんとやればやるほど、教える側と教わる側、それぞれの勉強になるような問題が多い

Java 100本ノックの効果は教える側と教わる側がそれぞれいるときに最も享受できると思います。教える側と教わる側がそれぞれ顔を付き合わせて問題に取り組むことで両者とも知識が深められます。

ポイントは

  • 問題の意図をちゃんと理解する
  • 解答・解説を理解し、コードを1行ずつしっかり追って理解する

です。nishikawaも色々と教える上で分からないことに直面する機会が多かったのでとても勉強になりました。

良くなかった点

  • プログラミング初心者向けではない
  • Javaを独学で勉強する場合には効果が薄い

良くなかった点はこの問題集は初心者向けに作られていないところだと思います。問題自体はある程度Javaもしくは何かのプログラム言語を使ったことがある人を前提にして居る節があるため、本当の初心者がやるには少し辛いと思います。ですので、この問題をやる場合はJavaの入門書を事前にある程度やっていることをお勧めします。

また、独学でやる場合理解が中途半端になる可能性があるので注意が必要だと思います。学習全般に言えると思いますが、クロスチェックはある程度必要なので、これも例外ではないと思います。

結局どうだったのか?

現在、1巡目を行なっていますが、結論から言うとかなりの成果が出ています。新人の方がとても優秀だと言うこともありますが、分からないところへの分析がよくできるようになってきているため質問が問題を解くごとに少なくなっています。

問題を解くことに関しては、まだ知識や経験が不足しているため、自力では難しいですが、コードを読んで分からない箇所を自信で調査し独力で理解するという行動ができるようになってきています。

以上を踏まえると、申し分ない成果が出ていると思います。しかし、今回新しく入った新人の方が優秀だということも多分にあるため、今後も様々な育成をやっていく中でastamuse開発部の育成方法をちゃんと確立できるように試行錯誤していきたいと思います。

デザイナーもデブサミに行った方がいい理由をざっくりまとめてみた

f:id:astamuse:20180228115428j:plain

こんにちは、@YojiShirakiです。デザイナーです。

先日、デブサミ2018がありましたね。当日のタイムラインでは各セッションに関してのツイートが流れ、はてブでは資料情報などがホットエントリーに入っており、今年も盛況だったことが窺えます。私はというと、突如の高熱(インフル)で全く起きれずスマホでタイムライン追って様子を見ていました。

私はデザイナーですがデブサミなどエンジニア向けの大型のイベントは極力参加するようにしていて、毎回かなりよい感触を得ています。そして毎回「これはデザイナーも来た方がいいのでは?」と思っています。

そこで今回は、デザイナーである私が過去数年に渡ってデブサミに参加した経験から、デザイナーがデブサミに行った方がいい理由をまとめました。ぜひご覧ください。

デブサミはエンジニアのためだけのイベントではない

まず大前提ですがデブサミ(Developers Summit)はもはやエンジニアだけのイベントではありません。名前だけみるとエンジニアのためのイベントに見えますが、決してそんなことはありません。試しに先日のデブサミ2018のセッションをご覧ください。

ざっと見ただけでもエンジニア以外にも通じるセッションがいくつもあります。

どれもプロジェクトマネージャーやプロダクトマネージャーにとっても聞く価値がある内容ですし、デザイナーにとってももちろん参考になる内容です。

他にもこんなのもあります。

最近ホットな働き方についてのセッションですね。エンジニアリングというのはあらゆるところに関係するので、デブサミというのも決して技術だけの話に留まらないのです。

情報収集効率が良い

デブサミなどの大型イベントは情報収集効率が非常に良いです。先ほど紹介した通り非常に多岐にわたる内容を2日間でまとめ聞きすることができます。仮にもしこれを別々の勉強会で聴こうと思ったら相当な時間をかけねばなりませんが、デブサミであれば2日で済みます。また空き時間は休憩スペースで仕事できるのでリモートで作業しながらセッションに参加ということもできます。

プレゼンの参考にも

また、デブサミで発表される内容は相応に吟味されているものが多いので情報の質も高いです(ハズレもありますが)。有料セミナーほどではないかもしれませんが、控え目に見てもエンジニアイベントで最大規模のものなのでプレゼンテーターもよく練習しています。時間の使い方、スライドの見せ方、ウケの取り方など、プレゼンテーションの参考になります。

今、技術で何ができて何が難しいのかを知れる

デブサミでいろいろなセッションを聞くと「今は、ここまでできるんだな」とか「これはまだ技術的に難しいのか」といった感触を肌で感じられます。これが本当にありがたく、デザイナーにとっては引き出しの数が増やすネタになる生産性向上にも繋がります。

例えば、サイトにチャットのシステム埋め込んでユーザーの体験性を向上したり、機械学習を利用してユーザーに対してよりよい情報を提供する、など技術的に実現可能なネタを理解できていればサービスの改善幅が格段に広がります。さらに、デブサミではそう言った話を実際の体験談として教えてくれるので、先回りして失敗を回避でき、実現可能性を高めてくれます

また生産性でいえば、ここ数年浸透したDevOpsの動きなどに代表されるような事例は非常に参考になります。チャットオプスや、ツール導入によるコミュニケーション品質の向上・作業時間の圧縮、プロジェクト成功のコツなど。

弊社でもチャットオプスは導入していて非常に助かってますが、こういった事例は実際に話を聞いてみると、わかることもたくさんあります。

他社のサービス開発の裏側を見ることができる

他社のサービス開発ってどうなってるか興味ありませんか?自社ではこうしているけど他ではどうしているんだろう、と。こういった話はデブサミでは本当にいろいろな方が話してくれています。「スクラムやったけどうまくいかなかったよ」とか「trello使ってこんな感じでプロジェクト進められました」など。

また、エンジニアとデザイナーの共生について垣間見ることもできます。エンジニアからはデザイナーがどういう風に見えているのか、またどういう風に巻き込もうとしているのか。こういった自分たちに対しての第三者の目線を知る機会としてもデブサミは非常に良い場所になっています。

デザインとデザイン業界の相対化

デブサミに出てみると「なるほどエンジニアの世界はそうなっているのか。翻ってデザインの世界はどうだろう?」と考えさせられます。決してデザインの世界を揶揄するわけではありませんが、そうやって相対化することで見えてくることは必ずあります。それはデザインの強みや弱み、デザイン業界の課題やアドバンテージなど。

例えば、昨年の11月にAdobe Maxがありました。私も参加したのですが、正直面白いところもあったけれど残念なところも少なくありませんでした。デブサミなどと比較すると「もっとこういう要素があった方が良かったな」と思える点が多々ありました。こういう風に考えられることも(デブサミに限らず)、自分の領域とは違うところに顔を出すメリットなのかと思います。

エンジニアと話せるようになる

これはとても大きいですね。普段のコミュニケーションが変わってきます。

私はもともとコード書くのが好きというのもあり隔てなく話せる方だと思いますが、デブサミやGCP Next Tokyo(Googleの主催する大型イベント)に参加してエンジニアのみんなと一緒に先端の情報に触れるとまた格段と話しやすくなります。

  • 「あのセッションで聴いた内容いいよね」
  • 「もっとこういう技術使ってワークフロー改善したらいいかもね」

と言ったような。

あとはいくつものセッションを聴いていると、だんだんとエンジニアがどういう考え方をして何に重きを置くのかということを体感として理解できるようになります(そう信じている、という方が正しいかもしれませんが)。こういった共通感覚を醸成できるのも大きな収穫になると感じます。

いずれにせよ、エンジニアとデザイナーは協力することで良いものを生み出していくので、お互いのことを知るというのは大事という、至極当然な話なのですが。

おわりに:デザイン以外の領域にも触れるマインドがとても大事

デザイナーは気づいたらコミュニティーの内側に閉じこもってしまいがちです。自分の世界を大事にするというか。でも、私たちデザイナーが相対するのは「人」ですから、閉じこもらずに様々な領域、少なくても自身の近接領域であるエンジニアリングやマーケティングの世界を知ることを是非大事にしてもらいたいな、と思います。また、日々の発想を豊かにするためにまったく違う領域に興味を持つ好奇心は常に高く持ちたいな、と。

では、本日も最後までお読みいただきありがとうございました。

例によって当社では一緒に開発してくれるメンバーを募集しております。カジュアル面談も随時行っておりますので、「ちょっと話聞きたい」という方は、このブログのサイドバー下にあるアドレスか@YojiShirakiあたりにDMいただければと思います。採用サイトもありますので↓↓↓のバナーから是非どうぞ!

(過去記事)

Spark でUnit Testを書く

こんにちは、朴と申します。

本日はSpark-testing-baseを使ってSpark処理の単体テストの書き方について触れてみたいと思います。
ローカルで並列処理の単体テスト動かすのは少しハードル高く感じるかもしれませんが、
ちょっとした設定でスムーズに動かせたので、設定から簡単なテストまで書いてみたいと思います。

Spark-testing-baseの概要

ローカルでSparkのプログラムの単体テストを書く為のフレームワークです
複雑な設定をせず簡単にSparkプログラムの初期化、起動ができます。
簡単な紹介など、以下のリンクから確認できます。
Spark-testing-base

設定

とりあえず、公式サイトにある通り設定を行います。

  • sbtプロジェクトのbuild.sbtに以下のdependencyを追加します。
    ※2.2.0の部分は実際使うSparkのバージョンに合わせてください。
"com.holdenkarau" %% "spark-testing-base" % "2.2.0_0.8.0" % "test"


  • OutOfMemoryError 防止の為以下の設定も追加して置きます、メモリは適宜調整してください。
fork in Test := true
javaOptions ++= Seq("-Xms512M", "-Xmx2048M", "-XX:MaxPermSize=2048M", "-XX:+CMSClassUnloadingEnabled")


  • テストでのparallel 実行を無効にする
parallelExecution in Test := false

以上で設定完了です。

書いてみる1

続いて公式サイトのwikiにあるサンプルを一個書いて、動作確認をします。

class test extends FunSuite with DatasetSuiteBase {
  test("simple test") {
    val sqlCtx = sqlContext
    import sqlCtx.implicits._

    val input1 = sc.parallelize(List(1, 2, 3)).toDS
    assertDatasetEquals(input1, input1) // equal

    val input2 = sc.parallelize(List(4, 5, 6)).toDS
    intercept[org.scalatest.exceptions.TestFailedException] {
        assertDatasetEquals(input1, input2) // not equal
    }
  }
}

IntelliJ IDEA起動して動かしますと以下のエラーが出てました。

java.lang.NoClassDefFoundError: org/apache/hadoop/hive/conf/HiveConf$ConfVars
...
...
Caused by: java.lang.ClassNotFoundException: org.apache.hadoop.hive.conf.HiveConf$ConfVars

エラー内容でググってみたらどうやらdependencyが足りないようなので、以下を追加します。
sparkVersionはご自身の環境に合わせてください。

"org.apache.spark" %% "spark-hive" % sparkVersion % "test"

今度無事起動するかと思ったら違うエラーが出てました。 どうやらHiveSession起動時にローカルだとうまく行かないみたいですね。

java.lang.IllegalArgumentException: Error while instantiating 'org.apache.spark.sql.hive.HiveSessionStateBuilder':
...
...
Caused by: java.lang.RuntimeException: java.lang.RuntimeException: Error while running command to get file permissions : java.io.IOException: (null) entry in command string: null ls -F C:\tmp\hive

Spark Hiveをoffにすることでエラーは回避できるみたいなので、
上記のテストケースの一番最初に以下を追加します。

class test extends FunSuite with DatasetSuiteBase {
  override implicit def enableHiveSupport: Boolean = false  // 追加
  test("simple test") {
    val sqlCtx = sqlContext
    import sqlCtx.implicits._

    val input1 = sc.parallelize(List(1, 2, 3)).toDS
    assertDatasetEquals(input1, input1) // equal

    val input2 = sc.parallelize(List(4, 5, 6)).toDS
    intercept[org.scalatest.exceptions.TestFailedException] {
        assertDatasetEquals(input1, input2) // not equal
    }
  }
}

これで無事起動できました。

 主なクラスの紹介

  • SharedSparkContext
    SparkContextをローカルで使える形で提供

  • RDDComparisons
    RDD比較用クラス

  • DataFrameSuiteBase
    DataFrameのテスト用

  • DatasetSuitBase
    Datasetのテスト用

  • StreamingSuiteBase
    streamのテスト用

各クラス使い方は公式サイトのwikiに乗ってる通り直感的で分かりやすいので、ここでは割愛します。

自分のテストを書いてみる

いよいよご自身のテストを書きます。
以下のようなクラウドファンディングデータを読み込んでそのデータが期待とおりとなってるか確認します。
以下データ一部※

{
  "raised": {
    "currency": "USD",
    "amount": 1685
  },
  "goal": {
    "currency": "USD",
    "amount": 2000
  },
  "short_description": "to find a better/safer way to diagnose, monitor and guide those with EGID's on their life journey",
  "name": "EoE Chompers",
  "project_id": "193451"
}
{
  "raised": {
    "currency": "USD",
    "amount": 50
  },
  "goal": {
    "currency": "USD",
    "amount": 12000
  },
  "short_description": "Help provide 70 children with a new roof to keep them healthy and a boundary wall to keep them safe!",
  "name": "A New Roof and Safety Wall for 70 children",
  "project_id": "193469"
}

テストコード

class MyTest1 extends FunSuite with DatasetSuiteBase {
  override implicit def enableHiveSupport: Boolean = false

  test("count should be equal") {
    val ds1 = spark.read.json("c:\\temp\\cf_example_projects.json.gz")
    assertTrue(ds1.count() == 38080) // 実際Datasetのレコード件数とファイルの行数が一致するか
  }

  test("id should be unique") {
    val ds1 = spark.read.json("c:\\temp\\cf_example_projects.json.gz")
    val projectIdCount = ds1.select("project_id").distinct().count()
    assertTrue(projectIdCount == 38080)
  }
}

ちょっと進化させてみる

上のファイルを読み込む部分は以下のようにメソッド化して、このメソッドについてテストを書きます

object MyObject {
  case class Cf(projectId : String, name : String, shortDesc : String, currency : String, goalAmount: Double,raisedAmount:Double)
  def json2ds(spark:SparkSession,path:String) : Dataset[Cf] = {
    import spark.implicits._
    val ds1 = spark.read.json(path)
    ds1.map { r =>
      Cf(
        r.getAs[String]("project_id"),
        r.getAs[String]("name"),
        r.getAs[String]("short_description"),
        r.getAs[Row]("goal").getAs[String]("currency"),
        r.getAs[Row]("goal").getAs[Double]("amount"),
        r.getAs[Row]("raised").getAs[Double]("amount")
      )
    }
  }
}


class MyTest2 extends FunSuite with DatasetSuiteBase {
  override implicit def enableHiveSupport: Boolean = false

  test("one of selected record should be exist") {
    val ds1 = MyObject.json2ds(spark,"c:\\temp\\cf_example_projects.json.gz")
    val result = ds1.where($"projectId".equalTo("193469"))
    val excepted = Seq(Cf("193469","A New Roof and Safety Wall for 70 children","Help provide 70 children with a new roof to keep them healthy and a boundary wall to keep them safe!","USD",15000d,50d)).toDS()
    assertDatasetEquals(excepted,result)
  }

  test("no such record") {
    val ds1 = MyObject.json2ds(spark,"c:\\temp\\cf_example_projects.json.gz")
    val result = ds1.where($"projectId".equalTo("xxxxxx"))
    val excepted = Seq(Cf("xxxxxx","A New Roof and Safety Wall for 70 children","Help provide 70 children with a new roof to keep them healthy and a boundary wall to keep them safe!","USD",12000d,50d)).toDS()
    intercept[org.scalatest.exceptions.TestFailedException] {
      assertDatasetEquals(result, excepted)
    }
  }
}

テストデータ作成用のクラス(Generator)も

使う場面がちょっと微妙ですが、テストデータ用のDataset、DataFrameを生成することも出来ます。

サンプルそのまま張り付けておきますが、こんな感じです。
動かすにはhttps://github.com/rickynils/scalacheck/blob/master/doc/UserGuide.mdというものが必要らしいです。

class SampleDatasetGeneratorTest extends FunSuite with SharedSparkContext with Checkers {
  test("test generating Datasets[String]") {
    val sqlContext = new SQLContext(sc)
    import sqlContext.implicits._

    val property =
      forAll(DatasetGenerator.genDataset[String](sqlContext)(Arbitrary.arbitrary[String])) {
        dataset => dataset.map(_.length).count() == dataset.count()
      }

    check(property)
  }

}

最後に

Sparkの単体テストについてはメジャーなやつがないのが現状だと認識してますので、
ここで紹介したのは一つの選択肢としてみて頂ければと思います
上記以外にもいくつか選択肢があるみたいですので、色々試してみるとご自身に合うものを見つけられるでしょう。

弊社ではエンジニア・デザイナー絶賛大募集中ですので、興味ある方は気軽にお話でも聞いてみませんか?

Copyright © astamuse company, ltd. all rights reserved.