こんにちはBASE株式会社取締役EVP of Developmentのえふしん( @fshin2000 )です。 今回は、年末の給与改定から運用を開始する評価グレード制導入のお話を書いてみたいと思います。 これまで人材採用時の給与決定や社員の評価時には、マネージャ間で相談し役員承認の上で給与を決めていましたが、その基準や空気感は詳しく社内のメンバーに共有できていませんでした。理由として、中途主体の採用だとどうしても前職給与に影響され、人によって給与にばらつきがでてしまうため、体系だった形に整える機会がなかったのですが、今度、社内に評価グレード制というものを導入することになり、各給与レンジの方に求めるスキルや意識についてまとめたのでこちらで公開いたします。 評価グレード制というのは、一般的に等級と呼ばれるもので、一定サイズ以上の会社のご経験がある方なら、類する制度はどこでもあると思いますので詳細説明は割愛いたします。 (採用面接等で詳しくご説明差し上げられれば幸いです ^^ ) 以前からある当社の報酬体系で特徴的なのは、年収7〜800万円以上とそれ以下で給与の上がり方が変わるということが挙げられます。社員の評価は半期毎に行っているのですが、700万円以下の給与の人はスキル向上がそのまま役割向上につながるレンジと捉えていて、仕事を頑張る努力が昇給に反映されやすいのに対して、700万円以上の人はそのような概念をなくして、その代わり、 役割や期待値の変更 に対して大幅な給与アップを目指す。エンジニアリングマネージャもそれを前提として期待を設定していくという考え方があります。 700万円以上の人は、国内の転職市場においても経験豊富なハイスキル層とみなされると思います。マネジメント側の責務として、評価面談やOKRの設定を通じて、大きな期待をかけ、大きな成果をあげてもらい、大きな昇給を実現することが仕事です。エンジニアリングマネージャは、チームメンバーをプロデュースするという仕事の結果、自分自身の評価と昇給にもつながります。 この以前から取っていた給与の構造を踏襲し、グレードを定めました。これまでやっていた給与決定プロセスを言語化したというのが、作業にあたってやったことです。 評価グレード制に至るまでの過程 歴史ある大企業や老舗企業で働いている人たちは、等級制度、評価制度が当たり前に存在していると思いますので、あまり意識したことはないかもしれませんが、スタートアップ企業が評価グレード制を導入する動機には組織の拡大におけるマネージャへの権限移譲の文脈が存在します。 数年前まで昇給額を役員で決めてた。役員もマネージャから報告されるメンバーの活躍を感じられる組織サイズでもあったし、役員がマネージャも兼ねるケースが多かったので、一定の納得感は得られていたと思われる。 役割や期待に対する給与レンジや昇給額のような基準は、役員とマネージャ間には存在していて、採用活動や半年ごとに行われる評価会議を重ねるたびにブラッシュアップされていった 組織が大きくなりマネージャも増えるなか、その基準を言語化することで、どうしたら給与が上がるのかをフレームワーク化し、目標設定と評価をスケールするようにしたもの 一般にマネージャに給与の提案権限を移譲するにあたって、評価クオリティを維持し、評価への納得感と事業成長を実現するための取り組みとして導入されるものが評価制度や等級制度ということになります。 評価グレードの分類 評価グレードは、 A1・A2・Ex1・Ex2・Ex3・Ex4の6段階 に分類されます。 ※A(エー)=Associate、Ex(イーエックス)=Expert 新卒やキャリアが浅い方はA1から始まって、グレードが上がっていけば行くほど、サービスや会社に対する影響範囲は広く、未来を見据えた課題解決や課題設定力に対する期待が設定されます。 グレードに対しては報酬の下限額が設定されています。上記例に挙げた700万円のラインはEx2の下限値に設定されています。 また、皆さんに親しみやすい役割名としてはリード職がありますが、現在、当社ではテックリードと呼ばれる役割の人がいます。彼らはEx3の枠に該当します。当社ではさらにテックリード of テックリードとしてのプリンシパルテックリードが設定されており、それが最上位のEx4に位置づけられます。完全にBASEの未来を作る期待に対して設定した役割です。 各グレードに対する報酬の上限額は設定されていますが、グレードをまたいだ金額の被りは存在しています。 これは中途採用において、実績のある方はもちろん、期待値込みで若くても高い給与で採用することを想定し、入社後に当社のサービスの経験を積んでいただく中で、適切なグレードに合うようにマネジメントしていくための高速道路の合流車線的なバッファとして存在しています。この辺をあまり厳密にしすぎると採用活動に影響が出てしまうので柔軟性をもたせています。 といろいろ前置きを書きましたが、抽象的には以下のようにグレードに対する期待が設定されています。 A1 (新入社員や経験の浅い社員) 指示/指導を受けながら業務を遂行する 自らの業務領域について、業務改善や課題解決の提案をする A2 特定領域において自立した業務遂行をする 所属チームの業務について、業務改善や課題解決の提案および実行する Ex1 特定領域において、 所属チームをリード する水準の事業成果を生む Ex2 特定領域において、所属チームをリード する水準の事業成果を生む 所属Division全体の課題解決 に影響力を持つ 同職種における社内比較で 高い専門性や課題解決能力 を有する Ex3 (テックリードなどのリード職相当) 全社をリード する水準の事業成果を生む 全社の将来的な課題 を解決する事業成果を生む 同業種における 全社トップレベルの高い専門性や課題解決能力 を有する Ex4(プリンシパルテックリードなど) 全社をリードする水準の事業成果を生む 全社の将来的な課題を解決する事業成果を生む 全社の課題解決に影響力 を持つ 同業種における 業界トップレベルの高い専門性や課題解決能力 を有する Web系エンジニアの具体例 以下は、各グレードをWeb系エンジニアに比較的具体例として割り当てたものになります。すべてを満たさなくてはグレードが上がらないというわけではありません。その人の個性と期待する役割にあわせて評価しますが、グレードが上がれば上がるほど、 未来をつくることへのビジョン、プロダクトクオリティの実現、不確実性へのチャレンジを求める ことになるという部分は、共通して期待することになります。 A1 (新入社員や経験の浅い社員) 通常プロジェクトの開発メンバーとして参加し、開発、テストを任せることができる 比較的平易な難易度のお客様のお問い合わせや不具合対応の解決を任せることができる 周囲の助言を受けながら、所々の問題を解決できる A2 通常プロジェクトの開発者として参加し、一人でも開発、テスト、リリースを任せることができる お客様問い合わせや不具合について、解決を任せることができる 本番運用の安定性実現のための障害対応、高負荷対応のオペレーションに参加できる Ex1 通常プロジェクトの技術責任者としてメンバーをリードすることができる (技術責任者とは主にプロジェクトの設計レビューを主導する人) 当社にて求められているソースコード、プロダクト等の品質向上を自ら実現し、メンバーに広げることができる 本番運用の安定性実現のため、障害対応、高負荷問題等を率先して発見、対応し解決に導ける 経験の少ないメンバーに対する技術指導を日常的に任せられる Webサービスを運営するエンジニアとしてPJと日常的な改善を並行して行うために、適切な段取り、スピード、クオリティを実現できる Ex2 難易度の高い技術課題やプロジェクト(決済の追加や商品オプション機能、抽選販売など)の開発の設計、改善について、見積もり、スケジュール通りの実現を任せることができる 技術的負債の返済を自ら先導し、解決することができる 現状のソースコード、プロダクトについて、チームでの品質向上を率先してリードできる 常に稼働しているサービスに目を向けて、技術的な問題を解決し続ける 自動テストやデプロイ改善等を通じて、デプロイ後の問題発見や運用中のサービス改善をリードできる 一つの技術に依存せず、自分が関わる事業領域で求められる技術への適応力がある。開発言語、フロントエンドやサーバサイド、インフラなどの技術概念に囚われず、近接領域の技術を学び続けて問題解決に貢献できる システム改善が必要になる難易度の高い障害対応を率先してリードしクローズに導ける Ex3 (テックリードなどのリード職相当) 難易度の高いPJを実現するためにアーキテクチャ設計、作業段取り、見積もりを行い、メンバーを引っ張ることでスケジュールと品質を実現する 計画の有無に関わらず、短期的、中期的な事業成長を見据えながら、現状のサービス、技術の問題に目を向けて、改善提案および改善実施ができる 技術提案、サービスの問題提起、研究等を常に行っている 自分にとって未知の技術を現状にフィットするように取り入れ、サービスの成長を実現することができる 品質、機能、スケーラビリティ、セキュリティ等を改善する技術的課題を提起し、メンバーをアトラクトしながら改善をリードできる Ex4 (プリンシパルテックリードなど) 会社の中期目標を技術で実現するための技術方針や組織方針の立案および遂行ができる 開発組織に起きる問題点を発見し、技術力の底上げに対する抜本的な施策、生産性の改善を任せることができる セキュリティ、ビジネス、スケーラビリティ等のリスクに目を向け続け、改善提案を行い、組織計画、開発計画に結びつける 今後も役割に対する肩書や、金額構成、トップラインの給与の上限額などは変えていきたいと思っています。Webサービスを支えるエンジニアは一人一人の主体的な活躍がすべてです。非・労働集約的な役割の働き方に対する制度として、ここで決めた制度が今後も固定的であるわけではなく、流動的に見直していけるように業績を上げていきたいと思っています。 それこそEx3やEx4のグレードの人たちが活躍し、サービスクオリティ、業績への寄与を行い給与のトップラインを向上させることが、全エンジニアのスキル、社会的評価、給与水準の底上げにもつながると考えていますし、それがやりやすい組織構造を常に模索していきたいと思っています。 エンジニアリングマネージャのグレード設定について エンジニアリングマネージャにも評価グレードの基準が設定されていますが、こだわりポイントだけ抜粋しますと、以下の特徴があります。 ・採用候補者の適切な給与提案ができる ・新規ビジネス等の際に送り出せるマネージャ、リード候補の育成ができる ・ 組織拡大、分割を前提としたマネージャの育成ができる つまり、人を育てていき、新規事業や組織変更に伴って、一番できる部下を送り出すことを前提としたマネジメントをしてくださいということです。安定した自分の城を作るのではなく、常に不確実である前提で会社全体が成長するように採用とチームを作ることに専念してください。 マネージャは新たに人を採用し、成長をプロデュースして、新たに送り出すことでBASEというサービスのドメイン知識や哲学を兼ね備えた人材が、新規事業や新しい組織のマネージャとして新しい活躍をするというループを描いていきたいと思っています。特に新人マネージャは、既存メンバーのいい兄貴、チームリーダーとしては積み上げた経験が使えるのですが、採用となると経験のない新しい取り組みになるので、時間の使い方として主体的に動けるようになるには時間がかかります。採用に対して、自分事かつ主体的に動けるようになって初めてマネージャとして一人前とみなされます。それはまた全体視点で事業を捉えられるようになり、未来を見据えるようになったという意味でもあります。 そして、よく大企業の新規事業で言われることとして、エースは温存され、そうでない人材が新規事業にあてがわれるという話があります。これはこれで大企業において若手がチャンスを得るという構図になっていると思いますが、当社のように年功序列ではなく若手をガンガン重用していきたい組織においては、なんなら一番できる人が抜けてしまうことを前提としたマネジメントを求めています。 例えば子会社のBASE BANK社を支えるプロダクトマネージャとテックリードは、元々、BASEの決済チームのど真ん中を支えていた若手メンバーでした。新規事業に手を上げてくれて、彼らは今、BASE BANKチームでいきいきと仕事をしていますが、そこでのチャレンジをまたBASEのチームにフィードバックしてもらいたいと思っています。そういったことの再現を今後もやっていきたいと思っています。 現状のエンジニア組織の課題 現状、Web技術に関しては、CTOとプリンシパルテックリードの2トップがサービスの最先端の進化をリードしています。しかし、増えゆくGMVを支えながら、機能性向上、プロダクト品質の向上等を行っていくにはとてもとても手が足りません。 こちらの記事 にある通り、来年以降、CakePHP2.xをなくしていくことをサービスを維持、成長させながら行うという難しいプロジェクトにも挑みたいです。おそらくDDD等のノウハウを活用して再設計をすることになると思いますが、それらを支えていく各分野のエキスパートであるテックリード候補やハイスキルエンジニア層、組織の作り手であるエンジニアリングマネージャ候補を募集していくことになります。 上のグレード表現で言うと、エンジニア組織をリードできるEx2以上の人たちを増やしながら、若手の有望株であるEx1候補を採用して、組織としてスケールさせていきたいです。そのためにもありとあらゆる方策を取って、社内のエンジニアのスキル向上はもちろんのこと、採用を推進していきたいと考えています。 もし、BASEの未来を作ることに興味を持っていただける方がいらっしゃったら是非お話しましょう。エンジニアとしての成長をチャレンジできる環境を用意したいと思っていますし、人材投資をできる環境は整っていますので、一緒に仕事をしましょう! binc.jp
ServiceDev所属、サーバサイドエンジニアの栗田です。 現在私は、ServiceDevのチームに所属し、ネットショップ作成サービス「BASE」及びショッピングアプリ「BASE」の機能開発を担当しています。 BASEでは主にQ毎にプロジェクトチームを編成し、チームで主体となって機能開発を行っていきます。 チームメンバー構成はプロジェクトの特性や規模により様々ですが、多くの場合、同じグループから1〜2名がプロジェクトにアサインされます。 今回はとある長期間プロジェクトで感じた事や・実際にこのように進めたよというところをサーバサイドエンジニアの視点から紹介したいと思います。 どんなプロジェクトだったか 今回紹介するプロジェクトは「BASE」の拡張機能である「BASE Apps」の1つである「商品オプション App」を開発するプロジェクトでした。 「商品オプション App」は商品にギフトラッピングやオーダーメイドで使えるオプションを設定できる拡張機能です。詳細は下記からご覧いただければと思います。 baseu.jp プロジェクトメンバー構成 プロジェクトマネージャ(PM) & ディレクター 1人 フロントエンドエンジニア 1人 サーバサイドエンジニア 3人 (開始 1人, 最終的に3人) ネイティブアプリエンジニア 2人 デザイナー 1人 キックオフからリリースまでの期間 10ヶ月ぐらいほど 私の立ち位置 サーバサイドエンジニアのまとめ役的な立ち位置でした。 初めはサーバサイドエンジニアは1人でしたが、最終的に3人に増員し 私は開発ディレクションをやりつつ、他のメンバーと共に開発をしていきました。 エンジニアリングマネージャ(EM)から私へ期待されていた事は 「とにかく不確実性を下げて、プロジェクトをコントロールできる状態にして欲しい」でした。 具体的には 日々の開発の進捗を把握して、プロジェクトメンバーやEMに共有すること 不確実な領域をどんどん触っていき想定外なことを少なくしていくこと 不安要素を取り除くため、部分的な本番化をしていき、また各フェーズのリリースの計画を建てること リリースに向けた現実的な進捗を把握して、EMと人員計画の相談をすること などを行いながらプロジェクトを進めていきました。 どんな特色のあるプロジェクトだったか 商品オプションは、無料・有料の商品オプションを商品に複数個紐付けられるという仕様で、今まで「BASE」では注文の価格の演算の概念が増えるという事例はほぼなく、注文の価格はあらゆる箇所に影響するので、サーバサイドエンジニアの私からすると「システムの全体に関わりかなりの工数がかかりそうだな?どうしようかな?」というのがプロジェクトが始まった当初に思っていた事でした。 実際に影響があったアプリケーションは社内用の管理画面やバッチ処理なども含めて9つほどありました。 リリースについては複数のフェーズがある事が当初よりわかっており デザインテーマ向け(ネットショップ作成サービス「BASE」のデザインテーマを作成していただいているディベロッパー向け) ショッピングアプリ「BASE」向け ネットショップ作成サービス「BASE」向け の3つのフェーズがある事が見えておりました。 それぞれにクリティカルパスが存在したので、タスクのボトルネックが発生しないようにプロジェクトを進める必要がありました。3つのフェーズの進行については プロジェクト内で週次で定例MTGを行い、PMが中心になって進捗確認をこまめに行い進めていきました。 見積もり・設計フェーズについて 以前からこの機能をリリースしたいという想いは社内にあり、要件はある程度固まっていました。 ので要件定義フェーズはあまりなく、見積もり・設計が始まりました。 今思えば、私はプロジェクト開始当初、入社して1年も経っていなかったので サーバーサイドのシステムの全体像は正直わからない所もありましたが、とりあえずやってみる事にしました。 見積もりの叩きを作成したのですが、規模も大きく、怪しい箇所も多いので自分1人で進めるのは危険だと判断して、EMに相談して1人のシニアエンジニアに見積もり・設計のサポート役としてアサインしてもらうことになりました。 そして、見積もり・設計がある程度進んだ所でチームレビュー・CTOレビューへの流れになりました。 設計レビューについては、同じチームの宮村が記載した記事がありますので、そちらをご覧いただければと想います。 devblog.thebase.in 余談ですがシニアエンジニアは予定していた育休のタイミングと被ってしまい、実装には一切関わらないこととなりました。ピンチ!w 開発初期フェーズについて 初期は1人で進めていましたが、少なく見積もっても6ヶ月以上かかりそうと見えており、1人でやるのは難しいとEMと共有認識があったので、EMに2人目のエンジニアをアサインしてもらうように動いてもらいました。 (BASEでは、以前はプロジェクトにサーバサイドエンジニアが1人でアサインされる事もあったのですが、最近はサービスの成長もあり、システムが複雑化していってるので、2人以上のアサインになることが多いです) 2人目のエンジニアのアサインを確保できた時は、ある程度プロジェクトも進んできたので、リリースターゲット月を決める必要がありました。特にどのQに収めるのかどうかは、BASEの開発組織として大きな関心事でした。 見積もりは終わっていたので、タスク一覧表はできていましたが正直、精度や抜け漏れがあるかどうか不安だったので、新しくアサインされたエンジニアと2人で時間をかけて全量確認する事にしました。 長期なプロジェクトだったので、ここで2人の目線を合わせる事が後々に響いていってとても大切だったと感じました。 開発フェーズに感じた事や・実際にこのように進めたこと 他のチームが動きやすいように、データの生成の流れに沿って開発を進める事が効率的だった。 一連の流れで開発できた方が開発の進捗も実感できるしフロントエンド・ネイティブアプリの開発がしやすくなります。 全部リファクタする訳にはいかないので、部分的に改修して先に改修とテストだけデプロイした。 嬉しい悲鳴で他のプロジェクトがリファクタとConflictする事もあった。逆に更に発生しないように積極的に本番化した。 サーバサイドエンジニアチームで日時で相談会、MTGをして相談しやすい環境を作った。 プロジェクト途中でコロナ期間へ入ったのでより頻度の高いコミュニケーションを取るようにした。 必要に応じてリモートではなく会社に集まった。 リリースターゲットに開発を収める事が難しいとわかったので、ラスト3ヶ月はEMと連携して3人目のサーバサイドエンジニアをアサインしてもらった。 ※ 前提:BASEでは並行して色々なプロジェクトが走っていていたり、負債が残っているコードも存在します。 QAテスト・リリースフェーズに感じた事や・実際にこのように進めたこと 品質が保てたものから、既存の不具合がでないようにガンガンデプロイしていった 全部で9つアプリケーションあったがコアとなるカートや決済の処理を除いて、ほぼ先出しでリリース前に本番化する事に成功した リリースによってデータが破壊的にならないようにして、いつでもリバートできるような計画をした QAテスト3つのフェーズがあったので、それぞれで必要な最小限を作成してQAテストを進めていった QAテストで必要なデータ一式をPMが用意してくれた為、開発でバタバタしていたが、効率に進める事ができた 3つのフェーズに分かれていたので、段階的に品質が上がっていき、不具合があった場合でも早期鎮火をする事ができた CTOとの本番化についての交渉をした BASEでは様々な事情があり、ステージング環境で複数日検証する事を許可しておりません 今回はリリースの規模と天秤にかけて特例をいただき、複数日検証をする事によって安全なリリースを可能にした リスクを分散させる為に各フェーズの機能の本番デプロイの日とユーザー公開日を分けた まとめ 今回10ヶ月と長いスパンでしたが、上記でお伝えしたような事を考えながらチーム開発をしていきました。 BASEにおける長期プロジェクトのチーム開発の雰囲気は伝わりましたでしょうか? 最後に長期間プロジェクトとなり辛い時もありましたが この機能をリリースして、多くのショップオーナーさんから声をいただき、無事に機能を届ける事ができて本当に良かったと感じました。
はじめまして。 BASE株式会社 SRE Groupに所属している富塚( @tomy103rider )です。 先日、弊社CTOが 「もうさばき切れない」アクセスが激増したECプラットフォームにおける負荷対策 https://devblog.thebase.in/entry/bsucon という記事を公開しました。 社内ではこのアクセス激増をきっかけに「サービスの監視をどうしていくか」「サービス/システムのアラートに対してのアクションはどうあるべきか」といったような監視に関する話題も改めて盛り上がっています。 そんな中でふと1年くらい前にBASE BANK 株式会社の東口 ( @hgsgtk )が社内で主催した「入門 監視」輪読会に参加したことを思い出し、その輪読会がどういう会だったかなど、改めて輪読会を振り返ってみようと思います。 「入門 監視」輪読会の目的は何だった? この輪読会を開催するにあたって主催者がしっかりと残していた社内ドキュメントがあり、そこには以下の3つの目的が書かれていました。 - オーナーズに安定的なサービスを提供したい - インフラ監視を理解する素地を形成して関心を強める - アプリケーション監視の素地を形成して関心を強める 「オーナーズのみなさんに安定的なサービスを提供したい」という強い思いを持ち、SRE Groupが主に対応しがちな監視という分野に、いわゆるバックエンドエンジニアも関心を持つ機会にしたかったということが挙げられていました。 どういう形式の輪読会だった? 週に1回、1時間、参加は自由(業務優先)、参加者は開発メンバーやSREメンバーやマネージャーもふらっと参加したりと、わいわいとした雰囲気の会でした。 日時 毎週木曜日 15:00〜16:00 進め方 全12章(付録含む)を各回で2章くらいをもくもく読む タイムスケジュール 30分:当日の対象章を読み、気づき・疑問を共有ドキュメントに書き留める 25分: 書き留めた気づき・疑問を共有・議論 5分:まとめ・次回対象の章を決めて解散 書籍 『O'Reilly 入門 監視 ――モダンなモニタリングのためのデザインパターン』( https://www.oreilly.co.jp/books/9784873118642/ ) www.oreilly.co.jp ※当時の実際の様子(こんなこともあろうかと撮っておいた写真) もくもく読んでいる時間は主催者が心地よい音楽を流してくれていました。こういう雰囲気や環境作りも充実感に繋がる大事なポイントなのだなと感じたのを覚えています。 輪読会から1年以上が経過して・・・ さて、ここまでは輪読会の様子をお伝えしましたが、「輪読会に参加していた人たちがその後何か監視に対する気持ちや行動に変化があったか」という点が一番知りたくなり、 Q. 1年前に実施した入門監視本の輪読会に参加して、その後、監視に対して意識や行動に変化はありましたか? という質問を参加していた人たちに投げかけ、それぞれの回答をまとめると以下のようになりました。 行動に変化があった 関係ありそうなアラートに対して何かしらアクションをするように心掛けるようになりました。 アプリケーション監視のパターンとして Health エンドポイントパターンを知り活用しました。 https://devblog.thebase.in/entry/2019/03/06/110000 Mackerelでのビジネス監視(とある数値の変化をチェック)を実際に入れてみました。 意識に変化があった Zabbixで監視システムを構築してきた経験があるので、すぐ同様のものを構築してしまいそうになるが、果たしてそれが企業にとって本当にいいことなのかどうかより強く考えるようになりました。 構造化ログにする重要性は、Elasticsearch/Kibanaで可視化する、とか、そこまでいわゆるバックエンドのエンジニアも自分でやると必要性が身にしみてくるなと最近思います。 それほど変わってないですが、アプリケーションエラー見直しを考えている中でエラー追跡も監視に入るかなと思っているので参考になったところはあるかもしれないです。 変化はなかった その後も監視に対して特に強いアクションをとれていないと思います。 実務でこの本を意識することは今までなかったと思います。 輪読会を途中離脱してしまい今も積ん読状態です! その後、何かしらアクションまで起こしている人が3割、意識に変化があった人が4割、特に変化はなかったと思っている人が3割くらいという結果でした。 まとめ この結果を見ると、輪読会の当初の目的である「関心を強める」という点では半数以上の参加者が何かしらの変化があったと(前向きに)捉えると有意義な会だったのではないでしょうか。 また、私個人としては、過去に他社で運用していた日々のインフラ運用経験から監視について色々知ったつもりになっていましたが、改めて初心にかえって書籍や他のメンバーから学んだことが多かったり、特に「ユーザ視点での監視」の大切さの意識が強くなったのは収穫でした。 とはいえ、今後より良いサービスを提供していくためには、監視や運用についてもまだまだ改善する必要があるというのが現実の組織課題としてあります。BASEのエンジニア組織では監視や運用の面についても更に改善/強化していく計画があり、このあたりの話題は今後計画が進んでいった際に記事が上がるかと思いますのでお楽しみに!
こんにちは。BASE BANK株式会社 Dev Division にて、 Software Developer をしている永野( @glassmonekey )です。 弊社ではAWS Lambdaを活用する機会が増えまして、 最近メジャーアップデートのあった「AWS SAM CLI」を使ってリリースフローの改善にチャレンジしてみました。 そこで、samコマンドで作成したサンプルプロジェクトをローカルで実行しデプロイする方法を紹介します。それに加えて、現状BASE BANKチームで行っている代表的な運用設定をご紹介します。 今回記事作成に際して、 サンプルプログラム を用意しているのでもしよければ手元でご確認ください。 なお、今回LambdaにはGoを採用しました。検証に使用した環境は以下の通りです。 macOS: 10.15.x (Catalina) SAM CLI: version 1.2.0 AWS CLI: aws-cli/2.0.50 Python/3.7.4 Darwin/19.6.0 exe/x86_64 Go: go1.15.2 darwin/amd64 SAM CLIとは SAMとは Serverless Application Model の略称で、 AWS Lambda のデプロイ管理に使われるツールで、 ローカル上のデバッグ 、 ビルド 、 デプロイ をサポートします。 公式のアナウンス によると7月に バージョン1 がリリースされました。 画像は AWS SAM Local(ベータ版) – サーバーレスアプリケーションをローカルに構築してテストする より引用しました。 またこの愛らしいリスのキャラクターは 公式の説明 によると "SAM the Squirrel (リスの SAM)" について SAM the Squirrel は、サーバーレスアプリケーションで使用されるリソースを定義するモデルで、AWS Serverless Application Model (AWS SAM) から名付けられました。SAM は、AWS ユーザーがサーバーレスアプリケーションを効果的かつ簡単に構築できるよう、ツリー (木) の中で居心地のよい生活を後にしました。 とのことで、なんだか愛着が湧いてきますね。 環境構築 samコマンドを実行するために必要な設定をしておきます。 1. AWS SAM CLIのインストール 最初に AWS SAM を動かすためのCLIをインストールします。 macOSの場合は 公式 に紹介されている通り、 Homebrew を使って簡単にインストールすることができます。 $ brew tap aws/tap $ brew install aws-sam-cli または、 公式で提供されているpipパッケージ を利用する方法もあります。 CI環境などでbrewを入れたくない場合はこちらがおすすめです。 $ pip install aws-sam-cli sam --version でバージョンが返ってきたらインストール成功です。 $ sam --version SAM CLI, version 1.2.0 2. AWS CLIのインストール 直接SAMの実行には関係ありませんが、動作確認などで必要になってくるのでこちらも 公式 の方法に従って入れておきます。 $ curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg" $ sudo installer -pkg AWSCLIV2.pkg -target / こちらも aws --version で結果が返ってきたらインストール完了です。 $ aws --version aws-cli/2.0.50 Python/3.7.4 Darwin/19.6.0 exe/x86_64 3. sam実行ユーザーの作成 AWSコンソールなどからsamコマンドを実行するユーザーを追加しておきます。 必要なポリシーなどは後ほど解説するので、この段階では AdministratorAccess を設定しておきます。 また、cliからも触れるように設定しておきます。 aws configure 4. dockerをインストールしておく ローカル実行を行う場合のみ、docker daemonが動いてないといけないのでインストールをしておいてください。 docker for mac は こちら からインストールできます。 SAMを使った開発入門 まず最初に公式が提供してくれるHello, Worldなapiをsamを使ってデプロイすることをためしてみます。 1. プロジェクトを作成する sam init を行うとsam用のプロジェクトの初期化を行うことができます。今回はサンプルプログラムを流用するので対話型の設定を行いますが、既にディレクトリ構成などが完成している場合は不要なフローです。 sam init 今回は入門用のAPIをぱぱっと作るので1を選びます。 Which template source would you like to use? 1 - AWS Quick Start Templates 2 - Custom Template Location Goを使うので4を選びます。 PHPも選択肢に来ないかなー Which runtime would you like to use? 1 - nodejs12.x 2 - python3.8 3 - ruby2.7 4 - go1.x 5 - java11 6 - dotnetcore3.1 7 - nodejs10.x 8 - python3.7 9 - python3.6 10 - python2.7 11 - ruby2.5 12 - java8.al2 13 - java8 プロジェクト名はデフォルトの sam-app のままで行います。 Project name [sam-app]: 今回は単純なapiを作成するので1を選びます。 AWS quick start application templates: 1 - Hello World Example 2 - Step Functions Sample App (Stock Trader) すると プロジェクトテンプレートもデフォルトの https://github.com/aws/aws-sam-cli-app-templates を使用した形でプロジェクトが初期化されています。 ├── Makefile <-- Make to automate build ├── README.md <-- This instructions file ├── hello-world <-- Source code for a lambda function │ ├── main.go <-- Lambda function code │ └── main_test.go <-- Unit tests └── template.yaml AWS SAM としてLambdaの構成管理しているのは template.yml になります。 これはCloud Formationのラッパーとなっており、基本的な文法は Cloud Formation に準拠します。 また、内容に関しての詳細は SAMのドキュメント や Cloud Formationのテンプレートリファレンス を一読することをおすすめします。 2. ローカルで実行してみる。 2.1 ビルド実行 実行の前にビルドをしてみます。 $ sam build 実行後に下記のようにbundle含めてデプロイ用のファイル群が作成される。 ├── .aws-sam │ └── build │ ├── HelloWorldFunction │ │ └── hello-world(バイナリ) │ └── template.yaml 生成内容の設定に関してはtemplate.ymlに記述されている CodeUri: hello-world/ Handler: hello-world と対応しているので、生成したいhandler名やソースディレクトリを変更したい場合はここを変更します。 2.2 ローカル実行 次にローカルで実行を行う sam local invoke を実行します。 するとAWSリソースを介さずにローカルで完結して結果が返ってくるはずです。 $ sam local invoke {"statusCode":200,"headers":null,"multiValueHeaders":null,"body":"Hello, $実行環境IPアドレス\n"} また -eオプションをつけることでイベント情報のjsonを渡すことも可能です。 特にAPIコール以外(SQS経由など)で呼び出されるLambdaの場合だとデバッグ用のイベントを都度作成するのも手間だったりするので、イベント情報も極力Git管理しておくことをおすすめします。 副次的効果として、チーム内にどのようなイベントのやりとりが発生するかの共有にもつながります。 $ sam local invoke -e path/to/event.json` なお、雛形は sam local generate-event $リソース名 $API名 で作成することができます。 例えば、 SQSのreceiveMessage のイベントのJsonは下記のような形式となります。 $ sam local generate-event sqs receive-message { "Records": [ { "messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78", "receiptHandle": "MessageReceiptHandle", "body": "Hello from SQS!", "attributes": { "ApproximateReceiveCount": "1", "SentTimestamp": "1523232000000", "SenderId": "123456789012", "ApproximateFirstReceiveTimestamp": "1523232000001" }, "messageAttributes": {}, "md5OfBody": "7b270e59b47ff90a553787216d55d91d", "eventSource": "aws:sqs", "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:MyQueue", "awsRegion": "us-east-1" } ] } 3. デプロイしてみる。 3.1 デプロイファイルの作成 初回デプロイの場合は --guided オプションを使用して対話形式でデプロイ設定ファイル samconfig.toml を作ります。 $ sam deploy --guided Stack Name [sam-app]: AWS Region [us-east-1]: ap-northeast-1 #Shows you resources changes to be deployed and require a 'Y' to initiate deploy Confirm changes before deploy [y/N]: n #SAM needs permission to be able to create roles to connect to the resources in your template Allow SAM CLI IAM role creation [Y/n]: Y HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y Save arguments to samconfig.toml [Y/n]: y 各項目に関してですが Stack Name … 内部的に使用するcloud formationのstack名。samを実行するユーザーはこのstack名に関しての権限が不足しているとデプロイに失敗するので、必要なので注意が必要です。最低限以下の権限が必要なことは確認しています。 "cloudformation:DescribeStackEvents", "cloudformation:CreateChangeSet", "cloudformation:DescribeChangeSet", "cloudformation:ExecuteChangeSet", "cloudformation:GetTemplateSummary", "cloudformation:DescribeStacks", Confirm changes before deploy: deploy前に確認を必要とするか。CI上で動かす想定なら n にしておくと良いです。 Allow SAM CLI IAM role creation: デプロイするlambdaに付与するロールを自動作成するか。自動作成する場合は余計な権限もつくことがあるので要注意です。 Save arguments to samconfig.toml: y ならこの対話型操作の設定内容を保存します。 すると以下のようなファイルが生成されます。次回以降の sam deploy 実行時はこの設定ファイルを見てくれるので、必要に応じて設定を書き換えると良いでしょう。 version = 0.1 [default] [default.deploy] [default.deploy.parameters] stack_name = "sam-app" s3_bucket = "aws-sam-cli-managed-default-samclisourcebucket-6qa86tkchc0g" s3_prefix = "sam-app" region = "ap-northeast-1" capabilities = "CAPABILITY_IAM" なお、 capabilities で指定できる値は以下のいずれかを設定することができます。 CAPABILITY_IAM CAPABILITY_NAMED_IAM CAPABILITY_RESOURCE_POLICY CAPABILITY_AUTO_EXPAND 詳細は AWS Serverless Application Repository開発者ガイド に記載されていますが、 template.yml 管理下のリソースの複雑さで設定の切り替えが必要なようです。Iamロールをtemplate.ymlで管理する場合などのケースでは要注意です。 今回はシンプルにlambdaのみのリソース管理化なのでデフォルトの CAPABILITY_IAM で良いようです。 3.2デプロイの実行 samconfig.toml が存在していれば sam deploy でデプロイされるはずです。 デプロイ結果のスクショ 無事にデプロイされました 👍 lambdaのコンソールを見に行くとAPI Gatewayの項目からエンドポイントが確認できるはずです。 コンソール画面を確認 確認できたエンドポイントを仮に https://hogehoge.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/ とすると結果が返ってくれば成功です。 $ curl https://hogehoge.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/ {"statusCode":200,"headers":null,"multiValueHeaders":null,"body":"Hello, $実行環境IPアドレス\n"} エンドポイントにcurlを投げてみるとローカル実行と同じようなレスポンスが返ってくるはずです。 しかし、ローカル実行時とは内部的にはネットワーク構成が異なっているので返ってくるIPは違います。 その他設定項目について 次に現状BASE BANKチームで行っている運用設定の一部をご紹介します。 環境ごとの設定の切り替え リソースのarnの切り替えなどを環境ごとに切り替えたい設定を外部から注入できるようにします。 今回はシンプルに APP_NAME と ENV を環境変数経由で受け取り表示するように書き換えてみます。 name := os.Getenv("APP_NAME") env := os.Getenv("ENV") return events.APIGatewayProxyResponse{ Body: fmt.Sprintf("%s@%s", name, env), StatusCode: 200, }, nil この環境変数を受け取るために、以下のようにトップレベルに Parameters を追加し、Functionリソース配下に Environment.Variables を追加します。 ここの意味としてはtemplateがパラメータとして受け取った値は環境変数としてFunctionリソースに受け渡すという形になります。 !Ref は Cloud Forrmationの関数 で、セクション間の参照を表します。 Parameters: ENV: Type: String AppName: Type: String Resources: HelloWorldFunction: ~~~ 省略 ~~~~ Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object Variables: ENV: !Ref ENV APP_NAME: !Ref AppName このようにしておくと実行時に Key=Value の形式でパラメータを渡すことができます。 $ sam local invoke \ --parameter-overrides 'ENV=local AppName=Hello' $ sam deploy \ --parameter-overrides 'ENV=dev AppName=Hello' 値を渡す方法は他にもあったりはしますが、ローカル実行とdeploy時の対照が取れているのところがおすすめなポイントです。 若干ハマったポイントとしてパラメータキーには _ などの記号を含むパラメータは読み込んでくれないようで APP_NAME ではなく AppName としています。 環境ごとのデプロイ設定 特にCI上ので実行を加味した場合、環境変数の注入用の parameter-overrides の他にも設定しておきたいパラメータがあります。 $ sam deploy \ --s3-bucket dev-sam-stacks \ --parameter-overrides 'ENV=dev AppName=Hello' \ --force-upload \ --no-fail-on-empty-changeset s3-bucket : cloud formationのアップロード先のバケット。基本的に環境ごとで、切り替えることになる思うので samconfig.toml から記述を消し、パラメータで受け取れるようにしておきます。 force-upload: ソースコードの変更を伴わないLambdaの設定値のみの変更の際に、正しくデプロイされないケースがあったのでフラグを追加しておきます。 no-fail-on-empty-changeset: 内容の変更がなくてもエラーにならないフラグです。CIで動かす場合を考えると、変更がないときも正常系と考えて良いはずなのでこのフラグを立てておきます。 Makefileの用意 以上を踏まえて環境ごとの設定に切り替えはあらかじめMakefile内に記述しておきます。 Makefileの用意を用意しておくと、チーム内にコマンドの共有ができるのと、CI 上で何かあったときに手元での検証がしやすくなるので便利です。 .PHONY: build test local-run local-up dev-deploy build: sam build # テストの実行 test: @cd ./hello-world/ && \ go test -v ./... # ローカルでlambdaを実行する local-run: build sam local invoke \ --parameter-overrides 'ENV=local AppName=Hello' # apiとして起動する場合 local-up: build sam local start-api \ --parameter-overrides 'ENV=local AppName=Hello' # デプロイする dev-deploy: build sam deploy \ --s3-bucket sam-app-stack \ --parameter-overrides 'ENV=dev AppName=Hello' \ --force-upload \ --no-fail-on-empty-changeset まとめ AWS SAM を使った入門と運用設定の一部を紹介しました。 もしこれから AWS SAM を使用される方々の助けになれれば幸いです。 従来の都度deployして確かめる方法だとどうしても1回の検証に時間がかかってしまい、Lambdaに手を出しづらい状況下だったので、今後の量産体制に無事に繋げられそうです。 バージョン1 になったことにより大分扱いやすくなった印象をうけました。 また、今回は時間の関係で導入まではできてないのですが local stack を使えばAWSリソース依存のテストもできそうなので、機会があればこちらも挑戦してみたいと思います。
こんにちは。BASE BANK 株式会社 Dev Division にて、 Software Developer をしている東口( @hgsgtk )です。 XP祭り2020 XP祭り2020 は、XPJUG(日本 XP ユーザーグループ)主催のベントです。2002 年から毎年行われていて、今年 2020 年は、9 月 19 日にオンライン開催されました。 xpjug.com 今回自分は初参加でした。LT 参加で申し込んでいたので、聴講者 && LT 発表の両方の視点で、参加レポートを書き連ねていきます。 TL;DR XP 祭り 2020 に参加しました 聴講レポート:『近代史とアジャイル』が面白かった 「時を超えたプログラミングの道 "XP はソーシャルチェンジである"」という発表をしました 聴講レポート:『近代史とアジャイル』が面白かった 聴講させていただいた内容、全て面白かったのですが、個人的に好きだった私の個人的ベストセッションが、Fumihiko Kinoshita さんの『近代史とアジャイル』というトークでした。 終盤のまとめスライドを引用しておりますが、2001 年のアジャイルマニュフェスト以前、にこれだけ大きな年表が出てくる話を聞いたことありませんでした。 『近代史とアジャイル』のスライドから引用 個人的な興味で、最近ソフトウェア自体ではなくて、哲学・社会心理学系っておもしろいな〜と浅く見回っていて、見回ってみると、ソフトウェア設計などの影にカント哲学やデカルト哲学が出てきます。 それらが歴史年表となって、アジャイルマニュフェストにいたる一枚のスライドに収められた光景に感動しました(そしてこの感動の末、もともと用意していた LT スライドをゴミ箱に入れて作り直し始めました)。 LT発表: 時を超えたプログラミングの道 "XPはソーシャルチェンジである" 当日の Lightning Talk 発表者は、 10 人で 9 番目でした。 実は「当日このテーマにしよう」と決め、事前に作っていた資料は捨て作り直しました。きっかけは、聴講レポートにあげたセッションを聞いて、昼休みに、改めて『Kent Beck, Cynthia Andres. エクストリームプログラミング』(以降、XP 白本と呼称します)を読み返したことでした。 www.amazon.co.jp XP まつりの熱を帯びた状態で読み返すと、「あぁ『XP はソーシャルチェンジである』というフレーズはこんな想いが込められていたのか...!!!」と、勝手に感動し、誰かに話したい気持ちが溢れた結果がこちらの資料でした。 "XP はソーシャルチェンジである" という言葉は 2 つの意思が凝縮されていると捉えました(それだけではないとも思っています)。 何からチェンジするのか = テイラー主義的組織構造からの脱却 どこを目指すのか = 生き生きと働くこと ひとつは、ソフトウェア開発におけるテイラー主義的社会構造からの脱却という意思。XP 白本には、「第 18 章テイラー主義とソフトウェア」という章があります。そこでは、テイラー主義がもたらす社会構造について次のように断言しています。 ソフトウェア開発で問題となるのは、テイラー主義に伴う仕事の社会構造だ。テイラーが提唱した「時間・動作研究」の儀式や道具こそなくなっているが、我々は無意識にこの社会構造を継承しているのである。 その社会構造は、ソフトウェア開発にまったく適していない。 そして、どこを目指したのか、という点についてですが、XP 白本には、「第 23 章時を超えたプログラミングの道」と言う章があります。「時を超えた」とくると、ソフトウェアエンジニアの頭によぎるのは、クリストファー・アレグザンダー氏の著書『時を超えた建設の道』です(主語が大きい自覚はちゃんとあります)。 www.amazon.co.jp これを読んだ Kent Beck 氏や Ward Cunniungham 氏たちは、クリストファー・アレグザンダー氏のパタン・ランゲージなどの考え方をソフトウェアを適用することを試み始め、現在のソフトウェア開発のコミュニティに馴染み深いデザイン・パターンや XP などにつながっていきます。 その過程で何を目指したのかは、この「第 23 章 時を超えたプログラミングの道」と「第 25 章結論」を読んでいくと、XP の目的・目指したいものが克明に書かれています。 XP白本 第25章 結論 から抜粋 "XP はソーシャルチェンジである" という何やらとらえどころの難しいフレーズも、XP をソフトウェア史上の「点」ではなく「線」で捉えると、その輪郭が浮き彫りになってくるような気がします。 ちなみに、すでに発表しようとして捨てた内容は、以前の開発チームブログに公開しているものでした。「抽象的な話より具体的な『今どうしたらいいのよが知りたいのよ』」派のあなたにおすすめです。 devblog.thebase.in また、最初は XP 白本の書評ブログとして書いていました。発表資料の内容 + 脱線(多め)になっています。 note.com 発表内容が、「だれかに話したい!」と言う衝動に駆られたものだったので、どれだけこの個人的な感動が伝わるだろうか、と思ったのですが、コミュニティが暖かく感謝感謝...。 【メモ】XP祭り2020 @hgsgtk さんのLT「時を超えたプログラミングの道 ”XPはソーシャルチェンジである” を読み直す」 とっても良かったです! https://t.co/vjyuaVFPRs #xpjug #ChistopherAlexander #Taylor pic.twitter.com/uND3V0A4Ti — Akapon (@Akapon2010) September 19, 2020 ペアデザインを始める過程で「XPはソーシャルチェンジである」という言葉を知って、ぼやっとしか分かっていなかったけれど、急にくっきりした感じある https://t.co/XBHjZHegf6 — Takahiro Hayashi / ぴーや (@taka_piya) September 19, 2020 この発表エモい。広島の河川景観は(原爆スラムを除けば)、まさに市民との対話によって形作られていったことを思い出す。計画プロセスの民主化によって生み出された芝生が広がる護岸は散歩しててとても気持ち良い場所になった。ソフトウェア開発もかくありたいよなと思う。 https://t.co/5IUwmvpNFq pic.twitter.com/P5XmzRdjap — hodagi (@hodahgi) September 19, 2020 建築の仕事からのアナロジーがソフトウェア開発に活きてくるの面白い🤔 https://t.co/5oTZP3oRz4 — Morito Ikeda (@_moricho_) September 19, 2020 XPまつり 2020 スタッフの方々へ謝辞 XP まつり 2020 開催ありがとうございました。昨今のコロナ禍で、Discord と Zoom を駆使したオンラインとなりましたが、Discord の盛り上がりもあって、XP 祭りの熱にしっかり 1 日巻き込まれて楽しい時間になりました。 この場を借りて御礼申し上げます。 おわりに そういえば、最近 @seike460 さんが配信されている podcast #46fm にて、関連話(デザイン・パターン起点ですが)をしていました。 #46fm Podcastを公開しました! 3回目は @hgsgtk さんをお招きしました! 46fm ep.3 「ISUCON10予選、パタン・ランゲージ、Go コーディングリーディング会、社内の小さなカイゼン @hgsgtk 」 https://t.co/XOUNKssLfq — せいけしろー (@seike460) September 19, 2020 そちらももし興味がありましたら(初めてラジオ形式で発音しているので日本語がカタコトですがご了承を...)。
前書き こんにちは、BASEのフロントエンドチームでエンジニアリングマネージャーをやっている松原( @simezi9 )です BASEではフロントエンドエンジニアの積極採用を行っています。 その過程で、面接を受けに来られた方によく「BASEはVueとTSを採用しているとのことですが、相性がいまいちじゃないですか?なんでVue+TSにしてるんですか?」 という感じの質問をいただくことがあります。 この記事は、そんなBASEのフロントエンドにおける、技術・・・というよりもVue.jsに対するスタンスについて嘘偽りなく答えてみよう、という記事になります なぜVueを採用したのか、その後 過去にも「 次世代の管理画面を作るフロントエンドの取り組み 」というエントリでVueを採用した経緯には軽くご紹介させていただきました。 それは端的に言えば「HTML/CSSを書いてきたデザイナー陣にも見た目がとっつきやすい」SFC、ひいてはVueの優れたインターフェイスによるものでした。 同時に静的検査による安定した開発体験を得られるTypeScriptを導入し、その力をフルに活かすためにVuexの採用はせず、 自前でstoreを用意する、という選択肢を取りました。 この路線は今に至るまで有効に機能していて、上記の記事で取り上げた「次世代管理画面」へのリプレースは主要な機能ではおおよそ完了し、 普段の開発業務でもVueもしくはTSのコードを書く時間が大半を占めるようになっています。 選択の評価 当時Vue.jsを採用したことは今でも正解であったと思っています。BASEでは二年前(2018年)時点では明確なフロントエンドを専任とする組織はなく、 フロントエンドエンジニアという肩書きを持ってその領域を専門的に担当するメンバーもほぼ不在でした。 技術をリプレースする際の心理的な抵抗感を最小限にして開発を前に進める、という目的は満たせましたし、機能的な不満点も現時点では特にありません。 そして、リプレースが進む中で独立したフロントエンドチームができ、 2018年度末には3名しかいなかったメンバーも今や9人、入社予定者を含めれば10人というチームに育ってきました。 実は、今のメンバーでもう一度リプレースを立ち上げるとしたらもしかしたらVue.jsは選ばないかもしれません。 それは何故かといいますと、「Vueを積極的に選ぶ理由が現時点ではなくなってしまったから」という一点によるものです。 最初にVue.jsを選定した際にはデザイナーが取り組みやすいことが大きな選定理由になりましたが、 BASEのフロントエンドチームが大きく成長し、きっちりとした設計(DDDやクリーンアーキテクチャのエッセンス・概念の導入・・・etc)、コードベースが積み上がっていくにつれて、フロントエンドのソースコードはデザイナーの手を離れフロントエンドエンジニアの持ち物に移行していきました。 それ自体はいいことでも悪いことでもなく、あくまでBASEの分業体制がそうなったという話です(デザイナーもコード書いていける方がいい、という話も勿論あります)。 ただ、そうなった場合に先述のSFCの親しみやすさはもはやそれほどメリットではありません。 むしろエンジニアがフロントエンドのコードを書くときによりベターな選択肢は何か?という点がポイントになります。 そうなったときにTSが半公式的にサポートしているReactは非常に有力な選択肢となります。 VueのTS及び型へのサポートは徐々に進化しており、来たるVue3へのメジャーバージョンアップで、最大の課題であったコンポーネントのpropsに型による制約を付けづらい問題もかなり解消されそうではありますが、 それでもReactとTSの親和性を10とすればVueとTSの現状の親和性は7か8(あくまで個人的な印象値)程度ではないかなと思います。 VueでJSXを採用することでより親和性を高めることも可能ですが、JSXでバリバリVueのコードを描くなら最初からReactを選んでおけばいい、という話でもあります。 またVue3へのアップデートの過程で、メジャーアップデートのアナウンスが成されてからもなかなかリリースが進展することなく、 結果的に多くの破壊的変更を伴うことが予測されるビッグバンリリースになりそうである、という点で今後のVueの開発サイクルに対して若干の不安がある面もあります。 ただし、Vueのよく練られたAPIや開発体験、NuxtやVue CLIなどのエコシステムは現時点でも十分に魅力的ですし、現時点ですでに本格的な採用に十分耐えられるものであるとも思っています。 少なくともあと数年は、Vueで書かれている部分をわざわざ別のフレームワークで書き直そうというような話にはならないと思っていますし、 アップデートに対する追従は積極的に行っていく予定です。 最後に 技術選定において判断軸はいろいろあるかと思いますが、BASEのフロントエンドにおいては特にVueに強くベットしていこうというわけではなく、 その時その時で社内環境、トレンドなどを総合的に判断して選定を行うことになると思います。 実際に社内ではコア機能のリプレースにWeb Componentsを活用したりNext.js(React)を利用した領域が生まれようとしています。 今後も新規プロダクトに関してはReact採用の機運はどんどんと高まっていくかと思います。 個人的な印象ではVueもReactも目に見えるUIを分解して、コンポーネントとして構築し直す感覚そのものは非常に近いものがあると思っていて、 両者のエッセンスの違いを理解してどちらも書けるということが、今後のフロントエンドエンジニアには当たり前のように求められていくのではないかと思っていますし、 BASEのフロントエンドエンジニアにおいても、どっちも書けて当たり前、という状態をちゃんと作っていきたいと思っています。 過去のBASEのフロントエンドの記事や登壇では基本的にVueの話をしてきましたので、 採用の場でも、React/Angularしか経験ないので〜というようなお話をいただく事も多々ありますが、 実のところ採用の場ではどのフレームワークが得意か、経験豊富かというのはそれほど重視していない点でもあります。 面接でもどちらかというとWebアプリケーション全体に対する知識(セキュリティ、ネットワークなども含む)や、プログラミングの基礎力・設計力などをお聞きしていることが多いです。 カジュアル面接という形で気軽に会社や現場の紹介をさせていただく場もご用意していますので、興味のある方はぜひ声をかけていただければと思います 採用情報はこちらから
基盤チーム所属の沖中( @okinaka )です。 「リファクタリング」という言葉、エンジニアのみなさんならご存知でしょう。 システムの振る舞いを変えずに内部を改善することを指す言葉です。 一般的に、コードの修正を指すことがほとんどですが、今回はデータベース設計のリファクタリングについてお話ししたいと思います。 絶版になってしまいましたが、 データベース・リファクタリング という書籍に様々な手法が紹介されていて参考になります。英語で良ければ 原書 はまだ入手可能ですね。 データベース・リファクタリング 作者: スコット W アンブラー , ピラモド・サダラージ 発売日: 2008/03/26 メディア: 単行本 Refactoring Databases: Evolutionary Database Design (Addison-Wesley Signature Series (Fowler)) (English Edition) 作者: Ambler, Scott W. , Sadalage, Pramod J. 発売日: 2006/03/03 メディア: Kindle版 商品並び替えの問題 弊社が運営する「 BASE 」というサービスは、無料でかんたんにネットショップを開設できるサービスです。Webサービスの他に、購入者向けショッピングアプリ「 BASE 」、ショップオーナー向けのショップ運営管理アプリ「BASE Creator」、外部システムとの連携のための BASE API なども提供しています。 ショップに商品を陳列する際の並び順は重要な情報です。並び順の情報は、 システムのいたるところで参照されています。 商品の並び順を管理している商品テーブルは、在庫管理などにも用いられるため頻繁に更新がかかるテーブルでした。 商品の並び順は、ショップごとに先頭を「1」として降順に番号がふられています。例えば、新規登録した商品を一番先頭に持っていきたい場合、他の商品の並び順も全て更新してあげる必要があります。 多くの商品をかかえるショップが管理画面などで商品を追加すると、大量の商品の並び順を更新する操作が行われるため、1つのテーブルに書き込みが集中してしまい、負荷が問題になっていました。 リファクタリングの方針 データベース・リファクタリング本で言うところの「テーブルの分割」を行いました。 並び順のデータを別テーブルで管理することで、書き込みを分散することができます。代わりにテーブルを JOIN するようにソースコードの修正が必要になります。 改善前 改善後 商品テーブル 商品id 商品名 : 並び順 商品テーブル 商品id 商品名 : 商品並び順テーブル 商品id 並び順 リファクタリングの流れ 以下の順で実施しました。 前準備 商品の並び順を管理する新しいテーブルを追加 商品テーブルと並び順のテーブルの値を同期 既存の並び順を新しいテーブルにインポート 修正したソースコードのリリース(複数回) 並び順を参照するコードを修正 並び順を更新するコードを修正 後処理 商品テーブルと並び順テーブルの同期を停止 移行期間中はトリガーで同期 ソースコードの修正は一人で作業するには広範囲で、全てを把握できているわけではありませんでした。 このまま一気に差し替えはリスクがあると判断し、サービス稼働中に無停止で段階的にリリースするために移行期間を設けました。 移行期間中は、商品テーブルと並び順のテーブルの値を同期する必要があり、 今回は、データベースのトリガーを利用することにしました。 トリガーとは、テーブルに対して INSERT / UPDATE / DELETE などを契機に処理を実行できるデータベースの機能です。環境や設定によっては利用できないこともあるのですが、幸い BASE のデータベースである Aurora は MySQL 互換ですので、利用することが可能でした。 以下にトリガーの例を示します。 商品テーブル (items) が INSERT された際に、並び順テーブル (item_list_orders) に内容を反映させています。 DELIMITER | CREATE TRIGGER item_list_orders_insert AFTER INSERT ON items FOR EACH ROW BEGIN IF NEW.list_order IS NOT NULL THEN INSERT INTO item_list_orders (item_id, list_order) VALUES (NEW.id, NEW.list_order); END IF ; END ; | DELIMITER ; 実際にやってみて データベースのエキスパートの方にも協力いただく必要はあったのですが、コードの修正作業は一人でできました。 移行期間を設けたことで、1つのリリースを影響範囲を極限まで絞り込んだことで動作確認しやすくなりました。 修正を一気にリリースしたい誘惑に抗いつつ、地道に作業をすすめていきました。 また、リファクタリングに欠かせない自動テストで動作に問題がないことを常に確認できました。 おかげさまで、大きなトラブルもなくリリースできました 🎉 (懸案だった更新のスループットも大幅に改善されたとのこと) おわりに データベースのリファクタリングは、正しい手順に沿って行えば、時間はかかりますが技術的には難しいことはありませんでした。 ミスした際の影響範囲の大きさから敬遠されがちですが、積極的にやる価値はあるのではないかと思いました。
BASE株式会社取締役 EVP of Development / PAY株式会社取締役 / BASE BANK株式会社マネージャのえふしんです。 新型コロナによる非常事態宣言下で起きたことについては、大変勉強をさせていただきました。 非常事態宣言下の巣ごもり消費、リアル店舗等でご活躍されている事業者様のEC利用が急増する中で、BASEにおいても例外ではなく、サービスに訪れるトラフィック急増、4月から5月の頭にかけては、サービスの安定性にも影響が出てしまうという状況が発生していました。 その中で起きていた一つの事象を解決した件が以下のCTOによる記事です。 devblog.thebase.in この記事はCTOやSREチームやWebアプリケーションのエンジニアの活躍で、負荷急増の問題解決をした一つの事例となります。 この対策を通じて、改めて認識したことがあります。 それは、 BASEに訪れるすべてのトラフィックを適切に受け止めて、適切に決済を完了させるという使命がこのサービスにはある ということでした。これがすべてのショップ、すべての購入者からの期待であり、その期待に応え続けることがサービスが成長するという意味です。 そんなのWebサービスなんだから当たり前だろ?と思うかもしれません。しかし、非常事態宣言下でのアクセス急増は、もし新型コロナがなかった場合に順調に成長した数年後の未来が突如やってきたというものでした。それだけ急速なDXが進んだという理解をしています。 その中で、ここから数年後の未来を迎えるために、今後、将来に渡ってサービスを改善し続けることの重要性を改めて感じることとなりました。そこには単純にAWSのインスタンス数をスケールアウトし、Auroraのインスタンススペックを上げるだけでは済まない未来が見えてしまったわけです。 PHPを使い続けていく意味 我々が提供しているBASEは、2012年に開発されたPHP + CakePHP2.x系で動いているコードを下地に機能追加と機能改善をし続けています。 僕がCTOだった時、そして、現CTOの川口に技術選定を委ねている現状においても、サービスの改善においてPHPから開発言語を変えるという選択は今のところ考えていません。 PHPを使う理由としては、 BASEの現状よりも高い成長を実現している他社実績を勘案するに、まだまだ成長に対するポテンシャルを兼ね備えている言語処理系である。 PHPという開発言語自身が、他の言語の良いところも取り入れて進化し続けている 少なくとも現状のWebのサーバサイド言語において、開発生産性も含めて、他の言語にまるっと切り替えてでも実現したい代替技術が見つかっていないというのが最大の理由です。 もちろん今後のスケーラビリティの実現に際してPHPでは無理ということになったら全然違う言語に変えるかもしれません。また、マイクロサービスとして新機能や新規事業において適材適所で様々な技術を追加採用していき、相対的にPHPの活用度が下がることはありえます。 BASE BANKチームはGo言語でサービスを開発していますし、データサイエンティストで構成されるData Strategyチームは機械学習で問題解決するために、Python、AWSやGCPを生かしています。 BASEの決済トランザクションを処理し、マイクロサービスの関係性になっているPAY.JPを運営するチームは、Pythonで書かれたWebサービスです。また、BASEチームにおいてもリリースはしていないもののGo言語で書かれたプロダクトも存在しています。BASEのフロントエンドは、Vue.jsやReactを活用したアーキテクチャへの変化も進んでいます。 会社全体としては特定の開発言語にこだわらない一方で、適材適所の技術選択にはこだわっていると表現するのが正しいでしょうか。 また、AWSやGCP、外部クラウドサービスとのAPI連携によって、相対的に、これまでPHPが担っていた機能や役割は少しずつ切り取られています。 これは時代の変化にあわせた適材適所化であり、サーバサイド言語はグルー(糊)としての役割が強くなります。フロントエンド、バックエンドに携わるエンジニアは、自動的に幅広い技術領域でのシステム構築力が求められていくと考えています。 最近はバックエンドのエンジニアにも、当然のようにフロントエンドのコードを書いてもらうための時間投資をしています。フロントエンドチームがきれいに整備したフロントエンド基盤をアプリケーションとして活かすコードを書くところは、当社のバックエンドエンジニアの当たり前のスキルだと考えています。逆にフロントエンドエンジニアにとってのサーバサイドもしかり、できる限り個々のエンジニアの心のなかにある聖域は無くしていきたいです。 雑に言えば、Webエンジニアであればフロントエンドからインフラまで全部見えるようになってという想いがあります。これは個人でWebサービスを作るなら当たり前のことですが、大規模開発においてWeb環境を取り巻く専門性と多様性の中で、何が良いかは議論は分かれるポイントです。ただ、CTOやプリンシパルテックリードは得意分野の振り幅はあれど、その辺、気にせず必要に応じて見てくれているので、僕はWebのエンジニアの理想像なのだと思います。ここから先は専門家に委ねるという引き際もまた技術の判断力ということでしょう。チームで解決すればいいので。いずれにせよ、その中の当社の技術スタックの一つにPHPが存在しているということです。 PHPからPHPへの移植 我々の差し迫った問題として、CakePHP2.xのライフサイクル終了を目前に、次のアーキテクチャへの移行が必要です。言うなれば、高齢化が進んでいるアーキテクチャを若返らせる必要があるということです。 既に、今年のプロジェクトとして重要機能のアーキテクチャ変更に手を付けていますが、更に、来年からは本格的に全体のアーキテクチャ変更をスケジューリングし、数年をかけてソフトウエア構造の若返りを実現して行こうと考えています。 また、もっと日常の問題として、PHP自身を使い続ける魅力として、PHP自身が開発言語のトレンドを取り入れて進化していると書きましたが、この考え方についていく難しさも存在しています。 BASEというプロダクトもリリースからなんだかんだと7年以上も経っています。新興のスタートアップ企業だと思っていましたが、当社のソースコードもそれなりに長い期間、競争力を維持している状態です。 まだまだ昔のソースコードが活躍している中、意識的に新しいPHPに対応したソースコードに書き換えて行かない限りは、PHPの進化というメリットを享受できません。 以前は、Ruby on Railsのように最先端への適応圧の高いフレームワークはまあまあリスクだと考えていましたが、当社のように成長、継続に時間とコストをかけられるWebサービスであれば、いずれにせよ最新の状態に変化をしていかないといけないので、必要経費として外的環境から変化を強制される方がまだ気持ちは楽なのかもしれません。 システム開発には「枯れたコードはいじるな」という定説が昔から存在しています。 既にリリースされているコードは十分安定しているから余計な修正はしてはいけないという考え方です。この考え方の元で教育されてきたエンジニアの人も多々いることでしょう。 後方互換性が維持されているPHPにおいては、この考え方に乗りやすいというメリットがあります。進化の歩みを止めたWebサービスを長く運営していくことについては、PHPの利用は向いていると考えることも可能です。 しかし、これは「Webシステムのコードはリリースした瞬間から劣化していく運命にあり、何もしないのは退化をもたらす」という概念と矛盾します。 誤解を恐れずに言うと、現状維持を許容する考え方が許されるのもPHPの強みであり、陥りやすい罠とも言えます。 自己責任でPHPの最新バージョンへの対応を意識してマネジメントしていかないと、どんどん最新環境への適応力が下がってしまい、働く人のスキルも含めて変化のコストが高くなっていってしまいます。 これを打破していく必要が我々にはあります。 エンジニアリングマネジメントの責務 このようなエンジニアリングプロセスの実現、意識の向上は、マネジメントサイドの仕事として意識的に行う必要があります。 どこかこれまで既存技術を良くしていくのは、意識も瞬発力も高いテックリード級の人がやる仕事だと考えていたところがありました。そのために日常のサービス開発をしているチームとは別に、基盤チームというビジネス主体の開発プロジェクトから切り離した技術チームを作り、その人達を中心に広げていければと思っていましたが、それだけでは望む状況にはなりませんでした。 そうではなく、当社で働くすべてのエンジニアが、毎日の仕事の中で、ソースコードをよくしていく、リファクタリングし変化をもたらせていく意識を持つ必要があるということにたどり着きました。 言い換えると、ビジネスの成長を実現する新機能のプロジェクト開発を進めるだけでは、事業継続性、サービス発展性の実現には足りないということです。 それ故に、エンジニアリングマネジメントとしては、チーム全員が変化を受け入れることを当たり前とするために、以下のことを意識的にやっていきます。 プロジェクトをこなす事以外に、日常的に既存コードをよくしていくための作業時間を確保する サービスを伸ばすことと、ソースコードやシステム全体をよくしていくことの両立ができ、高い生産性を実現するエンジニアを評価し、報酬に反映する。 そこでリーダーシップを発揮できる人をリード職やエンジニアリングマネージャに抜擢し、全体のレベルアップを図る このことに一緒に取り組んでくれるエンジニアの採用を強化する など。 このことをチーム全員で取り組んでいく必要があります。枯れたコードの安定性にサービス継続性を依存し、いつまで経ってもPHPの後方互換性に頼っているという状態では未来がありません。 事業継続性を実現するシステムズエンジニアリング このような事業継続を実現するための変化は、この業界においては式年遷宮と呼ばれる事が多いです。しかし、Webの場合は、サービス要件、セキュリティ要件、スケーラビリティ要件が刻一刻変わっていくため、個人的なイメージとしては、技術の伝承、現状維持を目的とした式年遷宮を例えにあげるのは、サービスの成長を前提とした概念としては少し物足りないという感覚を持っています。 個人的な好みとしてはこちらの例えで、2013年3月15日に行われた東急東横線の渋谷駅ホームの地下化に伴って行われた代官山駅の入れ替え工事がそれです。 渋谷という継続的に発展する都市を下支えするエンジニアリングの底力をこの映像から伺うことができます。 この工事は、一晩のうちに行われました。綿密な計画を練って、総勢、1200人で作業したというものです。チーム全体がこの役割を担うことで、サービス利用者になんら不便をかけずにサービスのアップデートを実現したこの映像をとてもリスペクトしています。 今後の発展のために このような前提の中で、BASEというサービスの現状は発展途上に他なりません。ここまで長々と書いてしまいましたが、直近における大きなtodoをまとめると、通常の事業成長のためのプロジェクト開発以外に、 来年からCakePHP2.x をやめるための計画を立てて開発計画を実行していく PHPの最新バージョンに適応するためのコードを書くことへの時間投資は常に意識する その他、思いきった新規アーキテクチャの導入など(実はもうやってるよ!) これらを実現し、技術力を底上げしていくための採用と組織構造を改良していくのがマネジメントの仕事になります。 BASE社で働くエンジニアは、今後、サービスを成長させ続けて流通総額を伸ばし続け、多くのショップオーナー様の成長を支えていくためにも、現状のままで良いという考え方は1mmも持たないで欲しいです。特に新型コロナの非常事態宣言下では、変化しないと先がないと言う未来が明らかに見えました。 当社のエンジニアは特定の言語を書きたい!みたいな価値観だけではなく(それはそれで否定しない)、成長するWebサービスを根幹から支えられる技術者として成長してほしいですし、そういう機会が目の前に転がっているのでCTOやテックリードだけにやらせずに、自らチャンスを拾っていって欲しいです。 そして、このサービスに携わる人達の技術力を下地に、勇気ある変革を実現していきたいと思っています。 そして一緒に手伝っていただけるエンジニアの方々を募集しております。やることは山程あるので助けてください! A-1.BASE_Webアプリケーションエンジニア/ショップオーナー向け開発 / BASE株式会社 また採用を一緒に手伝っていただけるVPoE候補も募集しております!とりあえずで結構ですので、皆さんのキャリアの選択肢の一つとしてZoomでお話しませんか? open.talentio.com
こんにちは。BASEでコミュニケーションデザイナーをしているszです。 この度リファインしたBASEのサービスロゴの制作過程を少しお話しできればと思い筆をとらせて頂きました。 目指したのはリブランディングではなくリファイン 創業から丸7年ほど、ネットショップ作成サービス「BASE」とショッピングアプリ「BASE」の顔となっていたサービスロゴ。今までのロゴはカラフルで愛らしくユーザーはもちろん社内のメンバーからもとても愛されていました。ロゴマークの部分である三角はアメリカ先住民族のテント「ティピ」で表していて、“インターネット上に小さな経済拠点をつくる”というプロダクトの想いを込めています。 そんなロゴですが、全く課題がないわけではありませんでした。 ティピの天辺部分の枝の処理が甘く少し視認性が弱かったり、ティピ全体の余白や角度が揃っていなかったりと細かく見ていくと、少し荒があったり、ロゴタイプの部分もカラフルな故に視認性が弱く、写真の上に載せたりすると文字の一部が溶けたり、白縁で処理して使う必要があったりとクリアしなければならない課題がありました。 しかしBASEというサービスのコアバリューは創業時から今も変わらず、アイデンティティの部分を大きく変えるのはまだ相応しいタイミングではないということもありました。 そこで目指したのが、サービスイメージを一新するのではなくリファイン(洗練)させることでした。 ロゴ制作者へのリスペクトを込めたインタビュー 今まで、BASEというサービスを支えてくれていたサービスロゴ。 創業当時にロゴを担当したデザイナーがどんな思いのもと作ったのか、ヒアリングするところからプロジェクトはスタートしました。改めてロゴのコンセプトや当時の制作の温度感やロゴタイプの選定プロセスをヒアリングしました。ロゴに紐づくグラフィック展開をみて、改めていいロゴだなぁと感じました。 デザインは必ず人が作っているものです。作った人を知るということで、次のデザインに向かうことができます。 ロゴ作成時のラフとグラフィック展開などです。 ティピの印象をどうするか リファインと言えど、どう作り上げるか様々な選択肢があります。 ティピもやり方次第では今と全く違った印象を持たせることができます。 そこで実施したのが、現BASEメンバーの非デザイナーの方々に、何も見ず記憶をたよりに5秒でロゴのティピを描いてもらい、そこからコアアイデンティティーが何かを探るとことをしました。 どのようにティピが印象付いているのかを確認することができ、リファインの判断基準が出来上がってきました。 ロゴタイプの選定 セリフ体やサンセリフ体さまざまなfontやキャップアンドローでBASEという文字を検証し、fontのバックグラウンドとBASEとの相性を確認していきました。 ある程度絞れてきたら、tipと組み合わせて検証もおこないました。 ここでポイントとなってきたのが、昔のロゴタイプ部分に使われていたfontがコンデンスドなfontであったということです。調べてみると20世紀初頭から中期の新聞の見出しから着想を得たものということがわかりました。コンデンスドはその特性上、情報量の多い文章との相性がよく文字数の少ないロゴとは少し相性が悪いところがあります。しかし全く印象を変えたfontも少し不安というメンバーの声もあり、コンデンスドのfontも候補に残しつつ、ティピとマージして調整に進みました。 カラー、ティピのディテールとロゴタイプのバランスを考える まずはティピを大雑把に絞り、ロゴのバランスを調整してバランスをみていきます。 ある程度ティピとロゴタイプが決まってきたらモックにはめて完成した時のインパクトを見極めていきました。 2案に絞り鶴岡さん(弊社代表取締役CEO)と話し、方向性の確認をして最終調整へ。 細かい修正を繰り返し完成したのがこちら! カラフルな印象だったロゴが少し大人びた印象に生まれ変わりました。 見慣れたロゴを変えるための準備 ロゴのリファインと言えども変えることにネガティブな意見がなかった訳ではありません。今までのロゴに対する愛着が、ユーザーにもメンバーにもありました。制作を開始した頃に「なぜ変えるの?」質問を受けることもありました。 その際には、視認性を含める課題を伝え、様々な意見を聞きつつプロジェクトを進めました。 プロジェクトメンバー間でも、プロダクトやサービスと同じようにサービスの顔であるロゴも進化し続けるべきだと認識を合わせて、リファインを進めました。 リモートと物理出社をうまく使い社内メンバーにチラ見せしながら進める 新型コロナウイルス感染症の影響で現在リモート推奨中のBASE社。しかし必要に応じてメンバーがオフィスに来ていたりもします。 ロゴリファイン担当のメンバーも必要に応じてオフィスに出社し、カラーの確認などをしていました。 そこで、制作途中のロゴを会議室の壁に張り出したままにして、あえてメンバーにも見えるようにしていました。これによりプロジェクトメンバー以外の人に「ロゴを変えるのかな」とあらかじめ変えることへの免疫をつけてもらっていました。また仮にネガティブな意見があるようであれば、はじめのうちに聞いておきたいという狙いもありました。制作途中もプロジェクトメンバー以外の意見も聞き、どう感じているかも常に意識して進めました。 これからもBASEのデザインは進化し続ける BASEのデザインはまだ進化の途中です。それはロゴも例外ではありません。ユーザーのためにMove Fastに新しい様々な機能提供してきたように時代に合わせてビジュアルアイデンティティーも変えて行く必要もあります。これからのBASEのデザインに是非ご期待ください!
こんにちは。BASE BANK 株式会社 Dev Division にて、 Software Developer をしている東口( @hgsgtk )です。 TL;DR GitHub Project でカンバン運用する際に、Issue 作成が少し面倒で、対応する GitHub Project を手動で指定しないといけない GitHub Actions の alex-page/github-project-automation-plus を用いて、Issue作成時に自動で GitHub Project に登録されるようにする ISSUE_TEMPLATE の作成・更新など、ささいなカイゼンを積極的にやる 背景 BASE BANK Dev Division での開発プロジェクトでは、GitHub Project でカンバン運用しています。 「 少人数でのアジャイル開発への取り組み実例 (一歩目の踏みだし方) | 詳説 | July Tech Festa 2020 登壇レポート 」にて、そのカンバンをちょっとだけチラ見せしておりました。 このカンバンには、Issueを作成して登録していくのですが、Issue を作成する際の ISSUE_TEMPLATE には、 GitHub Project は指定できません。そのため、Issue 作成時に対応するプロジェクトを指定していました。 これは、積もり積もると結構面倒な作業で、流れでポンポンIssueを作っていく際のリズムも途切れてしまいます。 ささいなカイゼンの重要性 最近、「 香川編集長 トヨタ生産方式 取材フル (生産量を「100倍」にしたトヨタ生産方式の秘密) | トヨタイムズ 」という YouTube の動画を見ました。老舗合羽メーカー「船橋」の医療用防護ガウンの生産をトヨタ社員がカイゼンして生産性を100倍にするという話です。 www.youtube.com そこで行われていたのは、「最新機器を導入しましょう」みたいな話ではなく、「ここにハサミをおいておいたら1秒早くなる」といった愚直なアイデアでした。 また、クレディセゾン常務取締役CTOの小野和俊さんの著書『 その仕事、全部やめてみよう――1%の本質をつかむ「シンプルな考え方」 』でも、毎日の「繰り返し」を、プログラマー的発想法で効率化することの重要性を説いています。 ちょっとしたことでも日常で行われる「繰り返し処理」をカイゼンしていくことは、チームの生産性・スループットを上げるために重要である、と学びました。 GitHub Actions で自動で登録する GitHub Actions で issue作成をフックに、指定した GitHub Project へ追加する、というものが、 Marketplace で公開されています。それが、 alex-page/github-project-automation-plus です。 github.com 設定方法はかんたんで、次のような yaml ファイルを .github/workflows/ 配下に入れるだけです。 name: 'Automatically add issue to basebankdev project' on: issues: types: [opened] jobs: automate-project-columns: runs-on: ubuntu-latest steps: - name: Move issues into pj column uses: alex-page/github-project-automation-plus@v0.2.4 with: project: githubprojet column: Backlog repo-token: ${{ secrets.AUTOMATION_TOKEN }} どのイベントをトリガーにするかはプロジェクトによりますが、本プロジェクトでは、 issues の opened のみをイベントトリガーに指定することで、作成時の issue を GitHub Project に登録するようにしています。 docs.github.com 注意点としては、レポジトリではなく、Organization 内プロジェクトボードにしている場合は、 secrets.GITHUB_TOKEN ではそのプロジェクトにアクセスできる権限を持っていません。 docs.github.com そのため、専用に admin:org を scope に含めた Personal Access Token を設定する必要があります。 これにより、Issue作成時の GitHub Project の手動指定と、作成したIssueを実際にプロジェクトのカラム(column)に追加する作業が不要になります。GitHub Project で Issue をトラッキングする運用における作業のリズムが改善されました。 ISSUE_TEMPLATEの使い分け その他にも、スプリント計画やレトロスペクティブの記録・アジェンダも、 GitHub Issue で行なっているため、複数の ISSUE_TEMPLATE を用意しています。 $ tree -L 1 .github/ISSUE_TEMPLATE .github/ISSUE_TEMPLATE ├── backlog_template.md ├── config.yml ├── retrospective_template.md └── sprint_planning_template.md ISSUE作成時は、下図のように複数のテンプレートから選択するようになります。 副次的な効果として、テンプレート化されたことで、それぞれのイベントの司会をローテーションできるようになっています。以前、「 朝会の司会はローテーションがオススメ 」というブログエントリーがありました。 www.agile-studio.jp その習慣イベントの継続性や当事者意識の高まりなどが期待されると言う話です。 実際に最近チームで、レトロスペクティブの司会・ファシリテーターをローテーションしていますが、それぞれの視点で様々なカイゼン点が見つかり、チーム運営が効率化される効果を感じています。 (例) Miro の振り返りテンプレートを自作して用意する ISSUE_TEMPLATE に毎回話しに上がる点を追加する おわりに ちょっとした GitHub Project 運用のカイゼン話でした。すぐにでも取り組める内容なので、似たような運用をされていたら、参考にいただければ幸いです。
はじめに CTOの川口 ( id:dmnlk ) です。 5月に オンラインmeetup をさせて頂きその中で「具体的な負荷対策に関しては開発ブログで!」と言っていた件ですが気づいたらもう9月になりかけていました。 コロナ禍においてネットショップ作成サービス「BASE」の利用者様が急増しました。 www.nikkei.com 5 月には 100 万ショップを超えるショップオーナー様にご利用していただいております。 今まで EC 事業を行っていなかった飲食店様や様々な業種の方が利用をはじめていただき、ショップオーナー様も購入者様共に短期の見通しでは想定をしていないアクセスが発生しました。 その途中でシステムとして対応しきれない面もあり、アクセス負荷によるサービスの不安定を招き皆様にはご不便や販売時間を変更していただくお願いなどをしてしまい大変申し訳ありませんでした。 現在では安定しておりますが、その中で一体 BASE にはどのような問題が発生していたのか、それをいかにして解決したのかを公開させていただこうと思います。 BASEのシステム構成について BASE は構成としてシンプルな Web アプリケーションになっており、オーナー様向け管理画面及び PC やスマートフォンでアクセスされるショップ画面を提供するアプリケーション、ショッピングアプリ「BASE」向け API アプリケーション、サードパーティ向け API アプリケーションなどがあり、データベースは単一のものをそれぞれが参照及び書き込みを行っています。ログ系データのみデータベースを別にしてあります。 アクセスが増えるとこのデータベースの負荷が高くなります。WebAP サーバーに関してはある程度スケールアウトやスケールアップが柔軟に行えるようになっておりますが、データベースに関してはそうはいきません。 データベースは Amazon Aurora MySQL を利用しています。 読み込みに関しては reader インスタンスを増やすことでスケールアウトが可能ですが書き込みに関しては容易には実現できません。 DBへの新規接続タイムアウト問題 コロナ禍において利用者が増えている最中、1 日の中でもアクセスが多い夜間帯でアプリケーションでエラーが多く発生する状態が観測され始めました。 そのエラーは DB への接続時に SQLSTATE[HY000] [2002] Connection timed out というものでした。 このとき、Aurora のメトリクスとして障害になりうるようなものは見当たりませんでした。 Connection 数が Max Connection の上限に達してしまっているならば、 Too many connections のエラーが出ているはずですが発生していません。 CPU や memory に関しても余裕がありました。 このエラーが発生しているとき、ブラウザ上でのアクセスも非常に待たされる状態です。 さらに、社内管理画面のようなアクセスが非常に少ないアプリケーションでも同様のエラーが発生していたので Apache などの WebAP が原因でないと推察していました。 原因が分からない状態ではありましたが、このまま放置することも出来ず利用者がまだまだ増えていく最中でしたので何かしらの対策を打つ必要がありました。 New Relic などのプロファイリングツールを用いて状態を見ていたところ、MySQL への接続に非常に時間がかかっていることはわかりました。 これはクエリの重さに依らず、非常にシンプルな SELECT でも起きていました。 設定でタイムアウトは 30 秒に設定していたので MySQL への接続それ自体に 30 秒かかってしまいアプリケーションとしてエラーになっているということです。 何が起きているかは分かるが、何故起きているが分からない状態で打てる手は多くありません。 アプリケーションで時間のかかっている処理などを少しでも改修するということは行っていましたが目に見える効果は大きくありませんでした。 インスタンスのスケールアップ あまり褒められるものではありませんが、とりあえず primary インスタンスのスケールアップを行うことにしました。 深夜に緊急メンテナンスを行い、primary インスタンスのスケールアップを行いました。 1段階上位のインスタンスへのスケールアップを行ったあと、状態は改善しました。 上記のエラーは夜間帯でも発生しなくなり、理由はわからないが何かしらの対策にはなったと胸を撫で下ろしました。 が、これから 2 週間ほど経ったあと同様のエラーが再発するようになってしまいました。 アクセスは更に増えていたので、また何かしらの性能限界に達してしまったのだということがわかりました。 インスタンスのスケールアップはまだ可能ではありましたが、延々と上げ続けるわけにもいきません。 コストパフォーマンスの面でも無駄が大きすぎますし、原因が分からない以上同様の問題にぶつかることは自明です。 事実、エラーが発生している状況でも Aurora の CPU 使用率は 10%程度しか上がっていません。 弊社では AWS のエンタープライズサポートに加入していますので、AWS の方にも調査を依頼しました。 各種メトリクスの提示や、エラー発生時のアプリケーションの状態などを AWS 側に提出しました。 back_logパラメータの変更 数日後 AWS の方から「back_log パラメータの変更を検討してはどうか」という回答を得ました。 AWS の観測によると当該時間帯、DB への新規接続が数万を超えており SYN の再送が起きていたということがわかりました。 これは Aurora 側で新規接続が受け付けられていない状態です。 新規接続が多くなりすぎて、Aurora の back_log が溢れ SYN/ACK が返却できないため SYN の再送が行われてしまっています。 back_log キューは「サーバアプリケーションが listen しているソケットが、accept していない確立済 TCP コネクションを保持するキュー」であり、これが溢れてしまうと Aurora(サーバー)がパケットを drop してしまうため SYN の再送が発生してしまうということになります。 https://blog.cloudflare.com/syn-packet-handling-in-the-wild/ http://u-kipedia.hateblo.jp/entry/2015/01/01/001135 Aurora にも back_log が設定されており、そのデフォルト値はインスタンスタイプによって自動的に引き上げられます。 スケールアップによって一時的に改善されたのは、この back_log パラメータが引き上げられたことによって一時的に受け入れられる新規接続が増えたことによるものでした。 度重なるアクセス増によって更に新規接続が増えたため、引き上げられた上限を超えたため再度 back_log から溢れてしまい接続が drop してしまったようです。 このパラメータの変更はデータベースの restart を伴うため、オンラインで行うことはできません。failover が行われるとはいえサービスの停止が必要です。 直近に深夜メンテナンスを行ったばかりで心苦しいところではありましたが、システムの安定化のために必要な措置として再度深夜メンテナンスを行い back_log パラメータを引き上げることにしました。 これはパラメータグループでいう back_log というパラメータになるので、ここを max_connections と同値に変更しました。 これによりシステムの安定度は大きく向上しました。 その他のデータストアへの対応 BASE では MySQL だけでなく Memcached や Redis を利用しています。 これらも自社で運用しているのではなくマネージドサービスの Amazon ElastiCache を利用しています。 データベース接続に関して問題がなくなったことで上記のデータストアへのアクセスに同様のエラーが発生していそうなことが分かってきました。 Amazon ElastiCache では Aurora のように back_log パラメータの変更が出来ません。 そこでアプリケーション側で対応することにしました。 PHPでの検索結果Persistent Connectionについて 新規接続を都度行うのではなくコネクションプーリングのように再利用することで新規接続を減らすことができます。 Memcached、Redis のコネクションオブジェクト作成時にそれぞれにオプションを指定することで可能です。 PHP ではこれを Persistent Connection、持続的接続と呼びます。 下記のドキュメントを参照し持続的接続を行うことで確立した接続を維持したまま、新たな接続を受け付けるようにしました。 https://www.php.net/manual/ja/memcached.construct.php https://github.com/phpredis/phpredis#pconnect-popen BASE のアプリケーションのデプロイでは Blue-Green deployment を利用しているため、デプロイ毎に新規インスタンス群が増えます。 待機系になったインスタンス群も、デプロイ後でも接続を保持してしまうので httpd の restart を行う必要がありました。 なお、MySQL への接続にも Persistent Connection を行うことは可能です。 PDO::ATTR_PERSISTENT によって管理されます。 有効にすることはフラグをオンにするだけなので実装コストがほぼ掛かりません。 https://www.php.net/manual/ja/features.persistent-connections.php ですが大きなデメリットがあります。 ドキュメントを参照すると 警告 持続的接続を使用する際にはまだいくつか心に留めておく必要がある注意 点があります。一つは持続的接続でテーブルをロックする場合にスクリプト が何らかの理由でロックを外し損ねると、それ以降に実行されるスクリプト がその接続を使用すると永久にブロックしつづけてしまい、ウェブサーバーか データベースサーバーを再起動しなければならなくなるということです。もう 一つはトランザクションを使用している場合に、トランザクションブロック が終了する前にスクリプトが終了してしまうと、そのブロックは次に同じ接続を使用して実行されるスクリプトに引き継がれる、ということです。 どちらの場合でも register_shutdown_function()を使用してテーブルの ロックを解除したりトランザクションをロールバックする簡単なクリーン アップ関数を登録することができます。しかしそれよりも良い方法は、テーブルロックやトランザクションを使用するスクリプトでは持続的接続を使用 せず、問題を完全に避けて通ることです(他の箇所で使用する分には問題あ りません)。 とあります。 これは接続が状態を持ってしまい、それぞれのケアをアプリケーション実装しなければいけないということです。 トランザクション処理のためにロックを確保している接続がエラーになってしまった場合などにその接続はロックを確保したままになってしまいます。 別のリクエストがその接続を利用とするとケアされていない場合ブロックしてしまうのは更なる障害を生んでしまいます。 トランザクションも同様です。 register_shutdown_function にロックやトランザクションを解除するような仕組みを作らなければなりません。 この処理が正しく動くことを検証することは相当量の検証が必要になるでしょう。 そのため、BASE では DB 接続へは Persistent Connection を利用することを採用しませんでした。 新規接続の限界 back_log の調整、他データストアの Persistent Connection によってしばらくは安定稼働させることができました。 しかし、この時の BASE のアクセス量の伸びは凄まじくこの構成でも接続エラーが発生するようになってしまいました。 ピーク時に秒間 2 万もの新規接続が primary インスタンスへ行われているといった状態です。 残された手段は primary のインスタンスに対しての接続数を如何にして減らすか、ということのみです。 前述のように PHP の Persistent Connection を使うことは新たなリスクを増やすことになります。 一般的に PHP+MySQL という構成だと ConnectionPool を用いることは稀です。なので利用できるミドルウェアもそこまで多くはありません。 ProxySQL や MaxScale というミドルウェアもありますが、これらの検証を行う時間的余裕がありません。これらを利用する場合、これ自体の可用性なども検証し運用する必要があります。 AWS からマネージドのコネクションプーリングとも呼べる RDS Proxy もありますがこの時点ではまだ GA になっておらずプロダクション環境に投入できません。 ここで出来ることアプリケーション側の接続をいかに reader インスタンスに行うか、ということです。 これはクエリを reader に向けるというよくある負荷対策ではなく、新規接続自体を reader に最初から向けるということが求められます。 弊社ではデータベースへのクエリ実行を primary や reader へ振り分けるのに弊社メンバーが作ったライブラリを利用しています。 どのようなライブラリなのか、というのは下記スライドを参照してください。 このライブラリの設定値の中で default_read というパラメータを true にすることで新規接続の時点で reader インスタンスへ接続を向けることが可能です。 Aurora はそのアーキテクチャ上、一般的に言われる primary と reader インスタンス間のデータ反映ラグがとても小さくなるようになっています。最大でも 100ms を超えることはありません。 ですが、全くのゼロでないのでそのラグが致命的な不具合になることがあります。ショップオーナーが変更した価格が反映されずに決済されてしまう、商品の在庫を超過して決済が行われるといった不具合だけは絶対に避けねばなりません。 なので default_read パラメータを有効にせず運用していました。 改めて、BASE というアプリケーションを見直すと主に 3 つの画面に分割されます。 ショップオーナー管理画面 ショップ情報や商品情報が表示され購入者が閲覧するショップ画面 決済処理を行うカート画面 これらはサブドメインで切り分けられていますが、コード及び稼働サーバーは同一です。 この中で 1 と 3 に関しては更新処理が多く行われており、この更新処理に不整合が起きると致命的な不具合となります。 ですが、2 のショップ画面に関しては更新処理はほとんどありません。あってもショップへのお問い合わせをする画面やチャット用の処理、くらいが主となります。 ここだけに絞るならば、default_read を true にするという選択肢は取れるのではないかと考えました。 最もリクエストが多いのもこの画面になるので効果は大きくなることも想定できます。 当初は 1 と 3 のインスタンス群と 2 のインスタンス群を別のサーバーとして振り分け、その場合のみ設定値を変更することも検討しましたが、新規接続をする前にリクエスト時のサブドメインによってこの設定値を可変にできることが判明したのでアプリケーションコードの変更を行いました。 結果として効果は覿面でした。 上記スライドにも上げられていますが、下記のように primary インスタンスへの接続は大幅に減少し reader への接続が増やすことができました。 connection count 上記の変更により圧倒的に BASE の安定度は向上し、ピーク帯においてもページが重かったり決済ができない、などといったことから解放されました。 余談とはなりますが CakePHP2 はデータソース毎に新規接続を作ります。 データベースインスタンスが別であればもちろんのこと、論理データベースが分割されていればその分データソースが分けられるので接続が増えることになります。インスタンスは同一でも、アカウント情報と注文情報などを論理データベースで分けるといったことはよくある構成ですが、これが全て別個の新規接続を生んでしまいます。 1 画面を表示する 1 リクエストにも関わらず複数の新規接続を生んでしまうのでここをうまく 1 つの接続を取り回せるような仕組みを開発することも新規接続を減らすために有効となります。 まとめ 今回 BASE において想定外であり未曾有の負荷であったことは言うまでもありません。 スケールアップだけでは対応できない、アプリケーションの単純なチューニングだけではどうにもならないという事象に初めて遭遇しました。 この中で、例えクラウドインフラを利用していても基礎的なミドルウェアや Linux の知識などが非常に重要であること、アプリケーションの構成を正しく理解しどのレイヤであれば思い切った対策を打てるかといったことを知っておくことの重要性を再認識しました。 合わせて、単純な DB の cpu/memory 使用率だけでなく新規接続の数など様々なメトリクスを監視することも重要になります。 なお、Aurora 1.19 にバージョンを上げると ConnectionAttempts というメトリクスが取得可能になるため、新規接続数をモニタリングすることが可能です(問題発生当時はこれより低いバージョンでした)。 AWS によりますと、Auroraのv2系にすることで更なるパフォーマンスの向上も見込めるということでしたのでアップデート計画を進めています。 今回は AWS の方のサポートが手厚かったことも大変助けになりました。 サポートケースの詳細を記すことはできませんが、弊社側でどのようなメトリクスを取得すれば調査に役立つかや具体的な検証用のソースコードの提供などもしていただきどれくらいの新規接続を行うと Aurora 側の限界値に達するかといった詳細情報まで頂きました。 このおかげで BASE としてどれくらいコネクションを減らすことが必要なのかの目算ができるようになりました。 もちろんこれでどんな時でも問題ないというわけではなく、新規接続をこれからも減らしたり負荷のかかる処理の分散、外部決済サービスへのリクエストの非同期化などまだまだやっていかなければなりません。 「BASE」というプラットフォームをご利用していただくショップオーナー様や購入者様の皆様がどれだけ増えても快適にご利用いただけるようこれからも改善を続けていきます。 弊社ではこのような大規模アプリケーションのインフラ運用やアプリケーション改善などを共に進めていってくれるメンバーを募集しています。 下記からご応募ください。 binc.jp いきなり応募ではなく、ちょっと話を聞いてみたいといった方でもお気軽にどうぞ。 TwitterへのDMも開放していますので是非。 twitter.com
こんにちは、Native Application Groupの大木です。2020/08/21に開催された TECH STAND #1 React Native にて、「最近のNative Modules開発について」というテーマで発表しました。 最近のNative Modules開発について React Nativeでネイティブアプリを開発していて、全くネイティブコードに触れなくてもいいかと言えば、実はそうではありません。 また、自分たちのユースケースに合うiOS/Androidのプラットフォーム機能にアクセスできるReact Nativeのライブラリが存在しない場合、自分たちでNative Modulesを開発する必要があります。 そのNative Modulesをどのように開発し、React Nativeで使えるようにしていくかについてお話しさせていただきました。 Native Modules開発で抑えるべきポイントはいくつかあるのですが、この発表では以下のポイントに絞って、説明をさせていただきました。 Bob というツールを使うとNative Modules開発のためのセットアップが簡単になる 知っておくべきアーキテクチャーについて SwiftなどNativeモダンな言語で開発する方法 react-native-commnity/Expo SDKは実装の参考になる 今後、Lean Coreでのコア機能のスリム化やRe-architectureなどの取り組みでReact Nativeが大きく改善していく中で、React Nativeへの理解をより深めるための助けになれば幸いです。 まとめ 今回登壇する機会を与えて下さったイベント運営スタッフの皆様に感謝いたします。また、React Native中級者〜上級者向けの実践的な内容ということで、他の方の発表からとても有用な知見を得ることが出来ました。
はじめに こんにちは、ネイティブアプリチームの筧です。 自分はモバイルアプリの開発は今まで Android でしか経験がなかったのですが、最近は iOS アプリ開発にコンバートしました。 はじめは Storyboard の扱いに慣れなかったり、AutoLayout の設定に色々と苦戦していたのですが少しずつ慣れていきました。 今回 UITableView を用いた新機能の開発を経験し、iOS エンジニアの先輩にレビューで課題点をあぶり出してもらい勉強になったので、いくつかポイントをピックアップして紹介します。 開発のお題 まずは簡単に今回のお題となった機能を実現するにあたって、求められる挙動をいくつか紹介します。 主に 2 種類の UITableViewCell を実装します 1 つは文字を入力できる UITableViewCell。 UITableViewCell の中に UITextView が埋め込まれている。 UITextView に入力するテキストを増やしたら、テキストに応じて UITextView ならびに UITextView の親となる UITableViewCell の高さを変更する。 データによって UITableViewCell の高さは異なる。 もう 1 つは選択形式の UITableViewCell。 各 Section の中から必ず 1 つの Cell が選択状態になっていること。 選択された Cell はチェックマークが表示される。 UITableViewCellの高さの計算について UITableViewCellの高さの見積もりをとる UITableView(UICollectionView)では estimatedRowHeight による UITableViewCell の高さの見積もり を指定することで、実際の高さの計算処理のパフォーマンスの向上が狙えます。ただ適当な高さを指定すればいいわけでなく、できるだけ実際の高さとのズレが小さく済むように指定しないといけません。ズレが大きいと結局スクロールがカクついたりする原因になることもあります。 すべての Cell において高さが等しいのであれば estimatedRowHeight を指定すればいいのですが、今回は Cell によって高さが異なります。そこで tableView(_:estimatedHeightForRowAt:) を用いて各 Cell ごとに見積もりの高さを指定しました。 func tableView (_ tableView : UITableView , estimatedHeightForRowAt indexPath : IndexPath ) -> CGFloat { if isHigh(at : indexPath ) { return 300 } return tableView.estimatedRowHeight } func isHigh ( for at : IndexPath ) -> Bool { // 高いheightを指定するべきか判定する // ... } (実際のコードではありません。 高さのキャッシュを設定して再利用する Estimating the Height of a Table's Scrolling Area The table view asks for estimates for every item in your table, so do not perform long-running operations in your delegate methods. Instead, generate estimates that are close enough to be useful for scrolling. 公式ドキュメントにこう書いてあるように UITableView は逐一見積もりの高さを要求するので、できるだけ省エネで各 Cell の見積もりの高さを求めて返す必要があります。そこで tableView(_:willDisplay:forRowAt:) で実際の Cell の高さを取得してキャッシュを生成します。 あとは tableView(_:estimatedHeightForRowAt:)にてキャッシュされた height があればそれを見積もりの高さとして返すような処理を追加します。 private var cacheCellHeights : [IndexPath: CGFloat] = [ : ] func tableView (_ tableView : UITableView , willDisplay cell : UITableViewCell , forRowAt indexPath : IndexPath ) { cacheCellHeights[indexPath] = ceil(cell.bounds.height) } func tableView (_ tableView : UITableView , estimatedHeightForRowAt indexPath : IndexPath ) -> CGFloat { if let height = cacheCellHeights[indexPath] { return height } if isHigh(at : indexPath ) { return 300 } return tableView.estimatedRowHeight } AutoLayoutの制約はできるだけシンプルに はじめは UILabel の height の制約を指定し、UILabel の width と表示するテキストに応じて必要な高さを計算し、制約の値を上書きするようなやり方で動的に高さを変更できる UILable を実装していました。以下のコードのような感じです。 @IBOutlet weak var label : UILabel ! @IBOutlet weak var labelHeight : NSLayoutConstraint ! // Viewの初期化をする func apply (text : String ) { // heightの制約の値を上書き labelHeight.constant = text.height(withConstrainedWidth : label.frame.width , font : UIFont.systemFont (ofSize : 12 )) } extension String { public func height (withConstrainedWidth width : CGFloat , font : UIFont ) -> CGFloat { let constraintRect = CGSize(width : width , height : .greatestFiniteMagnitude) let boundingBox = self .boundingRect(with : constraintRect , options : .usesLineFragmentOrigin, attributes : [.font: font] , context : nil ) return ceil(boundingBox.height) } } しかし今回は以下のような要素が絡むことで、制約のコンフリクトが起こりやすい設定となってしまっていました。 - 端末の画面サイズによって、諸々の View のサイズは異なる。 - UILabel の親 View となる UITableViewCell の高さが不変ではない。 なので高さの制約は削除し、親 View との上下左右の制約に留めることで、制約の不整合が起こりにくくなるように修正しました。 特に端末の画面サイズが異なることはモバイルアプリ開発においては常あることなので、できるだけ AutoLayout の制約をシンプルに保たねばと改めて自分を戒めました。 UITableViewCellのデータ更新について reloadRows(at:with:)は極力使用しないこと reloadRows(at:with:) は指定された Cell をリロードするメソッドです。リロードする際のアニメーションを指定できるので、ユーザーにわかりやすくリロードしている Cell を示すのには有効です。しかしこれは Cell の高さの再計算などの初期化処理を促すのでパフォーマンス観点で多用することは好ましくありません。これもまたスクロールなどがカクつく原因になりえます。 自分が今回やらかしたのは、ユーザーが Cell を選択するたびに Cell の表示を更新するために reloadRows(at:with:)を実行していました。これでは選択するたびに reloadRows(at:with:)が走るので、選択時に TableView の表示が崩れるかもしれません。 func tableView (_ tableView : UITableView , didSelectRowAt indexPath : IndexPath ) { // indexPathに応じたデータを更新 ... // 更新したデータをUITableViewCellに反映するために、該当するCellのリロードを促す tableView.reloadRows(at : [indexPath] , with : .none) } reloadRows(at:with:)を使わずにどう解決したかは次の章で紹介します。 UITableViewの各Cellの選択の制御について 前の章で述べたとおり、はじめは選択されるたびにデータの更新及び reloadRows(at:with:)による Cell の更新をする実装にしていました。 しかしこれでは以下の課題があります。 選択するたびに reloadRows(at:with:)することで、Cell の高さ計算などの初期化が走りパフォーマンスがよくない。 今どの Cell が選択状態なのか Model のデータを参照しないとわからない。UITableView のどの Cell が選択されているについての選択状態の管理が Model 側に侵入し、ロジックの境界が曖昧になっている。 これらは先輩のレビューによって以下のように改修されました。 方針としては、各 Section ごとにどの Cell が選択されているかについて選択状態を自前で管理していたところを、UITableView で管理するようにしたという感じです。 override func viewDidLoad () { super .viewDidLoad() // 複数のrowを選択状態として扱うことを許可する tableView.allowsMultipleSelection = true } override func viewWillAppear (_ animated : Bool ) { super .viewWillAppear(animated) // 画面初期化時は、各sectionのはじめのrowを選択状態にする if presenter.numberOfSections() > 0 { for i in stride(from : 0 , to : presenter.numberOfSections (), by : 1 ) { let index = IndexPath(row : 0 , section : i ) tableView.selectRow(at : index , animated : false , scrollPosition : .none) } } } func tableView (_ tableView : UITableView , willSelectRowAt indexPath : IndexPath ) -> IndexPath ? { if let selectedRows = tableView.indexPathsForSelectedRows { let selectedInSection = selectedRows.filter { $0 .section == indexPath.section } for deselectingIndexPath in selectedInSection { tableView.deselectRow(at : deselectingIndexPath , animated : false ) } } return indexPath } func tableView (_ tableView : UITableView , didSelectRowAt indexPath : IndexPath ) { // 選択に反応してなにか実行したいロジックがあればここに書く } @IBDesignable class CustomCell : UITableViewCell { @IBOutlet weak var selectIcon : UIImageView ! override func setSelected (_ selected : Bool , animated : Bool ) { super .setSelected(selected, animated : animated ) selectIcon.isHidden = ! selected } } まず tableView.allowsMultipleSelection = true を実行して、一度に複数の Row が選択状態として扱えるようにします。特に今回は「各 Section の中で、必ず 1 つだけが選択されている状態にする」という仕様があったため、選択状態を UITableView で管理する上で必須の設定となります。 そしてここが変更のポイントなのですが、選択されるたびに willSelectRowAt 内で tableView.indexPathsForSelectedRows から選択状態になってる indexpath を割り出し、さらにその中から Select の対象になってる IndexPath と section が一致する IndexPath を特定し、その IndexPath を deselect します。 willSelectRowAt 後は didSelectRowAt が走るので、didSelectRowAt 内で選択後に実行したい処理があれば実行します。このとき didSelectRowAt 内で対象になった Row を deselect するようなことはしません。選択状態は保持したままにします こうすることによって、選択中の Cell はデータを参照せずとも indexPathsForSelectedRows によって判別可能となりました。 そして 選択状態の管理は willSelectRowAt 、選択によって実行したい処理は didSelectRowAt と処理の分離ができて見通しが良くなりました。 また UITableViewCell 側の表示の変更は、UITableViewCell の setSelected(_:animated:) 内に書くことで、UITableViewCell 内で完結できます。選択状態の Cell のスタイルについては、 selectionStyle を用いて以下のように設定しておけば問題ありません。 cell.selectionStyle = .none おわりに 他にもレビューでもらったアドバイスは色々あるのですが、今回は UITableView に焦点を当てて紹介しました。今回の内容はもちろん同じくコレクション系の View を実装する UICollectionView でも有効です。 今回紹介したようなパフォーマンス観点での実装の工夫は、iOS アプリ開発に入門した方にとってははじめは仕様を実現するので手一杯で、なかなか意識をするのは難しいのではないでしょうか。ですがスクロールのカクつきや View の表示などのパフォーマンスが悪いと、ユーザー体験にモロに響くので、実際のプロダクト開発においては必須のテクニックだと思います。
こんにちは。BASE BANK 株式会社 Dev Division にて、 Software Developer をしている東口( @hgsgtk )です。 TL;DR バーティカルスライスでのデリバリーを可能な限り保つユーザーストーリーの分割はどうすればいいか ユーザーストーリーが 1 回のイテレーションで収まらないような場合に分割する 3つの分割軸「データ境界に沿って分割する」・「パフォーマンス制約をストーリーにする」・「アクターのモチベーションで分割する」をもって、ユーザーストーリーを分割する ビジネス価値の内訳要素に基づいて優先順位を考える 当記事の背景 BASE BANK Dev Division での開発プロジェクトでは、アジャイル開発の考え方・取り組みを取り入れています。その導入については、「 少人数でのアジャイル開発への取り組み実例 (一歩目の踏みだし方) | 詳説 | July Tech Festa 2020 登壇レポート 」にて紹介しています。 devblog.thebase.in アジャイル開発において、ユーザーストーリーをイテレーションごとに収まるような形で分割することは、プロダクトに対する検査と適応のリズムを得るために重要な取り組みです。ユーザーストーリーが大きすぎるものをそのまま取り組もうとすると、大きさゆえに見積自体の精度もより落ちてしまったり、その実現に期間を要することから顧客からのフィードバックも得づらくなります。 今回は、実際にネットショップ作成サービス「BASE」のプロダクト開発で行われた、「お金管理画面のリニューアル」を題材にします。プロジェクトや開発現場ごとにベターな形がありますので、完全な正解を提示するものではありません。しかし、いかにユーザーストーリーを分割するか、今回のプロジェクトを参考事例にしていただければ幸いです。 前提となるバーティカルスライスの考え方 「ユーザーストーリー分割を行うぞ」という行為の前提として、バーティカルスライスの考え方を紹介させていただきます。 これは、『 More Effective Agile “ソフトウェアリーダー”になるための28の道標 』という書籍では、より効果的にアジャイルの価値を引き出すための 1 つの基本原則として紹介されています。 短いスプリントがうまくいくには、動く機能を少しずつ頻繁にデリバリーする能力をチームが養わなければならない。こうした活動をサポートするために用いられる設計アプローチはバーティカルスライスと呼ばれる。バーティカルスライスは、増分的に機能または価値をデリバリーするために各アーキテクチャ層で変更を行う、というものである。 9.4 基本原則:バーティカルスライスでのデリバリー つまり、「XxxAPI を実装します」・「テーブルの設計をします」といったレイヤごとの 作業ではなく て、「ユーザーとして自身のメールアドレスを変更できる」といったように、 1 つのフルスタックの機能 を指します。 この考え方は、『 達人プログラマー 職人から名匠への道 』では、「 曳光弾(Tracer Bullets) 」という言葉で表現されています。エンドツーエンドで、フィーチャに必要なシステムの論理層すべてをまたいで実装すること、を指します。 ユーザーストーリーとは ユーザーストーリーという言葉を当たり前のテンションで使っていましたが、一応の扱い方も含めて、改めて定義しておきます。 ユーザーストーリーとは、ユーザー・顧客視点での「フィーチャ」記述を指すものとされています。そして、フィーチャとはソフトウェアを使う側の視点で記述される、xxx 画面等の機能ではなく「欲しい商品が注文できること」といった使い手にとっての価値のことです。 そして、ユーザーストーリーを実現するということは、使い手にとって価値のある動く機能が求められるため、結果的にバーティカルスライスでのデリバリーが必要になります。 特に決まった記述形式は無いですが、当プロジェクトでは、次の形式としていました。 <ユーザー>が、<機能・性能>にする。なぜなら<ビジネス価値>のためだ。 開発チーム内でそのユーザーストーリーの価値が明らかな場合は、 なぜなら<ビジネス価値>のためだ。 を省略可能としました。 いつ分割し、どう分割するか ストーリーが大きすぎて 1 回のイテレーションには収まらない場合や、より正確な見積が必要な場合に、ユーザーストーリーを分割することは有用でしょう。 イテレーションで収まる範囲にストーリーを分割することで、イテレーションで生まれた成果物に対してのフィードバックを得ることが出来ます。 『 アジャイルな見積りと計画づくり 価値あるソフトウェアを育てる概念と技法 』では、一例として次のような考え方をあげています。 データ境界に沿って分割する 操作の境界で分割する パフォーマンス制約をストーリーにする 優先度に沿って分割する 今回は、「 データ境界に沿って分割する 」と「 パフォーマンス制約をストーリーにする 」という 2 つの考え方を、実際のプロジェクトでどのように適用したかについて解説します。 また、プロジェクトを進めていく中で 「アクターのモチベーションで分割する」 という考え方で分割したものもあるので、こちらもご紹介いたします。 なお、どういうプロジェクト運営するかによって、分割後の単位をユーザーストーリーにするべきかは異なるでしょう。たとえば、『 締め切りが厳しいプロジェクトで、プロジェクト初期にまずやっておきたいこと 』では、 分解単位はユーザーストーリー単位にこだわらず、タスク単位になっても良い 、というやり方でプロダクトバックログをスプリントで終わる単位に分解する考え方を紹介されています。 当プロジェクトでは、プロダクトに対するフィードバックを早期にもらうことを重要視したこともあり、ユーザーストーリーを分割単位として進めました。 画面リニューアルプロジェクト 当記事にて実例として取り上げる、ネットショップ作成サービス「BASE」のお金管理画面のリニューアルプロジェクトを軽く紹介させていただきます。2020 年 7 月 30 日(木)、ショップオーナーが注文の売上を確認したり、その後の振込申請など BASE 上のお金を引き出したりする導線の起点である「お金管理画面」がリニューアルされました。 ↓リニューアル前 リニューアル前のお金管理画面 ↓リニューアル後 リニューアル後のお金管理画面 当プロジェクトでは、UI デザイン・体験を改善することはもちろんなのですが、その裏側では様々なレイヤーでテーマを持ったプロジェクトでした。 フロントエンドに焦点を当てると、Vue.js + TypeScript を利用した MPA(multi page application)化への対応が行われました。その背景については、『 「BASE」の管理画面リニューアルプロジェクトのこれまでとこれから 』や『 次世代の管理画面を作るフロントエンドの取り組み 』にて公開しております。 また、バックエンド側では、ここまでの継ぎ接ぎを続けて複雑化してきたコードのドメイン分析をもっての再整理、規模の大きいショップを運営しているショップオーナーでも快適に扱えるようパフォーマンスを改善する、といったところが主たる関心として高いものでした。 プロジェクト特性を分析する プロジェクトごとに有効な施策が異なるため、自身が携わるプロジェクトを分析することがまず第一ステップとして必要です。 お金管理画面とは、ショップオーナーが、E コマースプラットフォーム「BASE」での活動で発生した入出金が入出金履歴として反映されたり、銀行口座への振込申請や、資金調達サービス「YELL BANK(エールバンク)」での資金調達や支払状況の確認をするといった、売上・お金にまつわる導線の入り口になります。 さらに、E コマースプラットフォーム「BASE」はショップ開設数が 110 万ショップを超え、業態から規模まで多種多様です。ショップオーナーのビジネス状況によっては、たくさんの売上データを扱う必要が生まれ、パフォーマンス特性の問題も取り扱います。 以上の特性から、次のようにユーザーストーリーの分割の考え方を実践しました。 データ境界に沿って分割する たとえば、次のようなユーザーストーリーがありました。 ショップオーナーが、入出金履歴を一覧確認できるようにする この一文だけ見ると、1イテレーションで収まりそうな雰囲気のあるものですが、実際はとても大きなユーザーストーリーです。 E コマースプラットフォーム「BASE」で発生する入出金は、注文売上・振込申請・ショップコインによる売上・資金調達などと、バリエーションが多種多様です。 データ境界に沿って分割するという考え方は、たとえば、多様な情報を持つ検索画面があった場合に、「まず債務情報が見える」といった形である程度のデータ境界を設けて分割する、といったやり方です。 この分割では、エンドツーエンドのバーティカルスライスは保たれているので、特定のデータ境界の成果物を持ってスプリントレビューで顧客に見せることが出来ます。 1 つのユーザーストーリーを実現するために考慮するデータバリエーションが多い場合、有効な考え方になります。 この分割の考え方に基づいて、ユーザーストーリーは次のように分割しました。 Before: ショップオーナーが、入出金履歴を一覧確認できるようにする ↓ After: - ショップオーナーが、売上を確認するため、入出金履歴で売上を見れるようにする - 振込申請をしたショップオーナーが、入出金履歴で振込申請を見れるようにする 入出金履歴のデータ境界(売上・振込申請...etc)ごとに、ユーザーストーリーを分割しています。 パフォーマンス制約をストーリーにする たとえば、次のようなユーザーストーリーがありました。 ショップオーナーが、期間で入出金履歴を検索出来るようにする これは、特定期間内に発生した入出金履歴を検索するという機能ですが、入出金履歴が数十件のショップと、数十万件あるショップでは、求められるパフォーマンス要件が異なります。 『 The Elements of Programming Style, 2nd Edition 』にて、 Brian W. Kernighan 氏・P. J. Plauger 氏は、" Make it right before you make it faster. "(動くようになってから、早く動かすことを考えろ)と言っていました。 また、『 Martin Fowler @ OOP2014 "Workflows of Refactoring" 』にて、 Martin Fowler 氏は、Adding Function(機能追加)と Refactoring(リファクタリング)の帽子のかぶり直しという Kent Beck 氏の TDD のメタファーを紹介していました。その説明の中で、 「いかに早くするか」という観点における Performance の帽子 や、アイデアをスケッチしているような Exploring の帽子があることを口頭で補足していました。 パフォーマンス制約自体をユーザーストーリーにして分割することで、そのストーリーでは、 Performance の帽子をかぶることに集中できるので、作業効率上も利点があるといえるでしょう。 この分割の考え方に基づいて、ユーザーストーリーは次のように分割しました。 Before: ショップオーナーが、期間で入出金履歴を検索出来るようにする ↓ After: - 売上50件以上〜100件未満の順調売店ショップオーナーが、期間で入出金履歴を検索出来るようにする - 大規模売店ショップオーナーが、期間で入出金履歴を検索出来るようにする パフォーマンス要件が発生するような大規模ショップオーナーの考慮は、別のユーザーストーリーに分割しています。 アクターのモチベーションで分割する たとえば、次のようなユーザーストーリーがありました。 ショップオーナーが、お金管理画面を見れるようにする この画面は、様々なモチベーションを持ったショップオーナー、に対してユースケースが想定されています。 一例を上げると、 ショップ開設直後のショップオーナーが、BASE の機能を把握するために開く 振込申請中のショップオーナーが、振込申請の進捗を確認しに来る 資金調達中のショップオーナーが、支払状況を確認できるようにする ショップオーナーが、お金管理画面を見れるようにする。 と言っても、そのショップオーナーがやりたいこと・できることは様々です。そもそも振込申請ができるショップオーナーは、売上をあげていることが前提になります。また、まだ売上を上げていないアカウント登録したばかりのショップオーナーもいます。それぞれ状況が異なり、違うモチベーションを持つショップオーナーというアクターを一概に扱うとスコープが広がってしまいます。 このように、これらのアクターのモチベーションが交わり合っているようなユーザーストーリーは、バリエーションを吸収するために大きくなってしまいます。それに対して、アクターのモチベーションで分割することを試みました。 たとえば、ショップの状態によって異なる導線が用意されるような場合は、1 つのユースケースにまとめず次のように分けることができます。 Before: ショップオーナーが、お金管理画面を見れるようにする ↓ After: - ショップ開設直後のショップオーナーが、「お金管理画面で出来ること」を確認できるようにする - 振込申請中のショップオーナーが、振込申請の進捗を確認できるようにする - YELL BANK で資金調達中のショップオーナーが、支払状況を確認できるようにする 当該画面で、アクターが何をしたいのか、というモチベーションベースで、ユーザーストーリーを分割しています。 場合によっては、最初からユーザーストーリーを分けており、この観点で分割するまでもないケースもあるでしょう。しかし、まだユーザーストーリーの扱いに不慣れなチームであれば、異なるモチベーションが 1 つのユーザーストーリーに混在しているときに、「大きなユーザーストーリーになっていないか」見直す機会になります。 (追記)「ロールモデリング」の一種類が該当することを、Twitterでの反響の中で教えていただきました。目的・方法・状況・熟練度によってロールを分けることで詳しくペルソナを想定するといった発想です。今回の分割の考え方は「目的」でロールを分けていますね。詳しくは、角征典さんが2010年に実施された『 ユーザーストーリー ビギンズナイトの資料 』をご覧ください。 優先順位の考え方 いざ、ユーザーストーリーがそれぞれスプリントに収まる大きさに分解できると、その前後で優先順位をどう考えるかが顔を出すでしょう。 優先順位の高いものから着手していくことを計画する際に、ビジネス価値の高さを意識することになりますが、「ビジネス価値」ってなんだろうってなりませんか。最初、このビジネス価値という言葉に対してこれを言葉で説明できない自分がいるなと思いました。これについても、『 アジャイルな見積りと計画づくり 価値あるソフトウェアを育てる概念と技法 』では、そのビジネス価値の要素に次のような項目を上げています。 1. フィーチャの金銭価値 2. 開発(サポート)にかかるコスト 3. 開発を通じて学べる知識の量とその意義 4. 開発によって低減できるリスク これらのどの要素を重要視するかについては、各プロジェクトで異なるでしょうが、当プロジェクトにおいては、 3. 開発を通じて学べる知識の量とその意義 を重要視しました。 これは、以下のプロジェクト事情を加味した結果です。 実際にエンドユーザーに届けるリリースは、ユーザーストーリーごとに分割できるものが少ない。そのため、対象の機能リリースによる「1. フィーチャの金銭価値」は、優先順位にそこまで影響しない。 Sketch 段階のデザイン検討において必要なスコープの見通しを立てているため、ユーザーストーリーそれぞれは、画面リニューアルリリース時にはだいたい必要な開発になる(MUSTではない機能もいくつかスコープ内にあったため、ある程度可変ではありました)。そのため、「2. 開発(サポート)にかかるコスト」についても優先順位に対しての影響度は少ない。 「3. 開発を通じて学べる知識の量とその意義」は、優先順位の判断に影響のある観点たりうる(その理由は後述します)。「4. 開発によって低減できるリスク」の観点は、3 を考慮していく中で結果的に考えることになる。 リリース計画を考察する際、「スケジュール」・「スコープ」・「リソース」のどれを重要視するかという視点があります。当プロジェクトは、「スコープ」を重要視し、スケジュール・リソースの可変性が高く捉えておりました。 開発を通じて学べる知識の量とその意義 プロジェクトを考えるにあたり、「何が不確実な箇所でリスクとなりうるか」は重要なポイントです。リスクのアンテナを張るに当たり、Alexander Laufer の不確実性理論が、参考になります。 Alexander Laufer の不確実性理論は、ざっくり次のような不確実性の整理です。 目標の不確実性 (end uncertainty) (開発 PJ に対応させると、)何を開発するのか、スコープ・プロダクトの性質 方法の不確実性 (means uncertainty) (開発 PJ に対応させると、)どうやって開発するのか、技術・スキル・連携方法 これらの不確実性を低減させるためにプロジェクトを通して、開発対象のプロダクトについて知り、その作り方について知識を深めていかねばなりません。 取締役 EVP of Development の藤川(えふしん)が、『 ウィズコロナ時代にBASEを成長させていく2つの技術課題 』にて、コンポーネント化、アーキテクチャ刷新に対する学習コストへの適応、を技術的課題としてあげていました。 実際、これは、Alexander Laufer の不確実性理論でいうところの 方法の不確実性 (means uncertainty) が存在する状況です。 実際に当プロジェクトでは、frontend コードの実現方法が見えきっていない箇所の早期着手、backend コードにおけるドメインモデリングのコード化、が早期に来るような形で、ユーザーストーリーに優先順位をつけていきました。 分割したユーザーストーリーを用いたリリース計画とスプリント計画 このプロジェクトでは、リリース計画の中で、プロダクトバックログにユーザーストーリーを入れ、直近 2 スプリントくらいに何をするか、を優先付けし、それらは Miro を用いて可視化していました。 それぞれのユーザーストーリーに対して、開発メンバーで、プランニングポーカーを行いストーリーポイントをつけています。 以下の Miro は実際に使用したボードの一部です。すでに完了したプロジェクトなので、すべてのユーザーストーリーはどれかのイテレーション内に割り当てられていますが、計画策定当初は仮割当で置いておいて、直近のスプリントだけ実際に消化するユーザーストーリーとして割り当てていました。 実際に利用していたMiroのボード 実際に、スプリントが始まると、スプリント計画で実際の作業タスクに落とし込んでいくことになるので、作業時に使用するツールとシームレスになるように、別途タスク管理として GitHub Project を用いました。 さいごに これらの分割を実施したことにより、バーティカルスライスでのデリバリーが実現でき、次のような利点がありました。 プロジェクトの終盤の最終 QA で仕様の齟齬がたくさん見つかってしまう、といった事象を避けることが出来た 毎スプリント動くものを見せ続けたことで、進捗が明確だった プロジェクト開始当初まだ詰められていない要件・仕様についてスプリントレビューで動くプロダクトを見ながら確認できた ストーリーポイントを用いた見積もり方法や、顧客からフィードバックを貰いながら、目標の不確実性や方法の不確実性に対応していくプロジェクト運営において、イテレーションの成果物をいかに作業ではなく、ユーザーにとって価値のあるものにするか、は基礎的ですが重要なポイントでしょう。 大きなユーザーストーリーを目の前にしたそこの貴方にこの記事が参考になれば幸いです。
<アイキャッチ画像はメンバーの許可を得て掲載しています> 挨拶 はじめまして。デザイナーの河越です 2020年卒の新社会人として、4月からBASEのDesign Sectionで働いています。 なんだかんだでもう社会人5ヶ月目。この記事では、未経験からデザイナーとして入社するまでにしたことと、入社してから4ヶ月で取り組んだ業務や考えたことを振り返っていきます。 「当たり前のことしか言ってねぇ!」と思っても、優しく見守っていただけると嬉しいです🙇♀️ デザイナーとして入社するまでにしたことと まず簡単に私がBASEにデザイナーとして入社するまでのことを説明します。 私は2018年6月にBASE BANK株式会社のインターンとしてBASEグループに入社しました。 鶴岡さんのツイートがきっかけだったと思います! やるぞ!!! - 銀行をかんたんに。新会社BASE BANK立ち上げメンバー募集!! by BASE株式会社 ( @BASEec ) #wantedly https://t.co/nicGHulNbI — 鶴岡 裕太 / BASE, Inc. CEO (@0Q7) May 2, 2018 そこから約2年間(途中留学やお休みなどいただきながら)、BASE BANKでお金にまつわるプロダクトのリリースやグロースに携わりました。 BASE BANKで働く過程で、「 YELL BANK 」や BASE BANKのロゴ を作成した吉岡さんの活躍を見たことや、グロースにおける細かいUI改善を行いたくても自分にUI変更を扱えないもどかしさから、「私もデザイナーとしてプロダクト作りに関わりたい」と思うようになります。 デザイナーになりたい旨を社内のデザイナーの先輩方に相談したところ、なんと私専用の研修プログラムを作っていただけることに、、、! (今思えば、本当にやりたかったらこの時点でもっとUIデザインについて勉強しておくべきだったし、未経験からスタートという無茶なお願いを受け入れてくださったデザインチームの先輩方にも、温かく送り出してくださったBASE BANKチームにも感謝が止まりません😭) 2019年10月から、未経験の私をデザイナーとして育成するための、デザイン研修を開催していただきました。 デザイン研修 デザイン研修でやったこと デザイン研修では月ごとに cocoda! にお題として掲載されている、 ギフトサービスTANPのiOSアプリデザイン セールや送料無料キャンペーンなどを想定したバナー作成 「BASE」で過去に行ったキャンペーンのLP作成 progate を使ってコーディング自習 最終課題:「BASE」のデザインマーケットの改善案 などの課題が出され、それに対するアウトプットを作り、毎週一度BASEのデザイナーに1on1のレビューをしていただく機会をいただいていました。 最終課題に取り組んだ1ヶ月は週に2度レビュー会があり、Product Managementのメンバーや社内の他のメンバーにもフィードバックをもらいながらデザイン案を作りました。3月に最終的なアウトプットを神宮司さん(執行役員VP of Product)やDesign Sectionのマネージャーなどにプレゼンし、4月からBASEのデザイナーとして働く内定をいただきました。 デザインレビューは怖くない デザイン研修では週に1時間、レビューの時間をいただいていたのですが、最初の3~4ヶ月はとにかくレビューが怖くて、逃げ出したかったのを覚えています。 レビュー時間を「時間をかけて作ったアウトプットにダメ出しをされる時間」と捉えてしまい、「こんなに頑張ったのにまた振り出しに戻ってしまった...辛い...」「レビューでは私が考えられてなかったポイントばかり指摘されてぐうの音も出ん。デザイナーは視野が広い人しかできない職業で自分には向いていないんじゃないか...辛い...」と、レビューのたびにネガティブになっていました。 あるレビュー会のあと、落ち込んでいる私を見て先輩デザイナーが 「 レビューはアウトプットに対してのフィードバックであって、誰も人格を否定してるわけじゃないよ。ユーザーのためになるプロダクトを作るために、自分にはない視点から意見を受けれる機会だよ! 」 と声をかけてくれました。 自分にない視点を持っている人がアドバイスをくれる機会なんて超貴重です。 頭ではわかってたはずなのに、素直に受け入れられなくなってしまっていた私にはこの言葉がすごく響きました。 それからは、自分へのアドバイスとデザインに対するフィードバックを切り分けて聞くことができるようになり、レビューはもう怖くありません。逆に、レビューをせずにプロダクトが世に出る方が怖いです。 これからも、レビューは「Be Hopeful」な気持ちを持って参加したいと思います。 競合プロダクトのデザインをパクっても意味がない プロダクトを作る時、多くの人が競合プロダクトを調査すると思います。 私はデザイン研修の最終課題「BASEのデザインマーケットの改善案」の最初のレビュー時に、競合サービスを完全に模倣したアウトプットを提出しました。今思うと、競合調査をしました!というアピールもしたかったのかもしれません(笑) デザイナー「ここはどういう意図でこういうデザインにしたの?」 私「OO(競合サービス)がそうなってたからです!OOはたくさん使われてるすごいサービスなので、真似したらいいとおもいました!(アホ)」 というやりとりがありました。先輩は相当頭を抱えていたと思います。 そもそも本当にターゲットは同じ属性なのか 競合サービスはどういった意図でUIを作ったのか 利用者数の多い競合サービスには本当に使いづらいところがないのか を考え、理解しないと、「BASE」のユーザーにとって優しいサービスは作れません。 ユーザーの属性が違えば悩みや欲しいものも違うし、それに合わせたUIを設計しないと、ユーザーにストレスを感じさせてしまうからです。 今は、競合サービスやよく使うアプリやWebサービスを見るときには、そのデザインになった意図を考えるようにしています。今まで気づけなかったデザイナーの気遣いに気付けるようになり、インターネットサービスを使うのが100倍楽しくなりました! また、アプリの自動アップデートをOFFにし、アップデート前後でどうUIが変わったのか、なぜその変更が行われたのかもチェックするようにもしています。 careerhack.en-japan.com 入社して4ヶ月でやったこと 4月からは社員としてBASEで働いていて、「プロジェクト化されないような粒度の細かい改善を行うプロジェクト」という奇妙な名前のプロジェクトにアサインされています。 プロジェクト化されないような粒度の細かい改善を行うプロジェクト(以下改善PJ)は、「ユーザーからの改善要望は届いているけど、粒度が細かくてプロジェクト化するほどでもなく改善を後回しにしていた箇所を改善する」ためのプロジェクトです。 プロダクトはチームで作る プロジェクト内では、メンターの先輩がデザインの壁打ちをしてくれたり、デザインチーム内でレビューをもらったり、PMとバックエンド、フロントエンドエンジニアとQAをしたりと、とにかくたくさんの人と関わりを持ちます。 チームのメンバーと関わる機会が増えれば増えるほど、自分一人ではなく、チームでプロダクトの改善を行っているんだ!という実感が湧いて、勇気が出たし、プロダクトについてより深く考えるようになりました。 私は1Qの間に3つのデザイン改善を担当し、その中の2つがリリースされています。 自分がデザインしたものが世に出る体験が初めてで、リリースの瞬間はドキドキと、「早く使われて欲しい!」という期待と、少し不安もある、複雑な気持ちがありましたが、「もしユーザーからアンハッピーなフィードバックがたくさん来ても、みんなで考えれば解決される」という気持ちの余裕も今は持てています。 大きなプロジェクトだけがプロダクトを支えているわけではない デザイナーを志した当初は、「YELL BANK」のLPやサービスUIを作る先輩を見て「はやく新しいプロダクトを担当できるようになりたい!」と意気込んでいました。 しかし、改善PJを経験し、改善を喜んでくださるユーザーの声を聞くことで、大きなプロジェクトにならないアップデートでも、ユーザーのストレスを解消する小さな改善をMove Fastに行うことで「BASE」のブランド作りに貢献できるとわかるようになりました。 それに気づいてからは、改善PJでも扱われないさらに粒度の細かいもの(例えば1文字の誤字など)も、積極的に改善するようにしています。 作業は急いでする 改善PJにアサインされて、一番怖かったのが、私のデザインの遅延によってリリースが遅れたり、別の方の作業着手を遅らせてしまうことです。 これを防ぐために、自分がどのくらいの時間でどの分量の作業を終わらせられるかをなるべく正確に見積ってPMに伝えることを意識しています。 具体的には、実作業の時間が目標時間に対してどのくらい誤差があるのかを調べ、どのくらいの時間で全体の作業が終わりそうかを伝えていました。 自分の作業能力がわかるようになってきたので、間に合うかな?くらいの努力目標を自分の中で設定することで、作業に集中しないといけいない環境を作るようにもしています。 最初から最後までなるべく全速力で作業することで、作業効率が上がっている気がします。 最後に 長くなりましたが、デザイナーとして働き始めて感じたことを振り返ってみました。 未経験デザイナー・新卒ということもあり、とても手厚くサポートしていただいている最高の環境です。 私はインターンを卒業して社員になってから、もっとBASEが大好きになりました。 まだまだ先輩デザイナーの背中は見えないし、甘えてばかりの日々ですが、一刻も早く恩返しできるように日々努力していきたいです。これからも頑張ります!
Service Dev所属、サーバサイドエンジニアの宮村です。 現在私は、Service Devのチームに所属し、ネットショップ作成サービス「BASE」及びショッピングアプリ「BASE」の機能開発を担当しています。 BASEでは最近、機能開発の際に設計レビューを行うようにしています。その取り組みについて紹介したいと思います。 開発チームについて BASEの開発チームは、メンバーが増えるに従って専門化する形でチームを分割してきました。 現在、サービスの機能開発を主に担当しているService Dev Sectionは、バックエンドが担当領域を分担して2Group、フロントエンド、ネイティブアプリを担当するそれぞれ1Groupの計4つのGroupから成り、Service Devのエンジニアはいずれかのチームに所属する形となっています。 (組織図について興味を持たれた方は、こちらの 会社説明資料 をご確認いただければと思います。) 機能開発の際はそれらの職能別のGroupを横断する形でプロジェクトチームを編成し、プロジェクトチームが主体となって機能開発を行っていきます。チームのメンバー構成はプロジェクトの特性や規模により様々ですが、多くの場合、同じグループから1〜2名がプロジェクトにアサインされることとなります。 設計レビューを始めたわけ 機能の増加、開発メンバーの増加、並行するプロジェクトの増加により、新しく課題が見えてきました。エンジニアに対して多くのプロジェクトが立ち上がったことで顕著に現れたものもありました。 サーバサイドの領域を専門にするエンジニアが自分以外にプロジェクト内にはいない・少ない状態になるため、機能の品質が個人に依存しがちな状況になってしまっていた。早い段階で多くの目で見ることで、機能の品質を担保したい。 チームのコードレビューのプロセスは取り入れていたが、コードレビューの段階で指摘を受けると手戻りが大きいので、早い段階で既存のシステムに詳しいチームメンバーによるレビューを取り入れ、手戻りを少なくしたい。 コードレビュー時に初めてコードを渡されても仕様把握が難しいので、チームメンバー側が事前に新機能を把握しておきたい。 以前からコードレビューは必須としており、チームで品質を担保することを重視してきていましたが、設計段階でレビューを行うことで改善できることもあるのではないかと思い、設計レビューを始めてみることにしました。 設計レビューの実践 いつやるのか 設計レビューのタイミングは、プロジェクトにエンジニアが参加し、テーブル設計、画面設計がある程度できた頃、実装に入る前を目安としました。これまでの実績では、開発チームのキックオフから数日〜数週間の間に行われています。 どうやるのか プロジェクトの担当エンジニアが、レビュー用のドキュメントを作成します。それをもとに、チームメンバーに説明しフィードバックを受ける形でレビュー会を開催します。対面もしくはオンラインミーティングで、同期的に行うこととしており、所要時間は機能によりますが、30分から2時間程度としています。長くなる場合は、複数回に分けて実施することもあります。 ドキュメントとして必ず用意するようにしているのは、以下の内容です。 データベース設計 一度動き出すと変更のコストが大きいので、ER図を必ず用意して確認するようにしています。 アプリケーションのスケーラビリティ クリティカルな処理への影響 決済などお金に関わる箇所を中心に、不具合が発生すると影響が大きい部分は特に注視します。 その他、画面設計やシーケンス図など、機能を理解するための資料を必要に応じて用意します。 設計レビューを運用してみて 最初にやってみてうまくいかなかったこと 仕様理解のために画面イメージから説明を進めていたところ、機能の仕様やUIへのフィードバックが盛り上がってしまい、時間がかかりすぎてしまいました。サービスに対する思いが各々にあることはとても良いと思いますが、効率の面からはバランスを取る必要があります。 それらの部分は、プロジェクトチームでディレクターやデザイナーも含めて検討されたものであり、一番その機能を考えているのはプロジェクトチームのメンバーということは間違いないでしょう。これらの点についてはプロジェクトチームでの決定を尊重し、設計レビューでは実現方法にフォーカスしてレビューするようにしました。 機能の仕様やUIについては明らかに問題があると考えられる場合のみフィードバックすることにして、再度仕切り直すことにしました。 良い点 進め方は未だ改善を繰り返していますが、総合するとポジティブな面が多いと感じています。いくつかを箇条書きで挙げてみます。 ドキュメントを起こして他の人のレビューを受けるというプロセス自体で、設計が整理される効果がある 担当エンジニアが責任を持って設計するので大筋では問題ないことが多いが、やはりいくつかの有効な指摘がある レビュアが現在担当しているリリース前の機能との整合などを検討できるといったメリットもある レビューを受ける側のメリットとして、まだ実装を始める前なので指摘を受け入れて修正しやすい コードレビューの時点では、当然ですがコードはある程度書き終わっているので、その時点でこの変更は…という躊躇も生まれますが、それがないのは個人的にとても大きいと感じています。 もちろん、このレビューは開発を始める前のプロジェクトチームを含めて新機能に対する理解が深くはないタイミングで行われるので、すべてがここでレビューを受けたとおりには進みませんし、すべての問題を軌道修正できるわけでもありません。ただ、レビューを行ったほうが、開発起因での手戻りや課題が早い時点で発生するようになったというような気はします。 課題や注意点 準備段階に関しては、レビューのフォーマットが各人に任せるのではなく統一したほうがレビューする側がやりやすいのではないかということで検討しています。ただ、プロジェクトの特性などもあるので型を決めて守るというのが最善ではない気がしており、試行錯誤しているところです。 また、レビューまでにどのくらい詰めるか、という点も個人の感覚に頼るところが多いかもしれません。レビューを受けても大きな変更は必要ないだろうという程度には詰める必要がありますが、詰め切るのに時間をかけすぎても機能の提供に時間がかかってしまいます。 やりたいことは Move Fast にプロダクトを改善することなので、それを念頭に置いてよりプロセスの方も良い形に改善していきたいと思います。 設計レビュー後のプロセス 設計が承認されると、それをもとに見積もりを行い、各チームの開発に進んでいきます。この時点でプロジェクトのスケジュール、人員計画の見直しを行うようにしています。とりあえず始めてみて、遅れそうになったところ調整を行うのではなく、この段階で相談できるようになったことも、プロジェクト管理の観点からはポジティブな面と言えるかもしれません。(もちろん、開発開始後でも、必要があれば柔軟に対応していきます。) まとめ メンバーの増加、プロジェクトの増加という状況の中、サービス品質と開発スピードを維持するために、設計レビューを取り入れました。 最初は所属Group内で試験的に行っていましたが、最近では別チームも含め、ほぼすべてのPJを対象にレビューを行っています。また、チーム内でのレビュー後にマネージャやCTOといった意思決定者も交えたレビューを実施するようにもなり、少しずつ役割を広げて運用されています。 より良い開発が行えるよう、私たちも日々試行錯誤しながらやっているのですが、同じような課題を抱える方の取り組みの第一歩として、少しでも参考になれば幸いです。
BASE株式会社 Product Dev Division 基盤グループ Engineerの田中 ( @tenkoma )です。 ある出来事がきっかけで2要素認証にYubiKeyを購入して使ってみたので紹介します。 フィッシングに引っかからない自信を無くした話 1ヶ月半前の土曜夕方に、外出先で以下のツイートを見ました。 GitHub Japanさんからフィッシングらしきメールが来てたのでみなさんもお気を付けください pic.twitter.com/CsmkObwUS9 — Eiji Kitamura / えーじ (@agektmr) June 13, 2020 ちょうど数時間前に同じメール文面を見たような気がしたのと、同じく数時間前にPCでGitHub.comにログインしていたので、 「これはマズいかもしれない、引っかかったか?」と焦りました。 その場ではパスワード変更だけしました。急いで帰宅して、状況を調べました。その結果— GitHub またはGitHub Japanを騙るメールは見当たらなかった ブラウザの履歴に偽サイトにアクセスした履歴は無かった GitHub.com のSecurity logに自分の部屋とモバイル回線以外のIPからログインされたり操作されたログは無かった ので、フィッシングにひっかかったというのがほぼ思い違いであることがわかりました。(一安心) もしかすると、上記ツイート以外の注意ツイートを見たことを、メールで受信したと思い込んだのかもしれません。 この経験をしたことで、「上記のようなメールを受信したら、冷静にフィッシングかもと疑うこと無く、偽サイトにワンタイムパスワードごと渡してしまうかもしれない、入力情報を中継されたら、ログインされてしまうかもしれない」と思いました。 YubiKeyを購入して、普段の2段階認証にはそれを使う いままで、GitHubログインするときは、ID/パスワード入力には1Passwordを、 2段階認証(2FA)では、Authyを使った時間同期式のワンタイムパスワード(TOTP)を入力していました。 しかし両方とも人間が入力する情報なので、フィッシングで偽サイトにアクセスした場合に、両方を入力してしまうことができます。 (1Password ならURLも保存しておけば、ブラウザ拡張の補完候補で絞り込まれるので、偽サイトにアクセスしたとき、「候補に表示されない」ことで気づける可能性はあります) YubiKeyなどのキーデバイスを使うと、2FAではサーバー側のホスト名なども含め認証に必要なデータを生成します。 よって本物のGitHubログインにつかう認証データを、人間のミスで渡してしまうことはありません。 僕が購入したのは、YubiKey 5Ciです。 Amazon | Yubico - YubiKey 5Ci - USB-C / Lightning 認証セキュリティキー | Yubico | USBメモリ・フラッシュドライブ 通販 ワンタイムパスワードトークンYubiKey |(株)ソフト技研 MacBook Pro, iPhone X, Pixel 4で使いたかったので、USB Type-C, Lightning端子が付いている5Ciにしました。 GitHub.com の2FAにYubiKeyを設定すると、ログインはどうなる? 使い始める前は、「TOTPより面倒くさくなるのでは、端末毎に設定が必要とかだとつらいな」と思っていましたが、むしろ簡単になりました。 設定は、ページにアクセス後、YubiKeyをさして金属部分を触るだけなので省略します。 (日付をみると、GitHubフィッシングが話題になってすぐYubiKeyを買って設定したことが分かります) GitHub.com に設定したデバイスキー一覧 ログインで、ID/パスワードを入力して送信すると、次のように表示されます。 ID/パスワード送信後は、まずセキュリティキーを使った2要素認証をうながされる キーデバイスを設定すると優先してそれで認証するように促されるんですね。 「Use security key」をクリックして、YubiKeyを差し込み金属部分を触ると、ワンタイムパスワードが送信され、ログインが完了します。 僕の場合、Authyを使ったときより簡単になりました。 Authyの場合、 Authyを起動し GitHubのエントリを検索して表示し(設定が15個くらいある) クリップボードにコピーするか6桁の数字を覚え 貼り付けるか入力して送信 という感じなので、検索しなくてよいので楽です。 また、MacのChromeで有効にすると、他のデバイスでの設定は不要です。 FirefoxやSafariでも使えますし、Pixel 4(Chrome)やiPhone X(Mobile Safari)でもYubiKeyでの2FAが出来ました。 他にどんなサービスで使える? YubiKeyが使えるか試したところ、以下のサービスでは使えることが分かりました G Suite GitLab Twitter Facebook Sentry AWSマネジメントコンソール(rootアカウント、IAMともに) AWS 以外ではTOTPとキーデバイスの両方を同時に設定できるので、YubiKeyを紛失したときのリカバリーとしてTOTPも有効にしています。 個人でAWSのrootアカウントを持っているのですが(全然使えていませんが…)、現時点ではTOTPかキーデバイスの片方しか設定出来ず、YubiKeyを紛失したときのリカバリができないため、rootアカウントには設定していません。 まだ買ってないけど、TOTPのかわりに使える方法ってある? YubiKeyを使い始めてから知ったのですが、最近のMacではTouch IDが使えます。 2段階認証が、Touch IDを指で押さえるだけになるので、オススメです。 またPixel 4の顔認証もキーデバイスとして使えました。 iPhone XのFace IDは使えませんでした。 まとめ YubiKeyを使った2段階認証は、お金はかかるけど、フィッシングでの不正ログイン対策になります ログイン操作も、時間同期式のワンタイムパスワード(TOTP)より簡単になりました YubiKey紛失時のリカバリがかなり面倒なので、AWSマネジメントコンソールのrootアカウントは複数の2FAを設定出来るようになって欲しい YubiKey持ってない場合でも、MacのTouch IDやAndroidの顔認証が使える可能性はあります YubiKey、小さいので、財布とかに入れるとすぐに無くしてしまいそうです。 いまのところ、IDカードホルダーに付けているのですが、リモートワークだと常時付けてないので、別のネックレスのようなものか、リストバンドに付けられるといいかもしれない、と思っています。よい案があれば @tenkoma まで教えてください。
こんにちは。BASE BANK株式会社 Dev Division にて、 Software Developer をしている東口( @hgsgtk )です。 先日開催された July Tech Festa 2020 にて、「 少人数でのアジャイル開発への取り組み実例 (一歩目の踏みだし方) 」という表題で、発表させていただきました。 https://speakerdeck.com/hgsgtk/a-first-step-to-agile-movement 今回はその発表内容について、その思考過程で出会った書籍などを詳説として加えつつ、ブログとして書き下していきます。 発表資料 今回の発表資料は、Speakerdeck に公開しています。 発表内容を通じて解決したいことは、 率直に書くと、 数ヶ月前の自分が教えてほしかったこと です。数ヶ月前の自分は次のような状況でした。 漠然とチーム開発に課題を持っていている その課題に対して、アジャイル関連の施策が、有効な気がしているが、一歩踏み出せていない この資料は、そんな状況を目前としている方々のなにかの役に立てば、と思いまとめたものです。 また、アジャイルと一口に言っても様々な要素が絡んできますが、当該資料は、「チーム環境」に焦点を当てたものです。「 An Agile Way: アジャイルの「ライトウィング」と「レフトウィング」 」の整理では、 アジャイルのレフトウィング (協働でゴールに向かう「チーム環境」)の範囲をスコープとしています。 まずは現状を見る その状況において、私が出会って解決の糸口となったのは、「 みんなでアジャイル ―― 変化に対応できる顧客中心組織のつくりかた 」という書籍です。 www.oreilly.co.jp その中で、次のようなフレーズがありました。 成功するアジャイルの適用は、常に厳しく正直に現状を見ることから始まる。 何がうまくいっていて、何がうまくいっていないのか。アジャイルを今の仕事 のやり方をちょっと変えるだけのことと思っているなら、アジャイルから得られ るメリットもちょっとだけになるだろう。今のやり方を選んだ元になっている現 2章 自分たちの北極星を見つける そして、章の名前「2章 自分たちの北極星を見つける」にある通り、自分たちが大事にしたい・目指したい目標を、言語化することから始めています。 そこからアジャイルとの親和性を考える 自分たちの現状の課題・目指す方向性を言語化出来ると、アジャイル開発の考え方・取り組み方法との対応を考えることができます。 Manifesto for Agile Software Development に示されているアジャイル開発宣言や、「 アジャイルな見積りと計画づくり 価値あるソフトウェアを育てる概念と技法 」にて説明のあるような基本的な仕事の進め方、から、その実践の有無を考察しました。 アジャイルプラクティスを漸進的に導入する すべてのプラクティスを一気に導入することは、手一杯になりますし、一気に生まれた新しい手段・HOWを理解しようとすることに、関心が持っていかれる重力が生まれるでしょう。そのため、優先度にそって、少しずつプラクティスを拡大していくような変遷を、結果的にたどっています。 具体的には、 1. チーム自身の検査と適応 → 2. プロダクトに対する検査と適応 というフェーズをたどりました。 ここで取り組み始めたのは、まずチーム自身の検査と適応のリズムを作ることです。 1週間の スプリント(イテレーション) を設定、最初に計画( スプリント計画 )し、スプリント終了後に、自分たちチームの取り組みについて振り返る レトロスペクティブ を行う 見積もりに、相対的な大きさによって図る ストーリーポイント を利用 現在の状況を可視化するために カンバン管理 を行う カンバン管理は、かつてから Asana を使っていたのですが、うまく管理できていませんでした。今回の取り組みでは、 アジャイルの境界を開発チーム内とした ので、開発作業との親和性を考え、 GitHub Project を利用しました。 それ以外には、日々のコミュニケーションの機会であるデイリースタンディングは、以前から行ってました。 そして、その後、チームが作り出す成果・プロダクトの作り方に対してプラクティスを適用していきました。 プロダクトへのフィードバックループがより頻繁に回るように、スプリントごとの成果物に対する振り返り( スプリントレビュー )を行う フィードバックをもらうために、リリース計画を行う際の前提の考え方を変える( バーティカルスライス でのデリバリーへ) 不確実性を段階的に低減させていく意図 この変遷になった背景には、主に2つの理由を考えていました。 1つ目は、まずは具体的なプラクティスではなく、目標に目を向け、その方法の WHY に着目し、自身の取り組み・振る舞いに対する検査と適応のリズムを作り出すのを優先するという意図。 2つ目は、「 アジャイルな見積りと計画づくり 価値あるソフトウェアを育てる概念と技法 」にて紹介されている、開発プロジェクトの不確実性の考え方「 Alexander Lauferの不確実性理論 」です。この概念では、プロダクトにおける不確実性を次の2つに整理しています。 目標の不確実性 (end uncertainty) (開発PJに対応させると、)何を開発するのか、スコープ・プロダクトの性質 方法の不確実性 (means uncertainty) (開発PJに対応させると、)どうやって開発するのか、技術・スキル・連携方法 すべてのことを一気に片付けようとすると混乱が生まれがちです。そのため、まずは、チームの連携方法や動き方、についての方法の不確実性を低減させ、その後「どういうプロダクトを作るのか」という目標の不確実性を低減させるような取り組みを続ける、フェーズ分けとなりました。 バーティカルスライスでのデリバリーを前提とする 「プロダクトに対する検査と適応」を考えると、その具体的な施策は、プロダクト成果物に対するレビューを行うスプリントレビューが、一つ考えられます。これは、そもそも、イテレーションで生まれる成果物(スクラムの言葉では「インクリメント」でしょうか)に対して、フィードバックが得られるような計画をしていることが前提にあります。その前提において重要なことが、 バーティカルスライスでのデリバリー でしょう。 これは、「 More Effective Agile “ソフトウェアリーダー”になるための28の道標 」という書籍では、より効果的にアジャイルの価値を引き出すための一つの基本原則としても紹介されています。 短いスプリントがうまくいくには、動く機能を少しずつ頻繁にデリバリーする能力をチームが養わなければならない。こうした活動をサポートするために用いられる設計アプローチはバーティカルスライスと呼ばれる。バーティカルスライスは、増分的に機能または価値をデリバリーするために各アーキテクチャ層で変更を行う、というものである。 9.4 基本原則:バーティカルスライスでのデリバリー つまり、「XxxAPIを実装します」・「テーブルの設計をします」といったレイヤごとの 作業ではなく て、「ユーザーとして自身のメールアドレスを変更できる」といったように、 一つのフルスタックの機能 を指します。 実際に、プロダクトに対する検査と適応のループを回そうとすると、この考え方が必要になってくるため、リリース計画自体もこの考え方を前提にリプランニングをしました。 取り組みを始めてから 実際にこのような取り組みに踏み切ったのは、COVID-19の流行がはじまった今年の春からの話です。しかし、1weekのスプリントを通して、チーム開発についてのフィードバックループが、以前よりも早く回っていることを感じます。 具体的に目に見えるような差で言うと、JTF2020から2月弱前の2020年6月4日に、コネヒトマルシェというイベントで「 小さなチームが始めたアジャイル開発 」という発表をしました。目指す方向性は変わっていませんが、その中のチームの取り組み・実装方法は改善され、変容を遂げています。 チームやその周りを取り巻く状況は日々変わっていきますが、その不確実性の高い外部要因に対しても、スプリント単位での適応の議論ができているように感じています。 さいごに:July Tech Festa 2020 への謝辞 July Tech Festa 2020 とは、2020年7月25日(土)に開催された、カンファレンスです。今回、600名強?の参加申込みがあったとのことした。 techfesta.connpass.com ITに関わる全ての人の知的好奇心を満たすお祭りを作りたい。 その思いからJuly Tech Festaは生まれました。 興味のある技術に触れ、普段会えない人の話を聞き、 参加したエンジニアがスキルやキャリアについて考えるきっかけになれば。 そんな場を作ろうと今年も July Tech Festa 2020 を開催します。 個人的な話で恐縮ですが、自分が社会人エンジニアになってから初めてカンファレンス参加したのが、July Tech Festa でした。たしか July Tech Festa 2016 だったと思います。その際、「外の世界は想像以上に先へ進んでいる...!」と衝撃を受け、今回のカンファレンステーマであるように「 Extend Your Engineering Life! 」したことを、強い記憶として思っています。今回、そんなJuly Tech Festaのスピーカーとしてプロポーザルを採択いただいたのは、感慨深い想いでした。 今回、初のオンラインでのカンファレンスのなか、運営スタッフの方々には、この場を借りて感謝申し上げます。ありがとうございました。
CTOの川口です。 今回はアプリケーションのエラートラッキングツールについてです。 これまでの経緯 BASEでは主にPHPアプリケーションのエラートラッキングにRaygunを利用していました。 https://raygun.com/ これを採用したのは3年以上前で、当時BASEではPHP5.3を利用していたために利用できるツールは限られておりRaygunはPHP5.3でも動いたため採用されたようです。 今では7.3を利用していたのでこの条件は気にする必要はありませんが、積極的に変更する理由もなく使っていました。 当初はPHPのエラートラッキングにのみ利用していましたが最近はfrontendのエラートラッキングにも利用しています。 ここが辛いよRaygun まず料金が結構高めです。 APMやRealUserMonitoringなどの利用はしておらずエラートラッキングのみ使っています。 https://raygun.com/platform/crash-reporting APMはPHPに対応していませんし元々Newrelicを利用しています。 small business プランを利用しており、$249/month です。 https://raygun.com/platform/crash-reporting#pricing これは非常に高額というほどでもありません。 ですが、更にこの上のプランになると$899と一気に値段があがります。これは一気に高額になります。 これのしきい値がエラーイベントの件数になっており、月間の件数を超えてしまうとプランを変更する必要があります。 25万エラーを超えて100万エラーまで受け付けてくれるのはありがたいですが、結果的には30万イベント程度で済むであろう事が想定されコストパフォーマンスが悪くなります。 さらにRaygunはあまりPHPのサポートに積極的でなく、UTF-8以外を含むと問題が出たりします。 https://github.com/MindscapeHQ/raygun4php/pull/69 https://github.com/MindscapeHQ/raygun4php/pull/69#issuecomment-514351759 https://github.com/MindscapeHQ/raygun4php/issues/94 PRに対する反応も鈍いため弊社ではforkしてパッチを当てて運用していました。 WEB UIもあまり良いものでなく全体的に遅く、日付範囲でのサマリなどがし辛いと感じていました。 GitHubへのissue連携も古いAPIなどを利用しているようで、Raygunへ渡す権限があまりに強くこのあたりも問題です。 別のエラートラッキングツールに変更も話題には登っていましたが、ずるずると先延ばしていました。 エラー量増加に依るトラッキングの停止 現在のプランでは250,000 error events/monthを処理することが出来ます。 基本的にこの数を超えることはないのですが、ミドルウェアの変更などで想定外のエラーが出たりするとアクセス量が多いサービスの場合エラーイベントが一時的に大量に発生します。 ある時、これが複数回起きてしまいlimitを超えてしまいました。 完全にトラッキングが止まったわけではありませんが、エラートラッキングツールとして常用出来ません。 当然プランを上げれば動作するわけなのですが、3.5倍近い値段を払ってまで?という気持ちもありこのタイミングで乗換を検討しました。 Raygunのようなサービスでは過去のデータはそこまで重要度は高くありません。 まだ修正出来ていないエラーが有る場合別のトラッキングツールに乗り換えたところで発生することはわかっているので改めて収集すればいいので問題にはなりません。 料金も安く、機能的に優れているものに乗り換える方がメリットになると考えました。もちろん安いからと言って機能が十分でなければraygunでもいいですし別の高額なツールでも問題はありません。 乗り換え先 同様のエラートラッキングツールはいくつかあり Bugsnag Rollbar newrelic Airbrake などがあります。 今回は弊社で利用したことがあるメンバーもいたので、Sentryにすることにしました。 値段もRaygunより安価ですし、機能も豊富そうに見えます。 仮に特定の月にエラーが大量に発生しても、その量に応じて追加課金になるので今回のような事態になっても毎月のプランまで変える必要がなくて安心感があります。 https://sentry.io/pricing/ https://docs.sentry.io/accounts/pricing/#faq 14日はトライアルもできるので一時的な乗り換えに使って不満があればRaygunに戻る事もできます。 SDKも用意されています。弊社で使っているCakePHPを完全にサポートされているわけではないですがRaygunを利用しているコードに少し修正を加えるだけで動きそう、ということで移行をはじめました。 https://sentry.io/for/php/ 移行の実装は数時間で完了しました。 ここがすごいよSentry Sentryのエラートラッキング自体はraygunと別に変わりはありませんが、圧倒的に多機能である事がわかりました。 WEB UIを見てみると、動作も速く情報量が非常に多くあります。 Raygunの場合、環境毎にアプリケーションを登録しapi keyを差し替える必要がありますがSentryの場合はenvironmentを指定することで一つのアプリケーションとして登録することが出来ます。 特に便利だと感じたのはエラー時のスコープにある変数がSentry上で確認できるので、どのような変数によってエラーが起きるのかの調査が捗ります。 下記のような事象は「Undefined index: id」というエラーが発生した場合の表示です。 $favorites に特定indexのみないのかそもそも空を参照していたか、というのが判断可能であり、さらにitem_idも空配列ということがわかるのでなぜこのようなエラーが発生したかの調査にとても有用です。 error PHPのコードも一部表示されるので出先でちょっとした調査くらいならできそうです。 とはいえ勝手にSentryにコードがアップロードされているのでは?ということでセキュリティ的にちょっと心配になるのも事実です。 Spike Protectionという機能がデフォルトでオンになっており、一時的に大量にイベントが発生した場合などにイベントを破棄してくれるようです。 DB障害などがあると全てのアクセスでエラーイベントが発生し情報の精度は下がりつつイベント回数を消費してしまい課金額が上がってしまいがちですがこれはそれを回避してくれそうです。 https://docs.sentry.io/accounts/quotas/?_ga=2.25032318.591036687.1594604704-646375577.1594038001#spike-protection docs.sentry.io ここがつらいよSentry トライアルしている状態なので明確な不満があるわけではまだありません。 通知も細かく設定できるのですが、ここはちょっと慣れていないと大変だなという印象です。 RaygunはとりあえずSlack通知くらいだったらwebhookのurlを渡せばよかったのですが、どういう条件で通知するかというのを登録しないといけないので慣れるまでは戸惑いがありました。 他には「Allow Shared Issues」という機能がありカジュアルにエラーのURLを公開出来てしまうのは危険なのでオフにしました。 多機能であるがゆえに、どこを見ればいいか迷ってしまうなとは感じています。あまりにシンプルだったRaygunからの移行なため余計にそう思ってしまうのかもしれません。 おわりに まだトライアル段階なので使いこなせているというほどではないですが、SentryはRaygunよりも優れているツールだと感じました。 もちろんエラーは通知さえできればいいというものではなく解消していき狼少年にならないようにアプリケーションを改善していくことが重要ですが、どのような場合にエラーが出ているのかの調査がわかりやすく改善もしやすいです。 どのデプロイによってどのようなエラーが引き起こされたか、などを観測していきアプリケーションの改善に役立てていきたいと思います。
フロントエンドチームの右京です。 Vue.js 3 が 八月上旬にリリース予定 ということで、BASE でもバージョンアップに向けて少しづつアクションを始めています。 Vue.js 3 では多くの機能が追加され開発の幅が広がりますが、一方で削除や非推奨となる機能も多く頭を悩まされている方もいるのではないでしょうか、BASE もそうです。 この記事では ESLint とその Vue.js 向けプラグインの eslint-plugin-vue を利用した、deprecated となる機能へのアプローチを紹介します。 なぜ eslint-plugin-vue か ESLint には Vue.js の SFC のためのプラグインとして eslint-plugin-vue が開発されていて、BASE でもこれを利用しています。 このプラグインには vue/no-deprecated- で始まるルールがいくつかあります。これは非推奨になった機能を使用しているかどうかを検出するためのルールです。 これまでは Vue.js 2.6 で非推奨になった slot と scope に関する以下のルールのみでした。 vue/no-deprecated-slot-attribute vue/no-deprecated-scope-attribute vue/no-deprecated-slot-scope-attribute しかし、最近リリースされ開発の勧められている v7.0.0-alpha.x で多数のルールの追加が行われています。 例えば BASE の場合、Vue.js 3 の移行で特に課題だったのが filter の廃止です。 金額の変換に多くの filter を使用していたため、範囲も広く置き換え方法を模索していたところでした。 eslint-plugin-vue では、これを vue/no-deprecated-filter ルールを適用することで検出することできます。 このほかにも多数のルールが現在進行形で追加されています。 ルールの一覧は 7.0.0-alpha.x タグの docs や、@ota-meshi さんによる日本語での解説から参照できます。 https://github.com/vuejs/eslint-plugin-vue/tree/v7.0.0-alpha.9/docs/rules https://qiita.com/ota-meshi/items/ff0d70ef326657249727 BASE では多数あるルールの中でも、特に効果の大きそうな <template> に関するルールを中心に追加していくことにしました。 <script> 部分には vue-class-component を使用していることもあり、一旦優先するべきところではないと判断しています。 Monorepo と GitHub Actions を利用した別ラインでの継続的な改修 現行の Vue.js 2.x での開発ももちろん行われているため、突然 ESLint のルールを変更するのはハードルが高く感じ、しばらくの間は既存のルールを共存させることにしました。 これを実現するため、 yarn workspace で Monorepo として 7.0.0-alpha.x をインストールし、普段使用しているものとは別のルールを適用できるようにしています。 . ├── packages │ └── eslint-for-vue3 │ ├── node_modules │ │ └── eslint-plugin-vue // 7.0.0.alpha-x │ ├── .eslintrc.js // Vue 3 に向けた設定 │ └── package.json ├── node_modules | ... │ ├── eslint │ └── eslint-plugin-vue // 普段使っているバージョン ├── src // lint する対象 ├── .eslintrc.js // 普段使っている設定 ├── package.json └── yarn.lock eslint-for-vue3 の package.json で 7.0.0-alpha.x を dependencies に追加します。そして、この Monorepo のコンテキストで ESLint を実行する scripts を設定しています。 { " name ": " @base/eslint-for-vue3 ", " private ": true , " dependencies ": { " eslint-plugin-vue ": " 7.0.0-alpha.9 " } , " scripts ": { " lint ": " eslint -c ./.eslintrc.js --ext .vue ../../src " } } .eslintrc.js には普段使用しているルールに加えて、 vue/no-deprecated-* のルールを追加しています。 module.exports = { extends : "@baseinc/eslint-config-base" , rules: { 'vue/no-deprecated-slot-attribute' : 2, 'vue/no-deprecated-scope-attribute' : 2, 'vue/no-deprecated-slot-scope-attribute' : 2, 'vue/no-deprecated-filter' : 2, 'vue/no-deprecated-v-bind-sync' : 2, 'vue/no-deprecated-v-on-number-modifiers' : 2, 'vue/no-deprecated-events-api' : 2, 'vue/no-deprecated-functional-template' : 2, 'vue/no-deprecated-html-element-is' : 2, 'vue/no-deprecated-vue-config-keycodes' : 2, 'vue/no-deprecated-dollar-listeners-api' : 2, 'vue/no-deprecated-v-on-native-modifier' : 2, 'vue/no-deprecated-dollar-scopedslots-api' : 2, } } この状態で以下のコマンドで、普段使っているものとは別のルールを適用した ESLint を実行できます。 $ yarn workspace @base/eslint-for-vue3 run lint 対応が終了したらこの .eslintrc.js を普段使うものに昇格させ、Monorepo を削除してしまえばあとの片付けも簡単です。 GitHub Actions でデイリービルドを構築し、モチベーションを高める フロントエンドチームでは毎日十四時ごろからスタンドアップミーティングを行っており、これに合せて ESLint を実行するような GitHub Action を設定しています。日々進捗を確認する機会を設けることで、Vue.js 3 へのモチベーションも高めるようにしています。 name: lint for Vue.js 3 on: schedule: - cron: 0 5 * * * jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: node-version: '12.x' - uses: actions/cache@v1 with: path: node_modules key: ${{ runner.os }}-lintvue3-${{ hashFiles('**/yarn.lock') }} restore-keys: | ${{ runner.os }}-lintvue3- - run: yarn install --pure-lockfile --ignore-optional --network-concurrency 1 - run: yarn workspace @web/eslint-for-vue3 run lint - if: failure() env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} run: | curl \ -X POST\ --data-urlencode "payload=\ {\ \"text\": \":bomb: Vue.js 3 マデアト: https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID} \",\ }"\ ${SLACK_WEBHOOK} 以上です。 まとめ ESLint を利用した比較的気軽に導入できる Vue.js 3 への対応方法を紹介しました。 もちろんこのエラーがなくなったからといって Vue.js 3 への対応が終了するわけではありませんが、対応のとっかかりなどになれば幸いです。 ちなみにですが、特に Vue.js の比率の高いリポジトリにこれを実行した結果は以下でした。 ✖ 500 problems (500 errors)