株式会社メドレーのブログ - TECH PLAY

TECH PLAY

株式会社メドレー

株式会社メドレー の技術ブログ

全1414件

こんにちは。開発本部の 宍戸 です。 メドレーでは定期的に、テーマに沿って組織の技術的な底上げを行うための機会( タスクフォース と呼んでいます)を行っています。そのタスクフォースの1つとして先日、フロントエンド開発力のベースアップを目的としたタスクフォースを行いました。本記事では、その取組みについてご紹介したいと思います。 背景 メドレーには現在 20 人弱のエンジニアが在籍しており、その約半数がサーバーサイド出身者です。また普段の開発においては、一つの機能をフロントからサーバーサイドまで一貫して一人が担当するケースが多くあります。サーバーサイド出身者のフロントエンド開発のスキルセットには多少ばらつきはあるものの、普段の開発業務ではレビュー等でそれぞれサポートしつつ開発を行っています。 しかし、フロントエンドの基礎的な部分や最新の流れまで聞かれると不安なメンバーも少なくありません。フロントエンド出身のメンバーが主導し、改めて基礎や最新情報に関して整理・フォローを行うことで、組織全体のフロントエンドの開発力を高めていきたいと考えました。 タスクフォースの目的 今回のタスクフォースは『フロントエンドの基本や最近のトレンドに関して学ぶ』ことで『(フロントエンド開発における)技術選定、設計、実装ができる基礎を身につける』、そしてこれらをもとに『新規のプロジェクトで設計段階から自走できるようになる』ことを目的としました。 その中でも特にここ数年、変化の流れが早かった JavaScript を中心にトピックを選定しました。 参加者は、これまでサーバーサイド開発を中心に行ってきたメンバー数名です。背景でも触れたとおり、業務経験はそれぞれある前提でのスタートであったため、基礎をみっちりというよりは、基礎的な話から最近の話題までを一通り確認しながら、各自の持っている知識の整理と土台を固めることで、今後の設計や技術選定を行う際の指針を得ることを目的としました。 進め方 今回のタスクフォースは期間を 3 ヶ月と定め、毎週 1 時間程度集まって行いました。 毎週、事前に講師陣が選んだ資料を読んでおき、当日は講師陣が参加者の不明点、疑問点に対してフォローアップするという形式で進めました。その他には、社内のプロダクトでの利用事例なども交えながらテーマに関する質問会のような形で進むことが多かったです。 また毎回のタスクフォースの時間のあとに、参加者がその日の内容をまとめた議事録形式の資料を作成し、参加者全員と共有することで、その日に話された内容や、それぞれの理解度を再度確認するようにしました。 内容 およその流れは上記の通りですが、約 3 ヶ月でどのようなテーマに触れてきたのか、一部をご紹介します。 フロントエンドの基礎 序盤はこちらの資料を利用させていただきながら進めました。 ブラウザの仕組み: 最新ウェブブラウザの内部構造 Asg Boot Camp   HTML/CSS An Introduction to JavaScript ブラウザの仕組み、HTML/CSS の基本的な話のおさらい、JavaScript の話に関連して、これまでに出てきた AltJS についてもいくつか特徴や何故流行ったのかなどについて読み込みました。 この中でも、 ブラウザの仕組み: 最新ウェブブラウザの内部構造 で DOM の解析、レンダリング、レイアウトといったブラウザ内部で具体的に何が行われているのかといった話はここで確認できてよかったという声が多くありました。 JavaScript(基礎〜ES2015 以降) JavaScript の話題への導入編としてこちらを資料として読み込みました。 You Don’t Know JS: Up & Going JavaScript Garden このパートでは JavaScript の基礎は、あえて ES3〜5 をベースにすることで JavaScript と他言語との違い・特徴を再確認していきました。上記の内容を踏まえ、今では使わない書き方などについてはその理由も確認しながら進めていきました。 その後は Learn ES2015 · Babel を参照しながら、Promise, Class などは普段の開発でも当たり前のように利用しているものの、ES2015 以降での書き方は ES5 だとどのようになっていたかもここで同時に学習していきました。( Playground ・ TypeScript で、その雰囲気を見ることが出来ます) モダン JavaScript これまでの知識を踏まえ、モダンな JavaScript の利用(実装)例として、 jser.github.io と preact-www のソースを読んでいきました。 これまでの JavaScript の言語自体に関する内容から、ライブラリを利用したコンポーネント間でのデータフローや、コンポーネントのライフサイクルに関する部分まで確認していきました。また初見のプロジェクトであればどのあたりから目を通していくか、などコード全体の読み方についても講師陣からアドバイスがありました。また時折出てくる DOM API に「なんだっけこれ・・・?」などとなりつつもコードを紐解いていくことで改めてフロントエンド JavaScript の特徴的な部分を垣間見ることができたように思います。 また最後に、現在開発に利用されているツール群について、 Qiita:JavaScript フレームワーク選定の議論 を参考に確認しました。それぞれのツールがどのような背景で使われている(あるいはいない)のかなども合わせて確認をしました。 ここまでのテーマを振り返りつつ、JavaScript が言語としてどのように変化してきたかを考えた時、webpack や TypeScript がなぜ使われるのか、ようやく腹に落ちたように思います。また上記資料も、どのようなケースで何を選択するのかや、アプリケーションの寿命とライブラリやツールの寿命といった運用フェーズで理解していく必要のある事項にも触れられており、非常に参考になりました。 実際にやってみて 今回のタスクフォースでは、3 ヶ月という期間の中で、1 ヶ月半の時点と、全体終了後に振り返りを実施しました。 その中で、参加メンバーからは 業務においては必要な部分に絞った調査で終わってしまったり、周りのコードを参考にしたりすることでなんとなくできた気になってしまっていたが、今回改めて基礎的な知識を学習する、復習する時間としてできてよかった。 断片的でまばらな知識しか持っていなかった部分が資料を読み込むことで理解が深まった 数年前にバズってあとで読まない「あとで読む」ブクマ記事をきちんと読めてよかった フロントエンド経験の長い講師陣の生きた知見(ツラミなども含めて)を聞くことができたのはありがたかった などの感想が出ました。 私自身も参加していましたが、個人的には基礎部分を改めて固めることができた機会だったように感じています。 また、普段は新しいツールなどの情報のキャッチアップへの意識が向きがちですが、今回のタスクフォースで言語・ツールの変遷を一度通して見ることができたことで、新しく現れる技術がどういった課題を解決するものなのか、これまでに似たツールがあったのかどうかなどを調べる指針が得られたことはよかったのかなと思っています。 一方で、今回のタスクフォースの中では「コードを書く」時間は作りませんでした。これについては振り返りの中でも話題となりましたが、それについては TodoMVC などを参考に、自分で手を動かしてみることが必要だろうと今後の課題として挙げられました。このあたりは実務以外での個々の頑張りが必要になってくる部分かと思います。 まとめ 「サーバーサイドエンジニアのフロントエンド開発力の底上げ」をテーマとしたタスクフォースについてご紹介しました。こういった形で、同じようなスキルセットのメンバーが集まり、お互いにわからない部分について話をしたり、経験豊富なメンバーから、個人の経験を含めて話を聞くというのは、改めて非常に貴重な機会だったように思います。 こういった取り組みを繰り返していくことで、個々で尖った部分はもちろん伸ばしつつ、全体の底上げを行いながら、よりよいプロダクト開発に繋げられればと考えています。
こんにちは。開発本部の 宍戸 です。 メドレーでは定期的に、テーマに沿って組織の技術的な底上げを行うための機会( タスクフォース と呼んでいます)を行っています。そのタスクフォースの1つとして先日、フロントエンド開発力のベースアップを目的としたタスクフォースを行いました。本記事では、その取組みについてご紹介したいと思います。 背景 メドレーには現在 20 人弱のエンジニアが在籍しており、その約半数がサーバーサイド出身者です。また普段の開発においては、一つの機能をフロントからサーバーサイドまで一貫して一人が担当するケースが多くあります。サーバーサイド出身者のフロントエンド開発のスキルセットには多少ばらつきはあるものの、普段の開発業務ではレビュー等でそれぞれサポートしつつ開発を行っています。 しかし、フロントエンドの基礎的な部分や最新の流れまで聞かれると不安なメンバーも少なくありません。フロントエンド出身のメンバーが主導し、改めて基礎や最新情報に関して整理・フォローを行うことで、組織全体のフロントエンドの開発力を高めていきたいと考えました。 タスクフォースの目的 今回のタスクフォースは『フロントエンドの基本や最近のトレンドに関して学ぶ』ことで『(フロントエンド開発における)技術選定、設計、実装ができる基礎を身につける』、そしてこれらをもとに『新規のプロジェクトで設計段階から自走できるようになる』ことを目的としました。 その中でも特にここ数年、変化の流れが早かった JavaScript を中心にトピックを選定しました。 参加者は、これまでサーバーサイド開発を中心に行ってきたメンバー数名です。背景でも触れたとおり、業務経験はそれぞれある前提でのスタートであったため、基礎をみっちりというよりは、基礎的な話から最近の話題までを一通り確認しながら、各自の持っている知識の整理と土台を固めることで、今後の設計や技術選定を行う際の指針を得ることを目的としました。 進め方 今回のタスクフォースは期間を 3 ヶ月と定め、毎週 1 時間程度集まって行いました。 毎週、事前に講師陣が選んだ資料を読んでおき、当日は講師陣が参加者の不明点、疑問点に対してフォローアップするという形式で進めました。その他には、社内のプロダクトでの利用事例なども交えながらテーマに関する質問会のような形で進むことが多かったです。 また毎回のタスクフォースの時間のあとに、参加者がその日の内容をまとめた議事録形式の資料を作成し、参加者全員と共有することで、その日に話された内容や、それぞれの理解度を再度確認するようにしました。 内容 およその流れは上記の通りですが、約 3 ヶ月でどのようなテーマに触れてきたのか、一部をご紹介します。 フロントエンドの基礎 序盤はこちらの資料を利用させていただきながら進めました。 ブラウザの仕組み: 最新ウェブブラウザの内部構造 Asg Boot Camp   HTML/CSS An Introduction to JavaScript ブラウザの仕組み、HTML/CSS の基本的な話のおさらい、JavaScript の話に関連して、これまでに出てきた AltJS についてもいくつか特徴や何故流行ったのかなどについて読み込みました。 この中でも、 ブラウザの仕組み: 最新ウェブブラウザの内部構造 で DOM の解析、レンダリング、レイアウトといったブラウザ内部で具体的に何が行われているのかといった話はここで確認できてよかったという声が多くありました。 JavaScript(基礎〜ES2015 以降) JavaScript の話題への導入編としてこちらを資料として読み込みました。 You Don’t Know JS: Up & Going JavaScript Garden このパートでは JavaScript の基礎は、あえて ES3〜5 をベースにすることで JavaScript と他言語との違い・特徴を再確認していきました。上記の内容を踏まえ、今では使わない書き方などについてはその理由も確認しながら進めていきました。 その後は Learn ES2015 · Babel を参照しながら、Promise, Class などは普段の開発でも当たり前のように利用しているものの、ES2015 以降での書き方は ES5 だとどのようになっていたかもここで同時に学習していきました。( Playground ・ TypeScript で、その雰囲気を見ることが出来ます) モダン JavaScript これまでの知識を踏まえ、モダンな JavaScript の利用(実装)例として、 jser.github.io と preact-www のソースを読んでいきました。 これまでの JavaScript の言語自体に関する内容から、ライブラリを利用したコンポーネント間でのデータフローや、コンポーネントのライフサイクルに関する部分まで確認していきました。また初見のプロジェクトであればどのあたりから目を通していくか、などコード全体の読み方についても講師陣からアドバイスがありました。また時折出てくる DOM API に「なんだっけこれ・・・?」などとなりつつもコードを紐解いていくことで改めてフロントエンド JavaScript の特徴的な部分を垣間見ることができたように思います。 また最後に、現在開発に利用されているツール群について、 Qiita:JavaScript フレームワーク選定の議論 を参考に確認しました。それぞれのツールがどのような背景で使われている(あるいはいない)のかなども合わせて確認をしました。 ここまでのテーマを振り返りつつ、JavaScript が言語としてどのように変化してきたかを考えた時、webpack や TypeScript がなぜ使われるのか、ようやく腹に落ちたように思います。また上記資料も、どのようなケースで何を選択するのかや、アプリケーションの寿命とライブラリやツールの寿命といった運用フェーズで理解していく必要のある事項にも触れられており、非常に参考になりました。 実際にやってみて 今回のタスクフォースでは、3 ヶ月という期間の中で、1 ヶ月半の時点と、全体終了後に振り返りを実施しました。 その中で、参加メンバーからは 業務においては必要な部分に絞った調査で終わってしまったり、周りのコードを参考にしたりすることでなんとなくできた気になってしまっていたが、今回改めて基礎的な知識を学習する、復習する時間としてできてよかった。 断片的でまばらな知識しか持っていなかった部分が資料を読み込むことで理解が深まった 数年前にバズってあとで読まない「あとで読む」ブクマ記事をきちんと読めてよかった フロントエンド経験の長い講師陣の生きた知見(ツラミなども含めて)を聞くことができたのはありがたかった などの感想が出ました。 私自身も参加していましたが、個人的には基礎部分を改めて固めることができた機会だったように感じています。 また、普段は新しいツールなどの情報のキャッチアップへの意識が向きがちですが、今回のタスクフォースで言語・ツールの変遷を一度通して見ることができたことで、新しく現れる技術がどういった課題を解決するものなのか、これまでに似たツールがあったのかどうかなどを調べる指針が得られたことはよかったのかなと思っています。 一方で、今回のタスクフォースの中では「コードを書く」時間は作りませんでした。これについては振り返りの中でも話題となりましたが、それについては TodoMVC などを参考に、自分で手を動かしてみることが必要だろうと今後の課題として挙げられました。このあたりは実務以外での個々の頑張りが必要になってくる部分かと思います。 まとめ 「サーバーサイドエンジニアのフロントエンド開発力の底上げ」をテーマとしたタスクフォースについてご紹介しました。こういった形で、同じようなスキルセットのメンバーが集まり、お互いにわからない部分について話をしたり、経験豊富なメンバーから、個人の経験を含めて話を聞くというのは、改めて非常に貴重な機会だったように思います。 こういった取り組みを繰り返していくことで、個々で尖った部分はもちろん伸ばしつつ、全体の底上げを行いながら、よりよいプロダクト開発に繋げられればと考えています。
こんにちは。開発本部の 宍戸 です。 メドレーでは定期的に、テーマに沿って組織の技術的な底上げを行うための機会( タスクフォース と呼んでいます)を行っています。そのタスクフォースの1つとして先日、フロントエンド開発力のベースアップを目的としたタスクフォースを行いました。本記事では、その取組みについてご紹介したいと思います。 背景 メドレーには現在 20 人弱のエンジニアが在籍しており、その約半数がサーバーサイド出身者です。また普段の開発においては、一つの機能をフロントからサーバーサイドまで一貫して一人が担当するケースが多くあります。サーバーサイド出身者のフロントエンド開発のスキルセットには多少ばらつきはあるものの、普段の開発業務ではレビュー等でそれぞれサポートしつつ開発を行っています。 しかし、フロントエンドの基礎的な部分や最新の流れまで聞かれると不安なメンバーも少なくありません。フロントエンド出身のメンバーが主導し、改めて基礎や最新情報に関して整理・フォローを行うことで、組織全体のフロントエンドの開発力を高めていきたいと考えました。 タスクフォースの目的 今回のタスクフォースは『フロントエンドの基本や最近のトレンドに関して学ぶ』ことで『(フロントエンド開発における)技術選定、設計、実装ができる基礎を身につける』、そしてこれらをもとに『新規のプロジェクトで設計段階から自走できるようになる』ことを目的としました。 その中でも特にここ数年、変化の流れが早かった JavaScript を中心にトピックを選定しました。 参加者は、これまでサーバーサイド開発を中心に行ってきたメンバー数名です。背景でも触れたとおり、業務経験はそれぞれある前提でのスタートであったため、基礎をみっちりというよりは、基礎的な話から最近の話題までを一通り確認しながら、各自の持っている知識の整理と土台を固めることで、今後の設計や技術選定を行う際の指針を得ることを目的としました。 進め方 今回のタスクフォースは期間を 3 ヶ月と定め、毎週 1 時間程度集まって行いました。 毎週、事前に講師陣が選んだ資料を読んでおき、当日は講師陣が参加者の不明点、疑問点に対してフォローアップするという形式で進めました。その他には、社内のプロダクトでの利用事例なども交えながらテーマに関する質問会のような形で進むことが多かったです。 また毎回のタスクフォースの時間のあとに、参加者がその日の内容をまとめた議事録形式の資料を作成し、参加者全員と共有することで、その日に話された内容や、それぞれの理解度を再度確認するようにしました。 内容 およその流れは上記の通りですが、約 3 ヶ月でどのようなテーマに触れてきたのか、一部をご紹介します。 フロントエンドの基礎 序盤はこちらの資料を利用させていただきながら進めました。 ブラウザの仕組み: 最新ウェブブラウザの内部構造 Asg Boot Camp   HTML/CSS An Introduction to JavaScript ブラウザの仕組み、HTML/CSS の基本的な話のおさらい、JavaScript の話に関連して、これまでに出てきた AltJS についてもいくつか特徴や何故流行ったのかなどについて読み込みました。 この中でも、 ブラウザの仕組み: 最新ウェブブラウザの内部構造 で DOM の解析、レンダリング、レイアウトといったブラウザ内部で具体的に何が行われているのかといった話はここで確認できてよかったという声が多くありました。 JavaScript(基礎〜ES2015 以降) JavaScript の話題への導入編としてこちらを資料として読み込みました。 You Don’t Know JS: Up & Going JavaScript Garden このパートでは JavaScript の基礎は、あえて ES3〜5 をベースにすることで JavaScript と他言語との違い・特徴を再確認していきました。上記の内容を踏まえ、今では使わない書き方などについてはその理由も確認しながら進めていきました。 その後は Learn ES2015 · Babel を参照しながら、Promise, Class などは普段の開発でも当たり前のように利用しているものの、ES2015 以降での書き方は ES5 だとどのようになっていたかもここで同時に学習していきました。( Playground ・ TypeScript で、その雰囲気を見ることが出来ます) モダン JavaScript これまでの知識を踏まえ、モダンな JavaScript の利用(実装)例として、 jser.github.io と preact-www のソースを読んでいきました。 これまでの JavaScript の言語自体に関する内容から、ライブラリを利用したコンポーネント間でのデータフローや、コンポーネントのライフサイクルに関する部分まで確認していきました。また初見のプロジェクトであればどのあたりから目を通していくか、などコード全体の読み方についても講師陣からアドバイスがありました。また時折出てくる DOM API に「なんだっけこれ・・・?」などとなりつつもコードを紐解いていくことで改めてフロントエンド JavaScript の特徴的な部分を垣間見ることができたように思います。 また最後に、現在開発に利用されているツール群について、 Qiita:JavaScript フレームワーク選定の議論 を参考に確認しました。それぞれのツールがどのような背景で使われている(あるいはいない)のかなども合わせて確認をしました。 ここまでのテーマを振り返りつつ、JavaScript が言語としてどのように変化してきたかを考えた時、webpack や TypeScript がなぜ使われるのか、ようやく腹に落ちたように思います。また上記資料も、どのようなケースで何を選択するのかや、アプリケーションの寿命とライブラリやツールの寿命といった運用フェーズで理解していく必要のある事項にも触れられており、非常に参考になりました。 実際にやってみて 今回のタスクフォースでは、3 ヶ月という期間の中で、1 ヶ月半の時点と、全体終了後に振り返りを実施しました。 その中で、参加メンバーからは 業務においては必要な部分に絞った調査で終わってしまったり、周りのコードを参考にしたりすることでなんとなくできた気になってしまっていたが、今回改めて基礎的な知識を学習する、復習する時間としてできてよかった。 断片的でまばらな知識しか持っていなかった部分が資料を読み込むことで理解が深まった 数年前にバズってあとで読まない「あとで読む」ブクマ記事をきちんと読めてよかった フロントエンド経験の長い講師陣の生きた知見(ツラミなども含めて)を聞くことができたのはありがたかった などの感想が出ました。 私自身も参加していましたが、個人的には基礎部分を改めて固めることができた機会だったように感じています。 また、普段は新しいツールなどの情報のキャッチアップへの意識が向きがちですが、今回のタスクフォースで言語・ツールの変遷を一度通して見ることができたことで、新しく現れる技術がどういった課題を解決するものなのか、これまでに似たツールがあったのかどうかなどを調べる指針が得られたことはよかったのかなと思っています。 一方で、今回のタスクフォースの中では「コードを書く」時間は作りませんでした。これについては振り返りの中でも話題となりましたが、それについては TodoMVC などを参考に、自分で手を動かしてみることが必要だろうと今後の課題として挙げられました。このあたりは実務以外での個々の頑張りが必要になってくる部分かと思います。 まとめ 「サーバーサイドエンジニアのフロントエンド開発力の底上げ」をテーマとしたタスクフォースについてご紹介しました。こういった形で、同じようなスキルセットのメンバーが集まり、お互いにわからない部分について話をしたり、経験豊富なメンバーから、個人の経験を含めて話を聞くというのは、改めて非常に貴重な機会だったように思います。 こういった取り組みを繰り返していくことで、個々で尖った部分はもちろん伸ばしつつ、全体の底上げを行いながら、よりよいプロダクト開発に繋げられればと考えています。
こんにちは。開発本部の 宍戸 です。 メドレーでは定期的に、テーマに沿って組織の技術的な底上げを行うための機会( タスクフォース と呼んでいます)を行っています。そのタスクフォースの1つとして先日、フロントエンド開発力のベースアップを目的としたタスクフォースを行いました。本記事では、その取組みについてご紹介したいと思います。 背景 メドレーには現在 20 人弱のエンジニアが在籍しており、その約半数がサーバーサイド出身者です。また普段の開発においては、一つの機能をフロントからサーバーサイドまで一貫して一人が担当するケースが多くあります。サーバーサイド出身者のフロントエンド開発のスキルセットには多少ばらつきはあるものの、普段の開発業務ではレビュー等でそれぞれサポートしつつ開発を行っています。 しかし、フロントエンドの基礎的な部分や最新の流れまで聞かれると不安なメンバーも少なくありません。フロントエンド出身のメンバーが主導し、改めて基礎や最新情報に関して整理・フォローを行うことで、組織全体のフロントエンドの開発力を高めていきたいと考えました。 タスクフォースの目的 今回のタスクフォースは『フロントエンドの基本や最近のトレンドに関して学ぶ』ことで『(フロントエンド開発における)技術選定、設計、実装ができる基礎を身につける』、そしてこれらをもとに『新規のプロジェクトで設計段階から自走できるようになる』ことを目的としました。 その中でも特にここ数年、変化の流れが早かった JavaScript を中心にトピックを選定しました。 参加者は、これまでサーバーサイド開発を中心に行ってきたメンバー数名です。背景でも触れたとおり、業務経験はそれぞれある前提でのスタートであったため、基礎をみっちりというよりは、基礎的な話から最近の話題までを一通り確認しながら、各自の持っている知識の整理と土台を固めることで、今後の設計や技術選定を行う際の指針を得ることを目的としました。 進め方 今回のタスクフォースは期間を 3 ヶ月と定め、毎週 1 時間程度集まって行いました。 毎週、事前に講師陣が選んだ資料を読んでおき、当日は講師陣が参加者の不明点、疑問点に対してフォローアップするという形式で進めました。その他には、社内のプロダクトでの利用事例なども交えながらテーマに関する質問会のような形で進むことが多かったです。 また毎回のタスクフォースの時間のあとに、参加者がその日の内容をまとめた議事録形式の資料を作成し、参加者全員と共有することで、その日に話された内容や、それぞれの理解度を再度確認するようにしました。 内容 およその流れは上記の通りですが、約 3 ヶ月でどのようなテーマに触れてきたのか、一部をご紹介します。 フロントエンドの基礎 序盤はこちらの資料を利用させていただきながら進めました。 ブラウザの仕組み: 最新ウェブブラウザの内部構造 Asg Boot Camp   HTML/CSS An Introduction to JavaScript ブラウザの仕組み、HTML/CSS の基本的な話のおさらい、JavaScript の話に関連して、これまでに出てきた AltJS についてもいくつか特徴や何故流行ったのかなどについて読み込みました。 この中でも、 ブラウザの仕組み: 最新ウェブブラウザの内部構造 で DOM の解析、レンダリング、レイアウトといったブラウザ内部で具体的に何が行われているのかといった話はここで確認できてよかったという声が多くありました。 JavaScript(基礎〜ES2015 以降) JavaScript の話題への導入編としてこちらを資料として読み込みました。 You Don’t Know JS: Up & Going JavaScript Garden このパートでは JavaScript の基礎は、あえて ES3〜5 をベースにすることで JavaScript と他言語との違い・特徴を再確認していきました。上記の内容を踏まえ、今では使わない書き方などについてはその理由も確認しながら進めていきました。 その後は Learn ES2015 · Babel を参照しながら、Promise, Class などは普段の開発でも当たり前のように利用しているものの、ES2015 以降での書き方は ES5 だとどのようになっていたかもここで同時に学習していきました。( Playground ・ TypeScript で、その雰囲気を見ることが出来ます) モダン JavaScript これまでの知識を踏まえ、モダンな JavaScript の利用(実装)例として、 jser.github.io と preact-www のソースを読んでいきました。 これまでの JavaScript の言語自体に関する内容から、ライブラリを利用したコンポーネント間でのデータフローや、コンポーネントのライフサイクルに関する部分まで確認していきました。また初見のプロジェクトであればどのあたりから目を通していくか、などコード全体の読み方についても講師陣からアドバイスがありました。また時折出てくる DOM API に「なんだっけこれ・・・?」などとなりつつもコードを紐解いていくことで改めてフロントエンド JavaScript の特徴的な部分を垣間見ることができたように思います。 また最後に、現在開発に利用されているツール群について、 Qiita:JavaScript フレームワーク選定の議論 を参考に確認しました。それぞれのツールがどのような背景で使われている(あるいはいない)のかなども合わせて確認をしました。 ここまでのテーマを振り返りつつ、JavaScript が言語としてどのように変化してきたかを考えた時、webpack や TypeScript がなぜ使われるのか、ようやく腹に落ちたように思います。また上記資料も、どのようなケースで何を選択するのかや、アプリケーションの寿命とライブラリやツールの寿命といった運用フェーズで理解していく必要のある事項にも触れられており、非常に参考になりました。 実際にやってみて 今回のタスクフォースでは、3 ヶ月という期間の中で、1 ヶ月半の時点と、全体終了後に振り返りを実施しました。 その中で、参加メンバーからは 業務においては必要な部分に絞った調査で終わってしまったり、周りのコードを参考にしたりすることでなんとなくできた気になってしまっていたが、今回改めて基礎的な知識を学習する、復習する時間としてできてよかった。 断片的でまばらな知識しか持っていなかった部分が資料を読み込むことで理解が深まった 数年前にバズってあとで読まない「あとで読む」ブクマ記事をきちんと読めてよかった フロントエンド経験の長い講師陣の生きた知見(ツラミなども含めて)を聞くことができたのはありがたかった などの感想が出ました。 私自身も参加していましたが、個人的には基礎部分を改めて固めることができた機会だったように感じています。 また、普段は新しいツールなどの情報のキャッチアップへの意識が向きがちですが、今回のタスクフォースで言語・ツールの変遷を一度通して見ることができたことで、新しく現れる技術がどういった課題を解決するものなのか、これまでに似たツールがあったのかどうかなどを調べる指針が得られたことはよかったのかなと思っています。 一方で、今回のタスクフォースの中では「コードを書く」時間は作りませんでした。これについては振り返りの中でも話題となりましたが、それについては TodoMVC などを参考に、自分で手を動かしてみることが必要だろうと今後の課題として挙げられました。このあたりは実務以外での個々の頑張りが必要になってくる部分かと思います。 まとめ 「サーバーサイドエンジニアのフロントエンド開発力の底上げ」をテーマとしたタスクフォースについてご紹介しました。こういった形で、同じようなスキルセットのメンバーが集まり、お互いにわからない部分について話をしたり、経験豊富なメンバーから、個人の経験を含めて話を聞くというのは、改めて非常に貴重な機会だったように思います。 こういった取り組みを繰り返していくことで、個々で尖った部分はもちろん伸ばしつつ、全体の底上げを行いながら、よりよいプロダクト開発に繋げられればと考えています。
こんにちは。開発本部の 宍戸 です。 メドレーでは定期的に、テーマに沿って組織の技術的な底上げを行うための機会( タスクフォース と呼んでいます)を行っています。そのタスクフォースの1つとして先日、フロントエンド開発力のベースアップを目的としたタスクフォースを行いました。本記事では、その取組みについてご紹介したいと思います。 背景 メドレーには現在 20 人弱のエンジニアが在籍しており、その約半数がサーバーサイド出身者です。また普段の開発においては、一つの機能をフロントからサーバーサイドまで一貫して一人が担当するケースが多くあります。サーバーサイド出身者のフロントエンド開発のスキルセットには多少ばらつきはあるものの、普段の開発業務ではレビュー等でそれぞれサポートしつつ開発を行っています。 しかし、フロントエンドの基礎的な部分や最新の流れまで聞かれると不安なメンバーも少なくありません。フロントエンド出身のメンバーが主導し、改めて基礎や最新情報に関して整理・フォローを行うことで、組織全体のフロントエンドの開発力を高めていきたいと考えました。 タスクフォースの目的 今回のタスクフォースは『フロントエンドの基本や最近のトレンドに関して学ぶ』ことで『(フロントエンド開発における)技術選定、設計、実装ができる基礎を身につける』、そしてこれらをもとに『新規のプロジェクトで設計段階から自走できるようになる』ことを目的としました。 その中でも特にここ数年、変化の流れが早かった JavaScript を中心にトピックを選定しました。 参加者は、これまでサーバーサイド開発を中心に行ってきたメンバー数名です。背景でも触れたとおり、業務経験はそれぞれある前提でのスタートであったため、基礎をみっちりというよりは、基礎的な話から最近の話題までを一通り確認しながら、各自の持っている知識の整理と土台を固めることで、今後の設計や技術選定を行う際の指針を得ることを目的としました。 進め方 今回のタスクフォースは期間を 3 ヶ月と定め、毎週 1 時間程度集まって行いました。 毎週、事前に講師陣が選んだ資料を読んでおき、当日は講師陣が参加者の不明点、疑問点に対してフォローアップするという形式で進めました。その他には、社内のプロダクトでの利用事例なども交えながらテーマに関する質問会のような形で進むことが多かったです。 また毎回のタスクフォースの時間のあとに、参加者がその日の内容をまとめた議事録形式の資料を作成し、参加者全員と共有することで、その日に話された内容や、それぞれの理解度を再度確認するようにしました。 内容 およその流れは上記の通りですが、約 3 ヶ月でどのようなテーマに触れてきたのか、一部をご紹介します。 フロントエンドの基礎 序盤はこちらの資料を利用させていただきながら進めました。 ブラウザの仕組み: 最新ウェブブラウザの内部構造 Asg Boot Camp   HTML/CSS An Introduction to JavaScript ブラウザの仕組み、HTML/CSS の基本的な話のおさらい、JavaScript の話に関連して、これまでに出てきた AltJS についてもいくつか特徴や何故流行ったのかなどについて読み込みました。 この中でも、 ブラウザの仕組み: 最新ウェブブラウザの内部構造 で DOM の解析、レンダリング、レイアウトといったブラウザ内部で具体的に何が行われているのかといった話はここで確認できてよかったという声が多くありました。 JavaScript(基礎〜ES2015 以降) JavaScript の話題への導入編としてこちらを資料として読み込みました。 You Don’t Know JS: Up & Going JavaScript Garden このパートでは JavaScript の基礎は、あえて ES3〜5 をベースにすることで JavaScript と他言語との違い・特徴を再確認していきました。上記の内容を踏まえ、今では使わない書き方などについてはその理由も確認しながら進めていきました。 その後は Learn ES2015 · Babel を参照しながら、Promise, Class などは普段の開発でも当たり前のように利用しているものの、ES2015 以降での書き方は ES5 だとどのようになっていたかもここで同時に学習していきました。( Playground ・ TypeScript で、その雰囲気を見ることが出来ます) モダン JavaScript これまでの知識を踏まえ、モダンな JavaScript の利用(実装)例として、 jser.github.io と preact-www のソースを読んでいきました。 これまでの JavaScript の言語自体に関する内容から、ライブラリを利用したコンポーネント間でのデータフローや、コンポーネントのライフサイクルに関する部分まで確認していきました。また初見のプロジェクトであればどのあたりから目を通していくか、などコード全体の読み方についても講師陣からアドバイスがありました。また時折出てくる DOM API に「なんだっけこれ・・・?」などとなりつつもコードを紐解いていくことで改めてフロントエンド JavaScript の特徴的な部分を垣間見ることができたように思います。 また最後に、現在開発に利用されているツール群について、 Qiita:JavaScript フレームワーク選定の議論 を参考に確認しました。それぞれのツールがどのような背景で使われている(あるいはいない)のかなども合わせて確認をしました。 ここまでのテーマを振り返りつつ、JavaScript が言語としてどのように変化してきたかを考えた時、webpack や TypeScript がなぜ使われるのか、ようやく腹に落ちたように思います。また上記資料も、どのようなケースで何を選択するのかや、アプリケーションの寿命とライブラリやツールの寿命といった運用フェーズで理解していく必要のある事項にも触れられており、非常に参考になりました。 実際にやってみて 今回のタスクフォースでは、3 ヶ月という期間の中で、1 ヶ月半の時点と、全体終了後に振り返りを実施しました。 その中で、参加メンバーからは 業務においては必要な部分に絞った調査で終わってしまったり、周りのコードを参考にしたりすることでなんとなくできた気になってしまっていたが、今回改めて基礎的な知識を学習する、復習する時間としてできてよかった。 断片的でまばらな知識しか持っていなかった部分が資料を読み込むことで理解が深まった 数年前にバズってあとで読まない「あとで読む」ブクマ記事をきちんと読めてよかった フロントエンド経験の長い講師陣の生きた知見(ツラミなども含めて)を聞くことができたのはありがたかった などの感想が出ました。 私自身も参加していましたが、個人的には基礎部分を改めて固めることができた機会だったように感じています。 また、普段は新しいツールなどの情報のキャッチアップへの意識が向きがちですが、今回のタスクフォースで言語・ツールの変遷を一度通して見ることができたことで、新しく現れる技術がどういった課題を解決するものなのか、これまでに似たツールがあったのかどうかなどを調べる指針が得られたことはよかったのかなと思っています。 一方で、今回のタスクフォースの中では「コードを書く」時間は作りませんでした。これについては振り返りの中でも話題となりましたが、それについては TodoMVC などを参考に、自分で手を動かしてみることが必要だろうと今後の課題として挙げられました。このあたりは実務以外での個々の頑張りが必要になってくる部分かと思います。 まとめ 「サーバーサイドエンジニアのフロントエンド開発力の底上げ」をテーマとしたタスクフォースについてご紹介しました。こういった形で、同じようなスキルセットのメンバーが集まり、お互いにわからない部分について話をしたり、経験豊富なメンバーから、個人の経験を含めて話を聞くというのは、改めて非常に貴重な機会だったように思います。 こういった取り組みを繰り返していくことで、個々で尖った部分はもちろん伸ばしつつ、全体の底上げを行いながら、よりよいプロダクト開発に繋げられればと考えています。
こんにちは。開発本部の 宍戸 です。 メドレーでは定期的に、テーマに沿って組織の技術的な底上げを行うための機会( タスクフォース と呼んでいます)を行っています。そのタスクフォースの1つとして先日、フロントエンド開発力のベースアップを目的としたタスクフォースを行いました。本記事では、その取組みについてご紹介したいと思います。 背景 メドレーには現在 20 人弱のエンジニアが在籍しており、その約半数がサーバーサイド出身者です。また普段の開発においては、一つの機能をフロントからサーバーサイドまで一貫して一人が担当するケースが多くあります。サーバーサイド出身者のフロントエンド開発のスキルセットには多少ばらつきはあるものの、普段の開発業務ではレビュー等でそれぞれサポートしつつ開発を行っています。 しかし、フロントエンドの基礎的な部分や最新の流れまで聞かれると不安なメンバーも少なくありません。フロントエンド出身のメンバーが主導し、改めて基礎や最新情報に関して整理・フォローを行うことで、組織全体のフロントエンドの開発力を高めていきたいと考えました。 タスクフォースの目的 今回のタスクフォースは『フロントエンドの基本や最近のトレンドに関して学ぶ』ことで『(フロントエンド開発における)技術選定、設計、実装ができる基礎を身につける』、そしてこれらをもとに『新規のプロジェクトで設計段階から自走できるようになる』ことを目的としました。 その中でも特にここ数年、変化の流れが早かった JavaScript を中心にトピックを選定しました。 参加者は、これまでサーバーサイド開発を中心に行ってきたメンバー数名です。背景でも触れたとおり、業務経験はそれぞれある前提でのスタートであったため、基礎をみっちりというよりは、基礎的な話から最近の話題までを一通り確認しながら、各自の持っている知識の整理と土台を固めることで、今後の設計や技術選定を行う際の指針を得ることを目的としました。 進め方 今回のタスクフォースは期間を 3 ヶ月と定め、毎週 1 時間程度集まって行いました。 毎週、事前に講師陣が選んだ資料を読んでおき、当日は講師陣が参加者の不明点、疑問点に対してフォローアップするという形式で進めました。その他には、社内のプロダクトでの利用事例なども交えながらテーマに関する質問会のような形で進むことが多かったです。 また毎回のタスクフォースの時間のあとに、参加者がその日の内容をまとめた議事録形式の資料を作成し、参加者全員と共有することで、その日に話された内容や、それぞれの理解度を再度確認するようにしました。 内容 およその流れは上記の通りですが、約 3 ヶ月でどのようなテーマに触れてきたのか、一部をご紹介します。 フロントエンドの基礎 序盤はこちらの資料を利用させていただきながら進めました。 ブラウザの仕組み: 最新ウェブブラウザの内部構造 Asg Boot Camp   HTML/CSS An Introduction to JavaScript ブラウザの仕組み、HTML/CSS の基本的な話のおさらい、JavaScript の話に関連して、これまでに出てきた AltJS についてもいくつか特徴や何故流行ったのかなどについて読み込みました。 この中でも、 ブラウザの仕組み: 最新ウェブブラウザの内部構造 で DOM の解析、レンダリング、レイアウトといったブラウザ内部で具体的に何が行われているのかといった話はここで確認できてよかったという声が多くありました。 JavaScript(基礎〜ES2015 以降) JavaScript の話題への導入編としてこちらを資料として読み込みました。 You Don’t Know JS: Up & Going JavaScript Garden このパートでは JavaScript の基礎は、あえて ES3〜5 をベースにすることで JavaScript と他言語との違い・特徴を再確認していきました。上記の内容を踏まえ、今では使わない書き方などについてはその理由も確認しながら進めていきました。 その後は Learn ES2015 · Babel を参照しながら、Promise, Class などは普段の開発でも当たり前のように利用しているものの、ES2015 以降での書き方は ES5 だとどのようになっていたかもここで同時に学習していきました。( Playground ・ TypeScript で、その雰囲気を見ることが出来ます) モダン JavaScript これまでの知識を踏まえ、モダンな JavaScript の利用(実装)例として、 jser.github.io と preact-www のソースを読んでいきました。 これまでの JavaScript の言語自体に関する内容から、ライブラリを利用したコンポーネント間でのデータフローや、コンポーネントのライフサイクルに関する部分まで確認していきました。また初見のプロジェクトであればどのあたりから目を通していくか、などコード全体の読み方についても講師陣からアドバイスがありました。また時折出てくる DOM API に「なんだっけこれ・・・?」などとなりつつもコードを紐解いていくことで改めてフロントエンド JavaScript の特徴的な部分を垣間見ることができたように思います。 また最後に、現在開発に利用されているツール群について、 Qiita:JavaScript フレームワーク選定の議論 を参考に確認しました。それぞれのツールがどのような背景で使われている(あるいはいない)のかなども合わせて確認をしました。 ここまでのテーマを振り返りつつ、JavaScript が言語としてどのように変化してきたかを考えた時、webpack や TypeScript がなぜ使われるのか、ようやく腹に落ちたように思います。また上記資料も、どのようなケースで何を選択するのかや、アプリケーションの寿命とライブラリやツールの寿命といった運用フェーズで理解していく必要のある事項にも触れられており、非常に参考になりました。 実際にやってみて 今回のタスクフォースでは、3 ヶ月という期間の中で、1 ヶ月半の時点と、全体終了後に振り返りを実施しました。 その中で、参加メンバーからは 業務においては必要な部分に絞った調査で終わってしまったり、周りのコードを参考にしたりすることでなんとなくできた気になってしまっていたが、今回改めて基礎的な知識を学習する、復習する時間としてできてよかった。 断片的でまばらな知識しか持っていなかった部分が資料を読み込むことで理解が深まった 数年前にバズってあとで読まない「あとで読む」ブクマ記事をきちんと読めてよかった フロントエンド経験の長い講師陣の生きた知見(ツラミなども含めて)を聞くことができたのはありがたかった などの感想が出ました。 私自身も参加していましたが、個人的には基礎部分を改めて固めることができた機会だったように感じています。 また、普段は新しいツールなどの情報のキャッチアップへの意識が向きがちですが、今回のタスクフォースで言語・ツールの変遷を一度通して見ることができたことで、新しく現れる技術がどういった課題を解決するものなのか、これまでに似たツールがあったのかどうかなどを調べる指針が得られたことはよかったのかなと思っています。 一方で、今回のタスクフォースの中では「コードを書く」時間は作りませんでした。これについては振り返りの中でも話題となりましたが、それについては TodoMVC などを参考に、自分で手を動かしてみることが必要だろうと今後の課題として挙げられました。このあたりは実務以外での個々の頑張りが必要になってくる部分かと思います。 まとめ 「サーバーサイドエンジニアのフロントエンド開発力の底上げ」をテーマとしたタスクフォースについてご紹介しました。こういった形で、同じようなスキルセットのメンバーが集まり、お互いにわからない部分について話をしたり、経験豊富なメンバーから、個人の経験を含めて話を聞くというのは、改めて非常に貴重な機会だったように思います。 こういった取り組みを繰り返していくことで、個々で尖った部分はもちろん伸ばしつつ、全体の底上げを行いながら、よりよいプロダクト開発に繋げられればと考えています。
こんにちは。開発本部の 宍戸 です。 メドレーでは定期的に、テーマに沿って組織の技術的な底上げを行うための機会( タスクフォース と呼んでいます)を行っています。そのタスクフォースの1つとして先日、フロントエンド開発力のベースアップを目的としたタスクフォースを行いました。本記事では、その取組みについてご紹介したいと思います。 背景 メドレーには現在 20 人弱のエンジニアが在籍しており、その約半数がサーバーサイド出身者です。また普段の開発においては、一つの機能をフロントからサーバーサイドまで一貫して一人が担当するケースが多くあります。サーバーサイド出身者のフロントエンド開発のスキルセットには多少ばらつきはあるものの、普段の開発業務ではレビュー等でそれぞれサポートしつつ開発を行っています。 しかし、フロントエンドの基礎的な部分や最新の流れまで聞かれると不安なメンバーも少なくありません。フロントエンド出身のメンバーが主導し、改めて基礎や最新情報に関して整理・フォローを行うことで、組織全体のフロントエンドの開発力を高めていきたいと考えました。 タスクフォースの目的 今回のタスクフォースは『フロントエンドの基本や最近のトレンドに関して学ぶ』ことで『(フロントエンド開発における)技術選定、設計、実装ができる基礎を身につける』、そしてこれらをもとに『新規のプロジェクトで設計段階から自走できるようになる』ことを目的としました。 その中でも特にここ数年、変化の流れが早かった JavaScript を中心にトピックを選定しました。 参加者は、これまでサーバーサイド開発を中心に行ってきたメンバー数名です。背景でも触れたとおり、業務経験はそれぞれある前提でのスタートであったため、基礎をみっちりというよりは、基礎的な話から最近の話題までを一通り確認しながら、各自の持っている知識の整理と土台を固めることで、今後の設計や技術選定を行う際の指針を得ることを目的としました。 進め方 今回のタスクフォースは期間を 3 ヶ月と定め、毎週 1 時間程度集まって行いました。 毎週、事前に講師陣が選んだ資料を読んでおき、当日は講師陣が参加者の不明点、疑問点に対してフォローアップするという形式で進めました。その他には、社内のプロダクトでの利用事例なども交えながらテーマに関する質問会のような形で進むことが多かったです。 また毎回のタスクフォースの時間のあとに、参加者がその日の内容をまとめた議事録形式の資料を作成し、参加者全員と共有することで、その日に話された内容や、それぞれの理解度を再度確認するようにしました。 内容 およその流れは上記の通りですが、約 3 ヶ月でどのようなテーマに触れてきたのか、一部をご紹介します。 フロントエンドの基礎 序盤はこちらの資料を利用させていただきながら進めました。 ブラウザの仕組み: 最新ウェブブラウザの内部構造 Asg Boot Camp   HTML/CSS An Introduction to JavaScript ブラウザの仕組み、HTML/CSS の基本的な話のおさらい、JavaScript の話に関連して、これまでに出てきた AltJS についてもいくつか特徴や何故流行ったのかなどについて読み込みました。 この中でも、 ブラウザの仕組み: 最新ウェブブラウザの内部構造 で DOM の解析、レンダリング、レイアウトといったブラウザ内部で具体的に何が行われているのかといった話はここで確認できてよかったという声が多くありました。 JavaScript(基礎〜ES2015 以降) JavaScript の話題への導入編としてこちらを資料として読み込みました。 You Don’t Know JS: Up & Going JavaScript Garden このパートでは JavaScript の基礎は、あえて ES3〜5 をベースにすることで JavaScript と他言語との違い・特徴を再確認していきました。上記の内容を踏まえ、今では使わない書き方などについてはその理由も確認しながら進めていきました。 その後は Learn ES2015 · Babel を参照しながら、Promise, Class などは普段の開発でも当たり前のように利用しているものの、ES2015 以降での書き方は ES5 だとどのようになっていたかもここで同時に学習していきました。( Playground ・ TypeScript で、その雰囲気を見ることが出来ます) モダン JavaScript これまでの知識を踏まえ、モダンな JavaScript の利用(実装)例として、 jser.github.io と preact-www のソースを読んでいきました。 これまでの JavaScript の言語自体に関する内容から、ライブラリを利用したコンポーネント間でのデータフローや、コンポーネントのライフサイクルに関する部分まで確認していきました。また初見のプロジェクトであればどのあたりから目を通していくか、などコード全体の読み方についても講師陣からアドバイスがありました。また時折出てくる DOM API に「なんだっけこれ・・・?」などとなりつつもコードを紐解いていくことで改めてフロントエンド JavaScript の特徴的な部分を垣間見ることができたように思います。 また最後に、現在開発に利用されているツール群について、 Qiita:JavaScript フレームワーク選定の議論 を参考に確認しました。それぞれのツールがどのような背景で使われている(あるいはいない)のかなども合わせて確認をしました。 ここまでのテーマを振り返りつつ、JavaScript が言語としてどのように変化してきたかを考えた時、webpack や TypeScript がなぜ使われるのか、ようやく腹に落ちたように思います。また上記資料も、どのようなケースで何を選択するのかや、アプリケーションの寿命とライブラリやツールの寿命といった運用フェーズで理解していく必要のある事項にも触れられており、非常に参考になりました。 実際にやってみて 今回のタスクフォースでは、3 ヶ月という期間の中で、1 ヶ月半の時点と、全体終了後に振り返りを実施しました。 その中で、参加メンバーからは 業務においては必要な部分に絞った調査で終わってしまったり、周りのコードを参考にしたりすることでなんとなくできた気になってしまっていたが、今回改めて基礎的な知識を学習する、復習する時間としてできてよかった。 断片的でまばらな知識しか持っていなかった部分が資料を読み込むことで理解が深まった 数年前にバズってあとで読まない「あとで読む」ブクマ記事をきちんと読めてよかった フロントエンド経験の長い講師陣の生きた知見(ツラミなども含めて)を聞くことができたのはありがたかった などの感想が出ました。 私自身も参加していましたが、個人的には基礎部分を改めて固めることができた機会だったように感じています。 また、普段は新しいツールなどの情報のキャッチアップへの意識が向きがちですが、今回のタスクフォースで言語・ツールの変遷を一度通して見ることができたことで、新しく現れる技術がどういった課題を解決するものなのか、これまでに似たツールがあったのかどうかなどを調べる指針が得られたことはよかったのかなと思っています。 一方で、今回のタスクフォースの中では「コードを書く」時間は作りませんでした。これについては振り返りの中でも話題となりましたが、それについては TodoMVC などを参考に、自分で手を動かしてみることが必要だろうと今後の課題として挙げられました。このあたりは実務以外での個々の頑張りが必要になってくる部分かと思います。 まとめ 「サーバーサイドエンジニアのフロントエンド開発力の底上げ」をテーマとしたタスクフォースについてご紹介しました。こういった形で、同じようなスキルセットのメンバーが集まり、お互いにわからない部分について話をしたり、経験豊富なメンバーから、個人の経験を含めて話を聞くというのは、改めて非常に貴重な機会だったように思います。 こういった取り組みを繰り返していくことで、個々で尖った部分はもちろん伸ばしつつ、全体の底上げを行いながら、よりよいプロダクト開発に繋げられればと考えています。
こんにちは。開発本部の 宍戸 です。 メドレーでは定期的に、テーマに沿って組織の技術的な底上げを行うための機会( タスクフォース と呼んでいます)を行っています。そのタスクフォースの1つとして先日、フロントエンド開発力のベースアップを目的としたタスクフォースを行いました。本記事では、その取組みについてご紹介したいと思います。 背景 メドレーには現在 20 人弱のエンジニアが在籍しており、その約半数がサーバーサイド出身者です。また普段の開発においては、一つの機能をフロントからサーバーサイドまで一貫して一人が担当するケースが多くあります。サーバーサイド出身者のフロントエンド開発のスキルセットには多少ばらつきはあるものの、普段の開発業務ではレビュー等でそれぞれサポートしつつ開発を行っています。 しかし、フロントエンドの基礎的な部分や最新の流れまで聞かれると不安なメンバーも少なくありません。フロントエンド出身のメンバーが主導し、改めて基礎や最新情報に関して整理・フォローを行うことで、組織全体のフロントエンドの開発力を高めていきたいと考えました。 タスクフォースの目的 今回のタスクフォースは『フロントエンドの基本や最近のトレンドに関して学ぶ』ことで『(フロントエンド開発における)技術選定、設計、実装ができる基礎を身につける』、そしてこれらをもとに『新規のプロジェクトで設計段階から自走できるようになる』ことを目的としました。 その中でも特にここ数年、変化の流れが早かった JavaScript を中心にトピックを選定しました。 参加者は、これまでサーバーサイド開発を中心に行ってきたメンバー数名です。背景でも触れたとおり、業務経験はそれぞれある前提でのスタートであったため、基礎をみっちりというよりは、基礎的な話から最近の話題までを一通り確認しながら、各自の持っている知識の整理と土台を固めることで、今後の設計や技術選定を行う際の指針を得ることを目的としました。 進め方 今回のタスクフォースは期間を 3 ヶ月と定め、毎週 1 時間程度集まって行いました。 毎週、事前に講師陣が選んだ資料を読んでおき、当日は講師陣が参加者の不明点、疑問点に対してフォローアップするという形式で進めました。その他には、社内のプロダクトでの利用事例なども交えながらテーマに関する質問会のような形で進むことが多かったです。 また毎回のタスクフォースの時間のあとに、参加者がその日の内容をまとめた議事録形式の資料を作成し、参加者全員と共有することで、その日に話された内容や、それぞれの理解度を再度確認するようにしました。 内容 およその流れは上記の通りですが、約 3 ヶ月でどのようなテーマに触れてきたのか、一部をご紹介します。 フロントエンドの基礎 序盤はこちらの資料を利用させていただきながら進めました。 ブラウザの仕組み: 最新ウェブブラウザの内部構造 Asg Boot Camp   HTML/CSS An Introduction to JavaScript ブラウザの仕組み、HTML/CSS の基本的な話のおさらい、JavaScript の話に関連して、これまでに出てきた AltJS についてもいくつか特徴や何故流行ったのかなどについて読み込みました。 この中でも、 ブラウザの仕組み: 最新ウェブブラウザの内部構造 で DOM の解析、レンダリング、レイアウトといったブラウザ内部で具体的に何が行われているのかといった話はここで確認できてよかったという声が多くありました。 JavaScript(基礎〜ES2015 以降) JavaScript の話題への導入編としてこちらを資料として読み込みました。 You Don’t Know JS: Up & Going JavaScript Garden このパートでは JavaScript の基礎は、あえて ES3〜5 をベースにすることで JavaScript と他言語との違い・特徴を再確認していきました。上記の内容を踏まえ、今では使わない書き方などについてはその理由も確認しながら進めていきました。 その後は Learn ES2015 · Babel を参照しながら、Promise, Class などは普段の開発でも当たり前のように利用しているものの、ES2015 以降での書き方は ES5 だとどのようになっていたかもここで同時に学習していきました。( Playground ・ TypeScript で、その雰囲気を見ることが出来ます) モダン JavaScript これまでの知識を踏まえ、モダンな JavaScript の利用(実装)例として、 jser.github.io と preact-www のソースを読んでいきました。 これまでの JavaScript の言語自体に関する内容から、ライブラリを利用したコンポーネント間でのデータフローや、コンポーネントのライフサイクルに関する部分まで確認していきました。また初見のプロジェクトであればどのあたりから目を通していくか、などコード全体の読み方についても講師陣からアドバイスがありました。また時折出てくる DOM API に「なんだっけこれ・・・?」などとなりつつもコードを紐解いていくことで改めてフロントエンド JavaScript の特徴的な部分を垣間見ることができたように思います。 また最後に、現在開発に利用されているツール群について、 Qiita:JavaScript フレームワーク選定の議論 を参考に確認しました。それぞれのツールがどのような背景で使われている(あるいはいない)のかなども合わせて確認をしました。 ここまでのテーマを振り返りつつ、JavaScript が言語としてどのように変化してきたかを考えた時、webpack や TypeScript がなぜ使われるのか、ようやく腹に落ちたように思います。また上記資料も、どのようなケースで何を選択するのかや、アプリケーションの寿命とライブラリやツールの寿命といった運用フェーズで理解していく必要のある事項にも触れられており、非常に参考になりました。 実際にやってみて 今回のタスクフォースでは、3 ヶ月という期間の中で、1 ヶ月半の時点と、全体終了後に振り返りを実施しました。 その中で、参加メンバーからは 業務においては必要な部分に絞った調査で終わってしまったり、周りのコードを参考にしたりすることでなんとなくできた気になってしまっていたが、今回改めて基礎的な知識を学習する、復習する時間としてできてよかった。 断片的でまばらな知識しか持っていなかった部分が資料を読み込むことで理解が深まった 数年前にバズってあとで読まない「あとで読む」ブクマ記事をきちんと読めてよかった フロントエンド経験の長い講師陣の生きた知見(ツラミなども含めて)を聞くことができたのはありがたかった などの感想が出ました。 私自身も参加していましたが、個人的には基礎部分を改めて固めることができた機会だったように感じています。 また、普段は新しいツールなどの情報のキャッチアップへの意識が向きがちですが、今回のタスクフォースで言語・ツールの変遷を一度通して見ることができたことで、新しく現れる技術がどういった課題を解決するものなのか、これまでに似たツールがあったのかどうかなどを調べる指針が得られたことはよかったのかなと思っています。 一方で、今回のタスクフォースの中では「コードを書く」時間は作りませんでした。これについては振り返りの中でも話題となりましたが、それについては TodoMVC などを参考に、自分で手を動かしてみることが必要だろうと今後の課題として挙げられました。このあたりは実務以外での個々の頑張りが必要になってくる部分かと思います。 まとめ 「サーバーサイドエンジニアのフロントエンド開発力の底上げ」をテーマとしたタスクフォースについてご紹介しました。こういった形で、同じようなスキルセットのメンバーが集まり、お互いにわからない部分について話をしたり、経験豊富なメンバーから、個人の経験を含めて話を聞くというのは、改めて非常に貴重な機会だったように思います。 こういった取り組みを繰り返していくことで、個々で尖った部分はもちろん伸ばしつつ、全体の底上げを行いながら、よりよいプロダクト開発に繋げられればと考えています。
こんにちは。開発本部の 稲本 です。医療介護の求人サイト「 ジョブメドレー 」の開発を担当しているエンジニアです。 最近ジョブメドレーでは CircleCI2.0 への移行を行いました。移行の方法はもちろん、その際に調べたこと、CircleCI の新機能を利用してどうだったかなどを書いていきたいと思います。 課題感 弊社では、全プロダクト( CLINICS 、 MEDLEY 、 介護のほんね 、 ジョブメドレー )で CircleCI を利用しています。 ジョブメドレーでは CI によるテスト実行に 37 分前後掛かっていました(コンテナを 2 つ利用した実行時間です)。 さらに、開発メンバーが増えて来たこともあり、CI のリソースが足りなくなり開発効率が落ちかねない状況でした。 まぁよくある話ですよね。 コンテナを増やすというのも解決策の一つとしてはあるのですが、速度の改善に期待が出来ると評判も良かったので CirclecCI2.0 へ移行しました。 CircleCI2.0 への移行メリット 基本的には速度の改善に期待が出来る、というのが大きなメリットではありますが、公式では以下のように記載されています。 抜粋ですが大きな特徴としては以下の点でしょうか。 First-class Docker Support: Docker のネイティブサポートと Docker レイヤーキャッシュの導入 Workflows: ビルド、テスト、デプロイをジョブとして柔軟に管理できるようになった Advanced Caching: キャッシュの保存とリストアをイメージ、ソースコード、依存関係に対して行うことができるようになった。 この辺りの機能を活用し CI の速度改善へ繋げてみたいと思います。 ジョブメドレーのアプリケーション構成 移行の前提として、ジョブメドレーのアプリケーション構成について記載します。 フロントエンドのビルドを yarn+webpack で行い、生成したアセットを public/assets へ吐き出し、manifest ファイルのパスを rails の helper 経由で取得し読み込んでいます。(Rails4.2.x) このような構成のアプリケーションを CirlceCI2.0 でビルド、テスト、デプロイ出来るようにしていきます。 config.yml の全体像 今回、作成した config.yml はこのような形になりました。 ざっくりは build: bundle install, yarn install code_analyze: rubocop, brakeman, scss-lint rspec deploy: capistrano を行っており、ブランチによってどのジョブを実行するのかを workflows を利用して使い分けています。 詳しい解説は以降、記載していきます。 defaults : & defaults working_directory : ~/job-medley docker : - image : circleci/ruby:2.4.2-node-browsers environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : circleci/mysql:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : redis:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo version : 2 jobs : build : << : * defaults steps : - checkout - restore_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} - run : name : bundle install command : bundle install --jobs=4 --path=vendor/bundle - save_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} paths : - vendor/bundle - restore_cache : key : job-medley-yarn-{{ checksum "yarn.lock" }} - run : name : Yarn install command : | echo "Node $(node -v)" echo "Yarn v$(yarn --version)" yarn config set cache-folder ./yarn_cache echo "Yarn v$(yarn cache dir)" yarn install - save_cache : key : job-medley-yarn-{{ checksum "yarn.lock" }} paths : - node_modules - yarn_cache - persist_to_workspace : root : ~/job-medley paths : - ./* code_analyze : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run rubocop command : bundle exec rubocop - run : name : run brakeman command : bundle exec brakeman -qz - run : name : run scss-lint command : bundle exec scss-lint rspec : parallelism : 2 << : * defaults steps : - attach_workspace : at : ~/job-medley - restore_cache : key : job-medley-elasticsearch # rspec で es のコマンドを一部実行しているため、primary container 側へ install - run : name : Elasticsearch install command : | wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-x.x.x.tar.gz && \ tar -xvf elasticsearch-x.x.x.tar.gz && \ if [ -z "`elasticsearch-x.x.x/bin/plugin -l | grep analysis-kuromoji`" ]; then \ elasticsearch-x.x.x/bin/plugin -install elasticsearch/elasticsearch-analysis-kuromoji/x.x.x; fi - save_cache : key : job-medley-elasticsearch paths : - ./elasticsearch-x.x.x - run : name : database create command : bundle exec rake db:create environment : RAILS_ENV : test - run : name : run test command : | circleci tests glob 'spec/**/*_spec.*' \ | circleci tests split --split-by=timings --timings-type=filename \ | tee -a /dev/stderr \ | xargs bundle exec rspec \ --profile 100 \ --format RspecJunitFormatter \ --out rspec/rspec.xml \ --format progress environment : RAILS_ENV : test TEST_CLUSTER_COMMAND : elasticsearch-x.x.x/bin/elasticsearch - store_artifacts : path : artifacts/ - store_test_results : path : rspec/ deploy_qa : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run deploy command : | sh scripts/init_deploy.sh BRANCH="${CIRCLE_BRANCH}" bundle exec cap develop deploy deploy:restart deploy_only : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run deploy command : | BRANCH="${CIRCLE_BRANCH}" bundle exec cap production deploy deploy:restart workflows : version : 2 workflows : jobs : - build - code_analyze : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - rspec : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - deploy_qa : requires : - code_analyze - rspec filters : branches : only : develop - deploy_only : requires : - build filters : branches : only : /^sandbox.*|^master$|^staging$/ DockerImage の選定 元々、Docker を使わずに CI を回していましたが、CircleCI2.0 へ移行するに辺り Docker への利用に切り替えました。 ※ Specifying Container Images DockerImage は DockerHub へ登録されている CircleCI 公式のも の を利用しました。 アプリケーションの一部で React を使用しており、フロントのビルドは yarn+webpack を利用しています。その為、以下の image を選択しました。 circleci/ruby:2.4.2-node-browsers node のインストールと、E2E のテストに必要なソフトウェアがインストールされています。 ※詳細は こちらの記事 を参考にさせていただきました。 その他、現在利用している MySQL のバージョン、ElasticCacheRedis のバージョンと合わせた image を選択しました。 注意点としては、複数の DockerImage を利用する場合、一つ目に指定した image が primary として扱われます。 以下の例ですと、Ruby の image を最初に指定し、MySQL、Redis の image を指定していますが、MySQL コマンド自体は Ruby の image に含まれていないため、Ruby コマンドを実行できても MySQL コマンドを実行することは出来ません。 ※詳細は こちら に記載されています。 docker : - image : circleci/ruby:2.4.2-node-browsers environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : circleci/mysql:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : redis:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo また、用意されている image をカスタマイズする必要がある場合は、Docker でカスタム image を作り、public で良ければ Docker Hub へ登録、private が良ければ Amazon EC2 Container Registry へ登録しておくことで呼び出すことも可能になっています。 ※Using Custom-Built Docker Images https://circleci.com/docs/ja/2.0/custom-images/ ※Using Private Images https://circleci.com/docs/ja/2.0/private-images/ build の設定と cache CI で実行するアプリケーションの build に関してです。 checkout で github からコードを checkout し、その後の定義でアプリケーションのインストール、キャッシュ保存、キャッシュの展開を行っています。 steps : - checkout # Rails application setup - restore_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} - run : name : bundle install command : bundle install --jobs=4 --path=vendor/bundle - save_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} paths : - vendor/bundle save_cache: key に Gemfile.lock を指定することでキャッシュキーとして扱い、paths に設定したパスをキャッシュするようにしています。 restore_cache: key と一致するキャッシュがあれば、save_cache 時に指定したパスを展開し直しています。 run: こちらは rails のアプリケーションインストールしているだけです。 CircleCI1.0 よりもキャッシュ管理を柔軟に行えることがわかります。 circleci コマンドによる Rspec の並列実行 rspec によるテストの実行に関してです。 circleci コマンド を利用することでテストの並列実行を効率的に行うことが出来るます。 今回は --split-by=timings --timings-type=filename のオプションを指定し、ファイル名ベースでの分割でテストを実行します。 - run : name : run test command : | circleci tests glob 'spec/**/*_spec.*' \ | circleci tests split --split-by=timings --timings-type=filename \ | tee -a /dev/stderr \ | xargs bundle exec rspec \ --profile 100 \ --format RspecJunitFormatter \ --out rspec/rspec.xml \ --format progress environment : RAILS_ENV : test TEST_CLUSTER_COMMAND : elasticsearch-x.x.x/bin/elasticsearch - store_artifacts : path : artifacts/ - store_test_results : path : rspec/ store_artifacts: 以前からもある機能ですが、テスト結果の成果物を保存するパスになります。 store_test_results: こちらはテストの実行結果を保存しておくことで、コンテナ間で rspec の実行時間にばらつきが出ないよう、対象のファイルを最適に振り分けてくれるようなのですが、workflows を利用するとサポートされないようです。 ※参考: https://circleci.com/docs/ja/2.0/configuration-reference/#store_test_results このような形で Artifacts が保存されています。 また、artifacts には coverage と capybara の screenshot などを保存しています - simple_cov if ENV['CI'] SimpleCov.coverage_dir File.join(ENV['CIRCLE_WORKING_DIRECTORY'], 'artifacts', 'coverage') SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ SimpleCov::Formatter::HTMLFormatter ] SimpleCov.start do add_filter '/vendor/' add_filter '/spec/' add_filter '/config/' add_filter '/db/' end end capybara Capybara.save_and_open_page_path = File.join(ENV['CIRCLE_WORKING_DIRECTORY'], 'artifacts', 'capybara') if ENV['CI'] ※CircleCI2.0 から CI の環境変数が変わっています。詳細は以下のリンクへ記載されています。 Introduction to environment variables - CircleCI Introduction to environment variables in CircleCI circleci.com Workflows の設定 CircleCI2.0 から Workflows の利用が可能になりました。 Workflow orchestration - CircleCI Learn about using CircleCI workflows to orchestrate jobs circleci.com コンテナ毎に分割しジョブを実行することで更なる並列実行の効率化、及び、ジョブ間の依存関係まで設定できるようです。 ジョブメドレーではコードの静的解析に少し実行時間が掛かっていることから、多少の改善を図れると考え 単純に使ってみたかった こちらの機能を利用してみました。 workflows : version : 2 workflows : jobs : - build - code_analyze : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - rspec : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - deploy_qa : requires : - code_analyze - rspec filters : branches : only : develop - deploy_only : requires : - build filters : branches : only : /^sandbox.*|^master$|^staging$/ build: 各ジョブで実行前に行っておく処理を定義 code_analyze: rubocop、brakeman、scss-lint などの静的解析処理を定義 rspec: アプリケーションのテストを定義 deploy: デプロイに関する処理を定義 ジョブメドレーでは、ブランチ管理に Git-flow を採用していますが、それとは別に sandbox というテスト環境を用意し運用しています。 develop ブランチでコード解析やテストをクリアしたコードだけ、master へ反映し、master ではテストフェーズなしに deploy する構成を取っています。 極力、CI のリソースを節約するように各ブランチごとで実行する処理を分けています。 各ブランチの運用は以下の通りです。 feature: コード解析、テスト実行 sandbox: デプロイのみ実行(一時レビュー用ブランチ) develop: コード解析、テスト実行、デプロイ実行 master: デプロイのみ実行 上記の例では、 code_analyze: sandbox、master、staging ブランチ以外は実行 requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 rspec: sandbox、master、staging ブランチ以外は実行 requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 deploy_qa: develop ブランチでのみ実行 requires で依存関係を指定し、code_analyze、rspec が正常に終了しなければ実行されないようになっています。 deploy_only: sandbox、master、staging ブランチのみ利用するジョブ requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 どのような workflow が出来あがるのか、以下に例を示します。 feature ブランチの例: develop ブランチの例: master、sandbox ブランチの例: 今回の例だとブランチ毎に workflow を変えているため、ignore、only の書き方で意図せず振り分けされないように考慮は必要ですが、柔軟に workflow を作れることがわかると思います。(やり過ぎると読み解くのが大変になりそうですね) Workflows に関しては こちら に色々なパターンの組み方が記載されているので、こちらを読むとより理解が深まると思います。 ジョブ間でのデータ共有 ジョブを分けてビルドする=何回もアプリケーションの初期化が必要なんじゃないか? と当然疑問に思う点ではありますが、それに対する解決策も用意されています。 build : steps : ===省略=== - persist_to_workspace : root : ~/job-medley paths : - ./* deploy_qa : << : * defaults steps : - attach_workspace : at : ~/job-medley persist_to_workspace: 指定したパスにあるデータを一時的に保管してくれます attach_workspace: 保管済みのデータを展開してくれます この機能により、ビルドプロセスで生成したものを各ジョブで実行するコンテナへ渡すことが出来ます。 ただし、そもそもビルドプロセスでキャッシュを入れていることもあり、これ自体の効果は殆どありませんでした。 コンパイル済みのデータを受け渡す際には効果を発揮しそうですね。( 公式でも そのような利用を想定していそうです) 改善結果 肝心の速度改善結果です。結果は以下の通りになりました。 改善前: CircleCI1.0 rspec の実行時間: 26:59 以下は、CircleCI2.0 へ移行しただけの結果です。このケースでは workflows を利用していません。 改善後: CircleCI2.0 rspec の実行時間: 19:40 CircleCI1.0 から CircleCI2.0 へ移行することにより、 約 12 分程 テストの実行時間を短縮することが出来ました。 Workflows など特に利用していない、かつ、ビルドフェーズの実行時間も関係しないため、CircleCI2.0 を利用するだけで単純にテスト実行速度の向上を見込めることがわかると思います。 続いて Workflows を利用した結果です。 改善後: CircleCI2.0 with Workflows rspec の実行時間: 21:14 結果は、Workflows を利用しないケースと、利用したケースでは、Workflows を利用したほうが rspec の実行時間は長くなってしまいましたが、build-code-analyze-rspec の実行に掛かったトータルの時間に差は見られませんでした。 これは、「circleci コマンドによる Rspec の並列実行」のセクションへも記載した通り、store_test_results がサポートとされないことにより、コンテナ間での分散が最適化されていない為です。 コンテナ間で rspec の実行時間にばらつきが出ないよう、対象のファイルを最適に振り分けてくれるようなのですが、Workflows を利用するとサポートされないようです。 実行時間にばらつきが出てしまい、code_analyze のジョブを分散することで見込んでいた改善時間(約 3 分)とばらつきにより発生したテスト実行時間のロス( (20:01 - 14:57) / 2 = 2:32 )が大体同じであるため、トータルでの実行時間に差が出ない結果となりました。 ばらつきを出さない方法や、ジョブの分け方については今後も工夫してみたいと思います。 また、フロントエンドのテストをもう少し厚くしていきたいと考えているので、フロントエンドのテスト、サーバサイドのテストを Workflows を上手く使いながら分散していければ良いのかなとも思っています。 さいごに 移行に際して、 CircleCI2.0 の移行ガイド を読みながら進めていましたが、基本的な記法の変更、timezone、environment の定義方法の変更、variable の変更などが多々有り、ドキュメントを結構読み込まないとどこに何が定義できるのか把握できませんでした。 また、Workflows の組み立てなど 公式に良いサンプル は沢山あるのですが、依存関係の定義を色々試すのに苦労した気がします。 ※素直に小規模なアプリを用意して、 ローカルで circleci を実行 してみた方が効率良く進められたかもしれません。 ※ただ、 公式のドキュメント や CommunityForum をしっかり読めば余すことなく情報は合ったので非常に助かりました。 CircleCI2.0 でどのような事が出来るのか、それはどのように行えるのか。 この記事がその概観をつかむ助けになれば良いなと思っています。 参考リンク CircleCI2.0 へ移行するにあたり、以下の記事を参考にさせていただきました。ありがとうございます。 circleci/ruby:2.4.1-node-browsersって何入ってるのか知りたかった - Qiita 2018-11-19追記 https://github.com/CircleCI-Public/circleci-dockerfiles/blob/master/ruby/images/ いつの間にか公開されてました 動機 circleciが提供しているdockerファ... qiita.com CircleCI2.0のWorkflowsを試す “CircleCI2.0のWorkflowsを試す” is published by timakin. medium.com お知らせ メドレーでは、医療介護の求人サイト「 ジョブメドレー 」、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。
こんにちは。開発本部の 稲本 です。医療介護の求人サイト「 ジョブメドレー 」の開発を担当しているエンジニアです。 最近ジョブメドレーでは CircleCI2.0 への移行を行いました。移行の方法はもちろん、その際に調べたこと、CircleCI の新機能を利用してどうだったかなどを書いていきたいと思います。 課題感 弊社では、全プロダクト( CLINICS 、 MEDLEY 、 介護のほんね 、 ジョブメドレー )で CircleCI を利用しています。 ジョブメドレーでは CI によるテスト実行に 37 分前後掛かっていました(コンテナを 2 つ利用した実行時間です)。 さらに、開発メンバーが増えて来たこともあり、CI のリソースが足りなくなり開発効率が落ちかねない状況でした。 まぁよくある話ですよね。 コンテナを増やすというのも解決策の一つとしてはあるのですが、速度の改善に期待が出来ると評判も良かったので CirclecCI2.0 へ移行しました。 CircleCI2.0 への移行メリット 基本的には速度の改善に期待が出来る、というのが大きなメリットではありますが、公式では以下のように記載されています。 抜粋ですが大きな特徴としては以下の点でしょうか。 First-class Docker Support: Docker のネイティブサポートと Docker レイヤーキャッシュの導入 Workflows: ビルド、テスト、デプロイをジョブとして柔軟に管理できるようになった Advanced Caching: キャッシュの保存とリストアをイメージ、ソースコード、依存関係に対して行うことができるようになった。 この辺りの機能を活用し CI の速度改善へ繋げてみたいと思います。 ジョブメドレーのアプリケーション構成 移行の前提として、ジョブメドレーのアプリケーション構成について記載します。 フロントエンドのビルドを yarn+webpack で行い、生成したアセットを public/assets へ吐き出し、manifest ファイルのパスを rails の helper 経由で取得し読み込んでいます。(Rails4.2.x) このような構成のアプリケーションを CirlceCI2.0 でビルド、テスト、デプロイ出来るようにしていきます。 config.yml の全体像 今回、作成した config.yml はこのような形になりました。 ざっくりは build: bundle install, yarn install code_analyze: rubocop, brakeman, scss-lint rspec deploy: capistrano を行っており、ブランチによってどのジョブを実行するのかを workflows を利用して使い分けています。 詳しい解説は以降、記載していきます。 defaults : & defaults working_directory : ~/job-medley docker : - image : circleci/ruby:2.4.2-node-browsers environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : circleci/mysql:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : redis:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo version : 2 jobs : build : << : * defaults steps : - checkout - restore_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} - run : name : bundle install command : bundle install --jobs=4 --path=vendor/bundle - save_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} paths : - vendor/bundle - restore_cache : key : job-medley-yarn-{{ checksum "yarn.lock" }} - run : name : Yarn install command : | echo "Node $(node -v)" echo "Yarn v$(yarn --version)" yarn config set cache-folder ./yarn_cache echo "Yarn v$(yarn cache dir)" yarn install - save_cache : key : job-medley-yarn-{{ checksum "yarn.lock" }} paths : - node_modules - yarn_cache - persist_to_workspace : root : ~/job-medley paths : - ./* code_analyze : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run rubocop command : bundle exec rubocop - run : name : run brakeman command : bundle exec brakeman -qz - run : name : run scss-lint command : bundle exec scss-lint rspec : parallelism : 2 << : * defaults steps : - attach_workspace : at : ~/job-medley - restore_cache : key : job-medley-elasticsearch # rspec で es のコマンドを一部実行しているため、primary container 側へ install - run : name : Elasticsearch install command : | wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-x.x.x.tar.gz && \ tar -xvf elasticsearch-x.x.x.tar.gz && \ if [ -z "`elasticsearch-x.x.x/bin/plugin -l | grep analysis-kuromoji`" ]; then \ elasticsearch-x.x.x/bin/plugin -install elasticsearch/elasticsearch-analysis-kuromoji/x.x.x; fi - save_cache : key : job-medley-elasticsearch paths : - ./elasticsearch-x.x.x - run : name : database create command : bundle exec rake db:create environment : RAILS_ENV : test - run : name : run test command : | circleci tests glob 'spec/**/*_spec.*' \ | circleci tests split --split-by=timings --timings-type=filename \ | tee -a /dev/stderr \ | xargs bundle exec rspec \ --profile 100 \ --format RspecJunitFormatter \ --out rspec/rspec.xml \ --format progress environment : RAILS_ENV : test TEST_CLUSTER_COMMAND : elasticsearch-x.x.x/bin/elasticsearch - store_artifacts : path : artifacts/ - store_test_results : path : rspec/ deploy_qa : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run deploy command : | sh scripts/init_deploy.sh BRANCH="${CIRCLE_BRANCH}" bundle exec cap develop deploy deploy:restart deploy_only : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run deploy command : | BRANCH="${CIRCLE_BRANCH}" bundle exec cap production deploy deploy:restart workflows : version : 2 workflows : jobs : - build - code_analyze : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - rspec : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - deploy_qa : requires : - code_analyze - rspec filters : branches : only : develop - deploy_only : requires : - build filters : branches : only : /^sandbox.*|^master$|^staging$/ DockerImage の選定 元々、Docker を使わずに CI を回していましたが、CircleCI2.0 へ移行するに辺り Docker への利用に切り替えました。 ※ Specifying Container Images DockerImage は DockerHub へ登録されている CircleCI 公式のも の を利用しました。 アプリケーションの一部で React を使用しており、フロントのビルドは yarn+webpack を利用しています。その為、以下の image を選択しました。 circleci/ruby:2.4.2-node-browsers node のインストールと、E2E のテストに必要なソフトウェアがインストールされています。 ※詳細は こちらの記事 を参考にさせていただきました。 その他、現在利用している MySQL のバージョン、ElasticCacheRedis のバージョンと合わせた image を選択しました。 注意点としては、複数の DockerImage を利用する場合、一つ目に指定した image が primary として扱われます。 以下の例ですと、Ruby の image を最初に指定し、MySQL、Redis の image を指定していますが、MySQL コマンド自体は Ruby の image に含まれていないため、Ruby コマンドを実行できても MySQL コマンドを実行することは出来ません。 ※詳細は こちら に記載されています。 docker : - image : circleci/ruby:2.4.2-node-browsers environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : circleci/mysql:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : redis:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo また、用意されている image をカスタマイズする必要がある場合は、Docker でカスタム image を作り、public で良ければ Docker Hub へ登録、private が良ければ Amazon EC2 Container Registry へ登録しておくことで呼び出すことも可能になっています。 ※Using Custom-Built Docker Images https://circleci.com/docs/ja/2.0/custom-images/ ※Using Private Images https://circleci.com/docs/ja/2.0/private-images/ build の設定と cache CI で実行するアプリケーションの build に関してです。 checkout で github からコードを checkout し、その後の定義でアプリケーションのインストール、キャッシュ保存、キャッシュの展開を行っています。 steps : - checkout # Rails application setup - restore_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} - run : name : bundle install command : bundle install --jobs=4 --path=vendor/bundle - save_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} paths : - vendor/bundle save_cache: key に Gemfile.lock を指定することでキャッシュキーとして扱い、paths に設定したパスをキャッシュするようにしています。 restore_cache: key と一致するキャッシュがあれば、save_cache 時に指定したパスを展開し直しています。 run: こちらは rails のアプリケーションインストールしているだけです。 CircleCI1.0 よりもキャッシュ管理を柔軟に行えることがわかります。 circleci コマンドによる Rspec の並列実行 rspec によるテストの実行に関してです。 circleci コマンド を利用することでテストの並列実行を効率的に行うことが出来るます。 今回は --split-by=timings --timings-type=filename のオプションを指定し、ファイル名ベースでの分割でテストを実行します。 - run : name : run test command : | circleci tests glob 'spec/**/*_spec.*' \ | circleci tests split --split-by=timings --timings-type=filename \ | tee -a /dev/stderr \ | xargs bundle exec rspec \ --profile 100 \ --format RspecJunitFormatter \ --out rspec/rspec.xml \ --format progress environment : RAILS_ENV : test TEST_CLUSTER_COMMAND : elasticsearch-x.x.x/bin/elasticsearch - store_artifacts : path : artifacts/ - store_test_results : path : rspec/ store_artifacts: 以前からもある機能ですが、テスト結果の成果物を保存するパスになります。 store_test_results: こちらはテストの実行結果を保存しておくことで、コンテナ間で rspec の実行時間にばらつきが出ないよう、対象のファイルを最適に振り分けてくれるようなのですが、workflows を利用するとサポートされないようです。 ※参考: https://circleci.com/docs/ja/2.0/configuration-reference/#store_test_results このような形で Artifacts が保存されています。 また、artifacts には coverage と capybara の screenshot などを保存しています - simple_cov if ENV['CI'] SimpleCov.coverage_dir File.join(ENV['CIRCLE_WORKING_DIRECTORY'], 'artifacts', 'coverage') SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ SimpleCov::Formatter::HTMLFormatter ] SimpleCov.start do add_filter '/vendor/' add_filter '/spec/' add_filter '/config/' add_filter '/db/' end end capybara Capybara.save_and_open_page_path = File.join(ENV['CIRCLE_WORKING_DIRECTORY'], 'artifacts', 'capybara') if ENV['CI'] ※CircleCI2.0 から CI の環境変数が変わっています。詳細は以下のリンクへ記載されています。 https://circleci.com/docs/ja/2.0/env-vars/#circleci-environment-variable-descriptions Workflows の設定 CircleCI2.0 から Workflows の利用が可能になりました。 https://circleci.com/docs/ja/2.0/workflows/ コンテナ毎に分割しジョブを実行することで更なる並列実行の効率化、及び、ジョブ間の依存関係まで設定できるようです。 ジョブメドレーではコードの静的解析に少し実行時間が掛かっていることから、多少の改善を図れると考え 単純に使ってみたかった こちらの機能を利用してみました。 workflows : version : 2 workflows : jobs : - build - code_analyze : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - rspec : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - deploy_qa : requires : - code_analyze - rspec filters : branches : only : develop - deploy_only : requires : - build filters : branches : only : /^sandbox.*|^master$|^staging$/ build: 各ジョブで実行前に行っておく処理を定義 code_analyze: rubocop、brakeman、scss-lint などの静的解析処理を定義 rspec: アプリケーションのテストを定義 deploy: デプロイに関する処理を定義 ジョブメドレーでは、ブランチ管理に Git-flow を採用していますが、それとは別に sandbox というテスト環境を用意し運用しています。 develop ブランチでコード解析やテストをクリアしたコードだけ、master へ反映し、master ではテストフェーズなしに deploy する構成を取っています。 極力、CI のリソースを節約するように各ブランチごとで実行する処理を分けています。 各ブランチの運用は以下の通りです。 feature: コード解析、テスト実行 sandbox: デプロイのみ実行(一時レビュー用ブランチ) develop: コード解析、テスト実行、デプロイ実行 master: デプロイのみ実行 上記の例では、 code_analyze: sandbox、master、staging ブランチ以外は実行 requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 rspec: sandbox、master、staging ブランチ以外は実行 requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 deploy_qa: develop ブランチでのみ実行 requires で依存関係を指定し、code_analyze、rspec が正常に終了しなければ実行されないようになっています。 deploy_only: sandbox、master、staging ブランチのみ利用するジョブ requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 どのような workflow が出来あがるのか、以下に例を示します。 feature ブランチの例: develop ブランチの例: master、sandbox ブランチの例: 今回の例だとブランチ毎に workflow を変えているため、ignore、only の書き方で意図せず振り分けされないように考慮は必要ですが、柔軟に workflow を作れることがわかると思います。(やり過ぎると読み解くのが大変になりそうですね) Workflows に関しては こちら に色々なパターンの組み方が記載されているので、こちらを読むとより理解が深まると思います。 ジョブ間でのデータ共有 ジョブを分けてビルドする=何回もアプリケーションの初期化が必要なんじゃないか? と当然疑問に思う点ではありますが、それに対する解決策も用意されています。 build : steps : ===省略=== - persist_to_workspace : root : ~/job-medley paths : - ./* deploy_qa : << : * defaults steps : - attach_workspace : at : ~/job-medley persist_to_workspace: 指定したパスにあるデータを一時的に保管してくれます attach_workspace: 保管済みのデータを展開してくれます この機能により、ビルドプロセスで生成したものを各ジョブで実行するコンテナへ渡すことが出来ます。 ただし、そもそもビルドプロセスでキャッシュを入れていることもあり、これ自体の効果は殆どありませんでした。 コンパイル済みのデータを受け渡す際には効果を発揮しそうですね。( 公式でも そのような利用を想定していそうです) 改善結果 肝心の速度改善結果です。結果は以下の通りになりました。 改善前: CircleCI1.0 rspec の実行時間: 26:59 以下は、CircleCI2.0 へ移行しただけの結果です。このケースでは workflows を利用していません。 改善後: CircleCI2.0 rspec の実行時間: 19:40 CircleCI1.0 から CircleCI2.0 へ移行することにより、 約 12 分程 テストの実行時間を短縮することが出来ました。 Workflows など特に利用していない、かつ、ビルドフェーズの実行時間も関係しないため、CircleCI2.0 を利用するだけで単純にテスト実行速度の向上を見込めることがわかると思います。 続いて Workflows を利用した結果です。 改善後: CircleCI2.0 with Workflows rspec の実行時間: 21:14 結果は、Workflows を利用しないケースと、利用したケースでは、Workflows を利用したほうが rspec の実行時間は長くなってしまいましたが、build-code-analyze-rspec の実行に掛かったトータルの時間に差は見られませんでした。 これは、「circleci コマンドによる Rspec の並列実行」のセクションへも記載した通り、store_test_results がサポートとされないことにより、コンテナ間での分散が最適化されていない為です。 コンテナ間で rspec の実行時間にばらつきが出ないよう、対象のファイルを最適に振り分けてくれるようなのですが、Workflows を利用するとサポートされないようです。 実行時間にばらつきが出てしまい、code_analyze のジョブを分散することで見込んでいた改善時間(約 3 分)とばらつきにより発生したテスト実行時間のロス( (20:01 - 14:57) / 2 = 2:32 )が大体同じであるため、トータルでの実行時間に差が出ない結果となりました。 ばらつきを出さない方法や、ジョブの分け方については今後も工夫してみたいと思います。 また、フロントエンドのテストをもう少し厚くしていきたいと考えているので、フロントエンドのテスト、サーバサイドのテストを Workflows を上手く使いながら分散していければ良いのかなとも思っています。 さいごに 移行に際して、 CircleCI2.0 の移行ガイド を読みながら進めていましたが、基本的な記法の変更、timezone、environment の定義方法の変更、variable の変更などが多々有り、ドキュメントを結構読み込まないとどこに何が定義できるのか把握できませんでした。 また、Workflows の組み立てなど 公式に良いサンプル は沢山あるのですが、依存関係の定義を色々試すのに苦労した気がします。 ※素直に小規模なアプリを用意して、 ローカルで circleci を実行 してみた方が効率良く進められたかもしれません。 ※ただ、 公式のドキュメント や CommunityForum をしっかり読めば余すことなく情報は合ったので非常に助かりました。 CircleCI2.0 でどのような事が出来るのか、それはどのように行えるのか。 この記事がその概観をつかむ助けになれば良いなと思っています。 参考リンク CircleCI2.0 へ移行するにあたり、以下の記事を参考にさせていただきました。ありがとうございます。 https://qiita.com/inuscript/items/09d15ee52b1657872f80 https://medium.com/@timakin/circleci2-0%E3%81%AEworkflows%E3%82%92%E8%A9%A6%E3%81%99-1329042122fd お知らせ メドレーでは、医療介護の求人サイト「 ジョブメドレー 」、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 https://www.medley.jp/recruit/creative.html メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。
こんにちは。開発本部の 稲本 です。医療介護の求人サイト「 ジョブメドレー 」の開発を担当しているエンジニアです。 最近ジョブメドレーでは CircleCI2.0 への移行を行いました。移行の方法はもちろん、その際に調べたこと、CircleCI の新機能を利用してどうだったかなどを書いていきたいと思います。 課題感 弊社では、全プロダクト( CLINICS 、 MEDLEY 、 介護のほんね 、 ジョブメドレー )で CircleCI を利用しています。 ジョブメドレーでは CI によるテスト実行に 37 分前後掛かっていました(コンテナを 2 つ利用した実行時間です)。 さらに、開発メンバーが増えて来たこともあり、CI のリソースが足りなくなり開発効率が落ちかねない状況でした。 まぁよくある話ですよね。 コンテナを増やすというのも解決策の一つとしてはあるのですが、速度の改善に期待が出来ると評判も良かったので CirclecCI2.0 へ移行しました。 CircleCI2.0 への移行メリット 基本的には速度の改善に期待が出来る、というのが大きなメリットではありますが、公式では以下のように記載されています。 抜粋ですが大きな特徴としては以下の点でしょうか。 First-class Docker Support: Docker のネイティブサポートと Docker レイヤーキャッシュの導入 Workflows: ビルド、テスト、デプロイをジョブとして柔軟に管理できるようになった Advanced Caching: キャッシュの保存とリストアをイメージ、ソースコード、依存関係に対して行うことができるようになった。 この辺りの機能を活用し CI の速度改善へ繋げてみたいと思います。 ジョブメドレーのアプリケーション構成 移行の前提として、ジョブメドレーのアプリケーション構成について記載します。 フロントエンドのビルドを yarn+webpack で行い、生成したアセットを public/assets へ吐き出し、manifest ファイルのパスを rails の helper 経由で取得し読み込んでいます。(Rails4.2.x) このような構成のアプリケーションを CirlceCI2.0 でビルド、テスト、デプロイ出来るようにしていきます。 config.yml の全体像 今回、作成した config.yml はこのような形になりました。 ざっくりは build: bundle install, yarn install code_analyze: rubocop, brakeman, scss-lint rspec deploy: capistrano を行っており、ブランチによってどのジョブを実行するのかを workflows を利用して使い分けています。 詳しい解説は以降、記載していきます。 defaults : & defaults working_directory : ~/job-medley docker : - image : circleci/ruby:2.4.2-node-browsers environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : circleci/mysql:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : redis:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo version : 2 jobs : build : << : * defaults steps : - checkout - restore_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} - run : name : bundle install command : bundle install --jobs=4 --path=vendor/bundle - save_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} paths : - vendor/bundle - restore_cache : key : job-medley-yarn-{{ checksum "yarn.lock" }} - run : name : Yarn install command : | echo "Node $(node -v)" echo "Yarn v$(yarn --version)" yarn config set cache-folder ./yarn_cache echo "Yarn v$(yarn cache dir)" yarn install - save_cache : key : job-medley-yarn-{{ checksum "yarn.lock" }} paths : - node_modules - yarn_cache - persist_to_workspace : root : ~/job-medley paths : - ./* code_analyze : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run rubocop command : bundle exec rubocop - run : name : run brakeman command : bundle exec brakeman -qz - run : name : run scss-lint command : bundle exec scss-lint rspec : parallelism : 2 << : * defaults steps : - attach_workspace : at : ~/job-medley - restore_cache : key : job-medley-elasticsearch # rspec で es のコマンドを一部実行しているため、primary container 側へ install - run : name : Elasticsearch install command : | wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-x.x.x.tar.gz && \ tar -xvf elasticsearch-x.x.x.tar.gz && \ if [ -z "`elasticsearch-x.x.x/bin/plugin -l | grep analysis-kuromoji`" ]; then \ elasticsearch-x.x.x/bin/plugin -install elasticsearch/elasticsearch-analysis-kuromoji/x.x.x; fi - save_cache : key : job-medley-elasticsearch paths : - ./elasticsearch-x.x.x - run : name : database create command : bundle exec rake db:create environment : RAILS_ENV : test - run : name : run test command : | circleci tests glob 'spec/**/*_spec.*' \ | circleci tests split --split-by=timings --timings-type=filename \ | tee -a /dev/stderr \ | xargs bundle exec rspec \ --profile 100 \ --format RspecJunitFormatter \ --out rspec/rspec.xml \ --format progress environment : RAILS_ENV : test TEST_CLUSTER_COMMAND : elasticsearch-x.x.x/bin/elasticsearch - store_artifacts : path : artifacts/ - store_test_results : path : rspec/ deploy_qa : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run deploy command : | sh scripts/init_deploy.sh BRANCH="${CIRCLE_BRANCH}" bundle exec cap develop deploy deploy:restart deploy_only : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run deploy command : | BRANCH="${CIRCLE_BRANCH}" bundle exec cap production deploy deploy:restart workflows : version : 2 workflows : jobs : - build - code_analyze : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - rspec : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - deploy_qa : requires : - code_analyze - rspec filters : branches : only : develop - deploy_only : requires : - build filters : branches : only : /^sandbox.*|^master$|^staging$/ DockerImage の選定 元々、Docker を使わずに CI を回していましたが、CircleCI2.0 へ移行するに辺り Docker への利用に切り替えました。 ※ Specifying Container Images DockerImage は DockerHub へ登録されている CircleCI 公式のも の を利用しました。 アプリケーションの一部で React を使用しており、フロントのビルドは yarn+webpack を利用しています。その為、以下の image を選択しました。 circleci/ruby:2.4.2-node-browsers node のインストールと、E2E のテストに必要なソフトウェアがインストールされています。 ※詳細は こちらの記事 を参考にさせていただきました。 その他、現在利用している MySQL のバージョン、ElasticCacheRedis のバージョンと合わせた image を選択しました。 注意点としては、複数の DockerImage を利用する場合、一つ目に指定した image が primary として扱われます。 以下の例ですと、Ruby の image を最初に指定し、MySQL、Redis の image を指定していますが、MySQL コマンド自体は Ruby の image に含まれていないため、Ruby コマンドを実行できても MySQL コマンドを実行することは出来ません。 ※詳細は こちら に記載されています。 docker : - image : circleci/ruby:2.4.2-node-browsers environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : circleci/mysql:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : redis:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo また、用意されている image をカスタマイズする必要がある場合は、Docker でカスタム image を作り、public で良ければ Docker Hub へ登録、private が良ければ Amazon EC2 Container Registry へ登録しておくことで呼び出すことも可能になっています。 ※Using Custom-Built Docker Images https://circleci.com/docs/ja/2.0/custom-images/ ※Using Private Images https://circleci.com/docs/ja/2.0/private-images/ build の設定と cache CI で実行するアプリケーションの build に関してです。 checkout で github からコードを checkout し、その後の定義でアプリケーションのインストール、キャッシュ保存、キャッシュの展開を行っています。 steps : - checkout # Rails application setup - restore_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} - run : name : bundle install command : bundle install --jobs=4 --path=vendor/bundle - save_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} paths : - vendor/bundle save_cache: key に Gemfile.lock を指定することでキャッシュキーとして扱い、paths に設定したパスをキャッシュするようにしています。 restore_cache: key と一致するキャッシュがあれば、save_cache 時に指定したパスを展開し直しています。 run: こちらは rails のアプリケーションインストールしているだけです。 CircleCI1.0 よりもキャッシュ管理を柔軟に行えることがわかります。 circleci コマンドによる Rspec の並列実行 rspec によるテストの実行に関してです。 circleci コマンド を利用することでテストの並列実行を効率的に行うことが出来るます。 今回は --split-by=timings --timings-type=filename のオプションを指定し、ファイル名ベースでの分割でテストを実行します。 - run : name : run test command : | circleci tests glob 'spec/**/*_spec.*' \ | circleci tests split --split-by=timings --timings-type=filename \ | tee -a /dev/stderr \ | xargs bundle exec rspec \ --profile 100 \ --format RspecJunitFormatter \ --out rspec/rspec.xml \ --format progress environment : RAILS_ENV : test TEST_CLUSTER_COMMAND : elasticsearch-x.x.x/bin/elasticsearch - store_artifacts : path : artifacts/ - store_test_results : path : rspec/ store_artifacts: 以前からもある機能ですが、テスト結果の成果物を保存するパスになります。 store_test_results: こちらはテストの実行結果を保存しておくことで、コンテナ間で rspec の実行時間にばらつきが出ないよう、対象のファイルを最適に振り分けてくれるようなのですが、workflows を利用するとサポートされないようです。 ※参考: https://circleci.com/docs/ja/2.0/configuration-reference/#store_test_results このような形で Artifacts が保存されています。 また、artifacts には coverage と capybara の screenshot などを保存しています - simple_cov if ENV['CI'] SimpleCov.coverage_dir File.join(ENV['CIRCLE_WORKING_DIRECTORY'], 'artifacts', 'coverage') SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ SimpleCov::Formatter::HTMLFormatter ] SimpleCov.start do add_filter '/vendor/' add_filter '/spec/' add_filter '/config/' add_filter '/db/' end end capybara Capybara.save_and_open_page_path = File.join(ENV['CIRCLE_WORKING_DIRECTORY'], 'artifacts', 'capybara') if ENV['CI'] ※CircleCI2.0 から CI の環境変数が変わっています。詳細は以下のリンクへ記載されています。 Introduction to environment variables - CircleCI Introduction to environment variables in CircleCI circleci.com Workflows の設定 CircleCI2.0 から Workflows の利用が可能になりました。 Workflow orchestration - CircleCI Learn about using CircleCI workflows to orchestrate jobs circleci.com コンテナ毎に分割しジョブを実行することで更なる並列実行の効率化、及び、ジョブ間の依存関係まで設定できるようです。 ジョブメドレーではコードの静的解析に少し実行時間が掛かっていることから、多少の改善を図れると考え 単純に使ってみたかった こちらの機能を利用してみました。 workflows : version : 2 workflows : jobs : - build - code_analyze : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - rspec : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - deploy_qa : requires : - code_analyze - rspec filters : branches : only : develop - deploy_only : requires : - build filters : branches : only : /^sandbox.*|^master$|^staging$/ build: 各ジョブで実行前に行っておく処理を定義 code_analyze: rubocop、brakeman、scss-lint などの静的解析処理を定義 rspec: アプリケーションのテストを定義 deploy: デプロイに関する処理を定義 ジョブメドレーでは、ブランチ管理に Git-flow を採用していますが、それとは別に sandbox というテスト環境を用意し運用しています。 develop ブランチでコード解析やテストをクリアしたコードだけ、master へ反映し、master ではテストフェーズなしに deploy する構成を取っています。 極力、CI のリソースを節約するように各ブランチごとで実行する処理を分けています。 各ブランチの運用は以下の通りです。 feature: コード解析、テスト実行 sandbox: デプロイのみ実行(一時レビュー用ブランチ) develop: コード解析、テスト実行、デプロイ実行 master: デプロイのみ実行 上記の例では、 code_analyze: sandbox、master、staging ブランチ以外は実行 requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 rspec: sandbox、master、staging ブランチ以外は実行 requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 deploy_qa: develop ブランチでのみ実行 requires で依存関係を指定し、code_analyze、rspec が正常に終了しなければ実行されないようになっています。 deploy_only: sandbox、master、staging ブランチのみ利用するジョブ requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 どのような workflow が出来あがるのか、以下に例を示します。 feature ブランチの例: develop ブランチの例: master、sandbox ブランチの例: 今回の例だとブランチ毎に workflow を変えているため、ignore、only の書き方で意図せず振り分けされないように考慮は必要ですが、柔軟に workflow を作れることがわかると思います。(やり過ぎると読み解くのが大変になりそうですね) Workflows に関しては こちら に色々なパターンの組み方が記載されているので、こちらを読むとより理解が深まると思います。 ジョブ間でのデータ共有 ジョブを分けてビルドする=何回もアプリケーションの初期化が必要なんじゃないか? と当然疑問に思う点ではありますが、それに対する解決策も用意されています。 build : steps : ===省略=== - persist_to_workspace : root : ~/job-medley paths : - ./* deploy_qa : << : * defaults steps : - attach_workspace : at : ~/job-medley persist_to_workspace: 指定したパスにあるデータを一時的に保管してくれます attach_workspace: 保管済みのデータを展開してくれます この機能により、ビルドプロセスで生成したものを各ジョブで実行するコンテナへ渡すことが出来ます。 ただし、そもそもビルドプロセスでキャッシュを入れていることもあり、これ自体の効果は殆どありませんでした。 コンパイル済みのデータを受け渡す際には効果を発揮しそうですね。( 公式でも そのような利用を想定していそうです) 改善結果 肝心の速度改善結果です。結果は以下の通りになりました。 改善前: CircleCI1.0 rspec の実行時間: 26:59 以下は、CircleCI2.0 へ移行しただけの結果です。このケースでは workflows を利用していません。 改善後: CircleCI2.0 rspec の実行時間: 19:40 CircleCI1.0 から CircleCI2.0 へ移行することにより、 約 12 分程 テストの実行時間を短縮することが出来ました。 Workflows など特に利用していない、かつ、ビルドフェーズの実行時間も関係しないため、CircleCI2.0 を利用するだけで単純にテスト実行速度の向上を見込めることがわかると思います。 続いて Workflows を利用した結果です。 改善後: CircleCI2.0 with Workflows rspec の実行時間: 21:14 結果は、Workflows を利用しないケースと、利用したケースでは、Workflows を利用したほうが rspec の実行時間は長くなってしまいましたが、build-code-analyze-rspec の実行に掛かったトータルの時間に差は見られませんでした。 これは、「circleci コマンドによる Rspec の並列実行」のセクションへも記載した通り、store_test_results がサポートとされないことにより、コンテナ間での分散が最適化されていない為です。 コンテナ間で rspec の実行時間にばらつきが出ないよう、対象のファイルを最適に振り分けてくれるようなのですが、Workflows を利用するとサポートされないようです。 実行時間にばらつきが出てしまい、code_analyze のジョブを分散することで見込んでいた改善時間(約 3 分)とばらつきにより発生したテスト実行時間のロス( (20:01 - 14:57) / 2 = 2:32 )が大体同じであるため、トータルでの実行時間に差が出ない結果となりました。 ばらつきを出さない方法や、ジョブの分け方については今後も工夫してみたいと思います。 また、フロントエンドのテストをもう少し厚くしていきたいと考えているので、フロントエンドのテスト、サーバサイドのテストを Workflows を上手く使いながら分散していければ良いのかなとも思っています。 さいごに 移行に際して、 CircleCI2.0 の移行ガイド を読みながら進めていましたが、基本的な記法の変更、timezone、environment の定義方法の変更、variable の変更などが多々有り、ドキュメントを結構読み込まないとどこに何が定義できるのか把握できませんでした。 また、Workflows の組み立てなど 公式に良いサンプル は沢山あるのですが、依存関係の定義を色々試すのに苦労した気がします。 ※素直に小規模なアプリを用意して、 ローカルで circleci を実行 してみた方が効率良く進められたかもしれません。 ※ただ、 公式のドキュメント や CommunityForum をしっかり読めば余すことなく情報は合ったので非常に助かりました。 CircleCI2.0 でどのような事が出来るのか、それはどのように行えるのか。 この記事がその概観をつかむ助けになれば良いなと思っています。 参考リンク CircleCI2.0 へ移行するにあたり、以下の記事を参考にさせていただきました。ありがとうございます。 circleci/ruby:2.4.1-node-browsersって何入ってるのか知りたかった - Qiita 2018-11-19追記https://github.com/CircleCI-Public/circleci-dockerfiles/blob/master/ruby/images/いつの間に… qiita.com CircleCI2.0のWorkflowsを試す “CircleCI2.0のWorkflowsを試す” is published by timakin. medium.com お知らせ メドレーでは、医療介護の求人サイト「 ジョブメドレー 」、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。
こんにちは。開発本部の 稲本 です。医療介護の求人サイト「 ジョブメドレー 」の開発を担当しているエンジニアです。 最近ジョブメドレーでは CircleCI2.0 への移行を行いました。移行の方法はもちろん、その際に調べたこと、CircleCI の新機能を利用してどうだったかなどを書いていきたいと思います。 課題感 弊社では、全プロダクト( CLINICS 、 MEDLEY 、 介護のほんね 、 ジョブメドレー )で CircleCI を利用しています。 ジョブメドレーでは CI によるテスト実行に 37 分前後掛かっていました(コンテナを 2 つ利用した実行時間です)。 さらに、開発メンバーが増えて来たこともあり、CI のリソースが足りなくなり開発効率が落ちかねない状況でした。 まぁよくある話ですよね。 コンテナを増やすというのも解決策の一つとしてはあるのですが、速度の改善に期待が出来ると評判も良かったので CirclecCI2.0 へ移行しました。 CircleCI2.0 への移行メリット 基本的には速度の改善に期待が出来る、というのが大きなメリットではありますが、公式では以下のように記載されています。 抜粋ですが大きな特徴としては以下の点でしょうか。 First-class Docker Support: Docker のネイティブサポートと Docker レイヤーキャッシュの導入 Workflows: ビルド、テスト、デプロイをジョブとして柔軟に管理できるようになった Advanced Caching: キャッシュの保存とリストアをイメージ、ソースコード、依存関係に対して行うことができるようになった。 この辺りの機能を活用し CI の速度改善へ繋げてみたいと思います。 ジョブメドレーのアプリケーション構成 移行の前提として、ジョブメドレーのアプリケーション構成について記載します。 フロントエンドのビルドを yarn+webpack で行い、生成したアセットを public/assets へ吐き出し、manifest ファイルのパスを rails の helper 経由で取得し読み込んでいます。(Rails4.2.x) このような構成のアプリケーションを CirlceCI2.0 でビルド、テスト、デプロイ出来るようにしていきます。 config.yml の全体像 今回、作成した config.yml はこのような形になりました。 ざっくりは build: bundle install, yarn install code_analyze: rubocop, brakeman, scss-lint rspec deploy: capistrano を行っており、ブランチによってどのジョブを実行するのかを workflows を利用して使い分けています。 詳しい解説は以降、記載していきます。 defaults : & defaults working_directory : ~/job-medley docker : - image : circleci/ruby:2.4.2-node-browsers environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : circleci/mysql:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : redis:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo version : 2 jobs : build : << : * defaults steps : - checkout - restore_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} - run : name : bundle install command : bundle install --jobs=4 --path=vendor/bundle - save_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} paths : - vendor/bundle - restore_cache : key : job-medley-yarn-{{ checksum "yarn.lock" }} - run : name : Yarn install command : | echo "Node $(node -v)" echo "Yarn v$(yarn --version)" yarn config set cache-folder ./yarn_cache echo "Yarn v$(yarn cache dir)" yarn install - save_cache : key : job-medley-yarn-{{ checksum "yarn.lock" }} paths : - node_modules - yarn_cache - persist_to_workspace : root : ~/job-medley paths : - ./* code_analyze : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run rubocop command : bundle exec rubocop - run : name : run brakeman command : bundle exec brakeman -qz - run : name : run scss-lint command : bundle exec scss-lint rspec : parallelism : 2 << : * defaults steps : - attach_workspace : at : ~/job-medley - restore_cache : key : job-medley-elasticsearch # rspec で es のコマンドを一部実行しているため、primary container 側へ install - run : name : Elasticsearch install command : | wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-x.x.x.tar.gz && \ tar -xvf elasticsearch-x.x.x.tar.gz && \ if [ -z "`elasticsearch-x.x.x/bin/plugin -l | grep analysis-kuromoji`" ]; then \ elasticsearch-x.x.x/bin/plugin -install elasticsearch/elasticsearch-analysis-kuromoji/x.x.x; fi - save_cache : key : job-medley-elasticsearch paths : - ./elasticsearch-x.x.x - run : name : database create command : bundle exec rake db:create environment : RAILS_ENV : test - run : name : run test command : | circleci tests glob 'spec/**/*_spec.*' \ | circleci tests split --split-by=timings --timings-type=filename \ | tee -a /dev/stderr \ | xargs bundle exec rspec \ --profile 100 \ --format RspecJunitFormatter \ --out rspec/rspec.xml \ --format progress environment : RAILS_ENV : test TEST_CLUSTER_COMMAND : elasticsearch-x.x.x/bin/elasticsearch - store_artifacts : path : artifacts/ - store_test_results : path : rspec/ deploy_qa : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run deploy command : | sh scripts/init_deploy.sh BRANCH="${CIRCLE_BRANCH}" bundle exec cap develop deploy deploy:restart deploy_only : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run deploy command : | BRANCH="${CIRCLE_BRANCH}" bundle exec cap production deploy deploy:restart workflows : version : 2 workflows : jobs : - build - code_analyze : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - rspec : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - deploy_qa : requires : - code_analyze - rspec filters : branches : only : develop - deploy_only : requires : - build filters : branches : only : /^sandbox.*|^master$|^staging$/ DockerImage の選定 元々、Docker を使わずに CI を回していましたが、CircleCI2.0 へ移行するに辺り Docker への利用に切り替えました。 ※ Specifying Container Images DockerImage は DockerHub へ登録されている CircleCI 公式のも の を利用しました。 アプリケーションの一部で React を使用しており、フロントのビルドは yarn+webpack を利用しています。その為、以下の image を選択しました。 circleci/ruby:2.4.2-node-browsers node のインストールと、E2E のテストに必要なソフトウェアがインストールされています。 ※詳細は こちらの記事 を参考にさせていただきました。 その他、現在利用している MySQL のバージョン、ElasticCacheRedis のバージョンと合わせた image を選択しました。 注意点としては、複数の DockerImage を利用する場合、一つ目に指定した image が primary として扱われます。 以下の例ですと、Ruby の image を最初に指定し、MySQL、Redis の image を指定していますが、MySQL コマンド自体は Ruby の image に含まれていないため、Ruby コマンドを実行できても MySQL コマンドを実行することは出来ません。 ※詳細は こちら に記載されています。 docker : - image : circleci/ruby:2.4.2-node-browsers environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : circleci/mysql:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : redis:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo また、用意されている image をカスタマイズする必要がある場合は、Docker でカスタム image を作り、public で良ければ Docker Hub へ登録、private が良ければ Amazon EC2 Container Registry へ登録しておくことで呼び出すことも可能になっています。 ※Using Custom-Built Docker Images https://circleci.com/docs/ja/2.0/custom-images/ ※Using Private Images https://circleci.com/docs/ja/2.0/private-images/ build の設定と cache CI で実行するアプリケーションの build に関してです。 checkout で github からコードを checkout し、その後の定義でアプリケーションのインストール、キャッシュ保存、キャッシュの展開を行っています。 steps : - checkout # Rails application setup - restore_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} - run : name : bundle install command : bundle install --jobs=4 --path=vendor/bundle - save_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} paths : - vendor/bundle save_cache: key に Gemfile.lock を指定することでキャッシュキーとして扱い、paths に設定したパスをキャッシュするようにしています。 restore_cache: key と一致するキャッシュがあれば、save_cache 時に指定したパスを展開し直しています。 run: こちらは rails のアプリケーションインストールしているだけです。 CircleCI1.0 よりもキャッシュ管理を柔軟に行えることがわかります。 circleci コマンドによる Rspec の並列実行 rspec によるテストの実行に関してです。 circleci コマンド を利用することでテストの並列実行を効率的に行うことが出来るます。 今回は --split-by=timings --timings-type=filename のオプションを指定し、ファイル名ベースでの分割でテストを実行します。 - run : name : run test command : | circleci tests glob 'spec/**/*_spec.*' \ | circleci tests split --split-by=timings --timings-type=filename \ | tee -a /dev/stderr \ | xargs bundle exec rspec \ --profile 100 \ --format RspecJunitFormatter \ --out rspec/rspec.xml \ --format progress environment : RAILS_ENV : test TEST_CLUSTER_COMMAND : elasticsearch-x.x.x/bin/elasticsearch - store_artifacts : path : artifacts/ - store_test_results : path : rspec/ store_artifacts: 以前からもある機能ですが、テスト結果の成果物を保存するパスになります。 store_test_results: こちらはテストの実行結果を保存しておくことで、コンテナ間で rspec の実行時間にばらつきが出ないよう、対象のファイルを最適に振り分けてくれるようなのですが、workflows を利用するとサポートされないようです。 ※参考: https://circleci.com/docs/ja/2.0/configuration-reference/#store_test_results このような形で Artifacts が保存されています。 また、artifacts には coverage と capybara の screenshot などを保存しています - simple_cov if ENV['CI'] SimpleCov.coverage_dir File.join(ENV['CIRCLE_WORKING_DIRECTORY'], 'artifacts', 'coverage') SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ SimpleCov::Formatter::HTMLFormatter ] SimpleCov.start do add_filter '/vendor/' add_filter '/spec/' add_filter '/config/' add_filter '/db/' end end capybara Capybara.save_and_open_page_path = File.join(ENV['CIRCLE_WORKING_DIRECTORY'], 'artifacts', 'capybara') if ENV['CI'] ※CircleCI2.0 から CI の環境変数が変わっています。詳細は以下のリンクへ記載されています。 Introduction to environment variables - CircleCI Introduction to environment variables in CircleCI circleci.com Workflows の設定 CircleCI2.0 から Workflows の利用が可能になりました。 Workflow orchestration - CircleCI Learn about using CircleCI workflows to orchestrate jobs circleci.com コンテナ毎に分割しジョブを実行することで更なる並列実行の効率化、及び、ジョブ間の依存関係まで設定できるようです。 ジョブメドレーではコードの静的解析に少し実行時間が掛かっていることから、多少の改善を図れると考え 単純に使ってみたかった こちらの機能を利用してみました。 workflows : version : 2 workflows : jobs : - build - code_analyze : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - rspec : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - deploy_qa : requires : - code_analyze - rspec filters : branches : only : develop - deploy_only : requires : - build filters : branches : only : /^sandbox.*|^master$|^staging$/ build: 各ジョブで実行前に行っておく処理を定義 code_analyze: rubocop、brakeman、scss-lint などの静的解析処理を定義 rspec: アプリケーションのテストを定義 deploy: デプロイに関する処理を定義 ジョブメドレーでは、ブランチ管理に Git-flow を採用していますが、それとは別に sandbox というテスト環境を用意し運用しています。 develop ブランチでコード解析やテストをクリアしたコードだけ、master へ反映し、master ではテストフェーズなしに deploy する構成を取っています。 極力、CI のリソースを節約するように各ブランチごとで実行する処理を分けています。 各ブランチの運用は以下の通りです。 feature: コード解析、テスト実行 sandbox: デプロイのみ実行(一時レビュー用ブランチ) develop: コード解析、テスト実行、デプロイ実行 master: デプロイのみ実行 上記の例では、 code_analyze: sandbox、master、staging ブランチ以外は実行 requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 rspec: sandbox、master、staging ブランチ以外は実行 requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 deploy_qa: develop ブランチでのみ実行 requires で依存関係を指定し、code_analyze、rspec が正常に終了しなければ実行されないようになっています。 deploy_only: sandbox、master、staging ブランチのみ利用するジョブ requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 どのような workflow が出来あがるのか、以下に例を示します。 feature ブランチの例: develop ブランチの例: master、sandbox ブランチの例: 今回の例だとブランチ毎に workflow を変えているため、ignore、only の書き方で意図せず振り分けされないように考慮は必要ですが、柔軟に workflow を作れることがわかると思います。(やり過ぎると読み解くのが大変になりそうですね) Workflows に関しては こちら に色々なパターンの組み方が記載されているので、こちらを読むとより理解が深まると思います。 ジョブ間でのデータ共有 ジョブを分けてビルドする=何回もアプリケーションの初期化が必要なんじゃないか? と当然疑問に思う点ではありますが、それに対する解決策も用意されています。 build : steps : ===省略=== - persist_to_workspace : root : ~/job-medley paths : - ./* deploy_qa : << : * defaults steps : - attach_workspace : at : ~/job-medley persist_to_workspace: 指定したパスにあるデータを一時的に保管してくれます attach_workspace: 保管済みのデータを展開してくれます この機能により、ビルドプロセスで生成したものを各ジョブで実行するコンテナへ渡すことが出来ます。 ただし、そもそもビルドプロセスでキャッシュを入れていることもあり、これ自体の効果は殆どありませんでした。 コンパイル済みのデータを受け渡す際には効果を発揮しそうですね。( 公式でも そのような利用を想定していそうです) 改善結果 肝心の速度改善結果です。結果は以下の通りになりました。 改善前: CircleCI1.0 rspec の実行時間: 26:59 以下は、CircleCI2.0 へ移行しただけの結果です。このケースでは workflows を利用していません。 改善後: CircleCI2.0 rspec の実行時間: 19:40 CircleCI1.0 から CircleCI2.0 へ移行することにより、 約 12 分程 テストの実行時間を短縮することが出来ました。 Workflows など特に利用していない、かつ、ビルドフェーズの実行時間も関係しないため、CircleCI2.0 を利用するだけで単純にテスト実行速度の向上を見込めることがわかると思います。 続いて Workflows を利用した結果です。 改善後: CircleCI2.0 with Workflows rspec の実行時間: 21:14 結果は、Workflows を利用しないケースと、利用したケースでは、Workflows を利用したほうが rspec の実行時間は長くなってしまいましたが、build-code-analyze-rspec の実行に掛かったトータルの時間に差は見られませんでした。 これは、「circleci コマンドによる Rspec の並列実行」のセクションへも記載した通り、store_test_results がサポートとされないことにより、コンテナ間での分散が最適化されていない為です。 コンテナ間で rspec の実行時間にばらつきが出ないよう、対象のファイルを最適に振り分けてくれるようなのですが、Workflows を利用するとサポートされないようです。 実行時間にばらつきが出てしまい、code_analyze のジョブを分散することで見込んでいた改善時間(約 3 分)とばらつきにより発生したテスト実行時間のロス( (20:01 - 14:57) / 2 = 2:32 )が大体同じであるため、トータルでの実行時間に差が出ない結果となりました。 ばらつきを出さない方法や、ジョブの分け方については今後も工夫してみたいと思います。 また、フロントエンドのテストをもう少し厚くしていきたいと考えているので、フロントエンドのテスト、サーバサイドのテストを Workflows を上手く使いながら分散していければ良いのかなとも思っています。 さいごに 移行に際して、 CircleCI2.0 の移行ガイド を読みながら進めていましたが、基本的な記法の変更、timezone、environment の定義方法の変更、variable の変更などが多々有り、ドキュメントを結構読み込まないとどこに何が定義できるのか把握できませんでした。 また、Workflows の組み立てなど 公式に良いサンプル は沢山あるのですが、依存関係の定義を色々試すのに苦労した気がします。 ※素直に小規模なアプリを用意して、 ローカルで circleci を実行 してみた方が効率良く進められたかもしれません。 ※ただ、 公式のドキュメント や CommunityForum をしっかり読めば余すことなく情報は合ったので非常に助かりました。 CircleCI2.0 でどのような事が出来るのか、それはどのように行えるのか。 この記事がその概観をつかむ助けになれば良いなと思っています。 参考リンク CircleCI2.0 へ移行するにあたり、以下の記事を参考にさせていただきました。ありがとうございます。 circleci/ruby:2.4.1-node-browsersって何入ってるのか知りたかった - Qiita 2018-11-19追記https://github.com/CircleCI-Public/circleci-dockerfiles/blob/master/ruby/images/いつの間に… qiita.com CircleCI2.0のWorkflowsを試す “CircleCI2.0のWorkflowsを試す” is published by timakin. medium.com お知らせ メドレーでは、医療介護の求人サイト「 ジョブメドレー 」、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。
こんにちは。開発本部の 稲本 です。医療介護の求人サイト「 ジョブメドレー 」の開発を担当しているエンジニアです。 最近ジョブメドレーでは CircleCI2.0 への移行を行いました。移行の方法はもちろん、その際に調べたこと、CircleCI の新機能を利用してどうだったかなどを書いていきたいと思います。 課題感 弊社では、全プロダクト( CLINICS 、 MEDLEY 、 介護のほんね 、 ジョブメドレー )で CircleCI を利用しています。 ジョブメドレーでは CI によるテスト実行に 37 分前後掛かっていました(コンテナを 2 つ利用した実行時間です)。 さらに、開発メンバーが増えて来たこともあり、CI のリソースが足りなくなり開発効率が落ちかねない状況でした。 まぁよくある話ですよね。 コンテナを増やすというのも解決策の一つとしてはあるのですが、速度の改善に期待が出来ると評判も良かったので CirclecCI2.0 へ移行しました。 CircleCI2.0 への移行メリット 基本的には速度の改善に期待が出来る、というのが大きなメリットではありますが、公式では以下のように記載されています。 抜粋ですが大きな特徴としては以下の点でしょうか。 First-class Docker Support: Docker のネイティブサポートと Docker レイヤーキャッシュの導入 Workflows: ビルド、テスト、デプロイをジョブとして柔軟に管理できるようになった Advanced Caching: キャッシュの保存とリストアをイメージ、ソースコード、依存関係に対して行うことができるようになった。 この辺りの機能を活用し CI の速度改善へ繋げてみたいと思います。 ジョブメドレーのアプリケーション構成 移行の前提として、ジョブメドレーのアプリケーション構成について記載します。 フロントエンドのビルドを yarn+webpack で行い、生成したアセットを public/assets へ吐き出し、manifest ファイルのパスを rails の helper 経由で取得し読み込んでいます。(Rails4.2.x) このような構成のアプリケーションを CirlceCI2.0 でビルド、テスト、デプロイ出来るようにしていきます。 config.yml の全体像 今回、作成した config.yml はこのような形になりました。 ざっくりは build: bundle install, yarn install code_analyze: rubocop, brakeman, scss-lint rspec deploy: capistrano を行っており、ブランチによってどのジョブを実行するのかを workflows を利用して使い分けています。 詳しい解説は以降、記載していきます。 defaults : & defaults working_directory : ~/job-medley docker : - image : circleci/ruby:2.4.2-node-browsers environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : circleci/mysql:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : redis:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo version : 2 jobs : build : << : * defaults steps : - checkout - restore_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} - run : name : bundle install command : bundle install --jobs=4 --path=vendor/bundle - save_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} paths : - vendor/bundle - restore_cache : key : job-medley-yarn-{{ checksum "yarn.lock" }} - run : name : Yarn install command : | echo "Node $(node -v)" echo "Yarn v$(yarn --version)" yarn config set cache-folder ./yarn_cache echo "Yarn v$(yarn cache dir)" yarn install - save_cache : key : job-medley-yarn-{{ checksum "yarn.lock" }} paths : - node_modules - yarn_cache - persist_to_workspace : root : ~/job-medley paths : - ./* code_analyze : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run rubocop command : bundle exec rubocop - run : name : run brakeman command : bundle exec brakeman -qz - run : name : run scss-lint command : bundle exec scss-lint rspec : parallelism : 2 << : * defaults steps : - attach_workspace : at : ~/job-medley - restore_cache : key : job-medley-elasticsearch # rspec で es のコマンドを一部実行しているため、primary container 側へ install - run : name : Elasticsearch install command : | wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-x.x.x.tar.gz && \ tar -xvf elasticsearch-x.x.x.tar.gz && \ if [ -z "`elasticsearch-x.x.x/bin/plugin -l | grep analysis-kuromoji`" ]; then \ elasticsearch-x.x.x/bin/plugin -install elasticsearch/elasticsearch-analysis-kuromoji/x.x.x; fi - save_cache : key : job-medley-elasticsearch paths : - ./elasticsearch-x.x.x - run : name : database create command : bundle exec rake db:create environment : RAILS_ENV : test - run : name : run test command : | circleci tests glob 'spec/**/*_spec.*' \ | circleci tests split --split-by=timings --timings-type=filename \ | tee -a /dev/stderr \ | xargs bundle exec rspec \ --profile 100 \ --format RspecJunitFormatter \ --out rspec/rspec.xml \ --format progress environment : RAILS_ENV : test TEST_CLUSTER_COMMAND : elasticsearch-x.x.x/bin/elasticsearch - store_artifacts : path : artifacts/ - store_test_results : path : rspec/ deploy_qa : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run deploy command : | sh scripts/init_deploy.sh BRANCH="${CIRCLE_BRANCH}" bundle exec cap develop deploy deploy:restart deploy_only : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run deploy command : | BRANCH="${CIRCLE_BRANCH}" bundle exec cap production deploy deploy:restart workflows : version : 2 workflows : jobs : - build - code_analyze : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - rspec : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - deploy_qa : requires : - code_analyze - rspec filters : branches : only : develop - deploy_only : requires : - build filters : branches : only : /^sandbox.*|^master$|^staging$/ DockerImage の選定 元々、Docker を使わずに CI を回していましたが、CircleCI2.0 へ移行するに辺り Docker への利用に切り替えました。 ※ Specifying Container Images DockerImage は DockerHub へ登録されている CircleCI 公式のも の を利用しました。 アプリケーションの一部で React を使用しており、フロントのビルドは yarn+webpack を利用しています。その為、以下の image を選択しました。 circleci/ruby:2.4.2-node-browsers node のインストールと、E2E のテストに必要なソフトウェアがインストールされています。 ※詳細は こちらの記事 を参考にさせていただきました。 その他、現在利用している MySQL のバージョン、ElasticCacheRedis のバージョンと合わせた image を選択しました。 注意点としては、複数の DockerImage を利用する場合、一つ目に指定した image が primary として扱われます。 以下の例ですと、Ruby の image を最初に指定し、MySQL、Redis の image を指定していますが、MySQL コマンド自体は Ruby の image に含まれていないため、Ruby コマンドを実行できても MySQL コマンドを実行することは出来ません。 ※詳細は こちら に記載されています。 docker : - image : circleci/ruby:2.4.2-node-browsers environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : circleci/mysql:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : redis:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo また、用意されている image をカスタマイズする必要がある場合は、Docker でカスタム image を作り、public で良ければ Docker Hub へ登録、private が良ければ Amazon EC2 Container Registry へ登録しておくことで呼び出すことも可能になっています。 ※Using Custom-Built Docker Images https://circleci.com/docs/ja/2.0/custom-images/ ※Using Private Images https://circleci.com/docs/ja/2.0/private-images/ build の設定と cache CI で実行するアプリケーションの build に関してです。 checkout で github からコードを checkout し、その後の定義でアプリケーションのインストール、キャッシュ保存、キャッシュの展開を行っています。 steps : - checkout # Rails application setup - restore_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} - run : name : bundle install command : bundle install --jobs=4 --path=vendor/bundle - save_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} paths : - vendor/bundle save_cache: key に Gemfile.lock を指定することでキャッシュキーとして扱い、paths に設定したパスをキャッシュするようにしています。 restore_cache: key と一致するキャッシュがあれば、save_cache 時に指定したパスを展開し直しています。 run: こちらは rails のアプリケーションインストールしているだけです。 CircleCI1.0 よりもキャッシュ管理を柔軟に行えることがわかります。 circleci コマンドによる Rspec の並列実行 rspec によるテストの実行に関してです。 circleci コマンド を利用することでテストの並列実行を効率的に行うことが出来るます。 今回は --split-by=timings --timings-type=filename のオプションを指定し、ファイル名ベースでの分割でテストを実行します。 - run : name : run test command : | circleci tests glob 'spec/**/*_spec.*' \ | circleci tests split --split-by=timings --timings-type=filename \ | tee -a /dev/stderr \ | xargs bundle exec rspec \ --profile 100 \ --format RspecJunitFormatter \ --out rspec/rspec.xml \ --format progress environment : RAILS_ENV : test TEST_CLUSTER_COMMAND : elasticsearch-x.x.x/bin/elasticsearch - store_artifacts : path : artifacts/ - store_test_results : path : rspec/ store_artifacts: 以前からもある機能ですが、テスト結果の成果物を保存するパスになります。 store_test_results: こちらはテストの実行結果を保存しておくことで、コンテナ間で rspec の実行時間にばらつきが出ないよう、対象のファイルを最適に振り分けてくれるようなのですが、workflows を利用するとサポートされないようです。 ※参考: https://circleci.com/docs/ja/2.0/configuration-reference/#store_test_results このような形で Artifacts が保存されています。 また、artifacts には coverage と capybara の screenshot などを保存しています - simple_cov if ENV['CI'] SimpleCov.coverage_dir File.join(ENV['CIRCLE_WORKING_DIRECTORY'], 'artifacts', 'coverage') SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ SimpleCov::Formatter::HTMLFormatter ] SimpleCov.start do add_filter '/vendor/' add_filter '/spec/' add_filter '/config/' add_filter '/db/' end end capybara Capybara.save_and_open_page_path = File.join(ENV['CIRCLE_WORKING_DIRECTORY'], 'artifacts', 'capybara') if ENV['CI'] ※CircleCI2.0 から CI の環境変数が変わっています。詳細は以下のリンクへ記載されています。 Introduction to environment variables - CircleCI Introduction to environment variables in CircleCI circleci.com Workflows の設定 CircleCI2.0 から Workflows の利用が可能になりました。 Workflow orchestration - CircleCI Learn about using CircleCI workflows to orchestrate jobs circleci.com コンテナ毎に分割しジョブを実行することで更なる並列実行の効率化、及び、ジョブ間の依存関係まで設定できるようです。 ジョブメドレーではコードの静的解析に少し実行時間が掛かっていることから、多少の改善を図れると考え 単純に使ってみたかった こちらの機能を利用してみました。 workflows : version : 2 workflows : jobs : - build - code_analyze : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - rspec : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - deploy_qa : requires : - code_analyze - rspec filters : branches : only : develop - deploy_only : requires : - build filters : branches : only : /^sandbox.*|^master$|^staging$/ build: 各ジョブで実行前に行っておく処理を定義 code_analyze: rubocop、brakeman、scss-lint などの静的解析処理を定義 rspec: アプリケーションのテストを定義 deploy: デプロイに関する処理を定義 ジョブメドレーでは、ブランチ管理に Git-flow を採用していますが、それとは別に sandbox というテスト環境を用意し運用しています。 develop ブランチでコード解析やテストをクリアしたコードだけ、master へ反映し、master ではテストフェーズなしに deploy する構成を取っています。 極力、CI のリソースを節約するように各ブランチごとで実行する処理を分けています。 各ブランチの運用は以下の通りです。 feature: コード解析、テスト実行 sandbox: デプロイのみ実行(一時レビュー用ブランチ) develop: コード解析、テスト実行、デプロイ実行 master: デプロイのみ実行 上記の例では、 code_analyze: sandbox、master、staging ブランチ以外は実行 requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 rspec: sandbox、master、staging ブランチ以外は実行 requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 deploy_qa: develop ブランチでのみ実行 requires で依存関係を指定し、code_analyze、rspec が正常に終了しなければ実行されないようになっています。 deploy_only: sandbox、master、staging ブランチのみ利用するジョブ requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 どのような workflow が出来あがるのか、以下に例を示します。 feature ブランチの例: develop ブランチの例: master、sandbox ブランチの例: 今回の例だとブランチ毎に workflow を変えているため、ignore、only の書き方で意図せず振り分けされないように考慮は必要ですが、柔軟に workflow を作れることがわかると思います。(やり過ぎると読み解くのが大変になりそうですね) Workflows に関しては こちら に色々なパターンの組み方が記載されているので、こちらを読むとより理解が深まると思います。 ジョブ間でのデータ共有 ジョブを分けてビルドする=何回もアプリケーションの初期化が必要なんじゃないか? と当然疑問に思う点ではありますが、それに対する解決策も用意されています。 build : steps : ===省略=== - persist_to_workspace : root : ~/job-medley paths : - ./* deploy_qa : << : * defaults steps : - attach_workspace : at : ~/job-medley persist_to_workspace: 指定したパスにあるデータを一時的に保管してくれます attach_workspace: 保管済みのデータを展開してくれます この機能により、ビルドプロセスで生成したものを各ジョブで実行するコンテナへ渡すことが出来ます。 ただし、そもそもビルドプロセスでキャッシュを入れていることもあり、これ自体の効果は殆どありませんでした。 コンパイル済みのデータを受け渡す際には効果を発揮しそうですね。( 公式でも そのような利用を想定していそうです) 改善結果 肝心の速度改善結果です。結果は以下の通りになりました。 改善前: CircleCI1.0 rspec の実行時間: 26:59 以下は、CircleCI2.0 へ移行しただけの結果です。このケースでは workflows を利用していません。 改善後: CircleCI2.0 rspec の実行時間: 19:40 CircleCI1.0 から CircleCI2.0 へ移行することにより、 約 12 分程 テストの実行時間を短縮することが出来ました。 Workflows など特に利用していない、かつ、ビルドフェーズの実行時間も関係しないため、CircleCI2.0 を利用するだけで単純にテスト実行速度の向上を見込めることがわかると思います。 続いて Workflows を利用した結果です。 改善後: CircleCI2.0 with Workflows rspec の実行時間: 21:14 結果は、Workflows を利用しないケースと、利用したケースでは、Workflows を利用したほうが rspec の実行時間は長くなってしまいましたが、build-code-analyze-rspec の実行に掛かったトータルの時間に差は見られませんでした。 これは、「circleci コマンドによる Rspec の並列実行」のセクションへも記載した通り、store_test_results がサポートとされないことにより、コンテナ間での分散が最適化されていない為です。 コンテナ間で rspec の実行時間にばらつきが出ないよう、対象のファイルを最適に振り分けてくれるようなのですが、Workflows を利用するとサポートされないようです。 実行時間にばらつきが出てしまい、code_analyze のジョブを分散することで見込んでいた改善時間(約 3 分)とばらつきにより発生したテスト実行時間のロス( (20:01 - 14:57) / 2 = 2:32 )が大体同じであるため、トータルでの実行時間に差が出ない結果となりました。 ばらつきを出さない方法や、ジョブの分け方については今後も工夫してみたいと思います。 また、フロントエンドのテストをもう少し厚くしていきたいと考えているので、フロントエンドのテスト、サーバサイドのテストを Workflows を上手く使いながら分散していければ良いのかなとも思っています。 さいごに 移行に際して、 CircleCI2.0 の移行ガイド を読みながら進めていましたが、基本的な記法の変更、timezone、environment の定義方法の変更、variable の変更などが多々有り、ドキュメントを結構読み込まないとどこに何が定義できるのか把握できませんでした。 また、Workflows の組み立てなど 公式に良いサンプル は沢山あるのですが、依存関係の定義を色々試すのに苦労した気がします。 ※素直に小規模なアプリを用意して、 ローカルで circleci を実行 してみた方が効率良く進められたかもしれません。 ※ただ、 公式のドキュメント や CommunityForum をしっかり読めば余すことなく情報は合ったので非常に助かりました。 CircleCI2.0 でどのような事が出来るのか、それはどのように行えるのか。 この記事がその概観をつかむ助けになれば良いなと思っています。 参考リンク CircleCI2.0 へ移行するにあたり、以下の記事を参考にさせていただきました。ありがとうございます。 circleci/ruby:2.4.1-node-browsersって何入ってるのか知りたかった - Qiita 2018-11-19追記 https://github.com/CircleCI-Public/circleci-dockerfiles/blob/master/ruby/images/ いつの間にか公開されてました 動機 circleciが提供しているdockerファ... qiita.com CircleCI2.0のWorkflowsを試す “CircleCI2.0のWorkflowsを試す” is published by timakin. medium.com お知らせ メドレーでは、医療介護の求人サイト「 ジョブメドレー 」、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。
こんにちは。開発本部の 稲本 です。医療介護の求人サイト「 ジョブメドレー 」の開発を担当しているエンジニアです。 最近ジョブメドレーでは CircleCI2.0 への移行を行いました。移行の方法はもちろん、その際に調べたこと、CircleCI の新機能を利用してどうだったかなどを書いていきたいと思います。 課題感 弊社では、全プロダクト( CLINICS 、 MEDLEY 、 介護のほんね 、 ジョブメドレー )で CircleCI を利用しています。 ジョブメドレーでは CI によるテスト実行に 37 分前後掛かっていました(コンテナを 2 つ利用した実行時間です)。 さらに、開発メンバーが増えて来たこともあり、CI のリソースが足りなくなり開発効率が落ちかねない状況でした。 まぁよくある話ですよね。 コンテナを増やすというのも解決策の一つとしてはあるのですが、速度の改善に期待が出来ると評判も良かったので CirclecCI2.0 へ移行しました。 CircleCI2.0 への移行メリット 基本的には速度の改善に期待が出来る、というのが大きなメリットではありますが、公式では以下のように記載されています。 抜粋ですが大きな特徴としては以下の点でしょうか。 First-class Docker Support: Docker のネイティブサポートと Docker レイヤーキャッシュの導入 Workflows: ビルド、テスト、デプロイをジョブとして柔軟に管理できるようになった Advanced Caching: キャッシュの保存とリストアをイメージ、ソースコード、依存関係に対して行うことができるようになった。 この辺りの機能を活用し CI の速度改善へ繋げてみたいと思います。 ジョブメドレーのアプリケーション構成 移行の前提として、ジョブメドレーのアプリケーション構成について記載します。 フロントエンドのビルドを yarn+webpack で行い、生成したアセットを public/assets へ吐き出し、manifest ファイルのパスを rails の helper 経由で取得し読み込んでいます。(Rails4.2.x) このような構成のアプリケーションを CirlceCI2.0 でビルド、テスト、デプロイ出来るようにしていきます。 config.yml の全体像 今回、作成した config.yml はこのような形になりました。 ざっくりは build: bundle install, yarn install code_analyze: rubocop, brakeman, scss-lint rspec deploy: capistrano を行っており、ブランチによってどのジョブを実行するのかを workflows を利用して使い分けています。 詳しい解説は以降、記載していきます。 defaults : & defaults working_directory : ~/job-medley docker : - image : circleci/ruby:2.4.2-node-browsers environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : circleci/mysql:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : redis:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo version : 2 jobs : build : << : * defaults steps : - checkout - restore_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} - run : name : bundle install command : bundle install --jobs=4 --path=vendor/bundle - save_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} paths : - vendor/bundle - restore_cache : key : job-medley-yarn-{{ checksum "yarn.lock" }} - run : name : Yarn install command : | echo "Node $(node -v)" echo "Yarn v$(yarn --version)" yarn config set cache-folder ./yarn_cache echo "Yarn v$(yarn cache dir)" yarn install - save_cache : key : job-medley-yarn-{{ checksum "yarn.lock" }} paths : - node_modules - yarn_cache - persist_to_workspace : root : ~/job-medley paths : - ./* code_analyze : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run rubocop command : bundle exec rubocop - run : name : run brakeman command : bundle exec brakeman -qz - run : name : run scss-lint command : bundle exec scss-lint rspec : parallelism : 2 << : * defaults steps : - attach_workspace : at : ~/job-medley - restore_cache : key : job-medley-elasticsearch # rspec で es のコマンドを一部実行しているため、primary container 側へ install - run : name : Elasticsearch install command : | wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-x.x.x.tar.gz && \ tar -xvf elasticsearch-x.x.x.tar.gz && \ if [ -z "`elasticsearch-x.x.x/bin/plugin -l | grep analysis-kuromoji`" ]; then \ elasticsearch-x.x.x/bin/plugin -install elasticsearch/elasticsearch-analysis-kuromoji/x.x.x; fi - save_cache : key : job-medley-elasticsearch paths : - ./elasticsearch-x.x.x - run : name : database create command : bundle exec rake db:create environment : RAILS_ENV : test - run : name : run test command : | circleci tests glob 'spec/**/*_spec.*' \ | circleci tests split --split-by=timings --timings-type=filename \ | tee -a /dev/stderr \ | xargs bundle exec rspec \ --profile 100 \ --format RspecJunitFormatter \ --out rspec/rspec.xml \ --format progress environment : RAILS_ENV : test TEST_CLUSTER_COMMAND : elasticsearch-x.x.x/bin/elasticsearch - store_artifacts : path : artifacts/ - store_test_results : path : rspec/ deploy_qa : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run deploy command : | sh scripts/init_deploy.sh BRANCH="${CIRCLE_BRANCH}" bundle exec cap develop deploy deploy:restart deploy_only : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run deploy command : | BRANCH="${CIRCLE_BRANCH}" bundle exec cap production deploy deploy:restart workflows : version : 2 workflows : jobs : - build - code_analyze : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - rspec : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - deploy_qa : requires : - code_analyze - rspec filters : branches : only : develop - deploy_only : requires : - build filters : branches : only : /^sandbox.*|^master$|^staging$/ DockerImage の選定 元々、Docker を使わずに CI を回していましたが、CircleCI2.0 へ移行するに辺り Docker への利用に切り替えました。 ※ Specifying Container Images DockerImage は DockerHub へ登録されている CircleCI 公式のも の を利用しました。 アプリケーションの一部で React を使用しており、フロントのビルドは yarn+webpack を利用しています。その為、以下の image を選択しました。 circleci/ruby:2.4.2-node-browsers node のインストールと、E2E のテストに必要なソフトウェアがインストールされています。 ※詳細は こちらの記事 を参考にさせていただきました。 その他、現在利用している MySQL のバージョン、ElasticCacheRedis のバージョンと合わせた image を選択しました。 注意点としては、複数の DockerImage を利用する場合、一つ目に指定した image が primary として扱われます。 以下の例ですと、Ruby の image を最初に指定し、MySQL、Redis の image を指定していますが、MySQL コマンド自体は Ruby の image に含まれていないため、Ruby コマンドを実行できても MySQL コマンドを実行することは出来ません。 ※詳細は こちら に記載されています。 docker : - image : circleci/ruby:2.4.2-node-browsers environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : circleci/mysql:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : redis:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo また、用意されている image をカスタマイズする必要がある場合は、Docker でカスタム image を作り、public で良ければ Docker Hub へ登録、private が良ければ Amazon EC2 Container Registry へ登録しておくことで呼び出すことも可能になっています。 ※Using Custom-Built Docker Images https://circleci.com/docs/ja/2.0/custom-images/ ※Using Private Images https://circleci.com/docs/ja/2.0/private-images/ build の設定と cache CI で実行するアプリケーションの build に関してです。 checkout で github からコードを checkout し、その後の定義でアプリケーションのインストール、キャッシュ保存、キャッシュの展開を行っています。 steps : - checkout # Rails application setup - restore_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} - run : name : bundle install command : bundle install --jobs=4 --path=vendor/bundle - save_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} paths : - vendor/bundle save_cache: key に Gemfile.lock を指定することでキャッシュキーとして扱い、paths に設定したパスをキャッシュするようにしています。 restore_cache: key と一致するキャッシュがあれば、save_cache 時に指定したパスを展開し直しています。 run: こちらは rails のアプリケーションインストールしているだけです。 CircleCI1.0 よりもキャッシュ管理を柔軟に行えることがわかります。 circleci コマンドによる Rspec の並列実行 rspec によるテストの実行に関してです。 circleci コマンド を利用することでテストの並列実行を効率的に行うことが出来るます。 今回は --split-by=timings --timings-type=filename のオプションを指定し、ファイル名ベースでの分割でテストを実行します。 - run : name : run test command : | circleci tests glob 'spec/**/*_spec.*' \ | circleci tests split --split-by=timings --timings-type=filename \ | tee -a /dev/stderr \ | xargs bundle exec rspec \ --profile 100 \ --format RspecJunitFormatter \ --out rspec/rspec.xml \ --format progress environment : RAILS_ENV : test TEST_CLUSTER_COMMAND : elasticsearch-x.x.x/bin/elasticsearch - store_artifacts : path : artifacts/ - store_test_results : path : rspec/ store_artifacts: 以前からもある機能ですが、テスト結果の成果物を保存するパスになります。 store_test_results: こちらはテストの実行結果を保存しておくことで、コンテナ間で rspec の実行時間にばらつきが出ないよう、対象のファイルを最適に振り分けてくれるようなのですが、workflows を利用するとサポートされないようです。 ※参考: https://circleci.com/docs/ja/2.0/configuration-reference/#store_test_results このような形で Artifacts が保存されています。 また、artifacts には coverage と capybara の screenshot などを保存しています - simple_cov if ENV['CI'] SimpleCov.coverage_dir File.join(ENV['CIRCLE_WORKING_DIRECTORY'], 'artifacts', 'coverage') SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ SimpleCov::Formatter::HTMLFormatter ] SimpleCov.start do add_filter '/vendor/' add_filter '/spec/' add_filter '/config/' add_filter '/db/' end end capybara Capybara.save_and_open_page_path = File.join(ENV['CIRCLE_WORKING_DIRECTORY'], 'artifacts', 'capybara') if ENV['CI'] ※CircleCI2.0 から CI の環境変数が変わっています。詳細は以下のリンクへ記載されています。 Introduction to environment variables - CircleCI Introduction to environment variables in CircleCI circleci.com Workflows の設定 CircleCI2.0 から Workflows の利用が可能になりました。 Workflow orchestration - CircleCI Learn about using CircleCI workflows to orchestrate jobs circleci.com コンテナ毎に分割しジョブを実行することで更なる並列実行の効率化、及び、ジョブ間の依存関係まで設定できるようです。 ジョブメドレーではコードの静的解析に少し実行時間が掛かっていることから、多少の改善を図れると考え 単純に使ってみたかった こちらの機能を利用してみました。 workflows : version : 2 workflows : jobs : - build - code_analyze : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - rspec : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - deploy_qa : requires : - code_analyze - rspec filters : branches : only : develop - deploy_only : requires : - build filters : branches : only : /^sandbox.*|^master$|^staging$/ build: 各ジョブで実行前に行っておく処理を定義 code_analyze: rubocop、brakeman、scss-lint などの静的解析処理を定義 rspec: アプリケーションのテストを定義 deploy: デプロイに関する処理を定義 ジョブメドレーでは、ブランチ管理に Git-flow を採用していますが、それとは別に sandbox というテスト環境を用意し運用しています。 develop ブランチでコード解析やテストをクリアしたコードだけ、master へ反映し、master ではテストフェーズなしに deploy する構成を取っています。 極力、CI のリソースを節約するように各ブランチごとで実行する処理を分けています。 各ブランチの運用は以下の通りです。 feature: コード解析、テスト実行 sandbox: デプロイのみ実行(一時レビュー用ブランチ) develop: コード解析、テスト実行、デプロイ実行 master: デプロイのみ実行 上記の例では、 code_analyze: sandbox、master、staging ブランチ以外は実行 requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 rspec: sandbox、master、staging ブランチ以外は実行 requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 deploy_qa: develop ブランチでのみ実行 requires で依存関係を指定し、code_analyze、rspec が正常に終了しなければ実行されないようになっています。 deploy_only: sandbox、master、staging ブランチのみ利用するジョブ requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 どのような workflow が出来あがるのか、以下に例を示します。 feature ブランチの例: develop ブランチの例: master、sandbox ブランチの例: 今回の例だとブランチ毎に workflow を変えているため、ignore、only の書き方で意図せず振り分けされないように考慮は必要ですが、柔軟に workflow を作れることがわかると思います。(やり過ぎると読み解くのが大変になりそうですね) Workflows に関しては こちら に色々なパターンの組み方が記載されているので、こちらを読むとより理解が深まると思います。 ジョブ間でのデータ共有 ジョブを分けてビルドする=何回もアプリケーションの初期化が必要なんじゃないか? と当然疑問に思う点ではありますが、それに対する解決策も用意されています。 build : steps : ===省略=== - persist_to_workspace : root : ~/job-medley paths : - ./* deploy_qa : << : * defaults steps : - attach_workspace : at : ~/job-medley persist_to_workspace: 指定したパスにあるデータを一時的に保管してくれます attach_workspace: 保管済みのデータを展開してくれます この機能により、ビルドプロセスで生成したものを各ジョブで実行するコンテナへ渡すことが出来ます。 ただし、そもそもビルドプロセスでキャッシュを入れていることもあり、これ自体の効果は殆どありませんでした。 コンパイル済みのデータを受け渡す際には効果を発揮しそうですね。( 公式でも そのような利用を想定していそうです) 改善結果 肝心の速度改善結果です。結果は以下の通りになりました。 改善前: CircleCI1.0 rspec の実行時間: 26:59 以下は、CircleCI2.0 へ移行しただけの結果です。このケースでは workflows を利用していません。 改善後: CircleCI2.0 rspec の実行時間: 19:40 CircleCI1.0 から CircleCI2.0 へ移行することにより、 約 12 分程 テストの実行時間を短縮することが出来ました。 Workflows など特に利用していない、かつ、ビルドフェーズの実行時間も関係しないため、CircleCI2.0 を利用するだけで単純にテスト実行速度の向上を見込めることがわかると思います。 続いて Workflows を利用した結果です。 改善後: CircleCI2.0 with Workflows rspec の実行時間: 21:14 結果は、Workflows を利用しないケースと、利用したケースでは、Workflows を利用したほうが rspec の実行時間は長くなってしまいましたが、build-code-analyze-rspec の実行に掛かったトータルの時間に差は見られませんでした。 これは、「circleci コマンドによる Rspec の並列実行」のセクションへも記載した通り、store_test_results がサポートとされないことにより、コンテナ間での分散が最適化されていない為です。 コンテナ間で rspec の実行時間にばらつきが出ないよう、対象のファイルを最適に振り分けてくれるようなのですが、Workflows を利用するとサポートされないようです。 実行時間にばらつきが出てしまい、code_analyze のジョブを分散することで見込んでいた改善時間(約 3 分)とばらつきにより発生したテスト実行時間のロス( (20:01 - 14:57) / 2 = 2:32 )が大体同じであるため、トータルでの実行時間に差が出ない結果となりました。 ばらつきを出さない方法や、ジョブの分け方については今後も工夫してみたいと思います。 また、フロントエンドのテストをもう少し厚くしていきたいと考えているので、フロントエンドのテスト、サーバサイドのテストを Workflows を上手く使いながら分散していければ良いのかなとも思っています。 さいごに 移行に際して、 CircleCI2.0 の移行ガイド を読みながら進めていましたが、基本的な記法の変更、timezone、environment の定義方法の変更、variable の変更などが多々有り、ドキュメントを結構読み込まないとどこに何が定義できるのか把握できませんでした。 また、Workflows の組み立てなど 公式に良いサンプル は沢山あるのですが、依存関係の定義を色々試すのに苦労した気がします。 ※素直に小規模なアプリを用意して、 ローカルで circleci を実行 してみた方が効率良く進められたかもしれません。 ※ただ、 公式のドキュメント や CommunityForum をしっかり読めば余すことなく情報は合ったので非常に助かりました。 CircleCI2.0 でどのような事が出来るのか、それはどのように行えるのか。 この記事がその概観をつかむ助けになれば良いなと思っています。 参考リンク CircleCI2.0 へ移行するにあたり、以下の記事を参考にさせていただきました。ありがとうございます。 circleci/ruby:2.4.1-node-browsersって何入ってるのか知りたかった - Qiita 2018-11-19追記 https://github.com/CircleCI-Public/circleci-dockerfiles/blob/master/ruby/images/ いつの間にか公開されてました 動機 circleciが提供しているdockerファ... qiita.com CircleCI2.0のWorkflowsを試す “CircleCI2.0のWorkflowsを試す” is published by timakin. medium.com お知らせ メドレーでは、医療介護の求人サイト「 ジョブメドレー 」、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。
こんにちは。開発本部の 稲本 です。医療介護の求人サイト「 ジョブメドレー 」の開発を担当しているエンジニアです。 最近ジョブメドレーでは CircleCI2.0 への移行を行いました。移行の方法はもちろん、その際に調べたこと、CircleCI の新機能を利用してどうだったかなどを書いていきたいと思います。 課題感 弊社では、全プロダクト( CLINICS 、 MEDLEY 、 介護のほんね 、 ジョブメドレー )で CircleCI を利用しています。 ジョブメドレーでは CI によるテスト実行に 37 分前後掛かっていました(コンテナを 2 つ利用した実行時間です)。 さらに、開発メンバーが増えて来たこともあり、CI のリソースが足りなくなり開発効率が落ちかねない状況でした。 まぁよくある話ですよね。 コンテナを増やすというのも解決策の一つとしてはあるのですが、速度の改善に期待が出来ると評判も良かったので CirclecCI2.0 へ移行しました。 CircleCI2.0 への移行メリット 基本的には速度の改善に期待が出来る、というのが大きなメリットではありますが、公式では以下のように記載されています。 抜粋ですが大きな特徴としては以下の点でしょうか。 First-class Docker Support: Docker のネイティブサポートと Docker レイヤーキャッシュの導入 Workflows: ビルド、テスト、デプロイをジョブとして柔軟に管理できるようになった Advanced Caching: キャッシュの保存とリストアをイメージ、ソースコード、依存関係に対して行うことができるようになった。 この辺りの機能を活用し CI の速度改善へ繋げてみたいと思います。 ジョブメドレーのアプリケーション構成 移行の前提として、ジョブメドレーのアプリケーション構成について記載します。 フロントエンドのビルドを yarn+webpack で行い、生成したアセットを public/assets へ吐き出し、manifest ファイルのパスを rails の helper 経由で取得し読み込んでいます。(Rails4.2.x) このような構成のアプリケーションを CirlceCI2.0 でビルド、テスト、デプロイ出来るようにしていきます。 config.yml の全体像 今回、作成した config.yml はこのような形になりました。 ざっくりは build: bundle install, yarn install code_analyze: rubocop, brakeman, scss-lint rspec deploy: capistrano を行っており、ブランチによってどのジョブを実行するのかを workflows を利用して使い分けています。 詳しい解説は以降、記載していきます。 defaults : & defaults working_directory : ~/job-medley docker : - image : circleci/ruby:2.4.2-node-browsers environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : circleci/mysql:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : redis:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo version : 2 jobs : build : << : * defaults steps : - checkout - restore_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} - run : name : bundle install command : bundle install --jobs=4 --path=vendor/bundle - save_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} paths : - vendor/bundle - restore_cache : key : job-medley-yarn-{{ checksum "yarn.lock" }} - run : name : Yarn install command : | echo "Node $(node -v)" echo "Yarn v$(yarn --version)" yarn config set cache-folder ./yarn_cache echo "Yarn v$(yarn cache dir)" yarn install - save_cache : key : job-medley-yarn-{{ checksum "yarn.lock" }} paths : - node_modules - yarn_cache - persist_to_workspace : root : ~/job-medley paths : - ./* code_analyze : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run rubocop command : bundle exec rubocop - run : name : run brakeman command : bundle exec brakeman -qz - run : name : run scss-lint command : bundle exec scss-lint rspec : parallelism : 2 << : * defaults steps : - attach_workspace : at : ~/job-medley - restore_cache : key : job-medley-elasticsearch # rspec で es のコマンドを一部実行しているため、primary container 側へ install - run : name : Elasticsearch install command : | wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-x.x.x.tar.gz && \ tar -xvf elasticsearch-x.x.x.tar.gz && \ if [ -z "`elasticsearch-x.x.x/bin/plugin -l | grep analysis-kuromoji`" ]; then \ elasticsearch-x.x.x/bin/plugin -install elasticsearch/elasticsearch-analysis-kuromoji/x.x.x; fi - save_cache : key : job-medley-elasticsearch paths : - ./elasticsearch-x.x.x - run : name : database create command : bundle exec rake db:create environment : RAILS_ENV : test - run : name : run test command : | circleci tests glob 'spec/**/*_spec.*' \ | circleci tests split --split-by=timings --timings-type=filename \ | tee -a /dev/stderr \ | xargs bundle exec rspec \ --profile 100 \ --format RspecJunitFormatter \ --out rspec/rspec.xml \ --format progress environment : RAILS_ENV : test TEST_CLUSTER_COMMAND : elasticsearch-x.x.x/bin/elasticsearch - store_artifacts : path : artifacts/ - store_test_results : path : rspec/ deploy_qa : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run deploy command : | sh scripts/init_deploy.sh BRANCH="${CIRCLE_BRANCH}" bundle exec cap develop deploy deploy:restart deploy_only : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run deploy command : | BRANCH="${CIRCLE_BRANCH}" bundle exec cap production deploy deploy:restart workflows : version : 2 workflows : jobs : - build - code_analyze : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - rspec : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - deploy_qa : requires : - code_analyze - rspec filters : branches : only : develop - deploy_only : requires : - build filters : branches : only : /^sandbox.*|^master$|^staging$/ DockerImage の選定 元々、Docker を使わずに CI を回していましたが、CircleCI2.0 へ移行するに辺り Docker への利用に切り替えました。 ※ Specifying Container Images DockerImage は DockerHub へ登録されている CircleCI 公式のも の を利用しました。 アプリケーションの一部で React を使用しており、フロントのビルドは yarn+webpack を利用しています。その為、以下の image を選択しました。 circleci/ruby:2.4.2-node-browsers node のインストールと、E2E のテストに必要なソフトウェアがインストールされています。 ※詳細は こちらの記事 を参考にさせていただきました。 その他、現在利用している MySQL のバージョン、ElasticCacheRedis のバージョンと合わせた image を選択しました。 注意点としては、複数の DockerImage を利用する場合、一つ目に指定した image が primary として扱われます。 以下の例ですと、Ruby の image を最初に指定し、MySQL、Redis の image を指定していますが、MySQL コマンド自体は Ruby の image に含まれていないため、Ruby コマンドを実行できても MySQL コマンドを実行することは出来ません。 ※詳細は こちら に記載されています。 docker : - image : circleci/ruby:2.4.2-node-browsers environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : circleci/mysql:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : redis:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo また、用意されている image をカスタマイズする必要がある場合は、Docker でカスタム image を作り、public で良ければ Docker Hub へ登録、private が良ければ Amazon EC2 Container Registry へ登録しておくことで呼び出すことも可能になっています。 ※Using Custom-Built Docker Images https://circleci.com/docs/ja/2.0/custom-images/ ※Using Private Images https://circleci.com/docs/ja/2.0/private-images/ build の設定と cache CI で実行するアプリケーションの build に関してです。 checkout で github からコードを checkout し、その後の定義でアプリケーションのインストール、キャッシュ保存、キャッシュの展開を行っています。 steps : - checkout # Rails application setup - restore_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} - run : name : bundle install command : bundle install --jobs=4 --path=vendor/bundle - save_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} paths : - vendor/bundle save_cache: key に Gemfile.lock を指定することでキャッシュキーとして扱い、paths に設定したパスをキャッシュするようにしています。 restore_cache: key と一致するキャッシュがあれば、save_cache 時に指定したパスを展開し直しています。 run: こちらは rails のアプリケーションインストールしているだけです。 CircleCI1.0 よりもキャッシュ管理を柔軟に行えることがわかります。 circleci コマンドによる Rspec の並列実行 rspec によるテストの実行に関してです。 circleci コマンド を利用することでテストの並列実行を効率的に行うことが出来るます。 今回は --split-by=timings --timings-type=filename のオプションを指定し、ファイル名ベースでの分割でテストを実行します。 - run : name : run test command : | circleci tests glob 'spec/**/*_spec.*' \ | circleci tests split --split-by=timings --timings-type=filename \ | tee -a /dev/stderr \ | xargs bundle exec rspec \ --profile 100 \ --format RspecJunitFormatter \ --out rspec/rspec.xml \ --format progress environment : RAILS_ENV : test TEST_CLUSTER_COMMAND : elasticsearch-x.x.x/bin/elasticsearch - store_artifacts : path : artifacts/ - store_test_results : path : rspec/ store_artifacts: 以前からもある機能ですが、テスト結果の成果物を保存するパスになります。 store_test_results: こちらはテストの実行結果を保存しておくことで、コンテナ間で rspec の実行時間にばらつきが出ないよう、対象のファイルを最適に振り分けてくれるようなのですが、workflows を利用するとサポートされないようです。 ※参考: https://circleci.com/docs/ja/2.0/configuration-reference/#store_test_results このような形で Artifacts が保存されています。 また、artifacts には coverage と capybara の screenshot などを保存しています - simple_cov if ENV['CI'] SimpleCov.coverage_dir File.join(ENV['CIRCLE_WORKING_DIRECTORY'], 'artifacts', 'coverage') SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ SimpleCov::Formatter::HTMLFormatter ] SimpleCov.start do add_filter '/vendor/' add_filter '/spec/' add_filter '/config/' add_filter '/db/' end end capybara Capybara.save_and_open_page_path = File.join(ENV['CIRCLE_WORKING_DIRECTORY'], 'artifacts', 'capybara') if ENV['CI'] ※CircleCI2.0 から CI の環境変数が変わっています。詳細は以下のリンクへ記載されています。 Introduction to environment variables - CircleCI Introduction to environment variables in CircleCI circleci.com Workflows の設定 CircleCI2.0 から Workflows の利用が可能になりました。 Workflow orchestration - CircleCI Learn about using CircleCI workflows to orchestrate jobs circleci.com コンテナ毎に分割しジョブを実行することで更なる並列実行の効率化、及び、ジョブ間の依存関係まで設定できるようです。 ジョブメドレーではコードの静的解析に少し実行時間が掛かっていることから、多少の改善を図れると考え 単純に使ってみたかった こちらの機能を利用してみました。 workflows : version : 2 workflows : jobs : - build - code_analyze : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - rspec : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - deploy_qa : requires : - code_analyze - rspec filters : branches : only : develop - deploy_only : requires : - build filters : branches : only : /^sandbox.*|^master$|^staging$/ build: 各ジョブで実行前に行っておく処理を定義 code_analyze: rubocop、brakeman、scss-lint などの静的解析処理を定義 rspec: アプリケーションのテストを定義 deploy: デプロイに関する処理を定義 ジョブメドレーでは、ブランチ管理に Git-flow を採用していますが、それとは別に sandbox というテスト環境を用意し運用しています。 develop ブランチでコード解析やテストをクリアしたコードだけ、master へ反映し、master ではテストフェーズなしに deploy する構成を取っています。 極力、CI のリソースを節約するように各ブランチごとで実行する処理を分けています。 各ブランチの運用は以下の通りです。 feature: コード解析、テスト実行 sandbox: デプロイのみ実行(一時レビュー用ブランチ) develop: コード解析、テスト実行、デプロイ実行 master: デプロイのみ実行 上記の例では、 code_analyze: sandbox、master、staging ブランチ以外は実行 requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 rspec: sandbox、master、staging ブランチ以外は実行 requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 deploy_qa: develop ブランチでのみ実行 requires で依存関係を指定し、code_analyze、rspec が正常に終了しなければ実行されないようになっています。 deploy_only: sandbox、master、staging ブランチのみ利用するジョブ requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 どのような workflow が出来あがるのか、以下に例を示します。 feature ブランチの例: develop ブランチの例: master、sandbox ブランチの例: 今回の例だとブランチ毎に workflow を変えているため、ignore、only の書き方で意図せず振り分けされないように考慮は必要ですが、柔軟に workflow を作れることがわかると思います。(やり過ぎると読み解くのが大変になりそうですね) Workflows に関しては こちら に色々なパターンの組み方が記載されているので、こちらを読むとより理解が深まると思います。 ジョブ間でのデータ共有 ジョブを分けてビルドする=何回もアプリケーションの初期化が必要なんじゃないか? と当然疑問に思う点ではありますが、それに対する解決策も用意されています。 build : steps : ===省略=== - persist_to_workspace : root : ~/job-medley paths : - ./* deploy_qa : << : * defaults steps : - attach_workspace : at : ~/job-medley persist_to_workspace: 指定したパスにあるデータを一時的に保管してくれます attach_workspace: 保管済みのデータを展開してくれます この機能により、ビルドプロセスで生成したものを各ジョブで実行するコンテナへ渡すことが出来ます。 ただし、そもそもビルドプロセスでキャッシュを入れていることもあり、これ自体の効果は殆どありませんでした。 コンパイル済みのデータを受け渡す際には効果を発揮しそうですね。( 公式でも そのような利用を想定していそうです) 改善結果 肝心の速度改善結果です。結果は以下の通りになりました。 改善前: CircleCI1.0 rspec の実行時間: 26:59 以下は、CircleCI2.0 へ移行しただけの結果です。このケースでは workflows を利用していません。 改善後: CircleCI2.0 rspec の実行時間: 19:40 CircleCI1.0 から CircleCI2.0 へ移行することにより、 約 12 分程 テストの実行時間を短縮することが出来ました。 Workflows など特に利用していない、かつ、ビルドフェーズの実行時間も関係しないため、CircleCI2.0 を利用するだけで単純にテスト実行速度の向上を見込めることがわかると思います。 続いて Workflows を利用した結果です。 改善後: CircleCI2.0 with Workflows rspec の実行時間: 21:14 結果は、Workflows を利用しないケースと、利用したケースでは、Workflows を利用したほうが rspec の実行時間は長くなってしまいましたが、build-code-analyze-rspec の実行に掛かったトータルの時間に差は見られませんでした。 これは、「circleci コマンドによる Rspec の並列実行」のセクションへも記載した通り、store_test_results がサポートとされないことにより、コンテナ間での分散が最適化されていない為です。 コンテナ間で rspec の実行時間にばらつきが出ないよう、対象のファイルを最適に振り分けてくれるようなのですが、Workflows を利用するとサポートされないようです。 実行時間にばらつきが出てしまい、code_analyze のジョブを分散することで見込んでいた改善時間(約 3 分)とばらつきにより発生したテスト実行時間のロス( (20:01 - 14:57) / 2 = 2:32 )が大体同じであるため、トータルでの実行時間に差が出ない結果となりました。 ばらつきを出さない方法や、ジョブの分け方については今後も工夫してみたいと思います。 また、フロントエンドのテストをもう少し厚くしていきたいと考えているので、フロントエンドのテスト、サーバサイドのテストを Workflows を上手く使いながら分散していければ良いのかなとも思っています。 さいごに 移行に際して、 CircleCI2.0 の移行ガイド を読みながら進めていましたが、基本的な記法の変更、timezone、environment の定義方法の変更、variable の変更などが多々有り、ドキュメントを結構読み込まないとどこに何が定義できるのか把握できませんでした。 また、Workflows の組み立てなど 公式に良いサンプル は沢山あるのですが、依存関係の定義を色々試すのに苦労した気がします。 ※素直に小規模なアプリを用意して、 ローカルで circleci を実行 してみた方が効率良く進められたかもしれません。 ※ただ、 公式のドキュメント や CommunityForum をしっかり読めば余すことなく情報は合ったので非常に助かりました。 CircleCI2.0 でどのような事が出来るのか、それはどのように行えるのか。 この記事がその概観をつかむ助けになれば良いなと思っています。 参考リンク CircleCI2.0 へ移行するにあたり、以下の記事を参考にさせていただきました。ありがとうございます。 circleci/ruby:2.4.1-node-browsersって何入ってるのか知りたかった - Qiita 2018-11-19追記 https://github.com/CircleCI-Public/circleci-dockerfiles/blob/master/ruby/images/ いつの間にか公開されてました 動機 circleciが提供しているdockerファ... qiita.com CircleCI2.0のWorkflowsを試す “CircleCI2.0のWorkflowsを試す” is published by timakin. medium.com お知らせ メドレーでは、医療介護の求人サイト「 ジョブメドレー 」、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。
こんにちは。開発本部の 稲本 です。医療介護の求人サイト「 ジョブメドレー 」の開発を担当しているエンジニアです。 最近ジョブメドレーでは CircleCI2.0 への移行を行いました。移行の方法はもちろん、その際に調べたこと、CircleCI の新機能を利用してどうだったかなどを書いていきたいと思います。 課題感 弊社では、全プロダクト( CLINICS 、 MEDLEY 、 介護のほんね 、 ジョブメドレー )で CircleCI を利用しています。 ジョブメドレーでは CI によるテスト実行に 37 分前後掛かっていました(コンテナを 2 つ利用した実行時間です)。 さらに、開発メンバーが増えて来たこともあり、CI のリソースが足りなくなり開発効率が落ちかねない状況でした。 まぁよくある話ですよね。 コンテナを増やすというのも解決策の一つとしてはあるのですが、速度の改善に期待が出来ると評判も良かったので CirclecCI2.0 へ移行しました。 CircleCI2.0 への移行メリット 基本的には速度の改善に期待が出来る、というのが大きなメリットではありますが、公式では以下のように記載されています。 抜粋ですが大きな特徴としては以下の点でしょうか。 First-class Docker Support: Docker のネイティブサポートと Docker レイヤーキャッシュの導入 Workflows: ビルド、テスト、デプロイをジョブとして柔軟に管理できるようになった Advanced Caching: キャッシュの保存とリストアをイメージ、ソースコード、依存関係に対して行うことができるようになった。 この辺りの機能を活用し CI の速度改善へ繋げてみたいと思います。 ジョブメドレーのアプリケーション構成 移行の前提として、ジョブメドレーのアプリケーション構成について記載します。 フロントエンドのビルドを yarn+webpack で行い、生成したアセットを public/assets へ吐き出し、manifest ファイルのパスを rails の helper 経由で取得し読み込んでいます。(Rails4.2.x) このような構成のアプリケーションを CirlceCI2.0 でビルド、テスト、デプロイ出来るようにしていきます。 config.yml の全体像 今回、作成した config.yml はこのような形になりました。 ざっくりは build: bundle install, yarn install code_analyze: rubocop, brakeman, scss-lint rspec deploy: capistrano を行っており、ブランチによってどのジョブを実行するのかを workflows を利用して使い分けています。 詳しい解説は以降、記載していきます。 defaults : & defaults working_directory : ~/job-medley docker : - image : circleci/ruby:2.4.2-node-browsers environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : circleci/mysql:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : redis:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo version : 2 jobs : build : << : * defaults steps : - checkout - restore_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} - run : name : bundle install command : bundle install --jobs=4 --path=vendor/bundle - save_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} paths : - vendor/bundle - restore_cache : key : job-medley-yarn-{{ checksum "yarn.lock" }} - run : name : Yarn install command : | echo "Node $(node -v)" echo "Yarn v$(yarn --version)" yarn config set cache-folder ./yarn_cache echo "Yarn v$(yarn cache dir)" yarn install - save_cache : key : job-medley-yarn-{{ checksum "yarn.lock" }} paths : - node_modules - yarn_cache - persist_to_workspace : root : ~/job-medley paths : - ./* code_analyze : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run rubocop command : bundle exec rubocop - run : name : run brakeman command : bundle exec brakeman -qz - run : name : run scss-lint command : bundle exec scss-lint rspec : parallelism : 2 << : * defaults steps : - attach_workspace : at : ~/job-medley - restore_cache : key : job-medley-elasticsearch # rspec で es のコマンドを一部実行しているため、primary container 側へ install - run : name : Elasticsearch install command : | wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-x.x.x.tar.gz && \ tar -xvf elasticsearch-x.x.x.tar.gz && \ if [ -z "`elasticsearch-x.x.x/bin/plugin -l | grep analysis-kuromoji`" ]; then \ elasticsearch-x.x.x/bin/plugin -install elasticsearch/elasticsearch-analysis-kuromoji/x.x.x; fi - save_cache : key : job-medley-elasticsearch paths : - ./elasticsearch-x.x.x - run : name : database create command : bundle exec rake db:create environment : RAILS_ENV : test - run : name : run test command : | circleci tests glob 'spec/**/*_spec.*' \ | circleci tests split --split-by=timings --timings-type=filename \ | tee -a /dev/stderr \ | xargs bundle exec rspec \ --profile 100 \ --format RspecJunitFormatter \ --out rspec/rspec.xml \ --format progress environment : RAILS_ENV : test TEST_CLUSTER_COMMAND : elasticsearch-x.x.x/bin/elasticsearch - store_artifacts : path : artifacts/ - store_test_results : path : rspec/ deploy_qa : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run deploy command : | sh scripts/init_deploy.sh BRANCH="${CIRCLE_BRANCH}" bundle exec cap develop deploy deploy:restart deploy_only : << : * defaults steps : - attach_workspace : at : ~/job-medley - run : name : run deploy command : | BRANCH="${CIRCLE_BRANCH}" bundle exec cap production deploy deploy:restart workflows : version : 2 workflows : jobs : - build - code_analyze : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - rspec : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - deploy_qa : requires : - code_analyze - rspec filters : branches : only : develop - deploy_only : requires : - build filters : branches : only : /^sandbox.*|^master$|^staging$/ DockerImage の選定 元々、Docker を使わずに CI を回していましたが、CircleCI2.0 へ移行するに辺り Docker への利用に切り替えました。 ※ Specifying Container Images DockerImage は DockerHub へ登録されている CircleCI 公式のも の を利用しました。 アプリケーションの一部で React を使用しており、フロントのビルドは yarn+webpack を利用しています。その為、以下の image を選択しました。 circleci/ruby:2.4.2-node-browsers node のインストールと、E2E のテストに必要なソフトウェアがインストールされています。 ※詳細は こちらの記事 を参考にさせていただきました。 その他、現在利用している MySQL のバージョン、ElasticCacheRedis のバージョンと合わせた image を選択しました。 注意点としては、複数の DockerImage を利用する場合、一つ目に指定した image が primary として扱われます。 以下の例ですと、Ruby の image を最初に指定し、MySQL、Redis の image を指定していますが、MySQL コマンド自体は Ruby の image に含まれていないため、Ruby コマンドを実行できても MySQL コマンドを実行することは出来ません。 ※詳細は こちら に記載されています。 docker : - image : circleci/ruby:2.4.2-node-browsers environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : circleci/mysql:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo - image : redis:x.x.x environment : TZ : /usr/share/zoneinfo/Asia/Tokyo また、用意されている image をカスタマイズする必要がある場合は、Docker でカスタム image を作り、public で良ければ Docker Hub へ登録、private が良ければ Amazon EC2 Container Registry へ登録しておくことで呼び出すことも可能になっています。 ※Using Custom-Built Docker Images https://circleci.com/docs/ja/2.0/custom-images/ ※Using Private Images https://circleci.com/docs/ja/2.0/private-images/ build の設定と cache CI で実行するアプリケーションの build に関してです。 checkout で github からコードを checkout し、その後の定義でアプリケーションのインストール、キャッシュ保存、キャッシュの展開を行っています。 steps : - checkout # Rails application setup - restore_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} - run : name : bundle install command : bundle install --jobs=4 --path=vendor/bundle - save_cache : key : job-medley-app-{{ checksum "Gemfile.lock" }} paths : - vendor/bundle save_cache: key に Gemfile.lock を指定することでキャッシュキーとして扱い、paths に設定したパスをキャッシュするようにしています。 restore_cache: key と一致するキャッシュがあれば、save_cache 時に指定したパスを展開し直しています。 run: こちらは rails のアプリケーションインストールしているだけです。 CircleCI1.0 よりもキャッシュ管理を柔軟に行えることがわかります。 circleci コマンドによる Rspec の並列実行 rspec によるテストの実行に関してです。 circleci コマンド を利用することでテストの並列実行を効率的に行うことが出来るます。 今回は --split-by=timings --timings-type=filename のオプションを指定し、ファイル名ベースでの分割でテストを実行します。 - run : name : run test command : | circleci tests glob 'spec/**/*_spec.*' \ | circleci tests split --split-by=timings --timings-type=filename \ | tee -a /dev/stderr \ | xargs bundle exec rspec \ --profile 100 \ --format RspecJunitFormatter \ --out rspec/rspec.xml \ --format progress environment : RAILS_ENV : test TEST_CLUSTER_COMMAND : elasticsearch-x.x.x/bin/elasticsearch - store_artifacts : path : artifacts/ - store_test_results : path : rspec/ store_artifacts: 以前からもある機能ですが、テスト結果の成果物を保存するパスになります。 store_test_results: こちらはテストの実行結果を保存しておくことで、コンテナ間で rspec の実行時間にばらつきが出ないよう、対象のファイルを最適に振り分けてくれるようなのですが、workflows を利用するとサポートされないようです。 ※参考: https://circleci.com/docs/ja/2.0/configuration-reference/#store_test_results このような形で Artifacts が保存されています。 また、artifacts には coverage と capybara の screenshot などを保存しています - simple_cov if ENV['CI'] SimpleCov.coverage_dir File.join(ENV['CIRCLE_WORKING_DIRECTORY'], 'artifacts', 'coverage') SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ SimpleCov::Formatter::HTMLFormatter ] SimpleCov.start do add_filter '/vendor/' add_filter '/spec/' add_filter '/config/' add_filter '/db/' end end capybara Capybara.save_and_open_page_path = File.join(ENV['CIRCLE_WORKING_DIRECTORY'], 'artifacts', 'capybara') if ENV['CI'] ※CircleCI2.0 から CI の環境変数が変わっています。詳細は以下のリンクへ記載されています。 Introduction to environment variables - CircleCI Introduction to environment variables in CircleCI circleci.com Workflows の設定 CircleCI2.0 から Workflows の利用が可能になりました。 Workflow orchestration - CircleCI Learn about using CircleCI workflows to orchestrate jobs circleci.com コンテナ毎に分割しジョブを実行することで更なる並列実行の効率化、及び、ジョブ間の依存関係まで設定できるようです。 ジョブメドレーではコードの静的解析に少し実行時間が掛かっていることから、多少の改善を図れると考え 単純に使ってみたかった こちらの機能を利用してみました。 workflows : version : 2 workflows : jobs : - build - code_analyze : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - rspec : requires : - build filters : branches : ignore : /^sandbox.*|^master$|^staging$/ - deploy_qa : requires : - code_analyze - rspec filters : branches : only : develop - deploy_only : requires : - build filters : branches : only : /^sandbox.*|^master$|^staging$/ build: 各ジョブで実行前に行っておく処理を定義 code_analyze: rubocop、brakeman、scss-lint などの静的解析処理を定義 rspec: アプリケーションのテストを定義 deploy: デプロイに関する処理を定義 ジョブメドレーでは、ブランチ管理に Git-flow を採用していますが、それとは別に sandbox というテスト環境を用意し運用しています。 develop ブランチでコード解析やテストをクリアしたコードだけ、master へ反映し、master ではテストフェーズなしに deploy する構成を取っています。 極力、CI のリソースを節約するように各ブランチごとで実行する処理を分けています。 各ブランチの運用は以下の通りです。 feature: コード解析、テスト実行 sandbox: デプロイのみ実行(一時レビュー用ブランチ) develop: コード解析、テスト実行、デプロイ実行 master: デプロイのみ実行 上記の例では、 code_analyze: sandbox、master、staging ブランチ以外は実行 requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 rspec: sandbox、master、staging ブランチ以外は実行 requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 deploy_qa: develop ブランチでのみ実行 requires で依存関係を指定し、code_analyze、rspec が正常に終了しなければ実行されないようになっています。 deploy_only: sandbox、master、staging ブランチのみ利用するジョブ requires で依存関係を指定し、build が正常に終了しなければ実行されないようになっています。 どのような workflow が出来あがるのか、以下に例を示します。 feature ブランチの例: develop ブランチの例: master、sandbox ブランチの例: 今回の例だとブランチ毎に workflow を変えているため、ignore、only の書き方で意図せず振り分けされないように考慮は必要ですが、柔軟に workflow を作れることがわかると思います。(やり過ぎると読み解くのが大変になりそうですね) Workflows に関しては こちら に色々なパターンの組み方が記載されているので、こちらを読むとより理解が深まると思います。 ジョブ間でのデータ共有 ジョブを分けてビルドする=何回もアプリケーションの初期化が必要なんじゃないか? と当然疑問に思う点ではありますが、それに対する解決策も用意されています。 build : steps : ===省略=== - persist_to_workspace : root : ~/job-medley paths : - ./* deploy_qa : << : * defaults steps : - attach_workspace : at : ~/job-medley persist_to_workspace: 指定したパスにあるデータを一時的に保管してくれます attach_workspace: 保管済みのデータを展開してくれます この機能により、ビルドプロセスで生成したものを各ジョブで実行するコンテナへ渡すことが出来ます。 ただし、そもそもビルドプロセスでキャッシュを入れていることもあり、これ自体の効果は殆どありませんでした。 コンパイル済みのデータを受け渡す際には効果を発揮しそうですね。( 公式でも そのような利用を想定していそうです) 改善結果 肝心の速度改善結果です。結果は以下の通りになりました。 改善前: CircleCI1.0 rspec の実行時間: 26:59 以下は、CircleCI2.0 へ移行しただけの結果です。このケースでは workflows を利用していません。 改善後: CircleCI2.0 rspec の実行時間: 19:40 CircleCI1.0 から CircleCI2.0 へ移行することにより、 約 12 分程 テストの実行時間を短縮することが出来ました。 Workflows など特に利用していない、かつ、ビルドフェーズの実行時間も関係しないため、CircleCI2.0 を利用するだけで単純にテスト実行速度の向上を見込めることがわかると思います。 続いて Workflows を利用した結果です。 改善後: CircleCI2.0 with Workflows rspec の実行時間: 21:14 結果は、Workflows を利用しないケースと、利用したケースでは、Workflows を利用したほうが rspec の実行時間は長くなってしまいましたが、build-code-analyze-rspec の実行に掛かったトータルの時間に差は見られませんでした。 これは、「circleci コマンドによる Rspec の並列実行」のセクションへも記載した通り、store_test_results がサポートとされないことにより、コンテナ間での分散が最適化されていない為です。 コンテナ間で rspec の実行時間にばらつきが出ないよう、対象のファイルを最適に振り分けてくれるようなのですが、Workflows を利用するとサポートされないようです。 実行時間にばらつきが出てしまい、code_analyze のジョブを分散することで見込んでいた改善時間(約 3 分)とばらつきにより発生したテスト実行時間のロス( (20:01 - 14:57) / 2 = 2:32 )が大体同じであるため、トータルでの実行時間に差が出ない結果となりました。 ばらつきを出さない方法や、ジョブの分け方については今後も工夫してみたいと思います。 また、フロントエンドのテストをもう少し厚くしていきたいと考えているので、フロントエンドのテスト、サーバサイドのテストを Workflows を上手く使いながら分散していければ良いのかなとも思っています。 さいごに 移行に際して、 CircleCI2.0 の移行ガイド を読みながら進めていましたが、基本的な記法の変更、timezone、environment の定義方法の変更、variable の変更などが多々有り、ドキュメントを結構読み込まないとどこに何が定義できるのか把握できませんでした。 また、Workflows の組み立てなど 公式に良いサンプル は沢山あるのですが、依存関係の定義を色々試すのに苦労した気がします。 ※素直に小規模なアプリを用意して、 ローカルで circleci を実行 してみた方が効率良く進められたかもしれません。 ※ただ、 公式のドキュメント や CommunityForum をしっかり読めば余すことなく情報は合ったので非常に助かりました。 CircleCI2.0 でどのような事が出来るのか、それはどのように行えるのか。 この記事がその概観をつかむ助けになれば良いなと思っています。 参考リンク CircleCI2.0 へ移行するにあたり、以下の記事を参考にさせていただきました。ありがとうございます。 circleci/ruby:2.4.1-node-browsersって何入ってるのか知りたかった - Qiita 2018-11-19追記 https://github.com/CircleCI-Public/circleci-dockerfiles/blob/master/ruby/images/ いつの間にか公開されてました 動機 circleciが提供しているdockerファ... qiita.com CircleCI2.0のWorkflowsを試す “CircleCI2.0のWorkflowsを試す” is published by timakin. medium.com お知らせ メドレーでは、医療介護の求人サイト「 ジョブメドレー 」、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。
ジョブメドレーの開発運用を担当している 新居 です。 メドレーでは開発本部のメンバーの技術力底上げや課題解決を目的とした短期プロジェクト(タスクフォースと呼んでいます)を実施しています。この取り組みの一環として、6〜8 月はセキュリティ知識の底上げを目指した「セキュリティタスクフォース」を実施しました。今回は、その取り組み内容を紹介します。 背景 現在、メドレーの開発本部には約 20 名のエンジニアが在籍しており、それぞれ多種多様な開発経験やスキルセットを持ったエンジニアが集まっています。 そして、前職ではフロントエンド専門でやってきたエンジニアもサーバーサイドの開発を行ったり、またその逆のケースもあったりと、各自の専門領域にとらわれないスタイルでの開発を行うことも多々あります。 課題 そういった背景の中、エンジニアが増えていくにつれエンジニア間のスキルセットに差が生まれ、ばらつきが見られるようにもなっています。今後、更に組織が拡大していくのに伴い、こうしたエンジニア間のスキルセットの差も大きくなっていくことが懸念されます。 また、メドレーは医療ヘルスケア分野に向けてサービス提供を行っており、多くの個人情報を扱っていることはもちろん、医療・介護という領域の性質上、セキュリティには非常に気をつかう必要があります。データベースに入れて保守・運用している個人情報などの取り扱いや、システム改善や新機能開発などを行うときには必然的にセキュリティにも配慮して開発を進める必要があります。 そして背景のところでも述べたように、元々フロントエンド専門のエンジニアがサーバーサイドの開発に関わるケースや、そもそもサーバーサイド開発の経験が浅いエンジニアも中にはいて、サーバーサイドのセキュリティに関して自信がなかったり、具体的な対策方法がすぐに出てこないこともあるという課題がありました(当然ですが実際の開発では PR などでレビューして問題が起きないように対応しています)。 そこで、そういったメンバーのセキュリティ知識の底上げを行い、エンジニア間のスキルセットの差を縮めていくことが必要であると考えました。 取り組み 上述した通り、 スキルセットにばらつきや差が見られる 医療ヘルスケア分野は特にセキュリティに気を使う必要がある セキュリティに関して自信がない、具体的な対策方法がすぐに出てこないこともある といった課題感から、まずはフロントエンド専門でやってきたメンバーやサーバーサイド開発の経験が浅いメンバーをメインターゲットとして、セキュリティ知識の底上げをやっていくことにフォーカスしました。 目標としては、ウェブアプリケーション開発における最低限のセキュリティ知識や対策方法をしっかり再整理し、さらに開発で使っている Ruby on Rails 上でどのように対策するべきかを押さえるというところを目標におきました。 形式 形式としては、参加者に事前に教材の対象範囲を読んできてもらい、隔週開催の TechLunch(社内勉強会)終了後の約 20 分を利用して、内容の簡単な説明や補足、質疑応答、議論などを行う場(フォロー会)を設けました。 教材 以下を使用しました。 メイン教材:「IPA の安全なウェブサイトの作り方」 www.ipa.go.jp サブ教材:「Rails セキュリティガイド」 railsguides.jp メイン教材の「IPA の安全なウェブサイトの作り方」は、IPA が届出を受けた脆弱性関連情報を基にして作られており、セキュリティを考慮したウェブサイトを作る上での最低限の知識が整理できるだろうということで採用しました。 サブ教材の「Rails セキュリティガイド」は、Rails ではどのようにセキュリティの問題を回避しているのかといった方法が解説されており、実際の開発のときにどうすれば良いのかといったことが押さえられるだろうということで採用しました。 実際の開催スケジュールと、フォロー会の対象範囲はこちら。 取り組みを終えて 取り組みを終えて感じたこととしては以下になります。 技術的な観点 SQL インジェクションや XSS、CSRF などのメジャーな攻撃手法を参加者間で再整理できた 技術的に不安なところなどは「ここはこうですよね?」という感じで確かめ合うことができた 参加者が前職での経験談などをシェアしてくれる場面もあり、知見の共有ができた セキュリティに詳しいエンジニアも交えて話すことで、随所で効果的にツッコミをいただき、濃密な議論ができた ベテランエンジニアからは、昔流行った某サービスの某セキュリティ系障害の有名事例なども共有され、過去の歴史を知ることができる場となった 技術以外の観点 普段はチーム毎に黙々と仕事に取り組んでおり、チームを跨いであるひとつの話題(今回はセキュリティ)についてみんなと会話する機会は少ないので、知識の底上げはもちろんのこと、コミュニケーションの場としても良かった 今回のように質疑応答や議論ができる場を設けることにより、他のメンバーの経験や知見も効果的に共有することができ、教材の読み合わせや講義形式では得られない知識も共有でき、取り組みとしてはうまくいったかなあと思います。 まとめ ということで、今回はセキュリティタスクフォースについてご紹介しました。 セキュリティの知識はだれかひとりが押さえていれば良いというものではなく、開発に関わるエンジニア全員が最低限は押さえておく必要があると思います。 組織の拡大と共に、日々のプロダクトの運用・開発も大切ですが、それらを支えるエンジニアの知識の底上げなどの開発以外の部分もより大切になってきますし、そういった取り組みが組織力を高めていくのではないかと思います。 お知らせ メドレーでは、医療介護の求人サイト「 ジョブメドレー 」、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる 介護施設 の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 www.medley.jp 医療や介護とは全く違う業界で経験を積んできたエンジニア・デザイナーが多いですが、こうした定期的な勉強会などで必要知識をインプットしながら開発しています。 メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております!
ジョブメドレーの開発運用を担当している 新居 です。 メドレーでは開発本部のメンバーの技術力底上げや課題解決を目的とした短期プロジェクト(タスクフォースと呼んでいます)を実施しています。この取り組みの一環として、6〜8 月はセキュリティ知識の底上げを目指した「セキュリティタスクフォース」を実施しました。今回は、その取り組み内容を紹介します。 背景 現在、メドレーの開発本部には約 20 名のエンジニアが在籍しており、それぞれ多種多様な開発経験やスキルセットを持ったエンジニアが集まっています。 そして、前職ではフロントエンド専門でやってきたエンジニアもサーバーサイドの開発を行ったり、またその逆のケースもあったりと、各自の専門領域にとらわれないスタイルでの開発を行うことも多々あります。 課題 そういった背景の中、エンジニアが増えていくにつれエンジニア間のスキルセットに差が生まれ、ばらつきが見られるようにもなっています。今後、更に組織が拡大していくのに伴い、こうしたエンジニア間のスキルセットの差も大きくなっていくことが懸念されます。 また、メドレーは医療ヘルスケア分野に向けてサービス提供を行っており、多くの個人情報を扱っていることはもちろん、医療・介護という領域の性質上、セキュリティには非常に気をつかう必要があります。データベースに入れて保守・運用している個人情報などの取り扱いや、システム改善や新機能開発などを行うときには必然的にセキュリティにも配慮して開発を進める必要があります。 そして背景のところでも述べたように、元々フロントエンド専門のエンジニアがサーバーサイドの開発に関わるケースや、そもそもサーバーサイド開発の経験が浅いエンジニアも中にはいて、サーバーサイドのセキュリティに関して自信がなかったり、具体的な対策方法がすぐに出てこないこともあるという課題がありました(当然ですが実際の開発では PR などでレビューして問題が起きないように対応しています)。 そこで、そういったメンバーのセキュリティ知識の底上げを行い、エンジニア間のスキルセットの差を縮めていくことが必要であると考えました。 取り組み 上述した通り、 スキルセットにばらつきや差が見られる 医療ヘルスケア分野は特にセキュリティに気を使う必要がある セキュリティに関して自信がない、具体的な対策方法がすぐに出てこないこともある といった課題感から、まずはフロントエンド専門でやってきたメンバーやサーバーサイド開発の経験が浅いメンバーをメインターゲットとして、セキュリティ知識の底上げをやっていくことにフォーカスしました。 目標としては、ウェブアプリケーション開発における最低限のセキュリティ知識や対策方法をしっかり再整理し、さらに開発で使っている Ruby on Rails 上でどのように対策するべきかを押さえるというところを目標におきました。 形式 形式としては、参加者に事前に教材の対象範囲を読んできてもらい、隔週開催の TechLunch(社内勉強会)終了後の約 20 分を利用して、内容の簡単な説明や補足、質疑応答、議論などを行う場(フォロー会)を設けました。 教材 以下を使用しました。 メイン教材:「IPA の安全なウェブサイトの作り方」 www.ipa.go.jp サブ教材:「Rails セキュリティガイド」 railsguides.jp メイン教材の「IPA の安全なウェブサイトの作り方」は、IPA が届出を受けた脆弱性関連情報を基にして作られており、セキュリティを考慮したウェブサイトを作る上での最低限の知識が整理できるだろうということで採用しました。 サブ教材の「Rails セキュリティガイド」は、Rails ではどのようにセキュリティの問題を回避しているのかといった方法が解説されており、実際の開発のときにどうすれば良いのかといったことが押さえられるだろうということで採用しました。 実際の開催スケジュールと、フォロー会の対象範囲はこちら。 取り組みを終えて 取り組みを終えて感じたこととしては以下になります。 技術的な観点 SQL インジェクションや XSS、CSRF などのメジャーな攻撃手法を参加者間で再整理できた 技術的に不安なところなどは「ここはこうですよね?」という感じで確かめ合うことができた 参加者が前職での経験談などをシェアしてくれる場面もあり、知見の共有ができた セキュリティに詳しいエンジニアも交えて話すことで、随所で効果的にツッコミをいただき、濃密な議論ができた ベテランエンジニアからは、昔流行った某サービスの某セキュリティ系障害の有名事例なども共有され、過去の歴史を知ることができる場となった 技術以外の観点 普段はチーム毎に黙々と仕事に取り組んでおり、チームを跨いであるひとつの話題(今回はセキュリティ)についてみんなと会話する機会は少ないので、知識の底上げはもちろんのこと、コミュニケーションの場としても良かった 今回のように質疑応答や議論ができる場を設けることにより、他のメンバーの経験や知見も効果的に共有することができ、教材の読み合わせや講義形式では得られない知識も共有でき、取り組みとしてはうまくいったかなあと思います。 まとめ ということで、今回はセキュリティタスクフォースについてご紹介しました。 セキュリティの知識はだれかひとりが押さえていれば良いというものではなく、開発に関わるエンジニア全員が最低限は押さえておく必要があると思います。 組織の拡大と共に、日々のプロダクトの運用・開発も大切ですが、それらを支えるエンジニアの知識の底上げなどの開発以外の部分もより大切になってきますし、そういった取り組みが組織力を高めていくのではないかと思います。 お知らせ メドレーでは、医療介護の求人サイト「 ジョブメドレー 」、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる 介護施設 の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 www.medley.jp 医療や介護とは全く違う業界で経験を積んできたエンジニア・デザイナーが多いですが、こうした定期的な勉強会などで必要知識をインプットしながら開発しています。 メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております!
ジョブメドレーの開発運用を担当している 新居 です。 メドレーでは開発本部のメンバーの技術力底上げや課題解決を目的とした短期プロジェクト(タスクフォースと呼んでいます)を実施しています。この取り組みの一環として、6〜8 月はセキュリティ知識の底上げを目指した「セキュリティタスクフォース」を実施しました。今回は、その取り組み内容を紹介します。 背景 現在、メドレーの開発本部には約 20 名のエンジニアが在籍しており、それぞれ多種多様な開発経験やスキルセットを持ったエンジニアが集まっています。 そして、前職ではフロントエンド専門でやってきたエンジニアもサーバーサイドの開発を行ったり、またその逆のケースもあったりと、各自の専門領域にとらわれないスタイルでの開発を行うことも多々あります。 課題 そういった背景の中、エンジニアが増えていくにつれエンジニア間のスキルセットに差が生まれ、ばらつきが見られるようにもなっています。今後、更に組織が拡大していくのに伴い、こうしたエンジニア間のスキルセットの差も大きくなっていくことが懸念されます。 また、メドレーは医療ヘルスケア分野に向けてサービス提供を行っており、多くの個人情報を扱っていることはもちろん、医療・介護という領域の性質上、セキュリティには非常に気をつかう必要があります。データベースに入れて保守・運用している個人情報などの取り扱いや、システム改善や新機能開発などを行うときには必然的にセキュリティにも配慮して開発を進める必要があります。 そして背景のところでも述べたように、元々フロントエンド専門のエンジニアがサーバーサイドの開発に関わるケースや、そもそもサーバーサイド開発の経験が浅いエンジニアも中にはいて、サーバーサイドのセキュリティに関して自信がなかったり、具体的な対策方法がすぐに出てこないこともあるという課題がありました(当然ですが実際の開発では PR などでレビューして問題が起きないように対応しています)。 そこで、そういったメンバーのセキュリティ知識の底上げを行い、エンジニア間のスキルセットの差を縮めていくことが必要であると考えました。 取り組み 上述した通り、 スキルセットにばらつきや差が見られる 医療ヘルスケア分野は特にセキュリティに気を使う必要がある セキュリティに関して自信がない、具体的な対策方法がすぐに出てこないこともある といった課題感から、まずはフロントエンド専門でやってきたメンバーやサーバーサイド開発の経験が浅いメンバーをメインターゲットとして、セキュリティ知識の底上げをやっていくことにフォーカスしました。 目標としては、ウェブアプリケーション開発における最低限のセキュリティ知識や対策方法をしっかり再整理し、さらに開発で使っている Ruby on Rails 上でどのように対策するべきかを押さえるというところを目標におきました。 形式 形式としては、参加者に事前に教材の対象範囲を読んできてもらい、隔週開催の TechLunch(社内勉強会)終了後の約 20 分を利用して、内容の簡単な説明や補足、質疑応答、議論などを行う場(フォロー会)を設けました。 教材 以下を使用しました。 メイン教材:「IPA の安全なウェブサイトの作り方」 www.ipa.go.jp サブ教材:「Rails セキュリティガイド」 railsguides.jp メイン教材の「IPA の安全なウェブサイトの作り方」は、IPA が届出を受けた脆弱性関連情報を基にして作られており、セキュリティを考慮したウェブサイトを作る上での最低限の知識が整理できるだろうということで採用しました。 サブ教材の「Rails セキュリティガイド」は、Rails ではどのようにセキュリティの問題を回避しているのかといった方法が解説されており、実際の開発のときにどうすれば良いのかといったことが押さえられるだろうということで採用しました。 実際の開催スケジュールと、フォロー会の対象範囲はこちら。 取り組みを終えて 取り組みを終えて感じたこととしては以下になります。 技術的な観点 SQL インジェクションや XSS、CSRF などのメジャーな攻撃手法を参加者間で再整理できた 技術的に不安なところなどは「ここはこうですよね?」という感じで確かめ合うことができた 参加者が前職での経験談などをシェアしてくれる場面もあり、知見の共有ができた セキュリティに詳しいエンジニアも交えて話すことで、随所で効果的にツッコミをいただき、濃密な議論ができた ベテランエンジニアからは、昔流行った某サービスの某セキュリティ系障害の有名事例なども共有され、過去の歴史を知ることができる場となった 技術以外の観点 普段はチーム毎に黙々と仕事に取り組んでおり、チームを跨いであるひとつの話題(今回はセキュリティ)についてみんなと会話する機会は少ないので、知識の底上げはもちろんのこと、コミュニケーションの場としても良かった 今回のように質疑応答や議論ができる場を設けることにより、他のメンバーの経験や知見も効果的に共有することができ、教材の読み合わせや講義形式では得られない知識も共有でき、取り組みとしてはうまくいったかなあと思います。 まとめ ということで、今回はセキュリティタスクフォースについてご紹介しました。 セキュリティの知識はだれかひとりが押さえていれば良いというものではなく、開発に関わるエンジニア全員が最低限は押さえておく必要があると思います。 組織の拡大と共に、日々のプロダクトの運用・開発も大切ですが、それらを支えるエンジニアの知識の底上げなどの開発以外の部分もより大切になってきますし、そういった取り組みが組織力を高めていくのではないかと思います。 お知らせ メドレーでは、医療介護の求人サイト「 ジョブメドレー 」、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる 介護施設 の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 www.medley.jp 医療や介護とは全く違う業界で経験を積んできたエンジニア・デザイナーが多いですが、こうした定期的な勉強会などで必要知識をインプットしながら開発しています。 メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております!
ジョブメドレーの開発運用を担当している 新居 です。 メドレーでは開発本部のメンバーの技術力底上げや課題解決を目的とした短期プロジェクト(タスクフォースと呼んでいます)を実施しています。この取り組みの一環として、6〜8 月はセキュリティ知識の底上げを目指した「セキュリティタスクフォース」を実施しました。今回は、その取り組み内容を紹介します。 背景 現在、メドレーの開発本部には約 20 名のエンジニアが在籍しており、それぞれ多種多様な開発経験やスキルセットを持ったエンジニアが集まっています。 そして、前職ではフロントエンド専門でやってきたエンジニアもサーバーサイドの開発を行ったり、またその逆のケースもあったりと、各自の専門領域にとらわれないスタイルでの開発を行うことも多々あります。 課題 そういった背景の中、エンジニアが増えていくにつれエンジニア間のスキルセットに差が生まれ、ばらつきが見られるようにもなっています。今後、更に組織が拡大していくのに伴い、こうしたエンジニア間のスキルセットの差も大きくなっていくことが懸念されます。 また、メドレーは医療ヘルスケア分野に向けてサービス提供を行っており、多くの個人情報を扱っていることはもちろん、医療・介護という領域の性質上、セキュリティには非常に気をつかう必要があります。データベースに入れて保守・運用している個人情報などの取り扱いや、システム改善や新機能開発などを行うときには必然的にセキュリティにも配慮して開発を進める必要があります。 そして背景のところでも述べたように、元々フロントエンド専門のエンジニアがサーバーサイドの開発に関わるケースや、そもそもサーバーサイド開発の経験が浅いエンジニアも中にはいて、サーバーサイドのセキュリティに関して自信がなかったり、具体的な対策方法がすぐに出てこないこともあるという課題がありました(当然ですが実際の開発では PR などでレビューして問題が起きないように対応しています)。 そこで、そういったメンバーのセキュリティ知識の底上げを行い、エンジニア間のスキルセットの差を縮めていくことが必要であると考えました。 取り組み 上述した通り、 スキルセットにばらつきや差が見られる 医療ヘルスケア分野は特にセキュリティに気を使う必要がある セキュリティに関して自信がない、具体的な対策方法がすぐに出てこないこともある といった課題感から、まずはフロントエンド専門でやってきたメンバーやサーバーサイド開発の経験が浅いメンバーをメインターゲットとして、セキュリティ知識の底上げをやっていくことにフォーカスしました。 目標としては、ウェブアプリケーション開発における最低限のセキュリティ知識や対策方法をしっかり再整理し、さらに開発で使っている Ruby on Rails 上でどのように対策するべきかを押さえるというところを目標におきました。 形式 形式としては、参加者に事前に教材の対象範囲を読んできてもらい、隔週開催の TechLunch(社内勉強会)終了後の約 20 分を利用して、内容の簡単な説明や補足、質疑応答、議論などを行う場(フォロー会)を設けました。 教材 以下を使用しました。 メイン教材:「IPA の安全なウェブサイトの作り方」 www.ipa.go.jp サブ教材:「Rails セキュリティガイド」 railsguides.jp メイン教材の「IPA の安全なウェブサイトの作り方」は、IPA が届出を受けた脆弱性関連情報を基にして作られており、セキュリティを考慮したウェブサイトを作る上での最低限の知識が整理できるだろうということで採用しました。 サブ教材の「Rails セキュリティガイド」は、Rails ではどのようにセキュリティの問題を回避しているのかといった方法が解説されており、実際の開発のときにどうすれば良いのかといったことが押さえられるだろうということで採用しました。 実際の開催スケジュールと、フォロー会の対象範囲はこちら。 取り組みを終えて 取り組みを終えて感じたこととしては以下になります。 技術的な観点 SQL インジェクションや XSS、CSRF などのメジャーな攻撃手法を参加者間で再整理できた 技術的に不安なところなどは「ここはこうですよね?」という感じで確かめ合うことができた 参加者が前職での経験談などをシェアしてくれる場面もあり、知見の共有ができた セキュリティに詳しいエンジニアも交えて話すことで、随所で効果的にツッコミをいただき、濃密な議論ができた ベテランエンジニアからは、昔流行った某サービスの某セキュリティ系障害の有名事例なども共有され、過去の歴史を知ることができる場となった 技術以外の観点 普段はチーム毎に黙々と仕事に取り組んでおり、チームを跨いであるひとつの話題(今回はセキュリティ)についてみんなと会話する機会は少ないので、知識の底上げはもちろんのこと、コミュニケーションの場としても良かった 今回のように質疑応答や議論ができる場を設けることにより、他のメンバーの経験や知見も効果的に共有することができ、教材の読み合わせや講義形式では得られない知識も共有でき、取り組みとしてはうまくいったかなあと思います。 まとめ ということで、今回はセキュリティタスクフォースについてご紹介しました。 セキュリティの知識はだれかひとりが押さえていれば良いというものではなく、開発に関わるエンジニア全員が最低限は押さえておく必要があると思います。 組織の拡大と共に、日々のプロダクトの運用・開発も大切ですが、それらを支えるエンジニアの知識の底上げなどの開発以外の部分もより大切になってきますし、そういった取り組みが組織力を高めていくのではないかと思います。 お知らせ メドレーでは、医療介護の求人サイト「 ジョブメドレー 」、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる 介護施設 の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 www.medley.jp 医療や介護とは全く違う業界で経験を積んできたエンジニア・デザイナーが多いですが、こうした定期的な勉強会などで必要知識をインプットしながら開発しています。 メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております!