ZEALS TECH BLOG

チャットボットによる会話広告『fanp』を開発する株式会社ZEALSのテックブログです。技術やエンジニア文化について情報を発信します。

テクノロジーお師匠さんにトレタ元CTO 増井氏、ドリコム元技術担当執行役員 白石氏、MUGENUP CTO 横山氏がジョインしました!

https://cdn.user.blog.st-hatena.com/default_entry_og_image/152935579/1533178284500194

こんにちは!ZEALS CTO島田です。

弊社開発チームで“テクノロジーお師匠さん制度”を導入しました。
テクノロジーお師匠さん制度では、テック界隈で第一線で活躍なさっている方々に参画していただくことで、開発体制の組織化や技術力向上など、組織的な課題解決を目的としております。
今回、テクノロジーお師匠さん制度でジョインなさったのは、トレタ 元CTO増井氏ドリコム 元技術担当執行役員白石氏MUGENUP CTO横山氏です。

増井師匠

f:id:zeals-engineer:20181010174729j:plain

経歴

「風呂グラマー」や「IT芸人」の相性で呼ばれ、トレタやミイルを始めとしたB2C、B2Bプロダクトの開発を行う傍、業界著名人へのインタビューや年30回を超える講演、オープンソースへの関わりなど、外部へ向けた発信を積極的に行なっている。
「ムダに動いて、面白い事を見つけて、自分で手を動かして、咀嚼して、他人を巻き込んで、新しい物を楽しんで作る」を信条に日夜模索中。
日米で計4回の起業をしたのち、2018年10月に独立し"Product Founder"として広くプロダクトの開発に関わる。


レジュメはこちら

白石師匠

f:id:zeals-engineer:20181010174756j:plain

経歴

さまざまなBtoB・BtoCのサービスやインターネットインフラ構築のプロジェクトに携わる。
ソフトバンクグループ、 株式会社レコチョク等を経て、2012年ドリコムに入社、技術担当執行役員に就任。
2018年より株式会社メルカリに参画、テックカンパニーを目指す同社のエンジニア組織の強化を担当。
並行して株式会社スライストーンを創業、株式会社ZEALSを始めスタートアップから上場企業まで複数社の技術アドバイザーを務めている。

横山師匠

f:id:zeals-engineer:20181016105332j:plain

経歴

金融SIerにおいて業務管理システムの開発・運用に携わったのち、2012年よりドリコムに参画し、海外向けブラウザゲーム、ネイティブゲームをテックリードとして担当。
2014年から株式会社MUGENUPに参画し、サービスの企画からインフラ構築、アプリ開発全般に従事する。
2015年より同社CTOに就任し、技術戦略の策定、情報セキュリティ管理支援基盤の構築、新規事業開発に取り組む。
これまでのエンジニアリング経験を社会に活かしたいという思いから、ITサービス企業数社の技術アドバイザーおよびプロダクト開発を行っている。

さいごに

株式会社ジールスの開発組織では豊富な経験を持つお師匠さん方をお招きし、私達のVISIONである”日本をぶちあげる”という志を胸に日々思考して開発して参ります。
採用も積極的に行っておりますので、ご興味のある方はwantedlyからお気軽にご応募ください。
ランチでもなんでも、ご連絡お待ちしております!

www.wantedly.com www.wantedly.com zeals.co.jp

続きを読む

ZEALS初のエンジニア開発合宿に行ってきました!! @伊東

f:id:zeals-engineer:20181006184125j:plain

皆さんこんにちは!
プロダクトマネージャー兼サーバサイドエンジニアの福本です!

10月5日(金)〜6日(土)の2日間をかけて、ZEALSでは初となる『エンジニア開発合宿』を行いました!!
今回はZEALSの全社合宿でもお世話になっている旅館『山喜』にて合宿を行いましたので、その様子をご紹介できればと思います。

開発合宿の目的とZEALSの企業VALUE

  • From Zeal:業務から切り離された集中できる環境で、エンジニア全員が課題解決に熱狂する
  • Bet On Paradox:普段の業務では扱わない技術や分野に取り組むことで、チームの技術力やプロダクトの品質向上を行う
  • United Will:エンジニア全員が時と場所を同じくし共通の活動に取り組むことで、組織の力を向上させる (※ZEALSの企業VALUEについて、詳しくはこちらです!)

タイムテーブル

10月5日(金):1日目

  • 12:00~:旅館『山喜』にて現地集合
  • 13:00~:オープニング、チームに分かれ開発開始
  • 18:30~:各チームより中間発表!
  • 19:00~:夜ご飯
  • 21:00~:レクリエーション

10月6日(土):2日目

  • 09:30~:朝ごはん
  • 11:00~:オープニング、チームに分かれ開発開始
  • 16:00~:最終プレゼンテーション!
  • 17:00~:クロージング、解散

内容

  • 合宿で取り組みたいテーマをエンジニアが事前に考えてきて出し合いました!
  • テーマの中にやりたいものがあれば、エンジニア自らそのテーマに参加する方式を取りました!

f:id:zeals-engineer:20181005215322j:plain

  • 今回挙げられたテーマの中で実際に行われた開発は、以下の5つです!
    • プロダクトのセキュリティを強化する(僕はここに参加しました!)
    • 機械学習や人工知能、ディープラーニングをやってみる
    • プロダクトに活きる分析基盤を作る
    • 組織における課題解決のフレームワーク考案
    • ひたすらコードをリファクタリングする

1日目

  • チームによって協力しながら進めるチームもあれば...

f:id:zeals-engineer:20181005215334j:plain f:id:zeals-engineer:20181005221219j:plain

  • 個人で考え抜いて課題を前に進めるチームもありました!

f:id:zeals-engineer:20181005221240j:plain

  • 機械学習に取り組んだチームは、機能の設計からガッツリと取り組んでいましたね!

f:id:zeals-engineer:20181005215329j:plain

  • 1日目の終わりには各メンバーから中間発表を行い、経過のフィードバックを受けました!

f:id:zeals-engineer:20181005222309j:plain

  • 夜はメンバーお待ちかねのご飯...

f:id:zeals-engineer:20181005224220j:plain

  • その後は、持ち寄ったゲームをメンバー全員で楽しみました!!

f:id:zeals-engineer:20181005224611j:plain

2日目

2日目は朝ごはんを食べてから、夕方まで1日目の続きに取り組みます!

  • 各チーム集中して開発、さすがみんなエンジニアですね f:id:zeals-engineer:20181006185034j:plain

f:id:zeals-engineer:20181006185810j:plain

  • 16:00からは開発したもののアウトプットを全員に向けて発表しました!

f:id:zeals-engineer:20181006184608j:plain

f:id:zeals-engineer:20181006185310j:plain

各チームやメンバーの発表に対して、

  • こうしたらプロダクトに取り入れられるんじゃないか?
  • 今後はこうやって改善していこう!

という、とてもポジティブな意見が集まっていたのが印象的でした!

その後はついにクロージングということで、開発合宿のプログラムは終了。
振り返ればあっという間の2日間でした!

良かったところ・反省

良かったところ!

  • 開発合宿の目的3つをすべて達成できたこと!
  • 各メンバーの興味のある技術領域を知ることができたこと
  • 思いがけない観点からプロダクトに活かせる技術を発見できたこと
  • 開発から離れているメンバーが久しぶりにコードを書けたこと

反省...

  • 「何に取り組むのか」の粒度をもう少し下げるべきだった
    • 当日になってから何をするか考えるメンバーやチームもあり少し時間をロスしました
  • チームメンバーのまとまり方に差があった
    • 各個人で自由に取り組むチームもあれば、全員でがっちり協力するチームもありアウトプットに差がありました

最後に

2日間に渡って行われた、ZEALS初のエンジニア合宿の様子をご紹介させていただきました!
そして、業務時間を使っての合宿の機会を用意してくれたエンジニア以外のメンバーには改めて感謝です!
得られたものはたくさんありましたが、この10月から始まる下期に向けてチーム一丸となって最高のスタートを切れたことが、ZEALSにとって一番の収穫でした!
ZEALSは『次なる産業革命を起こし日本をぶち上げる』というVisionの達成のために、これからも変わらず全力で走り続けます!
そんなZEALSで日々開発をする僕たちエンジニアチームを、今後とも応援よろしくお願いします!

続きを読む

Getting started with Three.js basics.

f:id:zeals-engineer:20190102170235j:plain

This tutorial requires that you have a basic understanding of javascript and some knowledge of codepen and how to set up a project there. We’ll be recreating the project from the codepen below. It is quite simple and can be set up in around 15 minutes.

https://codepen.io/licebeam/pen/KGzWOw

Three.js is a javascript library that allows you to render 3d in html5 canvas dom elements using webGL. https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API

To setup, we need to create a basic html page that we can insert our "render" into via javascript. First we’ll add the following code to our index.html file.

 <html>
 
 <head>
 </head>
 
 <body>
 </body>

</html>

Secondly we’ll need to add a few css properties to our project. We’ll give the body a margin of zero to have it fill the page correctly. Additionally when we render our canvas element to the dom it will need to have it’s height and width set to fill the body. The code required is below.

body {
  margin: 0;
}

canvas {
  width: 100%;
  height: 100%;
}

Finally we can move on to setting up our Three.js project. Go ahead and add the Three.js cdn link to your javascript in the settings section. https://cdnjs.com/libraries/three.js/

To begin we need to create a new scene object in our javascript code.

var scene = new THREE.Scene();

The scene is where all of our other objects will render to in the future. Next we’ll set up our perspective camera, this will allow us to move around the scene as we please and it also allows us to change how much of the scene is viewable to the user.

var camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);

Next we’ll set up our webGL renderer which will in turn will allow us to render to our desired dom element.

var renderer = new THREE.WebGLRenderer();

We need to set the height and width of the renderer to match our window.

renderer.setSize(window.innerWidth, window.innerHeight);

Now we’ll create our canvas dom element to render into using document.body.appendChild.

document.body.appendChild(renderer.domElement);

Now that you’ve set up the rendering you’ll notice you still have nothing but a blank screen. This is because we need to create some geometry, meshes and materials to render to the screen don't worry it's easier than it seems. We’ll start with a simple square.

var geometry = new THREE.BoxGeometry(8, 8, 8);

The 3 values passed into BoxGeometry are the x, y and z scales of the object. You can make your geometry as big or as small as needed. Now that we have our cube we’ll need a material to apply to it. Think of a material as a skin that covers our cube's geometry.

var material = new THREE.MeshBasicMaterial({
  color: 0xff00f0,
  wireframe: true
});

Our material has two properties a color which takes a hex value and wireframe which is a boolean.

Material creation can be extremely daunting so I suggest you take a look at the different properties on the Three.js documentation here to gain a bit more understanding. https://threejs.org/docs/#api/en/materials/MeshBasicMaterial

Let’s create two more materials, we’ll use them for the other cubes we'll make later.

var material2 = new THREE.MeshBasicMaterial({
  color: 0xffff00,
  wireframe: true
});

var smallMaterial = new THREE.MeshBasicMaterial({
  color: 0xffffff,
  wireframe: true
});

Feel free to experiment with other properties sizes and colors for this example.

Next let’s try another method of creating geometry and create a triangle using vertices. Geometry is extremely complex and requires some knowledge of math in advanced situations. Take a look at the documentation for a more detailed example of what we’ll be doing next. https://threejs.org/docs/#api/en/core/Geometry

Let’s assign our new Geometry object to the variable smallGeometry.

var smallGeometry = new THREE.Geometry();

Each geometry has a property called vertices. Vertices are points in space that can be rendered. Essentially every polygon is made up of multiple vertices in different position.

Let’s make a triangle shape by pushing three vertices to the object in different positions. One thing to note is the term Vector3. If you are from a javascript background you may not be entirely familiar with this but simply put; it is just a set of x, y and z positions in space.

smallGeometry.vertices.push(
  new THREE.Vector3(0, 3, 1),
  new THREE.Vector3(-3, -1, 0),
  new THREE.Vector3(1, 2, 0)
);

Next we’ll push faces to our object, faces are just how each of our vertices connect. Allowing us to apply our materials over the faces of our object.

smallGeometry.faces.push(new THREE.Face3(0, 1, 2));

Next we’ll compute the boundaries of our object.

smallGeometry.computeBoundingBox();

Finally we need to create something to render with our new geometries and materials. We’ll begin by creating three different mesh objects that take two arguments: geometry and material, luckily we’ve already created these so feel free to mix and match.

var cube = new THREE.Mesh(geometry, material);
var cube2 = new THREE.Mesh(geometry, material2);
var centerCube = new THREE.Mesh(smallGeometry, smallMaterial);

Lastly we’ll add our new cubes to the scene so we can see them and setup our camera position to make sure they are in view.

scene.add(cube);
scene.add(cube2);
scene.add(centerCube);

camera.position.z = 5;

But wait, we should make them move. Animating your cubes is very simple. First we’ll create an animation function. Lastly when it comes to animation we’ll need to make sure we render the scene and camera correctly every frame with renderer.render.

var animate = function() {
  requestAnimationFrame(animate);

  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;

  cube2.rotation.x -= 0.01;
  cube2.rotation.y -= 0.01;

  centerCube.rotation.y -= 0.12;
  centerCube.rotation.x -= 0.0;

  renderer.render(scene, camera);
};

All we have to do now is call our animate function and our cubes should be animating on the screen.

animate();

Thanks for checking out this blog post, I hope it gave you a little bit of insight on how to set up a basic Three.js project.

-Dustin Front End Engineer at Zeals

React Render Props

f:id:zeals-engineer:20181002105736j:plain

Hi everyone, my name is Javen and I'm a front end engineer at ZEALS. Today I'm gonna teach you about Render Props!!

What are Render Props?

The term “render prop” refers to a simple technique for sharing code between React components using a prop whose value is a function.

Render Props is a React pattern that has gained a lot of attention over the past year or so. Many React engineers have gone through debates on whether High Order Components (HoC) or Render Props are better for their applications. When all is said and done, both patterns are great but each have their own pros and cons. However, today I'm going to discuss Render Props!

This is an example of a render prop component:

<MyRenderProp
  render={({ data }) => (
    <h1>Hi I'm a Render Prop Component! Here is my data: {data}</h1>
  )}
/>

As you can see in this component, "MyRenderProp", there is a "render" prop that is getting passed down. In this prop, there is a function that returns an <h1> element which renders out "data". "data" is a parameter that gets passed to that function. This is the basic gist of a Render Prop component.

When to use Render Props

It's really hard to know when to use a specific React pattern. It usually takes some experience and practice with multiple variations of components to know which pattern to use.

As for Render Props, it is suggested that whenever you want to be able to share state and/or behaviors that are encapsulated by the component, then you should want to use a Render Prop component.

Example in code

I will continue from the above (finished) example in order to demonstrate the effectiveness of Render Props. So in the example above, there is a component called "MyRenderProp" which wants to display some data with the <h1> element. But right now we don't know what that data and "MyRenderProp" looks like, so I will show it in the code below! 😅

import React from 'react';

class MyRenderProp extends React.Component {
  state = { data: 50 };

  handleIncrement = () => this.setState({ data: this.state.data + 1 });

  handleDecrement = () => this.setState({ data: this.state.data - 1 });

  render() {
    return (
      <div>
        {this.props.render({ ...this.state })}
        <button onClick={this.handleIncrement}>Increment 👆</button>
        <button onClick={this.handleDecrement}>Decrement 👇</button>
      </div>
    );
  }
}

In this code, we want to be able to share the value of "data". To achieve this, we can use this.props.render as a function to pass the "data" state to whatever gets rendered through the "render" prop!

Let's see this component in action!!! 😏🙃

function App {
  return (
    <div>
      <MyRenderProp
        render={({ data }) => (
          <h1>Hi I'm a Render Prop Component! Here is my data: {data}</h1>
        )}
      />
      <MyRenderProp
        render={({ data }) => (
          <p>The percentage of people using Render Props: {data}%</p>
        )}
      />
    </div>
  );
}

As you can see, "MyRenderProp" is fully reusable to anything that needs an increment/decrement button with some related data attached to it!

🎉And that's it! Our Render Props component is fully implemented! 🎉

f:id:zeals-engineer:20180925151843p:plain

However, there is another way to write this piece of code in a much nicer, cleaner, and readable way! (Well... at least it is to me...😅)

In our "MyRenderProp" component render function:

render() {
  return (
    <div>
      {this.props.children({ ...this.state })}
      <button onClick={this.handleIncrement}>Increment 👆</button>
      <button onClick={this.handleDecrement}>Decrement 👇</button>
    </div>
  );
}
In our "App" component return function:

return (
  <div>
    <MyRenderProp>
      {({ data }) => (
        <h1>Hi I'm a Render Prop Component! Here is my data: {data}</h1>
      )}
    </MyRenderProp>
    <MyRenderProp>
      {({ data }) => <p>The percentage of people using Render Props: {data}%</p>}
    </MyRenderProp>
  </div>
)

Two things changed:

  1. In the "MyRenderProp" component, this.props.render got changed to this.props.children.
  2. The "render" prop function on "MyRenderProp" got moved in between the opening and closing tags of "MyRenderProp".

Anything in between the opening and closing tags of a component can be considered a child of that component. That is why we can remove the "render" prop and replace this.props.render({ ... }) with this.props.children({ ... })! And it will still work the same way! 👍You can decide which one you want to use. There is always more than one right way to do finish the job!

Conclusion

This was a simple example that could have been implemented in many other ways, but the purpose was to show how Render Props works. I hope you got a better understanding of what Render Props are and how to use them. If you did, try it out for yourself next time you want to make a reusable component! Also if you need better explanations, I recommend you to read the React docs. I think it explains Render Props more in-depth than I did! 😂The docs and codesandbox should be linked at the bottom of this article.

Thank you for your time! Peace! ✌️

Javen

codesandbox.io

Render Props – React

続きを読む

Dangerを使って簡単なレビューを自動化した

f:id:zeals-engineer:20180921175230p:plain

みなさんこんにちは!

Railsエンジニアをやっとります、高久田(たかくだ)です。

今回は機械的なレビューを自動で行ってくれるDangerというgemを最近弊社でも導入したので、その時のお話をさせてください…

 

Dangerってそもそも何? 

DangerのGithubには以下のことが書かれています

 Stop saying "you forgot to …" in code review

 Formalize your Pull Request etiquette.

  

「あなたは〜をやることを忘れているよ。」ということをやめる。

プルリクエストの礼儀作法を形式化

 

つまり

「プルリクエストの礼儀作法を形式化し、指摘を自動化する」ための便利なgemです

 

導入背景

チーム開発をしていると、そのチームごとにプルリクエストの書き方の決まりやルールなどができてくると思います。例えば

  • テストは必ず書きましょう
  • レビューしてもらいたい時はWIPを外しましょう
  • labelを必ずつけましょう
  • 変更が多い場合はプルリクエストを分けましょう

…などなど

もちろん弊社でも上記のようなルールがあったのですが、

  • テストを書いていなかったり
  • WIPつけっぱなしのままレビュー依頼出しちゃったり
  • labelつけ忘れてたり
  • 1つのプルリクエストでの変更が多すぎたり

…などなどが発生しており、そのようなプルリクエストが上がるたびに同じ指摘を繰り返していました。

しかし、上記で上げたような指摘って誰にでもできるものですよね? いちいち同じ指摘する工数も工数なので自動化しよう!!というのがきっかけです

 

Danger導入

Circle CiでDangerを実行し、プルリクエストに自動でコメントします

 

Gemfileの設定

source "https://rubygems.org"
gem 'danger'

Gemfile編集後に'bundle install'コマンドを実行します

 

Dangerfile設定

'bundle exec danger init'コマンドを実行します

'danger init'を実行すると初期セットアップ実行され、'Dangerfile'が作成されます。

'Dangerfile'としてはクックパッド開発者ブログを参考に以下のように編集しました。

# ===== PR title =====
warn('PR is classed as Work in Progress') if github.pr_title.include? '[WIP]'

# ===== diff size =====
warn('PRの変更量が多すぎます。PRを分割しましょう!') if git.lines_of_code > 500

# ===== Test =====
raise('テストが書かれていません!') if `grep -r fdescribe specs/ `.length > 1
raise('テストが書かれていません!') if `grep -r fit specs/ `.length > 1
# ===== Label ====
labels = github.pr_labels
warn('labelを選択してください!') if labels.empty?

 

  • WIPがつけっぱなしのとき
  • プルリクエストの変更差分が多すぎるとき
  • テストが書かれていないとき
  • labelをつけていないとき

に自動でレビューを行ってくれる設定です。

 

'Dangerfile'を作成すると長文の説明文が流れてくるので、読みつつ、設定しつつenterで進めていきます

 

  • Step1 'Dangerfile'を作成しましたというメッセージ

 

  • Step2 bot用のGithubアカウントの作成を促されます。

'Danger'からプルリクエストに対してコメントの書き込みが行われるので、そのためのアカウントを作成しておくと良いです。

 

  • Step3 botアカウントでアクセストークンを作るように、と言われます。

リポジトリにアクセス可能なアカウントでAPI トークンを作成します。

個人のアカウントでも問題はないのですが、bot用のアカウントだと機械的に指摘されたコメントというように区別できてわかりやすいです

 

  • Step4 Ciの設定を行います。

詳しい案内はないのでGetting Set Upを参照します

Ciのsettingsで対象のリポジトリのAPI permissionsにトークンを登録します。

 

'.circleci/config.yml'に以下のように追記します

- run:
name: Run Danger file
command: bundle exec danger --verbose

 

最後に!

Circle Ciでdangerを使う場合は 'Only Build pull requests'を有効にし、プルリクエスト作成時のスキップを回避してください

 

これで設定は終了です。

プルリクエストをWIPつけっぱなしで作成するとちゃんと指摘してくれてますね! f:id:zeals-engineer:20180921173418p:plain

 

まとめ

このような感じで誰でもできるようなレビューはdangerにまかせて、本当にレビューする必要がある箇所に意識が集中できるようにどんどんしていきたいですね!

マシュマロチャレンジを実施しました!!

f:id:zeals-engineer:20190102170639j:plain
 

こんにちは。
エンジニアインターン生の荒木です。

先日、社内のエンジニアを中心に、
マシュマロチャレンジ を実施しました!

普段の業務にも通ずる学びを得られたので
その様子と学びを共有します。

マシュマロチャレンジ とは?

マシュマロチャレンジ とは、
その名の通り、制限時間内にどれだけ多くのマシュマロを
食べられるかを争う競技です!

 

というのは冗談で、、

マシュマロチャレンジ とは
チームビルディングを学ぶためのゲームで、

限られた量のスパゲッティの乾麺、紐、テープ、マシュマロを使い、
制限時間内にいかに高い塔をチームで建てられるかを競うゲームです。

TED Talk でも紹介されたことがありますので、
ご興味のある方はぜひ、ご覧になってください。

トム・ウージェック:塔を建て、チームを作る | TED Talk

 

いくつかルールがあり、

  • 制限時間は18分。
  • 塔の頂点にはマシュマロを設置しなければならない。
  • 塔は自立していなければならない。
  • 与えられた資材のみを使って塔を作らなければならない。

等が基本的なルールです。

このルールに則って、4人チームで塔の高さを競います。

なぜやるのか?

今回マシュマロチャレンジ を実施した理由としては、

  • 社内のメンバー内で共通の成功体験と失敗体験を作る
  • チームビルディングについて学ぶ
  • 息抜き

等があります。

マシュマロチャレンジ を通して得た学びを
実際の業務に活かしていくことが、期待される成果でした。

 

いざ、マシュマロチャレンジ 

さて、実際に4人チームを3つ作り、
マシュマロチャレンジ をやってみました。

チームのメンバーはランダムに決めました。

f:id:zeals-engineer:20180919132909j:plain

 

f:id:zeals-engineer:20180919132936j:plain

どのチームも様々なアイディアを出し合い、
タワーを建てていきます。 

しかし、結果、
自立した塔を建てられたチームは1チームのみでした。

そのチームのタワーがこちらです。

f:id:zeals-engineer:20180919133510j:plain

マシュマロの高さは56cm でした。
ちなみに世界記録は99cm だそうです。

ここで反省タイムを設けました。

ここで終わってしまってはこのゲームの価値が下がってしまうので
反省をして、その反省を活かせるように
今回は計2回のマシュマロチャレンジ を予定していました。

各チーム、何が問題で、それをどうすれば解決できるのか、
それを踏まえて次のゲームはどういう戦略で挑むのか、話し合います。

マシュマロチャレンジ (2回目)

f:id:zeals-engineer:20180919134726j:plain

2回目の結果は、

2チームが自立したタワーを作り、
前回タワーが倒れてしまったチームの片方が優勝しました。

その優勝チームのタワーがこちらです。

f:id:zeals-engineer:20180919134847j:plain

記録は1回目の優勝チームと同じ、56cmでした。

1回目に優勝したチームはより良いアイディアを立てたものの、
それを制限時間内に実現することができず、記録が下がってしまいました。

1回目に自立したタワーを作れなかったもう1つのチームは
改善策を立て、より強固で高い記録を出せるタワーを設計したものの
自立できるほどの強固さを実現できず、タワーは倒れてしまいました。

 

ここでまた、チーム内で反省タイムを設け、
今度はそれを全体で共有しました。

f:id:zeals-engineer:20180919135425j:plain

この反省タイムで出た振り返りには、

  • いいアイディアがあっても、制限時間内に結果を残せなければ、それは評価されないこと。
  • 役割分担をしたら、その後のコミュニケーションがとても重要だということ。
  • 品質管理をする人や、誰かの無謀な挑戦を止める人がいると、堅実な結果を残せること。
  • 常に必要な作業を機械化する(今回だと足場を補修する作業を、紐で足場を一時的に固定して進める)ことで、リソースを他のことに活用できたこと。
  • 最後になってマシュマロを乗せると、その重みでタワーが崩れたので、途中に何度かテストをすることが大事だということ。

等がありました。

これらは実際の仕事においても言えることが多いのではないでしょうか。

限られた時間、リソースを使って、どれだけ高い結果を残せるのか。

こうしたところを本質とするマシュマロチャレンジ は
ビジネスにおけるチームビルディングを学ぶのに、とてもいい題材でした。

 

最後に

上記のTED Talk の中で登壇者が話されていますが、
職種ごとにマシュマロチャレンジ の結果の平均をとると、

面白いことに、幼稚園児が
MBAの学生や弁護士、CEO よりも高い結果を残すそうです。

これはなぜかと言うと、
大人のチームの多くは、塔を設計し、役割を分けて
実際に塔を建て、最後にマシュマロを乗せる、
という流れで塔を建てます。

しかし多くの場合、
その塔はマシュマロの重みに耐えられません。

一方、幼稚園児たちの多くはまずマシュマロを手に取り、
小さな塔を建ててから、それを補強しながら塔を大きくしていきます。

結果、彼らはしっかりマシュマロの重みに耐えられる塔を作ることができます。

これは非常に示唆に富んだ話だと感じます。

自分たちのビジネスやプロダクトにおいて
マシュマロは一体何に当たるのか、
今後はそうしたことも意識しながら、日々の業務に取り組みたいと思います。

続きを読む

Browser Automation at Zeals

f:id:zeals-engineer:20190102170907j:plain

Intro

Lately, there has been so much movement at ZEALS. As we've expanded, we've been able to meet so many new clients. This has been both a tremendous boon for us as a company, and presented both interesting and tough problems for us on the engineer team to solve. As the our amount of clients increase, so does the amount of data. And as the data increases, our approach to handling said data must be a scalable solution, to free our hands to allow us to focus on bigger and better things. Recently, people would have to manually fill in web forms, which was draining worker's time. One strategy to increase our productivity is to use a headless browser to automate the task. This was suggested to me by our technology lead, and I went ahead and did the implementation, so I'd like to do a sort of introduction as to how I did it.

So many choices...

We needed a server that would be able to serve multiple requests to fill forms concurrently, would have a fairly simple API that would allow you to have the server open a headless web browser, take care of the form and close down. In the end, I decided that Node.js would be a great candidate. Not that I hadn't heard of Python/Selenium solutions before, but there are plenty of headless browser solutions for Node.js, and I was comfortable with Node, so it just seemed like a decent choice. Within the Node ecosystem, there are choices to be made. The top choices for using JS with a headless browser are:

  1. PhantomJS
  2. CasperJS
  3. Puppeteer

However, there are small details to be considered. While all of these choices are technically controlled by JS, what you get is slightly different.

PhantomJS is "a headless WebKit scriptable with Javascript", in other words it's not Node.js, it's a headless browser with a JS API. Not necessarily available from a Node.js process. CasperJS is a "scripting utility written in Javascript for PhantomJS or SlimerJS", meaning it relies on either one of those headless browser.

On the other hand, we have Puppeteer which "is a Node library which provides a high-level API to control headless Chrome over the DevTools protocol". Given that it was the best choice for what I wanted to do, has the most stars on Github, is provided by the Chrome team, AND has great documentation and a modern API, I had my winner. I can't stress this enough, Puppeteer really blows the competition out of the water. If you have a decent knowledge of async/await in ES7 and are aware of which scripts are being executed in the headless browser, as opposed to Node, then this is really just a joy to use.

On top of that, the fact that I'd would simply be able to require the library in my Node server just...almost brought a tear to my eye. :D

The Implementation

f:id:zeals-engineer:20180917114554p:plain

I won't try to bore you with too many details, but here's the gist of the server:

  • Express for the API
  • Puppeteer for headless browser

And here's a gist of what the server does:

  1. The server would except POSTs with JSON sets of instructions on where the form was, how to fill the form, and what was the indication the form was done being sent
  2. The server parses the instructions from the requester, if they seem to be valid, then continue
  3. A headless browser is opened with Puppeteer, if the browser gets the requested page, then the Express server sends a 200 back to the requester
  4. However, the server's not done yet. It goes through all the instructions, and whether it is successful or not, it logs the details

And to be honest, this was looking back now, not too hard to write. However, there are some gotchas that I think people should be aware of:

Gotchas

1. Headless browsers are browsers.

In Puppeteer's case, it's Chromium. And it does everything that that Chromium does. I mean EVERYTHING. It may seem obvious, but there were some weird things I had to learn. For example, a had one case where sending a webform caused an alert box to popup. Of course, since it's headless, I wasn't able to see that. I just assumed the script was hanging for some strange reason. It wasn't until I turned headless mode off (you can do that), that I realized my mistake. You can handle these sort of events with code, but you have to handle them! My advice is to debug with headless mode turned off, and learn to use events well.

2. Just because you have Puppeteer, doesn't mean you have Chromium.

Of course developing using Puppeteer was simple. I already had the Chromium process on my PC. When it comes time to deploy, you need to make sure whatever server/virtual machine/docker instance you're using has the proper software on it for this work. I went ahead and used docker and if you're interested to see how that works, you can check the official Puppeteer docs!

https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md#running-puppeteer-in-docker

See I told you the docs were great.

Closing

Browser automation has been a blast to do, and I hope I can do a bit more in the future and it remains part of our toolset. It's a bit hard to wrap your head around, but when it all comes together it really is beautiful!

Until next time!

- Aaron

続きを読む

React + FirebaseでSignUp実装

f:id:zeals-engineer:20180830205736p:plain

こんにちは。

サーバーサイドエンジニアのjoeです。

メンバーのReactキャッチアップのためにサンプルアプリを作ったので、公開したいと思います。

この記事は、React初心者を対象としています。

簡単なイベント操作から、データの保存までの全体像が把握できるようになるかと思います。

また、githubに残したので、ぜひ参考にしてみて下さい。

github.com

Reactプロジェクトの準備

create-react-appコマンドを使用して、新しくプロジェクトを作成します。

// コマンドをインストールしていない方は以下のコマンドでインストール
$ npm install -g create-react-app
// プロジェクトの作成
$ create-react-app react-firebase-sign-up

プロジェクトの作成が終わったら、Reactプロジェクトを起動してみます。

$ cd react-firebase-sign-up
$ yarn start

この画面が表示できたら、Reactプロジェクトの準備は終わりです。 f:id:zeals-engineer:20180830182740p:plain

Firebaseの準備

まず、TOPからコンソールへ移動を押し、Firebaseにログインします。

firebase.google.com

f:id:zeals-engineer:20180830182321p:plain

プロジェクトを追加ボタンを押し、プロジェクト名を入力した後に、プロジェクトを作成します。

f:id:zeals-engineer:20180830183903p:plain

f:id:zeals-engineer:20180830184110p:plain

Firebaseプロジェクトに入れたら、Authenticationの設定をします。

f:id:zeals-engineer:20180830184505p:plain

プロバイダ、メール/パスワードのステータスが無効になっているので、有効にします。

f:id:zeals-engineer:20180830184713p:plain

ここまでできれば、firebase側の設定は終わりです。

React側でメールアドレス/パスワードのフォームを作り、実際にSign Upしてみましょう。

ReactとFirebaseを連携し、SignUpしてみる

Formの作成

react-firebase-sign-up/src/App.jsのコードは消さずに、そのままFormを追記していきます。

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
        {/* ここから */}
        <div className="form">
          <form className="register-form">
            <input type="text" placeholder="email address"/>
            <input type="password" placeholder="password"/>
            <button>Sign Up</button>
          </form>
        </div>
        {/* ここまで追記 */}
      </div>
    );
  }
}

export default App;

ブラウザを確認すると、ダサいですが、メールアドレスとパスワードを入力するFormが出来上がりました!

f:id:zeals-engineer:20180830191757p:plain

ReactとFirebaseの連携

秘匿情報

まず、react-firebase-sign-up/src/config/firebase.jsを作成します。

Firebaseから秘匿情報を確認し、以下のようにコードを書きます。

*秘匿情報なので、git管理されている方は、.gitignoreに、/src/config/firebase.jsを追記する必要があります。

export default {
  apiKey: "**************",
  authDomain: "**************",
  databaseURL: "**************",
  projectId: "**************",
  storageBucket: "**************",
  messagingSenderId: "**************"
};

秘匿情報の取得方法は、Project Overviewをクリックし、以下のボタンをクリックするとモーダルで表示されます。

f:id:zeals-engineer:20180830192643p:plain

Firebaseを読み込む

まず、プロジェクトにfirebaseをインストールします。インストール後は、サーバを止め、 yarn startで再起動します。

$ yarn add firebase

次に、react-firebase-sign-up/src/App.jsにfirebaseの設定を追記します。

App.jsのコードは以下のようになります。

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

// ここから
import firebase from 'firebase';
import firebaseConfig from './config/firebase';

firebase.initializeApp(firebaseConfig);
// ここまで追記

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
        <div className="form">
          <form className="register-form">
            <input type="text" placeholder="email address"/>
            <input type="password" placeholder="password"/>
            <button>Sign Up</button>
          </form>
        </div>
      </div>
    );
  }
}

export default App;

最後に、メールアドレス/パスワードをfirebaseにPOSTしてみます。

メールアドレス/パスワードをfirebaseにPOST

POSTするために以下の順番で実装していきます。

1. emailとpasswordをstateに定義

mae.chab.in

2. emailとpassword stateを更新できるようにする

mae.chab.in

3. handleSignUpメソッド実装

developer.mozilla.org

4. firebase authのcreateUserWithEmailAndPasswordメソッドを使用して POST

Interface: Auth  |  Firebase

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import firebase from 'firebase';
import firebaseConfig from './config/firebase';

firebase.initializeApp(firebaseConfig);

class App extends Component {

  constructor(props){
    // 1. Stateの定義
    super(props)
    this.state = {
      email: '',
      password: '', 
    }
  }

  // 3. handleSignUpメソッドの定義
  handleSignUp = e => {
    e.preventDefault()
    // stateからemailとpasswordを取得する
    const { email, password } = this.state;

    // 4. firebaseにemailとpasswordをPOST
    firebase.auth().createUserWithEmailAndPassword(email, password)
      .then(user => {
        console.log(user);
        this.setState({ email: null, password: null })
      })
      .catch(error => {
        console.log('firebase error', error);
      });
  }


  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
        <div className="form">
          <form className="register-form">
            {/* 2. テキストが入力されるたびに、State emailが更新されるようにする */}
            <input 
              type="text" 
              placeholder="email address"
              onChange={e => this.setState({ email: e.target.value })}
            />
            {/* 2. テキストが入力されるたびに、State passwordが更新されるようにする */}
            <input 
              type="password" 
              placeholder="password"
              onChange={e => this.setState({ password: e.target.value })}
            />
            {/* 3. handleSignUpメソッドをonPress時に実行されるようにする */}
            <button onClick={e => this.handleSignUp(e) }>Sign Up</button>
          </form>
        </div>
      </div>
    );
  }
}

export default App;

ブラウザで、メールアドレス/パスワードを入力!

f:id:zeals-engineer:20180831135805p:plain

Sign Upをおして、firebase上でユーザーが作成されているか確認する。

f:id:zeals-engineer:20180830205506p:plain

確認できたら、SignUp成功!

firebase便利ですね!