2019年2月の記事一覧

ハコベルコネクトをリリースしました!

サーバサイドエンジニアの加藤です。
昨年8月に印刷から運送マッチングサービスのハコベルのチームに異動し、ハコベルコネクトの開発を進めてきました。

ハコベルコネクトとは

現在の物流業界における最大の課題はドライバー不足。ハコベルチームでは、現場の課題を調査し、その原因を探ってきました。見えてきたのは、複数の運送会社によって仕事が行われていることで、システム化が進まず紙・電話・FAXなどアナログで生産性を上げにくい現場環境でした。

ハコベルコネクトは、この情報断絶を解決すべく、大手物流荷主、一般貨物事業者など運送会社を自由度高くつなぐ物流プラットフォームを目指しています。

先月 1月24日に記者発表をし、日経新聞やTechCrunchにも取り上げられました。弊社CTOの泉がスマホのGoogle Chromeの新規タブで出てきたとのことで、社内でもちょっとした話題になりました。

今までも提供してきたサービスは、ハコベルカーゴ※に名称変更。これからもラストワンマイル向けのマッチングサービスを提供していきます。

仕事をする人に心地よい体験を

ハコベルコネクトは、PMやデザイナー・エンジニアが現場に足を運び、MVPを開発、実証実験を重ねて、徐々にその姿を明らかにしてできてきたプロダクトです。いくつもの運送会社の事業所に出向き、たくさんの方々にインタビューさせていただいたり、トラックに同乗させていただいたり。仕事をする人がどんな課題と向き合っているのか。様々なプロセスを経て、方向性が定まってきました。

ドライバーアプリイメージ

 

ハコベルコネクトという名前もその中で生まれてきました。SNSのように、会社と会社がつながりスムーズに情報のやりとりができることで、快適に仕事が出来るようにという想いが込められています。

ハコベルコネクトイメージ

技術負債の芽を最低限に ー今しかないでしょ!ー

さて、プロダクトとしてのリリースに向け、エンジニアとしてはどんなチャレンジがあったでしょうか。

  • 実証実験向けに急いで作られた側面があったため、既に技術負債気味なところがある
  • 業界独自の業務をモデリングしているため、キャッチアップしにくい
  • よくある機能でも複雑度が高く、要件の不整合が起きて開発が進みにくい

ハコベルチームには、私を含めラクスルの開発に関わってきたメンバーもいます。

「そうだ、ラクスルを作り直そう!」という投稿や「生まれ変わらNight -技術的負債からの一発逆転-」というイベントでご紹介させて頂いた通り、ラクスルは技術負債の課題に向き合ってきました。

(ちなみにまだまだ先はありますが、経営陣の理解もあり、ラクスルの技術負債の解消は着々と進んでいます。)

その教訓を活かして、ハコベルコネクトでは、リリース前に負債の芽の解消にも時間を使ってきました。リリース前ならば、ユーザー影響を気にせずにあらかじめアーキテクチャの整備を進めることが出来ます。「今しかないでしょ!」を合言葉に、気なっていたところはどんどん書き直しました。

ただし、特定業界向けのSaaSというサービスの成長特性を考えて、最初からドメイン分割やマイクロサービスを採用することはしていません。ラクスルで蓄積してきているベストプラクティスを取り入れ、まずはRails アプリケーションとしての Rail にきれいに乗るというところに集中しました。

フロントは、ラクスルの他のプロダクトでも採用しているVue.jsを使い、実証実験後にUIをフルリニューアル。Web APIが必要だったため、コントローラやサービスは約80%を書き換えました。

Web APIの開発中には、GraphQLが話題になったり、gRPC-Webが正式リリースになったりしたタイミングで、チーム内でGraphQLのPOCも行なったりしていたのですが、開発の状況を考慮して今回はオーソドックスにRESTful APIで開発していくことにしました。

フロントメンバーとのコミュニケーションやAPI エンドポイントの可視化のため、API仕様はSwaggerで記述することにしています。

チームでプロダクトを開発する ーペア&モブプロ、デザインスタジオー

先ほども書いた通り、ハコベルコネクトは、業界独自の業務をモデリングしているためキャッチアップしにくくチームの生産性がなかなか上がりにくい状態でした。

6ヶ月間でチームも倍増。新メンバーのキャッチアップスピードをあげたり、モチベーションを保ちつつ機能開発スピードを上げるのが重要課題になっていました。

そのため、複数人でコーディングするモブプログラミングやペアプログラミングを取り入れて、難しいドメイン知識を共有しつつ開発を進めたり、モチベーションが上がりにくい機能開発をわいわいと議論しながら進めました。

モブプログラミング用のスペースも導入され、今ではハコベルだけでなく他のチームで取り入れています。

モブプログラミングの様子

また、ラクスルの他のチームで行なっていた、コラボレーティブデザインの手法である「デザインスタジオ」も取り入れました。機能に対して色々なアイデアが出るのはもちろん、デザイナーも含めてこれから作る機能のデータ構造を共有したり、機能の背景を理解するのに役に立っています。

ハコベルチームには、運送業界出身のメンバーもいます。要件がわからない時はすぐに話を聞けるのも、チームで開発を進める上ですごく助けになりました。

新メンバー募集中です

さて、ハコベルコネクトはリリースしましたが、私たちの毎日を支えてくれている物流の現場には課題がたくさんあります。課題を解決すべく、ハコベルコネクトも成長させていきたいと思っています。

「仕組みを変えれば、世界はもっとよくなる」

エンジニアリングの力で世界を変えたいフロントエンドエンジニア、サーバサイドエンジニアを絶賛募集中です。興味を持たれた方は是非一度オフィスに遊びにきてください!

※ 2019/3/4 ハコベルマッチングからハコベルカーゴに再名称変更したためブランド画像更新しました。

“CircleCI agent received a kill signal midway through the job” と急に言われるようになった話(2/12追記)

ラクスルでサーバサイドエンジニアをやっている小林です。

追記(2019/02/12)

CircleCI のバグ(?)だったようで、すでに修正されてます。

また、原因を少し追ったので、追記しました。

結論

CircleCI の command 内で exit すると、エラーになるので、

true / false コマンドを使って回避しました。

 

本編

今日も元気に開発を行っていたら、CircleCI のテストが下記のようなエラーで

失敗するようなりました。

最初、メモリが足りなくて殺されたのかなと思い、Rebuild with SSH でコンテナに ssh して、

topps を見ていたのですが、どうやらメモリ不足というわけではなさそうでした。

また、過去にテストの通っていたブランチを Rebuild してもテストがコケるので、

CircleCI の挙動が何かしら変わったのかなと思い、.circleci/config.yml の設定を見直してみました。

すると、command 内で下記のようなことをしているコードがありました。

status=0
for file in $(
  circleci tests glob \
  "src/*/*Bundle/Tests/**/*Test.php" | \
  circleci tests split --split-by=timings
)
do
  php ./bin/phpunit -c app --log-junit $CIRCLE_TEST_REPORTS/phpunit/${file}.junit.xml ${file}
  if [ $? -ne 0 ]; then status=1; fi
done
exit $status

最後の exit が明らかに怪しいので、試しに消してみたところテストが通りました。

どうやら、exit すると circleci-agent も死ぬようになったのかなと推測されます。

というわけで、下記のように true / false コマンドを使うように修正しました。

status=true
for file in $(
  circleci tests glob \
  "src/*/*Bundle/Tests/**/*Test.php" | \
  circleci tests split --split-by=timings
)
do
  php ./bin/phpunit -c app --log-junit $CIRCLE_TEST_REPORTS/phpunit/${file}.junit.xml ${file}
  if [ $? -ne 0 ]; then status=false; fi
done
$status

変数にコマンドを代入すると、その変数を評価することで、コマンドを実行することができます。

2時間ほどハマったので、同じようにハマった方のお役に立てれば幸いです。

 

追記(2019/02/12)

CircleCI の挙動が何かしら変わった

のところを、もう少し深ぼってみました。

まず、再現条件をもう少し明確にするために、空のリポジトリに下記のような .circleci/config.yml を用意して CircleCI を走らせてみました。

version: 2
jobs:
  build:
    docker:
      - image: circleci/ruby:2.5.1

    steps:
      - checkout

      - run:
          command: exit 0

しかし、これではテストは失敗しませんでした。

問題の起きた .circleci/config.yml と見比べてみると、問題の起きたテストでは shell を変更していたので、下記のように .circleci/config.yml を修正してみました。

version: 2
jobs:
  build:
    docker:
      - image: circleci/ruby:2.5.1

    shell: /bin/bash --login

    steps:
      - checkout

      - run:
          command: exit 0

すると、前述のエラーと共にテストが失敗するようになりました。

shell を指定しない場合、 /bin/bash -eo pipefail で実行されているので、念の為、
/bin/bash -eo pipefail --login を設定してみましたが、やはりテストが失敗しました。

どうやら、/bin/bash --login を設定し、かつ exit するとダメなようです。

さて、--login オプションを指定すると、起動時に ~/.profile を、終了時に ~/.bash_logout を実行するようになります。

Man page of BASH#起動

そこで、Rebuild with SSH でログインして、~/.bash_logout の中身を見てみると、下記のようになっていました。

# ~/.bash_logout: executed by bash(1) when login shell exits.

# when leaving the console clear the screen to increase privacy

if [ "$SHLVL" = 1 ]; then
    [ -x /usr/bin/clear_console ] && /usr/bin/clear_console -q
fi

試しに、/usr/bin/clear_console を手動で叩いてみたところ、無事(?)「”CircleCI agent received a kill signal midway through the job”」というエラーと共にテストが失敗しました。

どうやら、/bin/bash --login で exit すると、~/.bash_logout内の /usr/bin/clear_console が実行され、テストが失敗する、というシナリオのようです。

さらに、/usr/bin/clear_console の中で何をやっているのかを追ってみました。

https://github.com/linuxmint/bash/blob/master/debian/clear_console.c

コードを見たところ、/dev/tty/dev/tty0/dev/console 、stdinstdoutstderr の順番に、ioctl(fd, KBDKBTYPE, &arg) を実行し、キーボードの種類が取得できたものについて、コンソールをクリアするという処理を行っていました。

特に kill している風でもなかったので、また、Rebuild with SSH でコンテナにログインして、開いているデバイスファイルを順に確認することにしました。

screen コマンドをインストールし、順番にデバイスファイルに接続していきます。

すると、screen /dev/console を実行すると、「”CircleCI agent received a kill signal midway through the job”」とエラーになってしまいました。

どうやら、/dev/console を参照しようとすると、エラーになるようです。

と、ここまで調べたところで、CircleCI側で修正されたようで、/dev/consoleを参照しても、エラーにならなくなりました。

無事、修正されたということで、追加の調査はここまでになりました。