ZEALS TECH BLOG

ZEALS Developers Blog

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

みなさんこんにちは!

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

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

 

Dangerってそもそも何?

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

 

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:20180919111210p: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

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実装

こんにちは。

サーバーサイドエンジニアの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便利ですね!

brew upgrade で mysql 8.0 にしてしまって bundle install で mysql2 でコケた時の話

どうも!Kodyです!(味わい深いことやってます)

 

今回、オンボーディングの中でインターン生(エンジニア)が環境構築してる時に事件が起こったのでメモ代わりに記しておきます。

bundle install できない...

迂闊に brew update してしまい bundle install するとこんなエラー吐かれた

------------------------------------------------

Installing mysql2 0.4.4 with native extensions

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

:
:
:

An error occurred while installing mysql2 (0.4.4), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.4.4'` succeeds before bundling.

------------------------------------------------

バージョン確認する

------------------------------------------------

mysql --version

# mysql  Ver 14.14 Distrib 8.0.xx, ...

------------------------------------------------

8.0じゃぁあん

完全にMySQLを消し去る

MacでMySQL5.7をアンインストールする

を参考にアンインストール(ありがとうございます)

実際に打ったコマンド(コピペ面倒だったので $は省略してます)

------------------------------------------------

brew remove mysql
brew cleanup
sudo rm /usr/local/mysql
sudo rm -rf /usr/local/var/mysql
sudo rm -rf /usr/local/mysql*
sudo rm ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist
sudo rm -rf /Library/StartupItems/MySQLCOM
sudo rm -rf /Library/PreferencePanes/My*
launchctl unload -w ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist
rm -rf ~/Library/PreferencePanes/My*
sudo rm -rf /Library/Receipts/mysql*
sudo rm -rf /Library/Receipts/MySQL*
sudo rm -rf /private/var/db/receipts/*mysql*

------------------------------------------------

PC再起動

コマンドが使えないことを確認

------------------------------------------------

mysql -v

# mysql: command not found

------------------------------------------------

mysql 5.7をインストール

------------------------------------------------

brew install mysql@5.7

------------------------------------------------

パスを通す

------------------------------------------------

echo 'export PATH="/usr/local/opt/mysql@5.7/bin:$PATH"' >> ~/.bash_profile
source ~/.bash_profile

------------------------------------------------

バージョン確認

------------------------------------------------

mysql --version

# mysql  Ver 14.14 Distrib 5.7.20, ...

------------------------------------------------

これで無事 bundle install できるようになりました!

Read more

LINE Messaging APIでクイックリプライを実装してみました。

こんにちは!!!

ZEALS CTO島田です。

2018年7月30日、LINE Messaging APIにクイックリプライが追加されました。

LINEのMessaging API公開から2年数ヶ月、、 遂にきました。

BOTらしいUXなので好きなんですよねーー、、嬉しいです!

 

早速、実装してみました。

 




  

クイックリプライの背景色がグレーなのが少し見にくいかもしれませんね。

に対応しているそうです。

 

Messengerのクイックリプライでは実現できていないカメラアクション、カメラロールアクションが実装されているのが印象的でした。

尚、Messengerのクイックリプライではユーザーがfacebookへ登録しているメールアドレス、電話番号を取得することができます。

JSONのちがい

LINEのJSONはこんな感じです。(サンプルソース引用)


 {
  "type": "text", // ①
  "text": "Select your favorite food category or send me your location!",
  "quickReply": { // ②
    "items": [
      {
        "type": "action", // ③
        "imageUrl": "https://example.com/sushi.png",
        "action": {
          "type": "message",
          "label": "Sushi",
          "text": "Sushi"
        }
      },
      {
        "type": "action",
        "imageUrl": "https://example.com/tempura.png",
        "action": {
          "type": "message",
          "label": "Tempura",
          "text": "Tempura"
        }
      },
      {
        "type": "action", // ④
        "action": {
          "type": "location",
          "label": "Send location"
        }
      }
    ]
  }
}

Messenger APIでのquick replyのJSON


{
  "recipient":{
    "id":""
  },
  "message":{
    "text": "Here is a quick reply!",
    "quick_replies":[
      {
        "content_type":"text",
        "title":"Search",
        "payload":"",
        "image_url":"http://example.com/img/red.png"
      },
      {
        "content_type":"location"
      }
    ]
  }
}

ネストは違いますが要素には大差ないですね。

 

UXは格段に向上するかと思われますので弊社でも積極的に導入していきたいと思います!

Read more

ZEALS TECH BLOGはじめます!

 

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

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

ZEALSではチャットボット、VUIなどコミュニケーションに関するプロダクトを開発しております。

それらのプロダクトを支える技術について、僭越ではございますが少しずつ発信していければと考えております。

また、このブログでは弊社の開発文化等も発信して参ります。

まだまだ発展途上の組織ですので、拙い知識や未熟な部分がございましたらご指導ご鞭撻のほどよろしくお願いいたします..!

 

それでは何卒よろしくお願いいたします!!

 

Read more