for Startups Tech blog

for Starupsのテックブログです

【フォースタ テックブログ】技術書典への初めての出版物を書籍にしていただきました!

テックラボグループが有志を募り、2020年12月に技術書典に応募。その後2021年5月にインプレス社経由で出版を果たした。今回の記事では出版に至った経緯とその裏側に迫る。

▽▽▽今回出版に至ったVol.1▽▽▽

https://www.amazon.co.jp/dp/B097D6B8QY

 

-この度は初の技術書典での出展および本の出版、おめでとうございます!
 そもそも技術書典に応募しようと思ったきっかけや走り出しはどんなものだったのですか?

井原:
軽い気持ちで「技術書典に出してみたいね」と提案したところ話が盛り上がり、自然と集まったメンバーで書くことになりました。10月から執筆作業に取り掛かり約2ヶ月間で仕上げていったのですが、話し合いで決めたのは「10ページを目安に書き上げること」程度で、テーマに関しては特に戦略を立てて決めることなく各々の興味関心が高い分野で好きに書き始めました。

井原

 

-技術書典への応募・本の出版にあたり大変だった点や苦労した点を教えてください。

藤井:
内容の質の高さを出すのに初めはプレッシャーを感じました。執筆自体初めてのことですし、個人ブログではなく会社として発信するものだったため、読者に何かしらの発見を与え、読んで良かったと思ってもらうにどうするべきかと随分苦悩しました。後々自身で振り返って「このテーマは他の人に負けないくらい考えた」と思えるくらい考え抜こうと自問自答を繰り返しながら書きました。

藤井

 

村林:
通常業務に加え、テックブログの執筆や勉強会、ウェビナーの登壇も控えていた中、応募時と出版時で記事のフォーマットが異なっていたことが発覚しそのディレクションや編集作業に思いの外手間取りました。具体的にはRe:VIEW StarterからRe:VIEWに変える作業だったのですが、フォーマット変更に伴い表示にズレが生じてしまってないかを一つ一つ確認する必要があったのです。結果かなり出版ギリギリの提出にはなりましたが、なんとか間に合いホッとしたのを覚えています。

-今回記事を書いたことで良かった点や学んだことなど簡単な感想を教えてください。

村林:
自身のやっていることの言語化に繋がった気がします。全体像を気にせずバラバラ書いていったからか普段自分が感じている点や思っていること等が文章として顕著に落とし込まれていく感覚はありました。

村林

 

戸村:
フォースタでの自身の歴史を棚卸ししていくような内容だったので、これまでの振り返りができました。ヒューマンキャピタリストとして人材紹介事業に携わっていた頃から、エンジニアとしてテックラボに参画し現在のCTOを任されるまでの軌跡とともに「組織」について触れられたのは自身にとってもとてもいい経験だったと思います。

藤井:
メンバーの新たな“強み”を知れました。例えば村林さんは大学時代新聞部だったこともあり、キャッチーなタイトルをつけるのが上手でした。本文を書き出したはいいものの、読みたいと思わせられるタイトルをつけるのは文字数が少ない分想像以上に難しかったので、それをサラッと出していた村林さんはシンプルに凄いなと。

「何よりも実際に書籍として手元に届いた時は本当に嬉しかった」と話す皆さん

 

-技術書典に出した後の反響等はありましたか?

戸村:
知人からの買いました連絡を何件かいただきました。当時、Twitterで技術書典の購入ツイートを購買者がつぶやく度Slackに流れるよう連携しており、その通知が届く度に皆で盛り上がっていました。中にはその後に個人的に挙げた振り返り記事を見て購入したとツイートしてくれた人も。
執筆当初に想像していたよりも多くの方に閲覧いただけたようです。

-書籍の話が来てから本が出るまではどんな流れだったのですか?

戸村:
技術書典を出してからすぐにインプレス社からDMが届きました。あまりに掲載直後のDMだったので思わず一瞬半信半疑になってしまった程です(笑)

ですがせっかくいただいた話ですし、Amazonや書店で並んだ方がより成果を形に残せると思い、出版することにしました。契約締結後はSlackでのやりとりに移行し、村林さんに出版準備全般のディレクションをお任せしました。

村林:
インプレス社から出版話を持ちかけられた2020年12月がちょうどサービスのリリースのタイミングだったため、準備期間は多少長めにいただきました。フォーマットの修正やAmazonでの書籍紹介文の作成、表紙をご担当いただく絵師決め、ラフ画すり合わせ等で都度やりとりしながら、無事2021年5月25日に出版することができました。

また、2021年7月に今回新たなメンバーで書き上げたVol.2を技術書典11に出しました。Vol.1とはまた違ったテーマを取り上げた渾身の一冊となっております!(急な宣伝)

techbookfest.org

-最後に、今回の総括をお願いします。

戸村:
フォースタートアップスのバリューの一つである “Be a Talent”は、「自らの生き様を社会に発信せよ」というメッセージが込められており、なかなかエンジニアとして体現が難しい中、テックブログや勉強会等で積み重ねてきたものを公に出せたのは良かったです。引き続き、技術書典も含め、よりいろんな挑戦を発信していけるチームにしていきたいと思っております。

CTO 戸村

Slackを最高に使いこなすためにフォースタがやっていること

f:id:forStartups:20210817154912j:plain

どうも、フォースタートアップスでエンジニアをやっています村林です。

皆さん「Slack」使っていますか?Slack最高ですよね。
弊社もSlackバリバリ使っていて、Slack無いと仕事できないくらいには依存しているのですが、組織が拡大する中で様々な問題が出てきました。

チャンネルが多すぎてよくわからない

弊社は誰でもチャンネルを作成できます。そのためどんどんチャンネルが作成されていき、その結果大量のチャンネルが存在しています。それだけなら良いのですが「チャンネル名のルールがない」「チャンネルの説明がない」などの理由から目的のチャンネルが探しづらい状況になってしまっていました。

これはいかんということでSlackの活用ガイドラインを一部の有志で考えました。

Slack活用ガイドライン、チャンネル命名のルール

原則: 部署名_チーム名_目的で作る
特に接頭句に関しては以下のものから使ってもらっています。

  • 部署内に閉じる場合

ac_ :アクセラレーション本部
cp_ :コーポレート本部
hr_ :人事
oi_ :オープンイノベーション
ta_ :タレントエージェンシー本部
tl_ :テックラボ

  • 部署をまたがる場合

all_ :全員いるチャンネル
pjt_ :部署がまたがる(2ヶ月以上)
tmp_ :一時的な集団(2ヶ月未満)

  • その他の用途

guest_ :他社の方との連携チャンネル
info_ :情報共有系
notify_ :システムからの通知
club_ :趣味系

以上がチャンネル名のルールです。

具体的な例としては

pjt_startupbdb
弊社が展開しているSTARTUP DBに関して話し合うチャンネル

all_branding_pr
社外向けの情報周知がされるチャンネル

club_ラーメン
ラーメンの画像を貼るチャンネル。「今日のラーメン」と書けばラーメンじゃない画像を載せても許される風潮がある。

そこまで堅苦しいものにすると、実運用されないなと考えたことから接頭句のみ縛りを加え、それ以外は比較的に自由に設定できるようになっています。このルールが作られてから半年くらいですが、最初は守られていないケースも多々ありましたが、最近は殆どこのルールに従って作成されています。

ちょっとした命名規則ですが、あるとないとでは検索性、視認性が段違いなのでSlackのチャンネル多すぎてお困りでしたら皆さんもぜひやってみてはいかがでしょうか。

DMが多い

これもあるあるですよね。
「みんなの注意を向けられるほどの内容でもない」「変なことを聞いて恥をかきたくない(恥をかく対象範囲を最小限にしたい)」などの色んな理由から人はpublicなチャンネルではなく、DMを使います。
気持ちはわかりますが、DMは完全に秘匿された状態なので、そこで交わされた内容は誰の目にも触れることがありません。知識が社員の間で偏在し、横展開されることもなくなります。

Slackの素晴らしいところのひとつに検索性の高さがあると思っています。
Slackは検索能力が素晴らしいので「なんでこうなってるんだろ?」「これ今どうなってるのだろう」ってなったときに検索すれば大体経緯が出てきます。これは対面、電話、Zoomのいずれのコミュニケーション手段も達成していない価値なので是非活用しましょう。

でもたまにDMで感謝を伝えたり、伝えられたりは好きだったりします。なんかいいですよね(個人の見解)

ということで、この状況を打破するために以下の指針を出しました。

DMはやめて個人チャンネルでやり取りする

個人チャンネルは「分報」「times」などとも呼ばれていますが、特定個人のためのチャンネルです。個人チャンネルはpublicで作られているため、誰がどこのチャンネルに入ろうが勝手ですし、検索にも出てきます。また個人チャンネルという特性上、その人に関する話題なら何を振っても良い(良さそう)なため、publicなチャンネルでありつつも投稿をする心理的ハードルを下げるという効果を狙っています。

 

ということで、slackの困りごととそれに対応した話でした。
Slackのガイドライン策定などは色んな人の思いを汲んでやらなければいけないため、正直とても面倒くさいし、別に誰からも喜ばれない行為ではあります。
ただ、ちょっとした指針があるだけでみんなハッピーになりますし、Slackをみんなが使いこなす様を見ていると嬉しいので引き続き改善していければ良いですね。

We are hiring !

フォースタートアップスはエンジニア・デザイナーを積極採用中です😃

もしこの記事を読んでフォースタートアップスに少しでもご興味をお持ち頂けましたら、下記の「話を聞きに行きたい」ボタンより気軽にエントリーしてください。

事業やチームについての説明から技術スタックの解説まで、CTOやチームメンバーからさせていただきます。

【フォースタ テックブログ】RepositoryFactoryパターンをVueのAPIリクエストに導入する

こんにちは。エンジニアの藤井(@yutafujii)です。
社内向けのプロダクト「タレントエージェンシー支援システム(SFA/CRM)」のエンジニアをしています。

プロダクトはフロントエンドをNuxt/TypeScript・サーバーサイドをRailsで実装しているのですが、今回はフロントエンドのAPIリクエスト処理にRepositoryFactoryパターンを導入した話をさせていただきます。

RepositoryFactoryパターンとは

RepositoryFactoryとはAPIを呼び出す設計のデザインパターンとして、JorgeというVueエヴァンジェリストによって2018年に紹介されました。

(原文)Vue API calls in a smart way
https://medium.com/canariasjs/vue-api-calls-in-a-smart-way-8d521812c322

(日本語訳)【Vue.js】Web API通信のデザインパターン (個人的ベストプラクティス)
https://qiita.com/07JP27/items/0923cbe3b6435c19d761

Jorge氏のブログでは以下のような問いかけがされます。

How many times have you seen examples with an instance of axios in each component?
(各コンポーネントにaxiosインスタンスが書かれてるような実装をどれくらい見たことがありますか?)

そしてそのように実装されているコードに対してJorge氏は問題提起しています。

What happens if the endpoint changes?
(エンドポイント変更したらどうする?)
How I can handle mocks or different endpoints to test it?
(動作確認のためにエンドポイントをモックしたくなったらどうする?)
What happens if you need to reuse a call?
(再利用したくなったらどうする?)
What happens if you need to refactor some call or move it to a Vuex actions?
(Vuexに処理を移植するとかリファクタするとなったら?)

後述しますが、最後の”リファクタリングしたくなった”のがまさに私たちの陥った状況でした。
この問題に対処するために考えられたのがRepositoryFactoryパターンのようです。

これは名前の通りRepositoryパターンとFactoryパターンを組み合わせた設計ということになります。Repositoryパターンはドメイン駆動設計(Domain-Driven Design, DDD)で提唱された考え方、Factoryパターンはオブジェクト指向言語のCreational Design Patternsの一つです。

Repositoryパターンは、ドメインモデルのまとまり(Aggregateと呼ばれます)ごとにデータアクセスを1箇所に集約するRepositoryを作成し、データレイヤのロジックとドメイン疎結合にするというもの、Factoryパターンとはインスタンスの生成ロジックを一元管理するFactoryを作成し、インスタンスを必要とするクライアントから生成ロジックを分離するものです。

雑な言い方をすれば、両者を組み合わせることで以下のようなメリットを享受できるということになります。

  • コードのメンテナンス性が向上(DRYに記述できる)
  • 拡張性が向上(横展開するときに短時間で実装ができる)

導入背景

さて、弊社では2019年ころからモノリシックなRailsアプリケーションをフロントエンドとバックエンドに分離してきています。フロントエンドはVue/Nuxt/TypeScriptを採用していますが、詳細は下記ブログに記載しています。

tech.forstartups.com


ゼロから作ってきたばかりということもあり、APIへのリクエストは各コンポーネント中からaxiosを利用していました。

しかし、実装量が増大するにつれてAPIへのリクエストで共通の修正を行う場合に該当箇所や対象ファイルも増大し、メンテナンスが難しくなりました。そして、あるタイミングで実際にaxiosの処理をrescueしたいという話になりました。

「axiosを書いた各コンポーネント全部の箇所に修正を入れていく方法は避けた方がよいので別の方法を考えましょう」と一緒に働くメンバーの方が色々調査してくれて、RepositoryFactoryパターンを採用することにしました。

実装する

まずRepositoryパターンを導入していきます。

ドメインごとにデータへアクセスする処理をそれぞれ1枚のRepositoryに集約し、axiosによるAPIリクエストはこのファイルから(このRepositoryを通して)のみ行われるようにします。

次にFactoryパターンを導入します。

今回のFactoryパターンにおける具体的な生成物はRepositoryです。
Factoryを記述するファイルを作成し、どのRepositoryを生成するかを(呼び出し元のクライアントではなく)Factoryが決定できるようにします。

最後にaxiosを直利用していたコンポーネントを修正します。

データに対するCRUDアクションを行うときは必ずRepositoryを通すのがRepositoryパターンです。従ってaxiosを直で利用せずにRepositoryを指定するということになりますが、直接Repositoryインスタンスを生成せずにFactoryに”生成依頼”するのがFactoryパターンなので、最終的にはコンポーネントはFactoryに対してRepositoryインスタンス生成の依頼を行うよう修正します。これが下の図の .$repository(‘user’) です。

これによって得られたRepositoryは共通のInterfaceが備わっているので、あとは取得したRepositoryへのメソッド呼び出しを行うよう書き換えます。

 

なお、実際にはFactoryを呼び出すにあたって事前にpluginでFactoryをNuxtAppにインジェクトしておきます(repositoryという名称をつけました)。こうすることで context.root.$repository でFactoryを呼ぶことができます。

import { Inject, NuxtApp } from '@nuxt/types/app'
import {
 ApiRepositoryFactory,
 RepositoriesType,
} from '@/factories/api-repository-factory'
 
export default ({ app }: { app: NuxtApp }, inject: Inject) => {
 const repositories = (name: string) => {
   return ApiRepositoryFactory.get(name)(app.$axios)
 }
 inject('repositories', repositories)
}
 
declare module 'vue/types/vue' {
 interface Vue {
   $repositories: RepositoriesType
 }
}

また、コンポーネントにおけるRepositoryを通したCRUDアクションはcomposition APIを利用してcompositionとして切り出し、コンポーネントでは当該compositionをimportして使っています。

pages/index.vue

import useUsers from '~/composables/useUsers'
 
export default defineComponent({
 components: { },
 setup(_, context: SetupContext) {
   const {
     get,
     post,
     // ...
   } = useUsers(context)

composables/useUsers.ts

import { computed, reactive, toRefs } from '@vue/composition-api'
 
export default (context: any) => {
 const state = reactive<{
   user: UserType
   loading: boolean
 }>({
   user: {},
   loading: true,
 })
 
 const get = async (userHash: string) => {
   const response = await context.root
     .$repositories('user')
     .get()
   // ...
 },
 
 return {
   ...toRefs(state),
   get,
   post,
   // ...
 }
}

実装の概要は以上ですが、RepositoryFactoryパターンをAPIリクエストに導入した全体像を記載しておきます。

実装してみて

実装を終えて数ヶ月が経ちますが、当初の目的であったAPIクライアントに関するエラーハンドリングを1箇所に集約して管理することができるようになり(そしてそれは再利用が可能)、設計を一度理解すればコード管理が行いやすくなりました。

フロントエンドにとってはBackend For Frontend(BFF)サーバー以降のAPIサーバー・各種データソースをデータレイヤと見做すことができますが、その意味でドメインモデルとデータレイヤの中間にドメインごとに(正確にはAggregateごとに)1種のRepositoryレイヤを設けたことのメンテナンス性の高さをチーム一同実感しています。

副次的な効果として、以前の実装では設計から落ちておりスクリプトエラーとして拾っていたAPIのエラーを全てリクエスト段階で捉えて監視ツールにロギングできたことで、バグ発見までの時間を短縮できたことがありました。

Factoryパターンに厳密に従っているわけではないものの、それでもDRYに書けた部分が多く、今後もこのパターンに沿ってAPIクライアント側の機能開発は拡張していきたいと思います。

参考文献

以下のブログは実装の際に参考にさせていただきました

Vue API calls in a smart way
https://medium.com/canariasjs/vue-api-calls-in-a-smart-way-8d521812c322

【Vue.js】Web API通信のデザインパターン (個人的ベストプラクティス)
https://qiita.com/07JP27/items/0923cbe3b6435c19d761

Repositoryパターン
https://medium.com/canariasjs/vue-api-calls-in-a-smart-way-8d521812c322

Factoryパターン
https://www.oodesign.com/factory-pattern.html

【フォースタ テックブログ】Tryを決めるだけでは意味がない。チームに成果を還元するための取り組み。

お疲れ様です。エンジニアのHur Junhaengです。
フォースタートアップス(以下、フォースタ)に今年の2月に入社しました。

今回は、スクラム開発を行っているチームが振り返りで決定するTryをどう管理するべきか個人的な見解を込めて、フォースタでどのように対応しているかについてご紹介していきたいと思います。

スクラムにおいての振り返り

そもそもの話になりますが、振り返りは何故必要なのでしょうか。

振り返りを行う目的は、組織ごと違いはあるものの「過去にあった出来事から学び、チームをよりよい方向に変化させる」という大枠は同じかと思います。なので、振り返りの結論としてはチームをよい方向に変化させるための次のアクションを決めることが必須不可欠になります。

スクラム開発を採用している組織において、振り返りそのものは珍しいことではありません。振り返りのフレームワークは数え切れないほど多く存在していますが、Keep・Problem・Try方式(以下、KPT方式)を使ったことがない組織は少ないでしょう。表現は少し変わってしまいますが、この方式の場合でも「続けるべきこと(Keep)」と「抱えている問題(Problem)」を洗い出して、最終的には「次のアクション(Try)」を決定するために振り返りをしていることが分かります。

どの方式が組織に適切なフレームワークかはさておき、他の振り返り方式を採用している組織においても、新しいTryを決定することは重要ではないでしょうか。ただ、Tryを決定するだけで終わってしまうと個人によって取り組みがズレてしまったり、継続的な管理ができないことが多いです。よって、一度決定されたTryはチームとして「Tryに対する評価」をすることで、その成果をチームに還元する必要があります。

チームが抱えている課題

私が働いているチームではKPT方式を含め、色んな振り返りフレームワークを実施しています。フレームワークごとに手法は異なりますが、最終的なアウトプットとしては複数のTryが決定されています。ただ、決定されたTryは体系的に管理されておらず、チームやメンバーの状況によって左右されるという問題が発生していました。

  • Tryによっては共通認識にズレがあり、メンバーごとの解釈が異なる
  • 目の前のタスクが優先され、新しい取り組みを忘れてしまう
  • 効果があっても、チーム全体の行動改善に繋がりにくい

明確なTryの評価フローがなかったので、Working Agreement(以下、WA)は存在しているが、良いTryだと評価されていても適切なタイミングでWAに反映されておらず、そのままフェードアウトしていくようなケースもありました。

振り返りを通じて、チームで議論して決定された方針が、知らない内に忘れられてしまうことは望ましくありません。チームとして、もう少しTryの扱いを改善する必要があると認識しました。

Try一覧とステータスを可視化

チームの問題を解決するために最初に取り入れたのは、決定されたTryを別ドキュメントにまとめることでした。今までは振り返りの時に作成した議事録の中で各Tryを記載していたので、Tryを確認するたびに作成された日の議事録を閲覧していました。スプリントを跨いでも一目で状況が分かるような仕組みを作り、Tryを取り組む際のフットワークをなるべく軽くする必要がありました。

専用の一覧ページには振り返りで決定されたTryを記載し、それぞれの進捗状況をステータスとして表示させます。 そのステータスは毎スプリントごとに再評価を行い、最終的にはチーム全体の行動を変化させるためにWAやチームのCultureとして還元することを目的にします。

In progress
: 最初にtryが決定されている時の状態
Keep
: Tryを継続し、今後も効果を図りつつ継続したい
Done
: 実施済み、または意識しなくても既にに達成されている
Close
: 実施できない、または実施する必要がなくなっている
WA
: Tryの結果、チームとして守るべき行動規約として決定されたもの
Culture
: Tryの結果、特に意識しなくてもチームに浸透している状態

Try一覧を作成してステータスを管理することは、常に最新状態であり、信頼できる情報元を1画面で提供することに意味があります。例えばメトリックス監視など、情報の可視化のためにダッシュボードにリソースの情報を集約させることを考えてみましょう。情報を集約し、現在のステータスを可視化することは継続的な管理手法の第一歩と言っても良いでしょう。

Tryのライフサイクル

先ほどご説明しましたが、Tryを評価することはTryを決定することと同じくらい重要です。リスト化されたTry一覧を管理することができれば、次は定期的な評価を行う必要があります。現在のチームでは2週間を1スプリントとして進めているので、スプリントの振り返りを行う際にTryを再評価を実施しております。

振り返りの実施結果としてTryが作られたら`In progress`として設定させ、1スプリントの実施時間を経て評価を行います。実行すること自体が目的であるタスクレベルのTryはこの時点でDoneに移行するケースが多いが、その他の場合はチームでそのTryを継続して取り組むべきかを検討する必要があります。

  • スプリントの中で、メンバーはそのTryを遵守して行動していたか。
  • 実施してみて、本来想定していた効果は得られたのか。
  • Tryの効果よりも、継続するためのコストが高くないか。

この中でTryをチームが継続して取り込む価値がないと判断されたらステータス`Close`に設定し、継続を中止します。また、1スプリントで評価できなかったTryに関しては次のスプントまで効果検証を継続します。数は多くないかもしれませんが、1スプリントで充分に効果検証を完了しており、チーム全体で今後も取り組みたいと判断する場合は`WA`や`Culture`に反映することもよいでしょう。

次のスプリントではこの`Keep`ステータスのTryを同じ方式で評価して行いますが、`Keep`状態として残り続けることは警戒する必要があります。評価のタイミングを先送りにし実施されないTryが残り続けることは、効果の判断ができないTryをチームとして意識し続けなければならいことを意味します。

私が働いているチーム場合、`Keep`ステータスから`Keep`ステータスに変化することは、最初Tryが決定から2スプリント(4週間)が経過していることを意味します。2スプリントが経過したにもかかわらずTryが残り続ける状況の場合、評価を阻害する要因が存在しているか確認する必要があります。その場合、阻害要因を無くすためにチームとして取り組むべきことを先に実施した方が良いでしょう。

最後にTryの結果をWAやCultureに反映することに決まった場合は、それぞれを専用のドキュメントとしてまとめ、常に最新の状態になるように管理しなければなりません。これはTry一覧を作成する際と同じく、継続的な管理を行うためです。チームが取り組んでいることを言語化することによって、メンバーの共通認識を促すことと同時に、新しいメンバーが参加する場合にもチームの働き方をスムーズに吸収することができます。

チームの今

全てのTryは一覧で管理されており、スプリントごとにその効果を検証しているので、どんなTryでもしっかり評価されるようになりました。また、Try一覧を作成してから3ヶ月間、22件のTryが作られましたが、`Keep`ステータスのTryは2件のみでその他は何からの形でチームに還元されています。

特にTryの結果、WAとCultureに4件の行動規約が追加されており、Tryのステータスが変更されたタイミングでWAとCultureを更新するので、常に最新の情報が反映されています。WAにはチームとして遵守すべき内容のみ記載することになってので、Tryの管理仕組みを取り入れる前と比べれば非常にコンパクトになっています。WAに収まらない項目はCultureに記載することによって、遵守すべきものとチームの文化を区別することができました。

WAの例 :
エラー対応を完了する際には、その根拠をコメントに記載する
Cultureの例 :
githubは1function - 1commitを原則とし、日本語でコミット内容の説明文を記載する

現在はTry一覧を朝会などでチームと確認する時間を作って、スクラムの一部として取り扱っています。今後チーム内で確認する時間を作らなくても、メンバーがTryを意識して働くような文化が染み付くようになったら、別途時間を作る事なくTryを継続していくことができるでしょう。

【フォースタ テックブログ】デザインスプリントをやってみて開発チームの目線を整えた話

 

はじめに

こんにちは!フォースタートアップス / テックラボ * の藤井(@yutafujii)です。
社内向けのプロダクト「タレントエージェンシー支援システム(SFA/CRM)」*のサーバーサイドエンジニアとして日々活動しています。

*テックラボ…テクノロジーとデザインによってfor Startupsをグロースさせるチーム
*タレントエージェンシー支援システム(SFA/CRM)…日本を代表するスタートアップと、それを加速させることができるタレント(才気あふれる人々)とのより多くの対話の機会を創出するための「マッチングプラットフォーム」

これまで少人数のエンジニアでスピードや機能を優先して開発を進めていたのですが、弊社にUXデザイナーが入社してきたことをきっかけに、プロダクトが巨大化する前ということもあり一度立ち止まってデザインスプリントを行うことにしました。

ここ数年で普及したデザイン思考、デザインシンキングをエンジニアが取り入れることで、

・プロダクトの目指すべきゴールを再度確認すること
・一つ一つの開発がきちんとゴールに向かっていると確信を持ちながら実装できる状態にすること

を達成したいと考えました。

デザインスプリントとは

デザインスプリントは一言でいえば「ビジネス課題に答える5つのプロセス」です。
デザインシンキングを取り入れて目的を達成しようとするアプローチのため、この名前がついています。

GV(Google Ventures)が提唱したプロセス(https://www.gv.com/sprint/)であり、UXデザイン・プロトタイピング・ユーザーテストをアウトプットとして、学びという新たなインプットを得る流れになります。

ソースコードは1行も書きません

デザインスプリントは一般的に、5日間、つまり丸一週間分をかけて行います。その概要は大まかに以下の通りです。

Day1: 意識合わせ・課題マップの作成・取り組む課題の選択

Day2: ソリューション出し(知の探索)・スケッチ・最終日にインタビューするユーザの選定

Day3: ソリューションを絞る(午前)・うまくいった姿までの過程をイラストに並べる(午後)

Day4: プロトタイプ作成(コーディングせずにUIデザインツールを使用する)

Day5: プロトタイプを用いたユーザーインタビュー・学び

プロセスが用意されていれば当然ながら各プロセスごとに道具(ツール・フレームワーク)もあります。
デザインシンキングの文脈で有名な Empathy Map もその一つです。
実際に行うときは、個別の事例に沿ってアレンジを加えると良いでしょう。

 

なぜやるのか

元々デザインスプリントは事業課題の答えを早いサイクルで見つけ出すことに適しています。

実際にコードを書かずに思考・プロトタイプ・ユーザーフィードバックにより仮説を検証するサイクルは魅力的なアプローチでしょう。

ただし私はそれに限られない良さがあると考えています。

それは、このプロセスを通して

・プロジェクトの目標の共有
・メンバー同士の考えや思考法の相互理解

という側面で効果があるためです。プロジェクトのブラッシュアップだけでなく、スタートアップなどの組織づくりにも有用です。

 

いつやるべきか

教科書的には、新たなプロダクトを実際にエンジニアが開発する「前」がベストなタイミングになります。
ただ、すでにプロダクトがあるという場合でも、例えば以下のような時には効果があると考えています。

・プロダクトが目標とする1年後の状態をすぐに言えない
・(技術的に)できることばかりを優先して開発している
・開発工数が小さい事項ばかり実装していることが2ヶ月続いている
・優先順位付けを行った結果のバックログが、プロダクトOKRのKRに貢献するものに見えない
・ユーザーのペルソナを聞くとメンバーによって回答がバラバラ。またはすぐ答えが出てこない
・ユーザーの課題を「それはまるで○○のよう」と身近な行為で例えてもらったときに回答がバラけてしまう。またはすぐ答えが出てこない
・とりあえずユーザーヒアリングを終えた
・チームメンバーが急激に増えている

など

 

ミニ・デザインスプリント

今回チームで実施したのは、このミニ版のようなものです。

1.事前に行ったユーザーヒアリングの内容を集約する
2.UXデザイナーが「一人デザインスプリント」を実施して叩き台となるレポーティング資料・ディスカッション資料を作る
3.チーム全員で資料の中身を議論する。発散して、収束させ、お互いの認識を"同期"させる

フレームワークに従ってレポートまで作ってくれたデザイナーさんに感謝です!

 

ゴール

最初にデザイナーが示したゴールはこちらです。

「メンバー全員が事業の目的・事業課題・プロダクトビジョン・ペルソナを共通認識として持つこと。誰に聞いても同じ答えが返ってくることで、新規メンバーとも課題や目的を共有出来る」

ちなみにこのゴールはとても重要で、起業家が集うBARで、とあるCTOに「まずはとにかくユーザーを知ること。徹底的に足を運び、エンジニアの誰に聞いても全く同じペルソナが返ってくるような状態にしなさい」と言われました。

 

雰囲気作り

見落としがちですが、雰囲気作りはとても重要です。

ゴールを達成するためには参加者に対してどのような姿勢で望んで欲しいのか、どのような行動を望むのかを最初に共有するとすごく良いです。

また、それをサポートするような小物を用意することも大事だったりします。

今回のゴールは「共通認識を持つこと」なので、ちょっとでも意見が違ったり違和感があったら遠慮せず発言することが望まれます。

本心で腹落ちしていないまま終えてしまっては本当の意味で「認識を共有した」とは言えません。

 

そしてそのためには(1)意見を言える気楽さ、(2)柔軟な発想ができる環境を用意した方が良いと考えました。

そのために私たちが行ったことは次のことです。

・ちょっと息抜きをしたくなるおやつ時に実施した(15時からスタート)
・お菓子を事前に持ち寄って(一人で食べきれない結婚式の引出物とかも笑)テーブルに並べた
・食べながらでOK
・もちろんコーヒーも準備
・地べたに座ったり、机に座ったり、立ったりして参加してOK
・発言をとにかく褒める
・ジョークもいれてみんなで笑う、面白いトピックもいれる
・大きな画面を使う

 

使用したフレームワーク・ツール

ざっくりとこんなフレームワークや資料を使用しました。

・User pains
・State it Simply
・Persona
・Empathy Map
・Story Board
・Hills

 

User pains

今回はミニ・デザインスプリントなので、最初にユーザーヒアリング結果をUXデザイナーへ渡しました。
こんな感じで機能要望がざっと40個ほどカテゴリー分けされて並んでいました。

 

State it Simply

・What we do?(それを5歳児にわかるように)
・Who is the users?
・What is their pain?
・What is our business for?

この辺りを言語化します。
この部分はどのくらい先まで見据えるかによっても書く内容(ビジネスの展望や新たなステークホルダーをユーザーにする長期戦略など)が異なってきますが、目先1年くらいにするといいと思います。

もちろん、全社の長期戦略からバックキャストし、プロダクトの長期ロードマップを作って認識共有することも大事なので、それは別途行いましょう。

意外と盛り上がるのが「 ”何をするのか” を5歳児にも説明できるように」だったりします。余分なところが削げ落ちて、動詞や名詞が研ぎ澄まされていくのがわかると思います。

Pain(課題)を考える時も、「それはまるで○○のようだ」と表現することを意識する。

私たちがデザインスプリントを実施したときには

・「それはまるでパズルのピースを埋めるような状態だ」
・「それはまるで料理を30個同時に作っているような状態だ」

などの意見が出て、結局

・「それはまるでパズルを10個同時に作っているような状態だ」

となりました。

 

Persona

ペルソナを設定します。

家庭環境・育ち・趣味・仕事への姿勢や性格などを具体例を含めながらその人のイメージが湧くまで書いていきましょう。

箇条書きで大丈夫です。

その人の名前もつけておくとその後何かと便利です(私たちは山崎翔大さんと飯山美咲さんというペルソナを作り上げました)。

実際には、この部分が最も大事です。

プロダクトによっては複数タイプのユーザーを抱えることがあると思います(プラットフォームがその典型)。その場合はそれぞれについてペルソナを立てて進めましょう。

 

Empathy Map

次に、山崎さんや飯山さん(=ペルソナ)が”言いそうなこと”、”やりそうなこと”、”考えそうなこと”、”感じていそうなこと”を書き表していきましょう。

特にTHOUGHTとFELTの部分は、なぜそれらが表に出てこない(口に出したり、行動にならない)のかを深く考えてみることが大切です。

 

Story Board

今のペルソナユーザーの状態(課題を抱えた状態とします)から、ユーザーが為したいことに至るまで、プロダクトがどんなふうに関与していくかを4コマ漫画的に絵と端的な言葉で書き表していきます。

私たちは6コマを用いて、今のユーザーが “こうして、こうして、こうなって、こうなって、ゴールの姿になる” 、という過程を描きました。

*引用元:https://uxdesign.cc/how-to-storyboard-experiences-fc051e2bc04d

 

Hills

プロダクトによって「誰が(Who)、どんな感じに(Wow)、何を(What)達成してる」のかを改めて考えます。

最も大事なのはWowです。Howではありません。

方法論から考えるのではなく、状態から考える。

描いた理想像では、ユーザーが「どんな気持ちを持って」「どんな感情で」成し遂げたかったコトを達成しているのだろうか?そういった視点が求められます。

どういうことか、少し思考例を示します。

 

例)30分かかるMRIでじっとしていられない子供に、MRIを受けてもらうには?

→ 鎮静剤を打つ(How)のではなく、MRI室を海賊船のようにして楽しみながら受けてもらおう(Wow)

ちなみにWowを考えるというのは、グロースハックでも出てくるアドバイスです。
ユーザーにとってのアハ・モーメント* の発見がPMF達成のサインといってもよいでしょう。

*アハ・モーメント…プロダクトの価値をユーザーが最大限に感じた瞬間

 

イデアリストの順位付け

ミニ・デザインスプリントでは以上を元にして、ペルソナとしたユーザーがStoryBoardに出てくるゴールの姿になるためのアイデアを出しました。

最後にそれらを、縦軸に各アイデアインパクト、横軸に効果の不確実性を描いてそれぞれのアイデアがどのあたりに位置するかマッピングしました。

当然ながら「インパクト大・確実性が高い」というゾーンが優先的な開発事項ということになります。

これらを見つめ直したところでスプリントを終了し、ちょっとした振り返りを行いましょう。

 

やってみてわかったこと

シンプルな本質を見つめることができる

今回4時間をかけて実際にやってみて、最初に感じたのは自分たちが何を作っているのかをちゃんと言語化できていないということです。

何となくでは説明できたけれど、「それって何?」のように1つ突っ込んで質問されるとスラスラと答えられなかったり、参加したエンジニア4人の認識や想いが完全に一致しているわけではなかったり…。

“誰に聞いても同じ答えが返ってくること” という状態を実現するには膝を突き合わせる時間と議論のフレームワーク(=デザインスプリント)がとても有効だと感じました。

 

Vision Driven

また、みんなで話すと自分の考えやチームとしての見解がどんどん研ぎ澄まされるというのも全員で実感しました。

 

この過程で最も重要な役割を果たしたのがMission, Vision, Valueです。

何度も何度も

「でもそれはMissionにある○○に添わないよね」とか

「私たちのMissionは○○だから、5歳児に説明すると○○な感じかな?」とか

「あの時CEOが○○って言ってたのを踏まえて○○の方がフィットする」とか、

会社として実現したい世界や数年先のゴールを意識して目の前に落とし込むことができました。

フォースタートアップスでは1週間に1回は全社MTGでCEOより、熱意や今の想いが聞けますし、毎週Slackでも欠かさず “今、考えていること” を共有してくれます。

そういうカルチャーにもとても助けられました。

 

フォースタートアップスのMVV (出所:会社HP

 

The Team

実際にやってみて、デザインスプリントはチームそのものを強くすると感じました。

私たちは普段からコミュニケーションがとても活発なチームだと思ってはいますが、プロダクトの本質やゴールを何時間も使ってみんなで議論すると、お互いをもっともっと深く理解することができます。

部活の合宿のような感覚で、長時間すぐ傍で過ごしてチームとして強くなるイメージかも知れません。

中には意見に相違があったり考え方が異なる部分もありますが、「同意」できなくてもいいのです。「理解」することがとても重要です。
お互いを知り、理解し、その上で一つの方向を向く。仲間を信頼する。

そのためにもデザインスプリントはいい時間になるはずです。

最後に

長々と書かせていただきましたが

社内向けのタレントエージェンシー支援システム(SFA/CRM)についてデザインスプリントを行った感想でした。

私たちは、日本を代表するスタートアップと、それを加速させることができるタレント(才気あふれる人々)とのより多くの対話の機会を創出するための「マッチングプラットフォーム」を創るという壮大なプロダクトを作っています。

試行錯誤しながら、日本から世界で勝つスタートアップ支援を行っていきたいと思います。

【フォースタ テックブログ】RailsのAutoloadingをClassicモードにしていたらエラーに悩まされたのでZeitwerkモードに移行した話

 

こんにちは。エンジニアの藤井(@yutafujii)です。

今日は、RailsのAutoloadingとReloadingについて解説しつつ、これにまつわる設定ミスでdevelopment環境においてエラーに悩まされたというエピソードをご紹介します。

AutoloadingとReloadingって?

RailsのAutoloadingとReloadingという言葉を、より実務上のありがたみとしてイメージできるように素朴な疑問から考えてみたいと思います。

なぜRailsではrequireを書かなくてもよいのか?
Rubyでは他のファイルを読み込む時には当該ファイルを明示的にrequireしておく必要があります。ところがRailsではモデルでもコントローラーでも、requireを書かずに多くの処理がうまく動きます。

これは、RailsRubyのメソッドをオーバーライトしているためです。具体的には、Moduleクラスのconst_missingというメソッドを上書きしています。このメソッドはメモリ上にロードされてない未知の定数を参照したときに発火するのですが、RubyではNameErrorが出るのに対して、上書きされたRailsのconst_missingではエラーを出す前にその定数が定義されていそうなファイルを推測して自動で探すようになっています。だからAutoloadingと呼ばれています。なお、自動で探す範囲はautoload_pathという変数で管理されています。

そしてもうひとつの疑問。
なぜRailsで開発しているときにファイルに加えた変更がすぐ反映されるのか?

例えばの話ですがproduction環境で稼働しているサーバーに入り、Railsのコントローラーのファイルを書き換えたとしても、その変更はサーバーを再起動しない限り反映されません。しかしdevelopment環境だとファイルを修正すると画面をリロードするだけでその変更が反映されます。Railsがこのような開発体験の良さを実現しているのは、development環境ではファイルの変更履歴をウォッチして、変更を検知したらサーバーが次のリクエストを受理したときに当該ファイルを読み直せるようにしているからです。これをReloadingと呼んでいます。

RailsがAutoloadingとReloadingのためにしていること

概略は説明した通りですが、コードベースでも該当箇所を紹介しておきます。
Autoloadingで説明したconst_missingメソッドのオーバーライトはActiveSupport::Dependenciesというモジュールに記載されています。

また、Reloadingで説明したファイルをウォッチしているというクラスはActiveSupport::FileUpdateCheckerというもので、そのexecuteメソッド(端的に言えばここで変更が生じているファイルをメモリからアンロードする)をコールしているのがRails::Application::Finisherというモジュールです。

Reloadingについて説明を加えると、このFileUpdateCheckerがautoloadされた定数を一旦全てアンロードしますので、次のサーバーリクエストの処理において変更を加えたコントローラーやモデルが参照されると、const_missingが発火してAutoloadingされ、結果として修正後の内容がロードされるという仕組みです。

設定を間違えたらdevelopment環境で見知らぬエラーが

正直に言って、こんなRailsの仕組みを理解したうえで実務の世界に入ったわけはなく、エラーに遭遇して初めてちゃんと調べただけです。

ここからはそのバグについてご紹介します。

私が入社した頃はRailsフルスタックのフレームワークとして利用していたのですが、途中からVueやNuxtをフロントにしてAPIサーバーとしての機能に集約してきました。そうした開発を進めていくなかで、development環境において次のようなエラーが出るようになりました。

A copy of Api::One has been removed from the module tree but is still active!

Api::Oneのコピーはモジュールツリーから削除されたけどまだ利用されています。」とでも訳すのかもしれないですがエラーメッセージの言っていることがイマイチよくわからず、backtraceをみたのですがアプリケーションのコードに到達する前のRailsのコードでエラーになっていたので、これは少し根が深そうだと思ってGoogle検索を頼りました。

同様のエラーに関する記事はいくつか見つかったのですが、実際に効果があったのはdevelopment環境のconfigを変更するという対処でした。

config/environments/development.rbにおいて「クラスをキャッシュしておくか」という設定(config.cache_classes・config.action_controller.perform_caching)をtrueにすることで確かにエラーは出なくなったのですが、これは一度ロードしたクラスをキャッシュし続けるという設定なのでReloadingが効かなくなり、Rails部分のソースコードは(より厳密にはautoload_pathに含まれるファイルは)変更するたびにアプリケーションサーバーを再起動しないと内容が反映されなくなります。

これは開発体験が非常に悪いので、Railsの仕組みを調べながら、根本原因を探していきました。

結論として、エラーの直接的な原因はdevelopment.rbの別の設定にありました。

「クラスのリロードを変更があった場合に限定する」という設定(config.reload_classes_only_on_change)がfalseになっていたために、ソースコードを変更しなくてもリクエストの都度autoloadされた定数を全てアンロードしていました。

この設定そのものが問題ではないのですが、フロントエンドをコンポーネント化してきたことと複合してエラーを生じさせていました。

すなわち、コンポーネント化されたページを開くとページロード直後にJavaScriptが複数のリクエストをほぼ同時にAPIサーバーへ送る状況が生まれたところ、前述のRailsの設定が理由でAPIサーバー側ではリクエストの処理前にautoloadされた定数が全削除され、その結果全く同じモジュールのAutoloadingが2本同時に走るRace condition(競争状態)が発生していました。同一モジュールのRubyオブジェクトが2つできてしまったことで、処理途中のequal?評価(RubyではオブジェクトIDの一致を確認するメソッド)がfalseになり、くだんのエラー

Api::Oneのコピーはモジュールツリーから削除されたけどまだ利用されています。」

が表示された、というわけです。

ちなみに、実際にエラーを起こしたのはルーティングからコントローラーを取得する処理action_dispatch/http/request.rbのcontroller_class_forという部分でした。コントローラー名の文字列から定数を取得するRailsのconstantizeメソッドでコントローラーを示す定数(例えるならApi::Parent::ChildController)をAutoloadingする時にエラーになっていました。

なぜこのような設定になっていたのか

ところで、問題の一因となったconfig.reload_classes_only_on_changeの設定はRailsプロジェクトの初期値がtrueなので、なぜこれがfalseに変更されたのか気になりました。

この変更は3年前に行われており。当時のプルリクにも多くの情報はなかったので推測ではありますが、事の発端はApplicationというモデルを作成したことだったと思われます。

当社のシステムは人材紹介業に関連するものであるために、”応募”の英訳にあたるApplicationという単語をモデル名で利用していました。しかし想像がつくようにApplicationというクラスはRailsプロジェクトそのものにも存在し(config/application.rb)、何らかの機構でApplicationモデルのAutoloadingが上手くできなかったようです。そこでRailsのイニシャライズ直後にapp/models/application.rbをrequireしておくような設定がconfigに書かれていました。

悲しいかなRailsではrequireしたファイルは通常のReloading時にはアンロードされないという性質があるために、今度はApplicationモデルのReloadingができない悩みを抱えていたと思われます、だから強制的に都度定数削除をするconfig.reload_classes_only_on_changeをfalseにしたのではないかと考えています。

今回のバグ修正においてこの部分も見直し、結果的にrequire_dependencyを利用しました。一応ですがRailsガイドではrequire_dependencyはラストリゾートであり最初に検討すべき手段ではないと書かれているのでご注意ください。なお後述するZeitwerkモードの導入でこの対応も不要になりました。

Autoloadingに関するRailsの設計上の疑問と直近の動向

もう少しだけこの定数のAutoloadingについて触れておきましょう。

紹介したエピソードではdevelopment.rbの設定ミスとVueを用いたフロントエンドの分離が競争状態を生んだエラーの理由だと説明しましたが、このエラーはどのRailsプロジェクトでも一般的に再現性があります。

エラーが起きる条件は「2本以上の同時リクエストを受けとりReloading & Autoloadingが2本同時に走ること」ですが、通常の開発のなかでファイルを修正した場合この条件を満たしてしまいます。

実際、フロントのコンポーネントにおけるcreatedフックなどで2本以上のAPIが同時に呼び出されるページでは、Rails API側のファイルを修正すると直後の画面リロード時だけはこのエラーが出ます(出ない時もあります)。ReloadingとAutoloadingが2本走って競争状態が生まれるためです。そのままもう1度画面リロードするとエラーは出なくなりますが、これはReloadingもAutoloadingも走らないからです。

このエラー再現性についてはReproduce用の個人プロジェクトも作って確認しました。

github.com

「これ、フロント分離しているプロジェクトだと悩む人多いんじゃないか?」と思ってRailsのイシューが既にあるか見てみると、確かに1件「LoadError when multiple threads try to load the same namespaced class」というイシューで修正の議論もなされていたようですが、Rubyの改修も必要な内容になっており、最終的には修正は行われていない様子でした。

その代わりだったのかはわかりませんが、Autoloadingの新しいやり方がRails 6.0から導入されています。

Zeitwerk(ツァイトヴェルク)というgemが正式に導入され、そもそものconst_missingに依拠したAutoloadingが見直されました。

なので、Zeitwerkモードを利用していれば、今日紹介したエラーに悩まされる心配はありません。Rails 6.0以前のAutoloadingの方法はClassicモードと呼ばれていますが、これはRailsガイドでdeprecatedとされているので早めに移行しておきましょう。

config/application.rbに1行追加するとZeitwerkモードに移行できます。

config.load_defaults "6.0" # Zeitwerk
config.autoloader = :classic # Classic

私の所属するプロダクトではRailsのバージョンこそ6に上げていたものの、こうした周辺機能のマイグレーションに気づけていない部分もあったので、次回以降気をつけていきたいと思います。

参考リンク

RAILS GUIDES

https://guides.rubyonrails.org/autoloading_and_reloading_constants_classic_mode.html
https://guides.rubyonrails.org/autoloading_and_reloading_constants.html

Rails GitHub

https://github.com/rails/rails/blob/main/activesupport/lib/active_support/dependencies.rb
https://github.com/rails/rails/blob/main/activesupport/lib/active_support/inflector/methods.rb

Rails Issue

https://github.com/rails/rails/issues/33209

Zeitwerk GitHub

https://github.com/fxn/zeitwerk#pronunciation

【フォースタ テックブログ】「ユニコーン企業のひみつ」を読んで自社の開発組織と比べてみた

こんにちは。サーバーサイドエンジニアの速水です。
今回は、「ユニコーン企業のひみつ――Spotifyで学んだソフトウェアづくりと働き方」という書籍のレビューを投稿させていただきます。

www.oreilly.co.jp

フォースタートアップス(以下、フォースタ)でも、スクラムをベースにしたアジャイル開発を行っているわけですが、事業環境や組織は日々変化しており、どう変化に対応していくべきなのか、悩みは尽きません。
ユニコーン企業のひみつ」は、SpotifyAmazonGoogleFacebookといったユニコーン企業はどうやっているのか?というのをヒントに、何万人もの従業員を抱える企業がなぜスタートアップのような組織・環境であり続けられるのかを紐解いていく内容となっており、印象に残ったところ、自らに引き寄せて考えたこと、感想をまとめました。

今回の書評は、弊社の村林(@bayashimura)がこちらのツイートを見つけたことがきっかけになっています。

村林はフォースタの開発組織であるテックラボのアジャイル旗振り役として、振り返りやチームビルディングを浸透させてきました。社内向けのプロダクト「タレントエージェンシー支援システム(SFA/CRM)」を開発しているチームでは、振り返りのファシリテーターを交代で行うなど、スクラムの要素を取り入れながら開発プロセスの改善に努めています。

tech.forstartups.com

tech.forstartups.com

不確実性だらけだからこそ学習が大事

スタートアップで取り組むソフトウェア開発は、不確実性だらけであると語られています。

「答え」が既にわかっているというつもりなら、それは思い込みだ。

わからないから、たくさん実験をして、失敗をすることもあり、ただ毎回インパクトと価値を計測しているから、前に進んでいける。わからないから、「答え」を見つけるために、各自が考えて、手を動かして、学習していかなければならない、と説かれていました。

自らに引き寄せると、やはり普段の仕事の内容は、「答え」がわかっているとは言えません。議論した上で「この方向だよね」という合意はあれど、それが絶対に正解とは言い切れないし、アプローチ方法も様々です。

テックラボでうまくできていると感じるのが、アプローチへの寛容さと、失敗に対する心理的安全性(失敗をしてはいけないという思い込みは払拭する)です。フロント、バックエンド、様々な視点から実現方法を考えるのはもちろん、そもそも手動の作業で同じような物を見せて解決できないか、ヒアリングして課題をもう少し深堀りたい、といったこともフラットに出し合うことができます。失敗はしないに越したことはありませんが、バグが入ったまま機能をリリースしてしまった、レビューでバグを見逃してしまった、という時もあります。そういった時に、チーム全体で今できるリカバリ策を考え、対応する姿勢があるからこそ、苦手な領域の開発であっても挑戦してみよう!という気になります。

一方、インパクトと価値の計測においては、まだまだ課題があるように感じています。社内向けプロダクトは、ビジネス上の価値とプロダクトの価値がぴったり一致はしないため、指標の設定、評価には苦戦しています。

自律、権限、信頼

ユニコーン企業ではアジャイル開発が企業文化に染み込んでおり、わざわざスクラムマスターを置いて形式としてのスクラムをやる必要はないようです。とても自律したチームであり、信頼があるからこそ、権限もしっかり持っています。ですが企業としてバラバラにならないための仕組みとして、"カンパニーベット"を設定するということもやっているようです。
※カンパニーベット(Company Bet):会社が取り組みたい重要事項を、終わらせたい順に並べたリスト。小さな目標ではなく、大きな取り組みに関するもの。

企業においてチームに権限を渡すというのは、そう簡単なことではないと思います。しかし、学習のスピードを出すためには必要なことでもあります。本書の中では経営側の視点で「現場の言い訳を取り除く」と表現されていますが、現場としても権限をもらう以上、本当に自分ごと化できないと辛いことになりそうです。渡す側、もらう側、双方の信頼あっての権限移譲で、それがあっての自律したチームなのだと理解しました。

また、見習いたいポイントとして、データ(数値、ファクト)と解釈(どういう意味を見出したか、仮説)を、フレームワークとして切り分けている点がありました。本書では、DIBBという、やるべきことを系統立てて検証するための意思決定フレームワークが紹介されており、データ(Data)、インサイト(Insight)、確信(Belief)、ベット(Bet)に分解して、整理されていました。
私はこれまで、人への伝わりやすさという観点で「主張+根拠づけとしてのデータ」をまとめてとらえることが多かったのですが、学習の最中ということを考えると、データと解釈をわかりやすく分けて共有した方がチームとしての学習は進むのかもしれません。私も意識してやってみようと思います。

まとめ

著者Jonathan Rasmusson氏のSpotifyでの経験を中心に、ユニコーン企業におけるソフトウェア開発で組織として気をつけていることがわかりやすくまとまっている1冊でした。特に、アジャイル開発におけるスクラムの形式的イメージを強く持っている方にとっては、それが浸透した先を知れる内容となっているので、面白いと思います。

フォースタではエンジニアを募集中です!
開発スタイルや雰囲気はもちろん、事業や技術スタックに関するお話もさせていただきますので、ご興味をお持ち頂けましたら、下記「話を聞きに行きたい」ボタンより気軽にエントリーいただければ幸いです。