TECH PLAY

BASE株式会社

BASE株式会社 の技術ブログ

580

はじめに どうも。BASEで開発をお手伝いしている 林( @intele ) です! 今回はBASEという大きなプロダクトでドメインを移行した話を、エンジニア目線で、振り返りながらお話したいと思います。 何をやったか BASEで使用しているドメインを thebase.in から thebase.com へ移行を行いました。 ただ、BASEではサブドメインを多用しているため、移行するドメインは thebase.in だけではなく、複数のサブドメインを含め、移行しました。 なぜ移行する必要があったか ****.thebase.in というサブドメイン運用されているショップで広告の効果計測ができなくなったため Apple が推進する App Tracking Transparency(以下ATT) の影響を受けて、Facebook広告の計測手法が変更され、効果計測ができなくなってしまったため ATT で効果計測ができる条件として Public Suffix List(以下PSL) に thebase.in 登録することが必須条件となる PSL に登録したドメインは、Cookie を持つことができなくなるため Cookie を持つことができないと、ログイン状態などを保持できなくなるため この5つの理由から、ドメインを移行することになりました。 移行することで、PSL に登録すること・Cookie を持つことができるようになるということを目指しました。 ※ATT と PSL の説明については省略します。 最初の見積 最初の見積は概算で期間6ヶ月程度とかなり甘く見積もっていました。 というのも 影響範囲が大きすぎて、短期間での詳細な見積は難しいだろう レビューを必ず行っているので、品質は一定レベルは担保されているだろう ユニットテストが充実しているので、修正を加えても動作の確認がしやすいだろう 設定ファイルにドメインが記載されているため、コードと深く結びついていないだろう という理由から、6ヶ月程度と見積もっていました。 この予測が甘かったと知るのは、実際の作業が始まってからのことでした… 問題の発覚 開発が進めば進むほど、問題が発覚していきました。 ドメインがコードに直接記載されていたり、ロジックに深く結びついている箇所が多数存在する ユニットテストが足りない、そもそも存在しない 特定の環境でしか動作しないロジックが存在する コードは存在するが動作はしてないデットコードが存在する など、開発が進むにつれて、見積が甘かったことが明らかになっていきました。 プロジェクトの仕切り直し このままでは、開発もリリースが難しいと判断し、開発チーム内で協議した結果、プロジェクトの仕切り直しをする事となりました。 仕切り直し後は、以下のような方針で開発を進めました。 01. 根幹改修 ドメインを切り替えるために必要な改修の根幹となる改修を行います。 具体的にはURLやドメインを扱ったりするClassの整備やアプリケーション全体に影響するRouting周りの改修を行います。 02. 部分改修 各ページやApps単位で改修を行い都度リリースを行います。 この段階ではドメイン変更は行わず、根幹修正で行った、URLやドメインを扱うClassを使用するようにアプリケーション全体を改修しました。 また、動作検証が難しい部分は、ユニットテストを追加することで、動作を担保し、それでも難しい場合は後続のQAで動作を担保するようにしました。 03. 全リリース 部分改修でリリースが行えなかった箇所をまとめて、アプリケーション全体のQAを行います。 QA完了後にリリースを行い、アプリケーションの振る舞いは変わらないが、ドメインの変更が容易に行える状態となります。 他にも、インフラ側で行う必要があるリダイレクト整理や設定を行います。 04. ドメイン切替 ドメインが容易に切り替えられる状態となったので、ドメインを切り替えた状態でQAを行います。 QA完了後にリリースを行い、ドメインの切り替えが完了となります。 リリース リリースは、深夜メンテナンスにてサービスを止めて行いました。 その当日も問題が発生し、リリースが出来ないかもしれない危機に直面しましたが、 なんとか問題を解決し、リリースまでこぎつけました。 また、大規模な変更を行ったため、大きな問題が起こる可能性も危惧し、万全の体制をとっていましたが、結果としては小さな不具合が10件程度で収まり、ユーザーの皆様に不便をかけることなく終えることが出来ました。 感想 これまでお話した通りリリースに至るまでの過程では色々と問題がありましたが、 プロジェクトのキックオフから、リリースまでの期間は約1年となり若干短い期間となりました。 短い期間で行えたのは常日頃からレビューやテストを徹底しているBASEの開発チームの努力の賜物だと思っています。
Tech Dept. 基盤グループエンジニアの @tenkoma です。 BASEには50以上のPHPプロジェクトのプライベートリポジトリがあります。 (アプリケーションは十数個で、残りの多くが、アプリケーションが依存するライブラリです) 過去4年ほどの間に新規に作られたリポジトリにはほぼ最初からPHPStanが導入されていますが、それ以前から開発していたリポジトリには導入されていないものが多数ありました。 それらのリポジトリにPHPStanを導入していったので、なぜ導入したか、導入方法、得られた効果について紹介します。 PHPStanとは PHPコードを実行せずに、実行時にエラーになりうる箇所を検出するツールです。PHPStanを利用しCIに組み込むと、テスト実行せずに検出できるバグの一部は、PHPStan解析で指摘してくれるので、コードレビューの負担が減ることが期待できます。 なぜPHPStanを既存のプロジェクトに導入したか 直接的なきっかけは、PHP 7.3で実行していたアプリケーションをPHP 8.0対応作業中、切り替え前の最終的な検証中にFatal Errorが発生したことです。 以下のようなコードでした。 <?php class ToaruService { public function __construct () { /* ... */ } public function make () : self { return new self ( /* ... */ ) ; } } class ToaruApiController { public $ toaruService ; public function endpoint () { $ toaruService = $ this -> toaruService ?? ToaruService :: make () ; $ toaruService -> apply ( /* ... */ ) ; // } } ToaruService クラスの make() はインスタンスメソッドですが、 ToaruApiController からは static 呼び出ししています。 実行すると以下のようなエラーが発生します。 PHP Fatal error: Uncaught Error: Non-static method ToaruService::make() cannot be called statically in /path/to/ToaruApiController.php:34 これは、PHP 7.0で非推奨になりPHP 8.0で削除された機能、「非staticメソッドのstatic呼び出し」で発生しています。 非 static メソッドに対する static 呼び出し - PHP 7.0.x で推奨されなくなる機能 - PHP 5.6.x から PHP 7.0.x への移行 その他の下位互換性のない変更 - 下位互換性のない変更点 - PHP 7.4.x から PHP 8.0.x への移行 ToaruService クラス、 ToaruApiController::endpoint() ともにテストコードはありましたが、テストコードではPHPUnitのモック機能によりテストダブルに置き換えられていました。 また、Deprecated Errorを抑制していたため、将来的に使えなくなる機能を見過ごしてしまっていました。 PHP バージョンアップ手順は大きく分けて (1) CircleCI でPHP 8.0でテスト実行や文法チェックを実行させる (2) 検証環境で PHP 8.0で動かして、E2Eのリグレッションテストを行う (3) ステージング環境・実運用環境を PHP 8.0に切り替える という手順で行いましたが、(2) の、ある程度終えたと思っていたタイミングで、基本的なエラーが検出できなかったため、社内のリポジトリで導入実績のあったPHPStanを導入することにしました。 今までPHPStanを使っていなかったプロジェクトへの導入方法 今回は以下の手順で導入しました。 なぜ導入するか、PHPStanとは何か、をドキュメントに書いて社内に共有する プロジェクトリポジトリに composer コマンドで、PHPStanを追加する PHPプロジェクトに合わせた設定ファイルを追加する level=0でベースラインファイルを生成する CIでも実行されるよう、設定する level=0でも無視できないエラーがある場合コードを修正する、もしくは問題ない場合は、解析対象から除外する これまでの変更をメインのブランチにマージする Slackに相談用チャンネルを用意し、PHPStanで相談できるようにする 今回重視したのは、プロダクションコードを網羅的に検査してPHPバージョンアップ作業の安全性を高めることでした。 そのため、level=0で導入し、既存のエラーはベースラインで一旦無視するようにしました。また相談用Slackチャンネルで導入直後のトラブルを素早く解決できる環境を用意しました。 なぜ導入するか、PHPStanとは何か、をドキュメントに書いて社内に共有した PHPStan導入は事前に計画していなかったため、当然社内への情報共有が0でした。 作業を始める前に、導入目的の言語化や、情報共有も兼ねて社内Wikiにドキュメントを追加して、なぜやっているのかわかってもらえるようにしました。 プロジェクトリポジトリに composer コマンドで、PHPStanを追加する Getting Started | PHPStan を見ながら、プロジェクトにPHPStanを追加しました。 $ composer require --dev phpstan/phpstan PHPStanはComposerパッケージとして配布されていて、いくつか別のComposerパッケージに依存しています。しかし、それらの依存パッケージは、 phpstan.phar ファイルにまとめられているので、 composer require --dev で追加したときに問題が起きにくくなっているようです。 参考: PHPStanをどうやってインストールするか この後、 First run のように、まず解析を実行してみて、PHPStanインストールが成功しているか確認しました。 $ Vendor/bin/phpstan analyse Controller --memory-limit=1536M # ...(中略)... [ERROR] Found 4078 errors なかなかの数のエラーが出ました。これらが全てアプリケーションの潜在的問題とは限りません。解析対象を /path/to/project/Controller のみで実行しましたので。 今回導入したプロジェクトには、他にも社内で開発したコードを含むディレクトリがあり、それらをPHPStanで解析してもらうために設定ファイルを書きました。 また、 --memory-limit=1536M で、使用メモリの上限を指定しています。プロジェクト全体(テストコードは除く)を解析すると、1GBでもメモリ確保に失敗するため、1.5GBを指定する必要があありました。 # memory_limit=128M で実行した時のエラー Child process error (exit code 255): PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes) in ... PHPプロジェクトに合わせて設定ファイルを追加する プロジェクトのルートディレクトリに設定ファイル phpstan.neon.dist を用意します。 今回導入したリポジトリでは以下のような設定になりました。 # phpstan.neon.dist parameters: level: 0 phpVersion: 80000 parallel: processTimeout: 1200.0 paths: - Config - Controller - Model - Vendor/foo - Vendor/bar - View - webroot # - Test # プロダクション・コードの非互換コード検出を優先して、テストコードは解析除外 scanDirectories: - Vendor 設定ファイルの要点をまとめると paths には、解析対象(PHPStanに問題を指摘してほしいPHPコード)のあるディレクトリを列挙します Vendor ディレクトリにも、リポジトリで管理しているファイルがある場合は、ここで明示します PHPアップグレード作業の安定性を高める目的で導入するため、まずはテストコードを除外しているので、コメントアウトで意図を明示しています scanDirectories には、 Vendor を指定しました。Composer でインストールしていて、自分たちで開発していないコードは scanDirectories や scanFiles に指定します。 となります。設定ファイルを書くことで、PHPStanがプロジェクトの構成を理解しますので、設定ファイルを少し付け足しては Vendor/bin/phpstan analyse --memory-limit=1536M を実行し、その結果を見て、 paths や scanDirectories を調整して、リポジトリに合った設定にして行きました。 ベースラインファイルを生成する 設定ファイルもある程度形ができたら解析を実行してみます。 $ Vendor/bin/phpstan analyse --memory-limit=1536M ------ ----------------------------------------------------------------------------- Line SomeApi/ApiClient.php ------ ----------------------------------------------------------------------------- 15 Access to an undefined property BaseInc\\WebApp\\ApiClient::$client. ------ ----------------------------------------------------------------------------- ------ ------------------------------------------------------------------------------------------------------------------ Line Services/SomeService.php ------ ------------------------------------------------------------------------------------------------------------------ 128 Access to an undefined property BaseInc\\WebApp\\Servises\\SomeService::$User. ------ ------------------------------------------------------------------------------------------------------------------ ... (以下、とてもたくさん省略) ... [ERROR] Found 2596 errors なかなかの数、エラーが出ました。中身をざっとみてみると、動的プロパティ(未定義のプロパティ)や、 @property アノテーションの記述ミスが大半でした。しかし、それ以外の指摘も多くあるようです。有用な指摘かもしれませんが、全て解消するとなると骨の折れる仕事になりそうです。 エラーがたくさん指摘されていてもアプリケーションが実運用できているなら、指摘されるエラーの多くは不具合につながらない指摘と推定できます。そのようなエラーを一括で除外してPHPStanを導入しやすくしてくれる機能が ベースライン です。今回は静的解析の導入を優先するため、ベースラインで既存のエラーの多くを一旦無視するようにしました。 ベースラインファイルを生成するには、 --generate-baseline オプションを付けて解析実行します。 $ Vendor/bin/phpstan analyse --memory-limit=1536M --generate-baseline phpstan-baseline.php Note: Using configuration file /path/to/project/phpstan.neon.dist. 4182/4182 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100% [WARNING] Baseline generated with 2381 errors. Some errors could not be put into baseline. Re-run PHPStan and fix them. 不穏な警告が表示されましたが、 phpstan-baseline.php が生成されました。 生成されたファイルは、以下のようになっています。 <?php declare ( strict_types = 1 ) ; $ ignoreErrors = [] ; $ ignoreErrors [] = [ 'message' => '#^Unsafe usage of new static \\\\ ( \\\\ ) \\\\ .$#' , 'count' => 1 , 'path' => __DIR__ . '/SomeApi/Request.php' , ] ; // ... (以下、とてもたくさん省略) ... 'path' に 'message' のエラーが 'count' 個ある、と読めます。 'path' が指定されているので、このPHPファイル以外で同じエラーは無視されませんし 'count' があるので、 '/SomeApi/Request.php' で同じエラーが増えた場合は、エラーが出るようになります。 設定ファイルで、生成したベースラインファイルを読み込むようにして、解析を再実行します。 # phpstan.neon.dist に以下の行を追加する includes: - phpstan-baseline.php % Vendor/bin/phpstan analyse --memory-limit=1536M Note: Using configuration file /Volumes/src/github.com/baseinc/web/phpstan.neon.dist. 4182/4182 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100% ------ --------------------------------------------------------------------- Line BaseInc/App/Services/SomeService.php ------ --------------------------------------------------------------------- 7 Class SomeService extends unknown class AbstractService. 💡 Learn more at <https://phpstan.org/user-guide/discovering-symbols> ------ --------------------------------------------------------------------- ... (以下、たくさん省略) ... [ERROR] Found 212 errors エラーが1/10以下に減りましたが、まだまだエラーが出ています。これらのエラーはベースラインでは無視できないようです。しかしベースラインは生成できたので、 phpstan-baseline.php , phpstan.neon.dist をコミットします。 level=0でも無視できないエラーがある場合コードを修正する、もしくは問題ない場合は、解析対象から除外する 200件あまりのエラーは、ベースラインで無視できないものでした。 これらのエラーに対して取れる選択肢は、以下の2つです。 エラーを修正する 解析対象から除外する エラー出力をながめてみると、その多くが Class SomeService extends unknown class AbstractService. というエラーでした。 以下のように定義している AbstractService を use を使わずに読み込んだ場合にエラーになりました。 <?php namespace BaseInc\\Services; class_alias ( AbstractService :: class , 'AbstractService' ) ; abstract class AbstractService { // 略 } これらは、PhpStormで簡単に修正でき、修正結果を他ならぬPHPStanで保証できるので、修正することにしました。 class_alias(...) も削除できました。 このエラーを修正した結果、10個程度に減りました。 残りのエラーについて、簡単なものは修正しましたが、難しいものは、除外することにしました。 excludePaths: analyse: # ベースラインで無視できず、修正困難なため解析対象外にする - Too/Dificalt/Fix/Error/Module.php CIでも実行されるよう、設定する CIでPHPStanを実行すると、テストコードを同時にコミットしていなくても、変更したプロダクションコードの問題を指摘してくれて大変便利です。 また、継続的に実行されないと、コード変更でエラーが増えてしまうので、CIで実行し、エラーは修正してもらうようお願いしています。 CircleCIでのjob設定は以下のようになります。 phpstan : docker : - image : cimg/php:8.0 resource_class : xlarge steps : - checkout - run : name : composer install command : | composer config --global github-oauth.github.com ${GITHUB_ACCESS_TOKEN} composer install --prefer-dist --no-interaction --no-scripts - run : name : create reports directory command : mkdir ~/reports/ - run : name : Run phpstan analyse command : Vendor/bin/phpstan analyse --no-interaction --error-format=junit --memory-limit=1536M > ~/reports/phpstan-junit.xml - store_test_results : path : ~/reports/ - store_artifacts : path : ~/reports/ エラー情報を JUnit フォーマットで出力し、 store_test_results でテスト結果として認識されるよう設定すると、PHPUnitテスト同様に、エラーが一覧できます。 PHPStan解析エラーがCircleCI結果に表示される PHPStanを実行するインスタンスのスペックを指定する resource_class: xlarge としています。 CircleCIは、 resource_class で、CPUコア数やメモリを増減できます。 PHPStanは、解析に使う論理CPUコア数が増えると解析時間が短くなるので、 resource_class を増やした時の効果が高いです。また使える論理CPUコア数が増えれば、1プロセスあたりに使うメモリ量は減ります。 PHPStan を実行してみて、メモリ不足で失敗せず、解析時間が長くならないような resource_class として、このリポジトリでは xlarge にしました。 他のリポジトリでは、 small で十分なリポジトリもあります。 これまでの変更をメインのブランチにマージする CIでPHPStan解析ができるようになりましたので、メインのブランチにマージします。 Slackに相談用チャンネルを用意し、PHPStanで相談できるようにする メインのブランチにマージ後すぐは、指摘されるエラーへの対応で困ることが発生するかもしれない、と思い、Slackに相談窓口としてチャンネル #help-dev-phpstan を作りました。 「新しくPHPStanでエラーになった場合の対応」について相談を想定してましたが、ほぼありませんでした。かわりに スローする例外の名前のtypoが見つかった、という情報共有 phpstan-baseline.php をコマンドで更新するには CI のログには、エラー内容が表示されなくて困っている TESTSタブに表示されるので、そちらを見てもらうよう案内した(CircleCIで、JUnit形式のレポートを指定するとわかりやすく表示してくれる機能) といった相談がありました。 得られた効果・まとめ PHPバージョンアップがしやすくなった 前述のような後方互換性のない振る舞い変更を、一部検知してくれるようになり「非staticメソッドのstatic呼び出し」も指摘されるので、まとめて修正することができました。 テストで実行されないコードの問題が見つけられるようになった 既存コードに存在した問題がいくつか見つかりました。 例えば、異常系処理でスローされる例外クラスが見つからない(存在しなかったり、クラス名にtypoがあったり)という指摘が数件ありました(実運用環境でスローされたことがなかったためか見過ごされていた) 導入前の懸念についてPHPStan導入後に思ったこと 以下のような懸念を抱いてました。 namespace のないPHPコードでは解析がうまくできないのではないか 多数のエラーを指摘され、導入までに長い時間がかかってしまうのではないか 実際作業してみると、namespaceのないコードも解析できますし、ベースラインを使うことで既存のエラーを除外しつつ新規の潜在的問題を指摘する能力を素早く導入できました。 参考資料 Find Bugs Without Writing Tests | PHPStan Getting Started | PHPStan PHPStanクイックガイド2023 (PHPerKaigi 2023 パンフレット p78〜) レガシーコードにPHPStanを導入するためのTIPS - RAKUS Developers Blog | ラクス エンジニアブログ PHPStanをどうやってインストールするか リリースして11年経過したPHPアプリケーションにPHPStanを導入した - Chatwork Creator's Note
10点満点でつけてもらったアンケートの回答です。 ごあいさつ はじめましての人ははじめまして、こんにちは!フロントエンドエンジニアのがっちゃん( @gatchan0807 )です テックブログに出てくるのはお久しぶりです 今回の記事では、4月末に社内で実施したイベント 「あの頃のオフライン勉強会の感覚を取り戻そう! オフラインリハビリ勉強会」 という取り組みをご紹介します! どんなイベント? BASE には #iikanji-conference-toudan というワーキンググループがあり、外部カンファレンスやイベントでの登壇の支援をしていく活動をしています (詳しくは2022年のアドベントカレンダーの記事で振り返りを行っているのでそちらをご覧ください!) devblog.thebase.in 今回の「あの頃のオフライン勉強会の感覚を取り戻そう! オフラインリハビリ勉強会」(以下、オフラインリハビリ勉強会)は、その #iikanji-conference-toudan 主催で実施したイベントで、 オフラインでゆるく社内に集まり、LTと寿司やお酒を囲んで技術の話をする感覚を取り戻そう! という趣旨で開催しました 結果的に オフライン会場に20人近く集まっていただき 、あらかじめお声がけしていた3本のLTと1本の自己紹介LT、さらには飛び込みで1本のLT( MPC について熱く語っていただきました)までお話いただくことができました! 🙌 🙌 🙌 なんで実施したの? 「もっと社内から登壇やイベントに参加してくれる人を増やすにはどのようなことをすればいいんだろうか…?」と私たちの中で分析している中で、以下のような仮説が立ちました コロナ禍もある程度落ち着いてきて、オフライン勉強会も増えてきてるが、 「前は色んなコミュニティのイベント行ってたけど、コロナ禍になってからあんま行けてなくて久々に行きたいな…でも久々すぎて喋れるかな…」 みたいな不安を持っている方が一定数いるんじゃないか…? この仮説から、 「いきなり社外のイベントに参加する前に、一旦社内でオフライン環境に慣れるためのリハビリできる環境作ってみない?」 という話になり、この会を開催することにした形です また、よくメンバーで話しているなかで出る課題感として「登壇して話す・話したいと思えるネタがない問題」というものがあります これについてメンバーで雑談をしている中で、過去の経験からふと「イベントで聞いた話・懇親会で人と話したことが話すネタになるきっかけになることもあったよね」ということに気づき、そういった技術雑談が発生する「カンファレンスの廊下」を何らかの形で社内に擬似的に作ることができれば登壇にチャレンジするサポートもできるのではないか?と思い、実施にいたりました 工夫・気をつけたところ 上記のような開催の目的を実現するために、いくつか工夫した部分があったので紹介します ほとんどが当たり前のようなことではあるのですが、細かいところにこだわりを持って会のクオリティを上げるための活動をしていました 参加のハードルをできるかぎり下げる 「リハビリ」を謳っている以上、少しでも参加することにハードルを感じてしまっては実施する意味がなくなってしまうので、ここをどのようにハードルを下げられるかを考えました 参加表明なしでも出社していたらフラっと来てもらってOK!というのを何度もアナウンス時に伝えておく 参加表明もSlack Reacjiの 🙋 や、古の「丿」コメントをするだけでOK!という形を取りました 開催日を金曜日にしない(この日はちょうどGWの前日というのもあって、余計に避けていました) たくさんの人に参加してもらうには、他の予定とバッティングしがちな金曜日を外すのが意外と大事だったりします 翌日まだ仕事があるというところで、自制しやすく実りある話がしやすい会になると良いな〜という目論見も実はひとつまみ入っていました LTの資料はつくらないことを推奨! 資料作りの時間がないから…というところで二の足を踏んで欲しくなかったので、資料なし登壇を推奨してアナウンスしていました あらかじめ声がけをしていたメンバー3名にも資料を作らないで!(一度話した内容の再演で資料があるのとかは大歓迎!)というお願いまでしちゃっていました 資料なしのLTって慣れていないとすごく難しいので、これに対応してくださった皆さんに感謝です… 自分も資料なしでLTをやってたんですが、ダラダラ話してしまって結果的に主催者が倍ぐらい時間オーバーするという事態になってしまいました(後続の登壇ハードルをできる限り下げたと思うことにしてギリギリ心を保ちました) あらかじめタイムテーブルで飛び込みLT歓迎タイムを用意する 乾杯 → 準備してもらったメンバーのLTパート → 飛び込み歓迎タイム 兼 歓談タイムの流れで実施し、最初のLTパートで話しきれなかった内容やLTから刺激をうけて話したいことができた方が話せるように枠を用意しました 結果的に、前述の通り1人がMPCに付いてアツく語ってくださりました🔥 何故かたまたま持っていたMPCを実際に叩いてみている時の写真 イベントの目的をあらかじめオープンにする 一般的な会議でも言われることですが「会のアジェンダと目的をまず明確にしよう」ということに注意してイベントの告知などをしていました イベントの目的をできる限り社内のメンバーに理解してもらうために、社内ドキュメントプラットフォームに実施意図や経緯をかんたんにまとめた記事を書いて、アナウンス時に公開していました この記事の「どんなイベント?」と「なんで実施したの?」の部分はその社内向け記事に書いていたものを少しだけいじって、内容はほぼそのまま公開しています また、イベントの目的に共感してもらうことも重要と考えて、イベントの名付けと開催に至るまでのストーリーをきちんと伝えられるような書き口の工夫などもしていました 感想などなど オフラインイベントの設営が久しぶりすぎて開始15分ほど「プロジェクターが繋がらない!なんで!」とバタバタ⁠してしまったり、LTの時間配分ミスってダラダラ話してしまったりと個人的なものも含めていくつも反省点はありますが、結果的に実施後のアンケートで高い満足度を得ることが出来てとても嬉しかったです! 嬉しすぎて記事の1行目にドカンと置いてしまってたこちら 他にも、この先の登壇やオフラインイベントの参加につながるようなことが出来ていたのかを確認する質問項目も置いており、結果としては以下のような形になりました おわりに 以上、4月末に実施した 「あの頃のオフライン勉強会の感覚を取り戻そう! オフラインリハビリ勉強会」 という取り組みについてのご紹介でした 今回紹介した内容をもとに、皆さんの所属する企業や団体でもオフラインイベントに体を慣らすための社内イベントなどを実施してみてもらえると嬉しいです! そしてその取り組みをまた記事にしてアウトプットとかしてもらえるとなお嬉しいです! これからも #iikanji-conference-toudan では引き続き様々な社内イベントを実施して、BASE社内からもっとたくさんの登壇者・登壇実績を積んだ方が出てくるようにサポートしていければなと思っています 最後までお読みいただきありがとうございました!
はじめに みなさん、こんにちは。BASEでエンジニアをしております田村( taiyou )です。 2023年4月6日に、ChatGPTを活用してショップオーナー向けに文章の作成をサポートする機能「 BASE AI アシスタント 」をリリースしました。そのため、この記事では、BASE AI アシスタントのシステム構成について紹介します。 今回は、システム設計についてのテックブログなのでChatGPTのプロンプトについての言及はしません。(要望があれば次のテックブログに執筆いたします!) また、前回のテックブログで「 IdPとしてSAML認証機能を自前実装した 」を執筆したのでこちらも是非見てみてください! BASE AI アシスタントとは BASE AI アシスタントとは、 ショップオーナーがよりクリエイティブな作業に時間に費やせるように機械学習・深層学習などのAIを用いて、ショップオーナーをアシストするサービス のことです。 2023年6月現在では商品登録/商品編集画面にある「商品説明文の例を書き出す」機能を指します。今後、他の機能も公開予定です。 BASE AI アシスタントとは システムの構成 アーキテクチャ 2023年6月現在では、BASE AI アシスタントのアーキテクチャは以下のようになっています。Vue.jsとCakePHPから構成される「商品登録/商品編集」システムからDSチームが管理するDS APIへリクエストし、ChatGPTに送信しています。 DSチームとは、Data Strategyチームのことで機械学習やデータ基盤などの専門知識を持つチームです。 システムの構成 「商品登録/商品編集」システムから直接ChatGPT APIへリクエストを送信しなかった理由は以下の通りです。 BASE AI アシスタントは機械学習・統計分析などの専門知識が必要になるため、領域的にDS APIを管理しているDSチームに責務を持たせたほうが組織的に適切である。 採用している言語がチーム間で異なり(PHP vs Python etc...)、また分割することでより適切な技術選定が可能になり、将来的な開発速度が向上する。 将来、BASE独自の文章生成モデルが誕生しても「商品登録/商品編集」システム側の対応が不要である。 上記の理由から「商品登録/商品編集」システムから直接ChatGPTにリクエストせずに、「商品登録/商品編集」システムとDS APIで領域を分割しました。 処理の流れ アプリケーションの処理の流れは以下の図の通りです。 Frontend : 生成リクエスト フォームがsubmitされたら、Backend(API)に商品情報を送信する Backend : ショップ情報を取得 商品説明文を生成するために必要なショップの情報(カテゴリ/...)をデータベースから取得する Backend : 商品説明文の生成リクエスト DS API : ChatGPTに送信 DS API : 生成された文字列を返却 処理の流れ 2023年4月リリース当初では、フォームを押下してから実際に商品説明文がショップオーナーに表示されるまでに20~30秒ほどかかりました。 ビッグシルエットTシャツの例 リリース後 上記の処理で正常に動作していたもののある日からうまく文章が生成されない事象が度々発生するようになりました。 原因は、 ChatGPTからのレスポンス時間が増加して、DS APIとBackend(API)の通信がタイムアウトした ためです。DS APIは AWS のAPI GatewayとLambdaで構成されたシステムなのですが、API Gatewayはタイムアウトの上限を30秒までしか設定できません。 原因は不明ですが、ChatGPT側のレスポンスタイムが30秒を超過したことでAPI Gatewayの接続がタイムアウトになり、結果としてBackend(API)でエラーになったのです。 改修 ChatGPTによる文章生成時間が30秒を超過した場合でも文章が表示されるようにで次のように処理を改修しました。 Frontend : 生成リクエスト フォームがsubmitされたら、Backend(API)に商品情報を送信する Backend : ショップ情報を取得 商品説明文を生成するために必要なショップの情報(カテゴリ/...)をデータベースから取得する Backend : 商品説明文の生成リクエスト DS API : 生成リクエストIDを発行し、文章を生成し始める Backend : 生成リクエストIDを返却 Frontend -> Backend : 生成リクエストID指定で取得リクエストを送信 文章が生成されていない場合は 生成中 ステータスが返却される 一定時間間隔で取得リクエストを送信しつづけるする 文章が生成されたら、商品説明文を返却する こうすることで仮に文章生成時間が30秒を超過してもエラーが発生しなくなりました。 今後の課題 上記の改修で仮に文章生成時間が30秒を超過してもエラーが発生しなくなり、正常応答率が更に向上しました。しかし、これはあくまで暫定的な対応であるため、ショップオーナーにより早く文章を生成し、表示する改修を行う必要があります。(こちらの対応はChatGPT側へ問い合わせ中です。) おわりに この記事では、ChatGPTを活用した「BASE AI アシスタント」のシステム構成について紹介しました。要望があれば次回以降にBASE AI アシスタントを実現するプロンプトエンジニアリングについての記事を書こうかと思います!
こんにちは! BASE BANKの松雪です。 来る2023/06/02(金)にオンラインでGo Conference 2023が開催されます。 我々BASE株式会社(BASE BANKチーム)は Goルドスポンサー で協賛し、スポンサーセッションにて1名登壇します! Go Conferenceとは Home | Go Conference 2023 GoCon2023 ※ The Go gopher was designed by Renee French. Illustrations by tottie. Go Conferenceは一般社団法人Gophers Japanが主催しているプログラミング言語Goに関するカンファレンスです。 今回10周年を迎えます。おめでとうございます! BASEでGoって使ってるの? ネットショップ作成サービス「BASE」のバックエンドはPHPで実装されており、 PHPerKaigi などPHPのカンファレンスに協賛、登壇しています。 しかしそれだけではなく、BASEのショップオーナー向けの金融決済事業を展開しているBASE BANKチームでは、資金調達サービスである「YELL BANK」、ショップの売上金をVisa加盟店の決済で利用できる「BASEカード」にてGoの分散サービスとして長く実装、運用をしています! thebase.com basecard-lp.thebase.com 登壇内容 次なるrouterパッケージ選定のしざまと決め手について by @Ren Ogaki https://sessionize.com/api/v2/jmtn42ls/view/Sessions 先日Goの軽量routerの代表格であるgorilla/mux擁するGorilla Web Toolkitがアーカイブされました。 私たちのチームで開発しているGoのWeb APIはすべてgorilla/muxに依存しており、対応を迫られました。 フォークしてチーム内でメンテナンスを行うことも考えられましたが、チームの規模的に無理があり他のパッケージへ移行する必要がありました。 そこで今回の発表では移行時に行った他のパッケージの比較検討や最終的な決断の意思決定について話します。 この発表を通してパッケージの選定基準などについて、同じくrouterや外部パッケージを移行したい方の手助けになれば幸いです。 router移行を主導した話をします! あまり起こることでもないので知見が溜まりづらい領域と思いますが、次にこういったことが起こったときに皆さんの役に立てる発表になればと思っています。 オフィスアワーも開催します! イベント当日はreBakoにて、オフィスアワーを開き参加者のみなさんをお待ちしております。 オフィスアワー中の弊社ブースでは常時エンジニアがおりますので、 直近話題になったGo関連のトピック・ブログ記事について BASE BANKでGoをどうやって使っているか BASE BANKのプロダクトって? などなど、是非気軽にお話しましょう! 宣伝 BASE BANKチームでは、フルサイクルエンジニアとして、Go, Python, PHPを中心にフロントからインフラまでを一気通貫で開発~運用を行っています。 それだけでなく要件定義から分析、ユーザーサポートまで一連のソフトウェアライフサイクルに主体性を持って関わることができます! devblog.thebase.in BASE BANKの働きざま、Goについてなど話を聞いてみたいという方は以下のリンクから気軽にご連絡ください! youtrust.jp それでは当日にお会いしましょう!
こんにちは!BASE株式会社 上級執行役員の藤川です。今年からTech DepartmentというBASE社の開発の成功や情報システム、セキュリティ等に責任を持つチームを運営しています。 システム障害はWebサービスを自社運用する企業にとって最重要な問題であり、サービス改善のきっかけになることも多々あります。ただ単に目の前の問題を場当たり的に解決するだけでなく、再現性を減らすために体制やシステム投資の見直しなどにもつながるきっかけになるものなので、そこで起きている本質的、潜在的な課題を見つけ出すことも障害対応の重要なミッションです。 また事件は現場で起きているわけで、障害要因となるものは、何もバグやシステム設定の不足や不備などに基づくものだけではありません。インターネットの世界が日常的に変化しているので、外乱としての障害要因も多々存在し、これらの問題と常に戦っています。 そういう不確実な状況下で、障害に対する対応力を培うことはWebサービスのエンジニアにとっては重要な成長のチャンスです。必ずしも自分が把握しきっていないシステムであってもエラーログやシステムの挙動を見ながら、起きている事象を予想しながら解決すべき問題にあたりをつけていく力は、Webシステムのスキルをひろげる絶好のチャンスです。このスキルは、どんな開発言語であろうと関係なく、どの会社に行っても生きる経験であり、Webサービスエンジニアの基礎力とも言えます。 最近のBASE開発チームは、事業テーマに応じて開発チームが分かれ始めていますし、BASE BANKやPayID、AIチームなど担当するリポジトリそのものが分かれていたりして、以前のようなモノリシックな体制から分散型の開発運営体制に移行しています。 そのような状態で適切な部署に障害対応がエスカレーションされるようになると、障害対応に慣れているチームとそうでないチームが分かれてきますし、また、毎月中途入社がいるようなチームであれば、日常のフローがわからない人が常に存在することから、障害発生時の対応フローを決めてほしい、という言葉が頻繁に出てくるようになります。 更に、我々が特性として持つ、お客様の情報を守るWebサービスプラットフォームという視点、クレジットカードなどの決済を提供するサービスという視点において、ステークホルダーが多いのも特徴で、ただシステムとしてのサービスを復旧するだけでなく、そこで起きている事象をしっかり分析し、ショップオーナーさん、関係省庁やパートナー企業への報告が必要ではないか?なども常に精査する必要があります。 これらをスムーズに実行するために、開発、CS、渉外担当、法務、営業などが集まって議論を行った結果として、障害対応フローを整えることにしました。それが以下の図です。 base-incident-flow ステップとしては、 障害初期調査 初期対応決定 障害対応(アクション) クロージング で構成されます。 0.障害発生 主たる障害発覚の入り口は下記の誰かであることが多いです。 ショップからの問い合わせ システムアラート ショップから営業担当への連絡 主になんらかの経路でエンジニアやCTOやVPoPに直接連絡が来ることが多いです。slackの#incidentチャンネルが作成され、共有チャンネルで全社に共有されます。incidentチャンネルが作られると100人以上の関係者が自動的にチャンネル登録されるようになっていて、とりあえずワラワラと人が集まってくる体制が整います。 ちなみに、チャンネル登録の自動化は、個人の裁量で参加の判断をしてもらってるので、そんなにincidentチャンネルにとりあえず参加する人がいるんだと言うことには驚きです。 1. 障害発見後の初動フェーズ ここが最重要なフェーズとなります。 ここで如何に適切な関係者に話を広げられるかが、リスク対応の範囲と対応スピードを決定します。 やはりエンジニアはシステム復旧に意識を集中したいものであり、そっちに関心が行ってしまいますので、ついつい別の話はしずらかったり声もかけづらいものです。 一方で、個人情報流出にまつわる意思決定は1分1秒を争います。過小でも過剰でもない情報把握をするための的を絞っていくことが求められます。 そのためシステム復旧と並行して、これを実現するために障害対応は別に、インシデントの対応を別途に行うチームを整理しました。incidentが発生し、個人情報にまつわる懸念がある場合、なんにせよ一旦、エスカレーションしてもらう流れを整えています。 2. 初期対応決定 フェーズ1では、わらわらと集まってきた人たちで議論をしながら問題の把握をし、その後、復旧に繋がっていくのですが、ここで一度、集まって議論を整理するタイミングを入れてほしいというのを伝えています。 システム復旧だけなら勝手知ったるエンジニアだけで対処可能なのですが、もうちょっと範囲が広がった場合、足並みをしっかり整えていかないと適切な対応ができない可能性があるからです。 急がば回れという言葉がありますが、初動の足並みを揃えるのはとても重要です。また、意思決定者、リーダーを決めて、その人を中心にincidentのマネジメントの旗振りをしていくことも求められます。 3. 障害対応、アクション システム改修・パートナーやお客様、関係者への連絡の段取り データ修正、返金対応等・関係省庁への連絡など 広報の調整等 対応方針が決まったら、あとは各役割のプロフェッショナルに作業が移譲されていきますので、エンジニアは各チームが動きやすくなるようなデータの準備などを行います。 余談ですが、さまざまな情報を集めて集約する時には、GoogleスプレッドシートやExcelの関数やピボットテーブルで分析することが多いですが、昨今はChatGPTで実現したいことに対するプログラムを出力したりして非常に役に立ちます。 主にやることはCSVに落としたデータを読ませて、大量のデータを名寄せしたり整理したりする作業なので、慌てているときに落ち着いてコードを書いてる状況でもないことから、かなり助かります。 4. クロージング 関係者のふりかえりの実施 incidentドキュメントの完成 マネージャmtg / 経営会議等への報告や再発防止に関する議論 障害対応が終わったら、振り返りをし、再発防止策等を議論します。 もし、開発の優先順位を変えてでも対応が必要になるようであればビジネスチームとの調整や議論は必須です。そして、技術的負債の返済と同じか、それ以上に再発防止策をしっかり議論し、今やること、これからやっていくことをしっかりまとめて実行していくことが大切です。 ここで物事をスルーすると絶対に後悔するので、しっかり優先順位の整理をします。 あとがき:タイトルの意味とお気持ち 最後にタイトルに書いた意味と、自分の気持について述べておきます。サービスに携わる人数が増えてくると障害に対する感度がちょっと落ちてしまい「どうせ誰かが対応してくれるだろう」となりがちなところがあります。 システム復旧にとどまらず、ステークホルダーへの考慮すべき点が増えてくると、障害発生時の検討のレベルが一段、複雑になってきます。ここでどれだけ自分が全体視点で前のめりに踏み込めるか?がすごく大切だと思っていて、自分が前のめりに踏み込むためにも、あえてワークフローを設定したというのもあります。 特にリモートワークで仕事しているときに発生した障害は、飛び込むための関心のエネルギーが、普段以上に必要な時があります。slackを見て、誰かがシステム復旧してるなってことを確認だけして、パソコンを閉じてしまえば目の前から事象は消え去ってしまうわけです。でも、そこで適切に判断しなかったことが、あとからツケとなって返ってくることもあり、やはり都度都度、影響範囲をしっかり議論し、「それほど問題ではない」ということをしっかり確認し、そうでなければリスクを洗い出し、管理することが必要だなと思いました。 Webサービスというソフトウェアの固有の事象として、毎日、何回もリリースするという特徴がありますが、言い換えると毎日システムを壊すきっかけを生み出していると言い換えることも不可能ではありません。そのリスクと戦うことがWebサービスのスピード感を実現するわけで、常にトレードオフを迫られています。 その中でやむを得ず起きてしまったシステム障害についての問題解決は、そこに携わるメンバーの技術力や対応力を育てるという成長の機会と考えることも可能です。Webサービスに携わる方々は、是非、前のめりに問題解決に勤しむことをおすすめします。
はじめに フロントエンドエンジニアの @mk0812 です。自分は普段BackOfficeというチームで新規機能開発を担当しています。 2023年3月〜5月あたりで社内の有志を集めて、Webアクセシビリティの勉強会を行いました。この記事はその勉強会の振り返りをしていきます。 ⁠参加者 ⁠フロントエンドエンジニア: 4名  デザイナー: 4名 ⁠勉強会で使用した参考書 Webアプリケーションアクセシビリティ──今日から始める現場からの改善 (WEB+DB PRESS plus) なぜアクセシビリティの勉強会を実施したか 私自身が今回、この勉強会の主催をやりました。私が実施した動機としましては下記にあたります。 フロントエンドの実装であまりアクセシビリティを意識してこなかった WAI-ARIAが定めた仕様に基づくHTML属性(例: aria-label 属性)をなんとなく使っている部分がある もっと社内でアクセシビリティを広めていきたい これらの動機を踏まえて勉強会を実施しました。 実施するにあたっての参加者の経緯 勉強会にあたってまずは人集めというところですが、上記に記載ある通り8名ほど勉強会に参加してくださりました。有志で集めた際にアクセシビリティの勉強会に参加した経緯を聞きました。 参加した経緯 ↑のようにfigjamを使ってディスカションをしながら勉強会を行った ⁠エンジニア視点 アクセシビリティ気になりつつあまりちゃんと勉強したことない 利用できるユーザを増やすためには「正しいHTMLの書き方=それがアクセシビリティにつながる」と思ったから ⁠デザイナー視点 マシンリーダブルに作るための前提知識が少ない、デザインを起こすときにどういう部分に意識すべきかわからなかった ユーザインタビューなどのリサーチを通じて興味を持ったから このような感じでエンジニアとデザイナーで勉強会に参加した経緯は違います。しかし今後取り組むにあたって、エンジニアとデザイナーの共通言語ができて、品質の良いデザインやコードが作れていけばいけるように頑張ろうかなと思いました。 勉強会の形式 figjamを使ってオンラインでやりました。 毎週1時間くらい 全8回くらいやりました。 勉強会の一例が下記のような感じです。毎回ではないですがディスカッションのテーマを考えて、BASEの今後の活動に少しでも役に立ててもらおうと工夫しました。 勉強会の流れ ⁠振り返り この勉強会で意識した点は下記2点になります。 ディスカッションの頻度を増やす BASEの現状あるUI/UXから改善点を探る ディスカッションの頻度を増やす 上記の「勉強会の形式」でも触れましたがディスカッションのテーマを考えて、事前にディスカッションのネタを用意しました。 下記添付画像はディスカッションの例になります。勉強会の後半部分はこのような感じで各章のテーマに沿って皆さんが「話す」「考える」「次に活かせる」といったいわゆる『参加型』を意識しました。 ディスカッションの流れ ディスカッションを通じて、私自身が実は知らなかったことがたくさん気づいたところでもありました。普段の画面確認などはあまりキーボード操作などを意識しなかったのですが実はその操作の中で改善点があったりと...さまざまな意見が出てとても良いディスカッションになりました。 BASEの現状あるUI/UXから改善点を探る 本に沿って、BASEが提供してるサービスそのもので使用してるコンポーネントが使いやすいかどうかをみなさんで議論して改善策を探ったりしました。 例えば第5章で「複雑なUIパターンの改善」という章があります。ここでは モーダル ⁠通知 ⁠ツールチップ などとある程度どのサービスでもあるようなコンポーネントとなりますが、これらのコンポーネントがきちんとアクセシビリティに配慮してるか、勉強会に参加した皆さんとUI見て探ったりしました。またこの本にはサンプルコードが載っていたのでサクッと試したりもできてとても助かりました。 ⁠感想 勉強会を終えて感想を参加していただいた皆さんからもらいました(下記添付)。 参加者の感想 ⁠エンジニア視点 セマンティックなHTMLを完全理解した。レビューの時もアクセシビリティを意識していきたい。 フロントエンドの知見が深まった、サンプルコードを踏まえてとても理解が深まった ⁠デザイナー視点 BASEのデザインを知るいいきっかけになった 普段プロジェクトに閉じたデザインしか見てなかった、全体のデザインを触れられてよかった ⁠全体 改善案を出すワークで結構意見が出てきたりしたので、アクセシビリティに限らず何かテーマを絞って、みんなが普段考えているBASEの改善点を話すのはいいのではないか 内容も濃くて、全員受けてもいいんじゃないというくらい良い内容だった 他職種の見解が聞ける機会(エンジニア⇄デザイナー)があったのはよかった まとめ BASEのミッションは「 Payment to the People, Power to the People 」を掲げています。そのミッションの中に「世界のすべての人に」というフレーズがあり、BASEを使っていただけるショップオーナーをはじめ、「どんな人でもショップオーナーになれる」ためにはやはりアクセシビリティ対応は不可欠だと思っています。 また私をはじめとしてアクセシビリティに対しての課題などを話し合ってちょっとずつではありますが、改善していく動きをしています。この改善を続けて良いサービスを作り上げていこうと思います。 以上です、最後までお読みいただきありがとうございました。
はじめに こんにちは、BASEのPay IDチームでAndroidエンジニアをしている 小林( @eijenson )です。 ショッピングアプリ「Pay ID」のAndroid版アプリの開発を担当しています。 本アプリでは2023年4月にあと払い(Pay ID)という、新しい決済方法の支払いに対応したアプリをリリースしました。 「あと払い(Pay ID)」を提供開始 新たな自社決済ネットワークへの第一歩 これらの機能はJetpack Composeで実装していますが、その際に解決に時間のかかった箇所の紹介と、解決した内容を紹介していきます。 使用言語/ライブラリのバージョン Kotlin 1.7.10 Jetpack Compose 1.3.0 Paging 3.1.1 paging-compose 1.0.0-alpha17 navigation-compose 2.5.2 1.非Compose画面からCompose Navigationを使って引数付きの画面に遷移する Compose間の画面遷移はCompose Navigationを使うと楽に書くことができます。 https://developer.android.com/jetpack/compose/navigation?hl=en @Composable fun NavigationApp( val startDestination: String /*最初の遷移先*/ ) { val navController = rememberNavController() NavHost(navController = navController, startDestination = startDestination) { composable( "profile" , ) { ProfileScreen( onNavigateToFriends = { navController.navigate( "friendsList" ) }, /*略*/ ) } composable( "friendslist" ) { FriendsListScreen( /*略*/ ) } } } これで、Profile画面からFriendList画面への遷移が実現できます また、例えばリスト画面から1つの詳細画面に飛びたいといった場合、itemId等の引数が必要になることが多いです。 その場合は url/{itemId}といった形で引数を渡すことができます. @Composable fun NavigationApp( val startDestination: String /*最初の遷移先*/ ) { val navController = rememberNavController() NavHost(navController = navController, startDestination = startDestination) { composable( "profile" , ) { ProfileScreen( onNavigateToFriends = { navController.navigate( "friendsList" ) }, /*略*/ ) } composable( "friendslist" ) { FriendsListScreen( onNavigateToFriends = { navController.navigate( "friend/1234" ) }, /*略*/ ) } composable( "friend/{itemId}" ) { FriendScreen( /*略*/ ) } } } 問題 しかし、Pay IDアプリは現状全画面がJetpack Navigationに移行していないため、非Compose画面からのCompose Navigationの画面遷移をすることになりました。 そこで問題になったのが、今回の機能は最初の遷移した画面から、引数が必要な画面ということでした。 アーキテクチャの原則として、アプリが最初に遷移する画面は固定であることが望ましく、それに準ずる形でCompose Navigationの制約で最初に指定する画面は固定である必要があります。 Android developers ナビゲーションの原則 Composeを使用したナビゲーション#NavHostの作成 画面遷移をJetpack NavigationやCompose Navigationに完全移行している場合は、NavHostが遷移する最初の画面が起動時の画面になるため、問題は無いです。 ですが、今回は途中からCompose Navigationを使うため、この制約に引っかかりました。 @Composable fun NavigationApp( val startDestination: String = "friend/1234" /* friend/1234に最初に遷移したい*/ ) { val navController = rememberNavController() NavHost(navController = navController, startDestination = startDestination) { /* 略 */ composable( "friend/{itemId}" ) { FriendScreen( /*略*/ ) } } } freind/1234の画面に直接遷移しようとした場合にはstartDestinationにfriend/1234を指定したいのですが、そうすると java.lang. IllegalArgumentException : navigation destination friend / 1234 is not a direct child of this NavGraph というエラーが表示されて失敗します。 解決策 調査や試行錯誤をした結果、 composable( "friend/itemId" , arguments = listOf(navArgument( "itemId" ) { type = NavType.StringType; defaultValue = "1234" }) ){ /* 略 */ } のように item_idを/{itemId}ではなく/itemIdにする argumentsにを設定し、defaultValueに最初に遷移したい値を指定する と期待した動作になりました。 前述のとおり、Navigation Composeでは初期遷移は固定の想定なので、ライブラリのバージョンアップによって動きが変わってしまう可能性があります。 今後もJetpack Composeへの移行と遷移処理をNavigation Composeに寄せる作業を進めていき、こちらの書き方は変えていく予定です。 2.スクショ禁止や明るさMAXをJetpack Composeで実現する あと払い(Pay ID)ではコンビニで支払いを行うためのバーコードを表示しています。 その際にトラブル防止のためにバーコードをスクリーンショットをできないようにしていたり、読み取りやすいように画面の明るさをMAXにしたりしています。 val window: Window? = activity.window // 画面をONのままにする と スクリーンショットを撮れないようにする window?.addFlags(FLAG_KEEP_SCREEN_ON or FLAG_SECURE) // 輝度を最大に指定する window?.attributes?.screenBrightness = BRIGHTNESS_OVERRIDE_FULL 問題と解決策 しかし、この設定は同じActivityの違う画面上でも明るい状態になってしまいます。 そのため、画面を閉じた際には明るさの設定等をもとに戻す必要があります。 Jetpack Composeの画面表示で、画面が閉じられたことを検知するにはDisposableEffectのonDIsposeイベントを使用します。 https://developer.android.com/jetpack/compose/side-effects?hl=en#disposableeffect そういったことを含めて、コードに表すと以下のような実装になりました。 @OptIn (ExperimentalMaterial3Api :: class ) @Composable fun MyScreen( viewModel: MyViewModel // 略 ) ){ val activity = LocalContext.current.findActivity() val uiState by viewModel.uiState.collectAsState() if (uiState is MyViewModel.UiState.Success) { activity?.let { activity -> val window: Window? = activity.window // 輝度を最大に指定する window?.attributes?.screenBrightness = BRIGHTNESS_OVERRIDE_FULL // 画面をONのままにする と スクリーンショットを撮れないようにする window?.addFlags(FLAG_KEEP_SCREEN_ON or FLAG_SECURE) } DisposableEffect( Unit ) { onDispose { activity?.let { val window: Window? = activity.window // 輝度を指定しない window?.attributes?.screenBrightness = BRIGHTNESS_OVERRIDE_NONE // "画面をONのままにする と スクリーンショットを撮れないようにする" の設定を解除 window?.clearFlags(FLAG_KEEP_SCREEN_ON or FLAG_SECURE) } } } // uiStateに応じたUI表示処理等 } uiStateはFlowのStateFlowを用いてAPIの実行結果を受け取れるようにしています。 ロード中や通信失敗時に明るくなったりスクショが撮れないようになったりしないように、通信成功時のみ設定を有効にしています。 3.ページングの最後項目取得 リストの一番下の要素にだけレイアウトを変更したいという事になり、最後の要素を検知する必要がありました。 そのため、 val pagingList = currentState.pagingData.collectAsLazyPagingItems() LazyColumn() { items(items = pagingList, key = { it.id }) { item -> val isLast = pagingList[pagingList.itemCount - 1 ]?.id == item.id, if (isLast){ // Text()等 } /* 略*/ } } のように実装していました。 問題 しかし上記のやり方は良くなかったことがわかり、pagingのListは要素にアクセスしようとした際にそれが最後間近の場合、Pagingライブラリ側の必要に応じて追加読み込みをします。 つまり、 pagingのリストの最後にアクセスする 追加読み込みする Composeの描画のため、isLastの判定するためにpagingListの最後の要素にアクセスする 追加読み込みが発生する 繰り返す と、全ての要素を読み込む事になってしまいました。 解決策 そのため、最後の要素かどうか判定する処理を少し変えました。 val isLast = pagingList[pagingList.itemCount - 1 ]?.id == item.id, // ↓ val isLast = if (pagingList.loadState.append.endOfPaginationReached){ pagingList[pagingList.itemCount - 1 ]?.id == item.id } else { false } endOfPaginationReachedは通信による情報の取得の結果、中身が空だった場合にtrueが返ってくるので、判定に使用しています https://developer.android.com/topic/libraries/architecture/paging/v3-network-db?hl=ja#implement-remotemediator 補足 実装時は上記のような書き方で解決をしていましたが、本記事を書くにあたり、より調べてみたところ val isLast = pagingList.itemSnapshotList.lastOrNull()?.id == item.id のようにすれば同じように追加読み込みが発生することなく判定ができました。 今までのは、全てを読み込んだ最後にしか最後用のレイアウトは適応できなかったです。 ですが、こちらは、現在のリストの中で最後の要素かどうかを判定できるため、 1ページ目の最後の要素に最後用のレイアウトを適応する 追加読込して、2ページ目の結果を表示した際には2ページ目の最後の要素に最後用のレイアウトを適応する とページそれぞれのタイミングでより適切なレイアウトを表示することができます。 まとめ 今回は、Jetpack Composeで機能を実装したときに困ったところとその解決策をいくつか紹介しました。 記事では大変だった箇所ばかり紹介していますが、Jetpack Composeは全体的には書きやすく、RecyclerViewやConstraintLayoutといった、汎用性は高いが使いこなすのに時間のかかるものを踏まえて、かんたんに似たようなことをできるようにしようといった雰囲気を感じることのできる良い仕組みだと思います。 これからも機能や対応レイアウトが増えていくのが楽しみです。 おわりに 最後になりますが、BASEではAndroid/iOSのエンジニアを募集しています。 興味のある方はぜひ気軽にご連絡ください! Android: 採用情報 iOS: 採用情報
BASEのCartDevチームでバックエンドエンジニアをしている遠藤( @Fendo181 ) です。 自分が所属しているCartDevチームは主にBASEにおける決済開発を担当しております。 購入者様が商品を購入する際の決済だったり、オーナー様が利用するカート機能周りの開発、保守運用を行ってます。 今回、この記事では自分が所属するCartDevチームの取り組みを紹介する「月刊CartDev」というドキュメントを作った経緯や、運用方法について紹介します。 また、実際に社内で共有してみてどのような反応があったかについても書きます。 月刊CartDev が作られた背景について 月刊CartDev が作られた背景には2つ理由があります。 (1) 遠藤( @Fendo181 ) がそもそも入社したばかりで、CartDevでの働き方を理解したい。 (2) CartDevチームで取り組んでいる内容をチーム内で閉じるのではなく他部署に知見を積極的に共有して、他チームでも改善できる体制に貢献したい。 (1)はそのままの理由です。 (2)の理由についてはお話する前にまずCartDevチームの成り立ちについて説明します。 CartDevチームが作られた背景について CartDevチームはBASEの中でも 目的別組織 として作られたチームであり昨年の2022年の7月に結成しました。 BASEにおける「目的別組織」を少しだけ説明すると、特定の領域や機能に対してチーム全体が継続的に運用を行い、責任を持つ組織体制の1つになります。 CartDevチームが結成される前はカート機能の開発を行う専任チームはなく有志的に集まったメンバーが担当したり、お問い合わせ対応を行っていました。しかし、このままではスケールの面でも好ましくないということでカート機能の開発と保守運用に責任を持つ為に作られました。 CartDevチームの成り立ちについて以前テックブログで公開された以下の記事も参考になるので一部記述を抜粋します。 BASEの課題としてEOLを迎えたフレームワークからの移行を進めています。その中でもカート機能はまず初めに移行が完了した機能になります。ですが、移行して終わりではありません。サービスは成長していくので併せて機能を改修していく必要がありますが、新しいアーキテクチャを理解せずに間違った方向で改修が進むと複雑な負債を生み出してしまう可能性もあります。またアラート対応やパッケージ更新などの日々の運用もあり下記のような課題がありました。 新しいアーキテクチャをどう適切に開発していくのか? アラート対応やパッケージ更新などの運用はどうするか? 上記の課題をカート機能をリニューアルしたエンジニアが有志的に対応していましたが、スケール面において好ましくない状況だったため、カートチームとし>て組成して、開発・運用・グロースを含めて責任を持つのが望ましい形なのではないかと考えた結果、リニューアルしたエンジニアを集めてカートチームが誕生しました。 ref: カートチームを振り返る - BASEプロダクトチームブログ 上記の背景もありCartDevチームは他のチームと違い後述する Sentry の監視体制だったり、 Dependabot を使ったライブラリのアップデートに関して意欲的に取り組んでおります。 そういった取り組みは仕組みだけではなく、チームメンバーによる独自の文化が根付いていると配属してから感じました。 同時に、CartDevチームで出来ている事が、事情によって他チームでは出来ていない課題も気づきました。 こういった状況がある中でCartDevチームで取り組んでいる技術トピックを共有し、他チームにもCartDevチームの良い部分を積極的に取りくめる様に情報共有したいと思い「月刊CartDev」を作成しました。 CartDevで紹介した内容について 次に「月刊CartDev」でどんな内容を共有しているか説明します。 前述したように Cart DevチームはBASEの決済領域に関わる問題に対して責任を持ち、運用しております。 具体にこれは 担当大臣(運用業務) という名目で現在4つあります。 Dependabot担当大臣 Dependabot を用いた追従活動。 Dependabotによって届くライブラリアップデートの通知を確認し、定期実行や誰かが手動実行した際にも発生するPullRequestを確認し対応する。 Sentry担当大臣 Sentry の治安維持活動。 SlackでSentryのアラートが流れてくるチャンネルを見たり、メール通知を確認して対応する。 メンテナンス担当大臣 外部決済会社のメンテナンスエラーからの防衛活動 メンテナンスの連絡を毎回確認し、必要と判断した場合にメンテナンスの設定および 、 NewRelic アラート の ON / OFF を行う。 cs_q担当大臣 CSチーム経由で届くオーナー様からのお問い合わせ対応活動。 お問い合わせを起点に、 CartDevチーム宛てに飛んでくる調査依頼や仕様の質問などを NewRelic や Asana を使って一次対応する。 この4つの担当大臣を1ヶ月ごとにローテーションしながら各メンバーで対応するように現在運用しています。 また上記の「担当大臣」以外にもCartDevチームのメンバーが実際にプロジェクトで行った改善や、リリースした機能のPullRequestも取り上げて共有しました。 数値を計測して共有する 上記の担当大臣(運用業務)で紹介した4つの項目については対応時の計測値を共有しています。 Dependabot担当大臣で管理するPull RequestはGitHubで管理しているのでGitHubの検索で期間やラベルでフィルタリングして、Dependabotで作られたPull Requestがどれだけマージされているか?を計測できます。 以下は2023年1月辺りのDependabotで作られたPull Requestがマージされた数が取得できます。 is:pr is:closed label:dependencies merged:2023-01-01..2023-01-31 Sentry担当大臣の場合も簡単に計測ができます。 Issuesページから日付を指定できるので、その機能を使って絞り込みを行い計測をしています。 Sentryはただ対応した数を載せるよりも いかに早くアラートを検知してすぐに対応している様子 を伝えるのが大事だと思ったので、数だけではなく実際のSlackでのやりとりのキャプチャーも載せるようにしました。 メンテナンス担当大臣は、社内のドキュメントツールで活用している Kibela にまとめられるので対応数だったり、具体にどんなメンテナンスを行ったのか?を紹介しました。 cs_q担当大臣はAsanaの 高度な検索 を使って計測が可能でした。 これは自分が配属する前からユーザーから届いたお問い合わせに関しては調査が必要なものはCSチームのメンバーがAsanaで最初に管理しています。 従ってGitHub同様にAsanaでもタグや時間を指定してフィルタリングができます。 この機能を使ってメンバーがアサインされている且つ、時間を指定して1ヶ月辺りにCartDevチームが対応したお問い合わせ対応の数も計測できました。 以上より「月刊CartDev」では担当大臣(運用業務)の対応した実績数と、実績の詳細が確認できるURLを記述して社内に共有しました。 月刊CartDevを共有してからのフィードバックについて 月刊CartDevはまだ1月号と2月号しか出せてないのですが、「読者アンケート」を題して社内で読んだ人からフィードバックを頂いています。 フィードバックを一部取り上げると以下のコメントを頂きました。 Cartチームの活動内容がよくわかった Sentry担当大臣は結構みんながはまるエラーの宝庫なのでどんどん共有していきたいですね BASEの基盤なので、色々大変だとは思いますが頑張ってください!! 今後の月刊CartDevの改善について 現在作っている「月刊CartDev」のメインコンテンツが「担当大臣」の実績で、ほとんど数値を共有して終わっています。 読者アンケートのフィードバックで頂いた意見を読むと「担当大臣」の実績や数値を載せても他チームに需要がないケースもある事がわかりました。 アンケートを読むと、どのチームもSentryやNewRelicなどの監視ツールの運用や知見を読みたい事がわかったので今後は「担当大臣」の実績や数値よりも「CartDevでのSentryを使った監視体制について」など、テーマを絞って社内で共有していければと考えています。 まとめ 同じ会社でも規模が大きくなったりメンバーが増えると他チームが何をしているのかが、わかりづらい状況は常に発生してくると考えています。 他チームで改善が出来ている事を読んだり、聞いたりするだけでもモチベーションが上がったり、他チームの取り組みを知る事で相談しやすくなると思うので今後も「月刊CartDev」を通じて社内で積極的に情報共有される環境を目指して運営して行こうと思います。
こんにちは! バックエンドエンジニアの高町咲衣です! この記事では、PHPでDDD(ドメイン駆動設計)を扱う際に気になる「値オブジェクトを更新=作り直した時のメモリ周りの挙動」について調査した結果をまとめています。 値オブジェクトは不変である DDDの文脈における値オブジェクト(ValueObject)の特徴の一つとして、 不変(immutable)である ことが挙げられます。 値オブジェクトは「値を表現する」オブジェクトであり、例えばプリミティブな値であるint、stringなどと同じように取り扱うべきだとされています。 // プリミティブな値を用いた、ごく一般的な感覚のコード例 $number = 1; // 値をセットする $number = 2; // 値を入れ直す var_dump($number); // 2 var_dump($number === 1); // false // プリミティブな値を用いて、値そのものを変更した例(実際にはこんなことできない) $number = 1; // 値をセットする $number- > setValue(2); // 今入っている値そのものに変更操作を行なう var_dump($number); // 1 var_dump($number === 1); // false // 左辺の「1」は内部的に2で、右辺の「1」は内部的に1なので等しくない。わけがわからないよ よって、次のようなコードはNGとされます。 // NGな値オブジェクトコード例 // 呼び出し元での操作 $valueObject = new ValueObject($value); // 値をセット $valueObject- > setValue($newValue); // 今入っている値そのものに変更操作を行なう // 操作対象の値オブジェクト class ValueObject { private $value; public function __construct ($value) { $this- > value = $value; } public function setValue($value) { $this- > value = $value; // 一度設定した値を変更してはいけない } } ではどうするのかというと、次の例のように「新たなインスタンスを生成して返す」ようにします。 // 一般的な値オブジェクトの変更コード例 // 呼び出し元での操作 $valueObject = new ValueObject($value); // 値をセット $valueObject = $valueObject- > setValue($newValue); // 値を入れ直す // 操作対象の値オブジェクト class ValueObject { private $value; public function __construct ($value) { $this- > value = $value; } public function setValue($value) { return new self($value); // 値は変更せず、新しい自身のインスタンスを返却する } } なるほどですね! しかしここで一つ、懸念が生まれます。 回数を重ねるとメモリはどうなる? return new self($value) が何度も行われた時、メモリはどうなるのでしょう? 調べてみました! まず前提として、 ValueObject を持つ集約 Aggregate に対して操作を行なうものとします。 // 検証コード // str_repeat("1234567890", 1024) は、10KBのデータを生成し、計測する値をある程度大きくすることで細かい誤差の影響を少なくします。 public function execute() { echo '------START------'."\n"; // 10KBの値を持たせる $aggregate = new Aggregate(str_repeat("1234567890", 1024)); echo "\n------集約生成直後------\n"; echo memory_get_usage()."\n"; echo "------集約生成直後------\n"; for ($i = 1; $i <= 10; $i++) { $aggregate-> setValue(str_repeat("1234567890", 1024)); echo "\n------{$i}回目の値セット------\n"; echo memory_get_usage()."\n"; echo "------{$i}回目の値セット------\n"; } echo "\n------END------\n"; } まずはNGとされる、値そのものを変更したパターンから まずはNGとされている例から見ていきます。 // 集約クラス class Aggregate { private $value; public function __construct ($value) { $this- > value = new ValueObject($value); } public function setValue($value) { $this- > value- > setValue($value); } } // 値オブジェクトクラス class ValueObject { private $value; public function __construct ($value) { $this- > value = $value; } public function setValue($value) { $this- > value = $value; } } オブジェクトの生成が何度も行われないので、メモリはそんなに使わなさそうな予感がします。 出力結果を見てみましょう。 // NGパターンの出力結果 >>> $test- > execute(); ------START------ ------集約生成直後------ 25078576 ------集約生成直後------ ------1回目の値セット------ 25078656 ------1回目の値セット------ ------2回目の値セット------ 25078752 ------2回目の値セット------ ------3回目の値セット------ 25078816 ------3回目の値セット------ ------4回目の値セット------ 25078944 ------4回目の値セット------ ------5回目の値セット------ 25079008 ------5回目の値セット------ ------6回目の値セット------ 25079136 ------6回目の値セット------ ------7回目の値セット------ 25079136 ------7回目の値セット------ ------8回目の値セット------ 25079264 ------8回目の値セット------ ------9回目の値セット------ 25079392 ------9回目の値セット------ ------10回目の値セット------ 25079392 ------10回目の値セット------ ------END------ 値そのものを変更している=新規にオブジェクトを生成していないので、回数を重ねてもメモリ使用量に大きな変化はありませんね。 予想通りの結果であると言えます。 推奨される「値オブジェクトを毎回生成して入れ直す」パターン 次に、推奨されている( return new self($value) する)パターンです。 // 集約クラス class Aggregate { private $value; public function __construct ($value) { $this- > value = new ValueObject($value); } public function setValue($value) { $this- > value = $this- > value- > setValue($value); } } // 値オブジェクトクラス class ValueObject { private $value; public function __construct ($value) { $this- > value = $value; } public function setValue($value) { return new self($value); } } こちらは懸念の通り、オブジェクトを毎回生成するのでメモリ使用量が比例的に上がってしまいそうな感じがします。 出力結果を見てみましょう。 // 推奨パターンの出力結果 >>> $test- > execute(); ------START------ ------集約生成直後------ 25078792 ------集約生成直後------ ------1回目の値セット------ 25078872 ------1回目の値セット------ ------2回目の値セット------ 25078968 ------2回目の値セット------ ------3回目の値セット------ 25079032 ------3回目の値セット------ ------4回目の値セット------ 25079160 ------4回目の値セット------ ------5回目の値セット------ 25079224 ------5回目の値セット------ ------6回目の値セット------ 25079352 ------6回目の値セット------ ------7回目の値セット------ 25079352 ------7回目の値セット------ ------8回目の値セット------ 25079480 ------8回目の値セット------ ------9回目の値セット------ 25079608 ------9回目の値セット------ ------10回目の値セット------ 25079608 ------10回目の値セット------ ------END------ おや?特にメモリ使用量が上がってはいませんね。 NGパターンとそんなに差がありません。 インスタンスは適宜破棄されている PHPでは「参照のなくなったインスタンス」はガベージコレクションにより破棄され、自動的にメモリ解放されます。 確かにこのテストケースでは return new self($value) した後「古いValueObject」を参照している箇所が存在しないので、インスタンスが破棄(=メモリ解放)されていそうです。 気になるので、インスタンスの破棄タイミングを見てみましょう。 破棄タイミングの調査にメモリ使用量の出力は必要ないので、テストコードを次のように書き換えます。 // テストコード // メモリ使用量の出力をしないようにする public function execute() { echo '------START------'."\n"; // 10KBの値を持たせる $aggregate = new Aggregate(str_repeat("1234567890", 1024)); for ($i = 1; $i <= 10; $i++) { $aggregate-> setValue(str_repeat("1234567890", 1024)); } echo "\n------END------\n"; } また、インスタンスの生成・破棄のタイミングを知りたいので、値オブジェクトクラスで適宜文字列を出力するように書き換えます。 // 値オブジェクトクラス // インスタンスの生成と破棄のタイミングで文字列を出力する class ValueObject { private $value; public function __construct ($value) { echo "\n-----------インスタンスを生成します-----------\n"; $this- > value = $value; } public function setValue($value) { return new self($value); } public function __destruct () { echo "\n-----------インスタンスを破棄します-----------\n"; } } 出力結果を見てみましょう。 >>> $test- > execute(); ------START------ -----------インスタンスを生成します----------- -----------インスタンスを生成します----------- -----------インスタンスを破棄します----------- -----------インスタンスを生成します----------- -----------インスタンスを破棄します----------- -----------インスタンスを生成します----------- -----------インスタンスを破棄します----------- -----------インスタンスを生成します----------- -----------インスタンスを破棄します----------- -----------インスタンスを生成します----------- -----------インスタンスを破棄します----------- -----------インスタンスを生成します----------- -----------インスタンスを破棄します----------- -----------インスタンスを生成します----------- -----------インスタンスを破棄します----------- -----------インスタンスを生成します----------- -----------インスタンスを破棄します----------- -----------インスタンスを生成します----------- -----------インスタンスを破棄します----------- -----------インスタンスを生成します----------- -----------インスタンスを破棄します----------- ------END------ -----------インスタンスを破棄します----------- なるほどなるほど。 最初の生成と最後の破棄を除くと、交互に生成・破棄が行われていることがわかります。 つまり、次のような動作をしているのではないかと思われます。 // 値オブジェクトクラスの動作予想 public function setValue($value) { // インスタンスを生成する return new self($value); } // メソッドを抜けたら参照の消えた古いインスタンスが破棄される まとめ ということで、DDDの値オブジェクトの扱いで推奨される return new self($value) は、 メモリ的に心配はない ということがわかりました! もちろん 他から参照があればインスタンスは破棄されません が、そのあたりをちゃんと考慮した設計にしたいですね!
懇親会で集合写真を撮るBASE株式会社メンバーの様子 こんにちは!桜が満開になり、心浮き立つお花見シーズンですね。 さて、この度は、2023/03/23(木)~2023/03/25(土)に開催された PHPerKaigi 2023 にプラチナスポンサーとして協賛し、3名のメンバーが登壇しました。 今回は、登壇者 3 名からコメントと、会場の様子やセッションについてお届けします! PHP カンファレンス 2023 とは 2023/03/23(木)~2023/03/25(土)の 3 日間にわたって PHPerKaigi 2023 が開催されました。 BASE はこれまでにも開催されている PHPerKaigi への登壇並びにスポンサードをコミュニティ貢献活動として行って参りました。 今回はプラチナスポンサーとして当カンファレンスに協賛しています。 プラチナスポンサー一覧の左下にBASE株式会社のロゴ 登壇者のコメント 02 ( @cocoeyes02 ) speakerdeck.com 02です。今回は3年ぶりにメジャーバージョンアップとなったPHPUnit 10の話をしました。 今回の登壇準備の一環で、3年分のChangeLogを追って読んでいましたが、実際にやってみると想像以上に大変だということがわかりました。 ただ、IssueやPull Requestを読んでいく過程でPHPUnitのコミッター・メンテナーの考えや思想というのが徐々に見えてきて、とても勉強になりました。 今後もPHPUnitだけでなく、普段使用しているライブラリやフレームワークをChangeLogベースでリーディングしていこうと思います。 スライドにも書いていますが、今回のトークで話し切れなかった話題は後日テックブログに載せようと思っています。お楽しみに。 永野 ( @glassmonekey ) speakerdeck.com 永野です。今回はPHPをブラウザで動かすという面白内容で話をいたしました。 WebAssembly = ブラウザで用いられる技術 = PHPは関係ない、というイメージを払拭できた内容だったのではないでしょうか? 個人的にはWebAssemblyに関してはプロダクションの利用が広まってきていると感じており、特に脱コンテナという文脈では結構身近になってきているなと感じております。バックエンドエンジニアとして考えると抑えておきたいスキルかなと考えています。 特に先日 OpenFunctionがWasmをサポートした という記事もあるようにFaaSを使う規模だとコンテナは結構ヘビーな印象を持っていたので活用の幅は広がると考えています。 また、発表にインパクトがあるようにデモ用のPHPのPlaygroundサービスである php-play.dev も便利やらの感想を聞けたことは大変作者冥利につきました。 ぜひご活用ください。 php-play.dev Futoshi Endo ( @Fendo181 ) speakerdeck.com 遠藤です。最終日のLTで「PsySHを使った効率的なデバッグ方法について」というタイトルで紹介しました。 普段PHPを使ってデバッグをしていると var_dump や pritn_r などを使って実行後に中身を見るという流れになると思うのですが、 PsySH を使う事で対話的にターミナル上で確認できて便利です。 PHPでのデバッグツールと言えば「Xdebug」が有名ですが、素早くブレイクポイントを貼ってデバッグする時には PsySHが便利な場面があるので、是非活用してみてください! オフライン会場の様子 オフライン会場の様子をお届けします! こちらは Futoshi Endo さんのLTの時の様子ですね。制限時間間近になると聴講者の皆さんがペンライトを振る斬新な流れになっていました! 他にも数年ぶりに懇親会が開催されたり、お菓子なども充実していました! オフライン会場の様子は Googleフォト で共有されていますので、ぜひそちらも併せてご覧ください! 現地で見たセッションを一部紹介 takemoto です!今回は一般参加者としてセッションを聴講していました!その中でも気になったセッションについて一部紹介します。 PHPの最高機能、配列を捨てよう!! @uzulla 土曜の朝イチの発表でしたが、いい意味で眠気を吹き飛ばしてくれた発表でした。(是非アーカイブ動画を見てほしい) PHPの配列は他言語でいうところの「Vector, Map, Hash, List, Iterable」などの機能を備えており、なんでもできる最高機能です。しかし、なんでもできるが故にカオスを生み出しやすいので(自己責任で)捨てよう!と言った内容でした。 かくいう私も新卒の頃はPDOから取得してきたクソデカ連想配列を数ファイルにわたって引き回し、加工に加工を加えた末に出来上がった何かを型の支援もないまま、どういう風に扱っていたのかもう思い出せないですし、そういうコードはできればもうあまり書きたく(読みたく)ないと思うのでとても共感できる内容でした。 時間を気にせず普通にカンニングもしつつ ISUCON12 本選問題を PHP でやってみる @sji_ch オンライン登壇であったのにも関わらず、今年のPHPerKaigiのモリアガリトーク賞に選出された発表で、ISUCON12本選問題をPHPを使った実装で優勝チームと同等のスコア(Goでの実装で約34万点)を目指した試みが紹介されていました。 ISCCONは毎年Golangを使ったチームの活躍が目立っているので、「PHPがどこまでやれるのか」は非常に興味深いトピックでした。 発表の中で触れられていた作業は主に以下のような内容でした。 ミドルウェアの設定を優勝チームのリポジトリからコピってくる DBにインデックスを貼る PHPプロファイラで処理速度を計測 → ボトルネックになっているSQLを直す マスタ参照をキャッシュ利用するようにする シャーディングDB追加 PDOの生成コストが高いので、リクエスト間でPDOインスタンスを使い回せるようにする。 CPUがサチったので 余ってるDBサーバーのCPUでWebを回す ひたすらプロファイルを見て地道な改善 発表の途中で「CPU処理でネイティブコードの言語に勝てないのは自然なので、余ってるインスタンスはDBサーバーでも使え!」と言う主張があり非常に競技者的な目線の発想で思わず笑ってしまいました。 最終的なスコアは約35万点まで伸びて(制限時間という縛りはなかったですが)優勝チームを超えたので、PHPでも最適化すればかなりいいパフォーマンスが出せることを知れて、とても勉強になりました。 Laravelへの異常な愛情 または私は如何にして心配するのを止めてEloquentを愛するようになったか @KentarouTakeda Laravelがどのような思想で作られていて何を目指しているかを紹介した発表でした。 Laravelの思想に沿ってLaravelの機能をデフォルトのまま使うコードを書くことで、コンテナ化やスケールが容易になることが豊富なサンプルコードを例に説明されていて、改めてフレームワークの思想や基本設計を知ることは大切なことなんだなと感じました。 Laravelは何を目指しているのかを知ることができるエピソードとして、Laravel 10から戻り値アノテーションをタイプヒントへと修正する影響範囲の大きいPRが発表内で紹介されていました。 この修正は最終的にLaravelの作者自身が(長い議論の末)戻り値をmixedに戻したそうです。このことに対して登壇者の方は「Laravelはジュニアからシニアまで使っていけるFWを目指しており、その結果万人にとってちょっとづつ使いづらくはなっている」といった解釈をされていて「しかしLaravelのこういう思想は我々も採用や開発効率という点で恩恵を受けている。Laravelの利用を後押しすることでWeb開発をもっとより良くできる」という結論で締め括っていました。Laravelへの愛が詰まったとても心温まる発表でした。 謝辞 協賛・社員のスピーカー参加を通して PHP コミュニティの盛り上がりに貢献することができ、弊社としても大変有意義な時間となりました。 スタッフの方々には業務でお忙しいにも関わらず、多くの時間をカンファレンス準備へ注いでいただいたかと思います。この場を借りて御礼申し上げます。 それでは、また来年の PHPerKaigi でお会いしましょう!
BASEでバックエンドエンジニアをしている、遠藤( @Fendo181 )です。 2023年3月18日に開催された「 YAPC::Kyoto 2023 前日祭 」と、2023年3月19日に開催された「 YAPC::Kyoto2023 」に参加してきました。 「ブログを書くまでがYAPC」 という事でこの記事では参加レポートを書きます。 結論を先に言うと「 YAPC::Kyoto2023 最高でした。 」というのが自分の感想になります。 「何をもって最高だったのか?」というのはこの記事のまとめに書きますので、まずは参加レポートから紹介していきます。 この記事では自分のセッションも含めて「YAPC::Kyoto 2023 Reject Con」と「YAPC::Kyoto 2023」で発表されたセッションの中でも特に良かった8件を紹介しています。紹介しきれてなかった発表も沢山あるので、気になる方はタイムテーブルからセッションの詳細などを見て探しみてください。 YAPC::Kyoto 2023 タイムテーブル また、当日の感想や他の人が書いた参加レポートはTwitterでハッシュタグ、 #yapcjapan で追う事ができますので、こちらも是非ご覧になってみてください。 YAPC::Kyoto 2023 Reject Con PHP8によるデザインパターン入門 by FutoshiEndo speakerdeck.com ref: YAPC::Kyoto 2023 前日祭の「YAPC::Kyoto 2023 Reject Con」で登壇します - BASEプロダクトチームブログ 前夜祭での発表でしたがトップバッターだったので凄く緊張してました。 YAPCはPerlだけにとどまらない技術者たちが好きな技術の話をし交流するカンファレンスというのは知っていたのですが、PHPの話題で喋っても大丈夫かな...?という気持ちが強かったです。 また 「 Design Patterns: Elements of Reusable Object-Oriented Software 」で紹介されている23個のデザインパターンが作られた歴史的な背景も説明するスライドもあったので限られた時間でPHP8の文法も混ぜつつ説明ができるかは凄く悩みました。 結果的には社内の同僚から沢山レビューを貰い当日は時間内におさまる形で発表ができました。 お忙しい中でレビューしてくださった、 @glassmonekey さん、 @Panda_Program さん、 @nazonohito51 さん、 O2 さんの皆さんありがとうございました。 また、このスライドを作成するにあたってはBASEに在籍されていた Kazuki Higashiguchi さんの以下のスライドをとても参考にさせて貰いました。 改めてこの場で感謝を伝えさせてください。ありがとうございました。 デザインパターンを出自から深く理解する / understanding design pattern from the origin デザインパターンの使い方を パタン・ランゲージとの比較から考える / design-pattern-usage-inspired-by-pattern-language 自分が紹介したスライドを見た方はわかると思いますが「まとめ」の後の「最後に伝えたい事」で「 "How" age faster than "Why" 」をテーマに「手段にとらわれず、本質を追い求めましょう」というメッセージを追加しました。 YAPC::Kyoto には学生の方も参加される事をしっていたので少しでも響くメッセージがあればと思い入れました。 ただ、デザインパターンを覚えれば良いではなくて、本質を追い求めていく姿勢が大事という事が伝えれて良かったと思います。 インシデントレスポンスを自動化で支援する Slack Bot で人機一体なセキュリティ対策を実現する by hiboma speakerdeck.com hiboma さんによるSlack Botを使ったインシデント時の支援についての紹介でした。 具体的にはGMOペパボでの活用事例について紹介があり、インシデントマニュアルの呼び出しや、初期衝動を呼び出してチャンネルを作成したり、関係者に自動で連絡が飛ぶようにしたり、ポストモーテムの作成支援等で使われている事例が紹介されておりました。 インシデント対応に関して個人的に関心が高かったのでここで紹介されているSlack Botでの活用は現職でも今すぐに取り入れたいと思いました。 一時的なページにアクセスができない問題や、連携先の外部サービスによって機能が使えなくなる等と、影響範囲の規模は関係なく障害は常に起きるものだと認識しています。そういった常に発生するインシデントに対して、復旧作業を優先するように Slack Bot が支援する体制というのは、どこの企業でも取り入れて良いと思ったので、凄い参考になりました。 チーム開発における様々なボトルネックの整理 by すてにゃん speakerdeck.com この発表では すてにゃん さんが実際にチーム開発を通じて感じたボトルネックに対する考えた方や解決方法について紹介されていました。 改善サイクルが回っていない話から、チーム内の連携のイマイチになってしまっている例を提示しており、そこからの具体的な解決方法までわかりやすくて説明していました。チーム開発での課題は、リモート体制になってから顕著化していると思っていたのでともて刺さる内容で、スライドの中では「スコープ×カテゴリ」で絞るお話がされており参考になりました。 こういったボトルネックは放置しておくとチーム開発の速度低下になってしまうので自分も聞いていて実践したくなりました。 try { Support Engineer } catch($e) { joy, pride, and prospect } by kyanny docs.google.com kyanny さんの発表では GitHub Enterprise のサポートエンジニアとして、これまで行ってきた仕事や、やりがいについて紹介されていました。 自分が前職で CRE(Customer Reliability Engineering)をしていた事もあったので 「目の前の具体的な問題を解決するところ」や「フィードバックサイクルが短いところ」などはとても共感をしました。 また同時にしんどい所でもあげていた「小さい締め切りに追われるところ」も胸が痛くなるぐらいわかる部分でした。 サポートエンジニアやCREでも目の前で困っているユーザ様の課題を拾って解決したり、改善するというのは言葉では表しきれない達成感や喜びがあります。また、CS(Customer Support)さんとも連携したり、社内間で同僚とのコミュニケーションが必要なスキルなので 「(テキスト)コミュニケーションを通じて、いかに迅速に相手と意思疎通して問題点を明らかにし解決に導くか」 はとても納得しながら聞いてました。 YAPC::Kyoto 2023 小さく始め、長く続けるOSS開発と貢献 by Songmu ghq や peco を開発し、メンテナンスされているsongmu さんによりOSS開発に関する発表でした。 OSS開発によってどんなメリットがあるのか?の話では設計力が身についた話だったり、コミュニティにおいて仲間が出来たというお話がされておりました。またOSS開発について「ある意味プロダクトマネジメントができる」という視点での紹介もされており勉強になりました。 一番印象に残っているのが 「 正しいコードの先にある個性豊かな美しいコード 」 というワードで、とても心に響いたのを覚えています。 良い設計のために名前付けをする事が大事なのはわかっているのですが、「コーディングの世界でも文学のような個性が現れる世界があるのか...!」と気になりました。まるで小説の作家ごとの文体や行間の細かい癖が、コードの世界にもあり、個性豊かで美しく現れているのはOSS開発を始めたくなる強いメッセージだと思いました。 入門 障害対応 「サービス運用はTry::Catchの繰り返しだよ、ワトソン君」 by RyuichiWatanabe@gurasan speakerdeck.com Ryuichi Watanabe さんによる 障害対応フローにおける一連の作業の流れ紹介した上で、実際にサイトにアクセスが出来なくなったケースを例に具体的に対応する事を書いていました。このスライド、本当にわかりやすいです。 障害対応は常に発生する一方で、対応方法について属人化している部分があります。 影響範囲の特定から関係者への通知、早期復旧作業の一連の流れのエッセンスを上手くまとめており、非常に参考になると思いました。 またこのスライド中で紹介されていた 「障害対応能力向上施策」と障害対応時のナレッジと解決方法をまとめた 「Playbook」の作成は今すぐでも導入したい内容でした。 Playbookについては始めて聴く言葉だったのですが、メルカリのテックブログでも Playbook について言及されており勉強になったのでリンクを共有しておきます。 ref: メルペイのシステム運用とPlaybookの共通管理への挑戦 | メルカリエンジニアリング あの日ハッカーに憧れた自分が、「ハッカーの呪縛」から解き放たれるまで by あらたま speakerdeck.com cake.jp のCTOである あらたま さんによるハッカーに憧れた一人のエンジニアがギャップに苦しみながらキャリアを模索し、組織での役割も考えながら「ハッカーとは何であり、何でないのか?」を自分視点で説いた、素晴らしい発表でした。 自分もベストスピーカーとして投票をしたのですが1つの映画を見終わった後の満足感がありとても良かったです。 ハッカーになろう (How To Become A Hacker) という有名な記事があります。 何を隠そう自分もC言語のポインタが理解できない学生の頃からこの記事を何度も読んでは自分を鼓舞して、ハッカーに憧れていた一人のエンジニアでした。 そういった意味で「ハッカーの呪縛」というのはとてもわかる内容でした。 発表の中で「事業・技術の2つの軸を同時に極める事は難しい」という題材から第3の軸である「組織」を例に整理して「ハッカーにあり続けるために」へ導くまでのスライドは、今働いているエンジニアや、これからエンジニアになりたい人にも響く内容で素晴らしいスライドだったと思います。 そしてスライドの中で紹介されていた 「 Whatから出すケーパビリティがなくても、WhyからWhatまでを正しく理解し、Howに責任を持てるエンジニアにならなければならない 」はとても響いたメッセージでした。 改めてベストスピーカー賞おめでとうございます。 YAPC::Kyoto 2023 キーノート: 私とPerlとYAPCとはてなと私 モブがメインキャラを目指す話 by Yasuhiro Onishi speakerdeck.com 株式会社はてな の取締役 組織・基盤開発本部長の大西さんによる発表で、はてな誕生秘話の歴史から大西さんが、一人のモブ(社員)からエンジニアとして会社へ貢献し、組織を引っ張っていくメインキャラになる為の人生が紹介されていました。 個人的にはもう一つのベストスピーカー賞はこのキーノートだと思っています。 エモーショナルな話がメインだと登壇者のブログ記事に書いてあったのですが、一人のエンジニアとして組織に配属していれば誰もが共感する内容でとても良かったです。個人的にPerlコミュニティでの熱意が大西さんを動かして、キーノートで自らもYAPC::kyoto 2023で発表し、参加している方へ熱意を与えてる一連の流れが素晴らしく泣ける発表でした。 後日アーカイブ動画が公開されると思うので、機会があれば是非動画で見てその熱意を受け取って欲しいです。 発表お疲れ様でした。 そして、ありがとうございました。 まとめ YAPC::Kyoto 2023 が、自分にとって始めての「YAPC」参加でした。 YAPC参加する前からPHPやRubyの技術コミュニティでの勉強会やカンファレンスにも参加した事があったのですが「YAPC」ならではの良かった事の1つにPerl技術コミュニティの存在が大きいと感じました。 Yasuhiro Onishi さんのキーノートでも 「YAPC::Asia Tokyo 2006」の話が紹介されていたり、 あらたまさんのスピーカーでも 「YAPC::Asia 2011」の話が出ていたり等、過去の登壇者の発表に感化されて技術を磨き、そして再度「YAPC」で発表をするといった、一種の師弟継承が垣間見える瞬間がありました。 それはPerlに限らずどの技術コミュニティでも起きている話なのですが、YAPCに限った話で言うとPerlに限らず色んなプログラミング言語の技術コミュニティに影響を与えていると思いました。それはYAPCが「Yet Another Perl Conference」という意味であり、 Perlだけにとどまらない技術者たちが好きな技術の話をし、交流するカンファレンスだからだと思います。 そういった意味では全てのエンジニアが参加して楽しめるというのはとても素晴らしい事であり、参加できた事を嬉しく誇りに思いました。 本当にありがとうございました。 開催するにあたって沢山準備をして尽力された運営に皆さん、そして当日のスタッフの皆様お疲れ様でした。 次回も開催されると思うのでまた会場に足を運んで参加したいと思います。 おわり 記事内で紹介した登壇者のブログ記事一覧 https://tech.pepabo.com/2023/03/24/yapc-kyoto-2023/ https://blog.stenyan.jp/entry/2023/03/20/094654 https://blog.kyanny.me/entry/2023/03/20/005140 https://ryuichi1208.hateblo.jp/entry/2023/03/21/223424 https://onishi.hatenablog.com/entry/2023/03/20/141549
2023年3月19日に「YAPC::Kyoto 2023」が 開催されます。 yapcjapan.org その前日の2023年3月18日に前夜祭で開催される「YAPC::Kyoto 2023 Reject Con」に遠藤( @Fendo181 )が登壇します。 yapcjapan.connpass.com YAPC とは YAPCはYet Another Perl Conferenceの略で、Perlを軸としたITに関わる全ての人のためのカンファレンスです。 Perlだけにとどまらない技術者たちが好きな技術の話をし交流するカンファレンスで、技術者であれば誰でも楽しめるお祭りです! 今回の「YAPC::Kyoto 2023」のテーマは「try/catch」になります。 YAPC::Japanとして初めての試みとなる「会場と配信のハイブリッド形式」で開催されるカンファレンスなため、チケットを持っている方はオンラインでカンファレンスに参加する事ができます。 当日のタイムテーブルは以下をご覧ください。 https://yapcjapan.org/2023kyoto/timetable.html 発表する内容について 「PHP8によるデザインパターン入門」というタイトルで2023年3月18日の13:10~13:20の間で発表します。 このタイトルにした背景には「 PHPによるデザインパターン入門 」という、2006年に刊行された名書があります。この本では「Adapter」や「Singleton」など有名なデザインパターンをPHPを使って紹介されています。一方で本で書かれているPHPのバージョンは5.x系で、このとき型宣言も列挙型もまだ導入されていませんでした。 その後PHP7から「型宣言」が導入され、PHPは昔と比べて堅牢にコードが書けるプログラミング言語になりました。 読み進めながら写経していると「はたして最新のPHP8で書き直したらどんな違いがあるのか? もしくはデザインパターンで解決したい本質は変わらないのか?」という素朴な疑問が出てきて、掘り下げてわかりやすく説明したいと思い上記のタイトルになりました。 この発表では各PHPのバージョンで書き直したデザインパターンを比較し、PHP8で書き直した場合の変更点や、PHP8の新しい文法についても紹介したいと思います。 おわりに 自分としては本選考で選ばれなかったものの、前夜祭の「YAPC::Kyoto 2023 Reject Con」で採択して頂けた事に YAPC::Japanの運営の皆様に心から感謝しています。当日は参加者の方が少しでもtry/catchして、関心を持っていただけよう発表をしたいと思います。 また自分もYAPC::Kyotoに参加するのが始めてなので、一人の参加者としても「YAPC::Kyoto 2023」を楽しみたいと思います。
2023/03/23(木) ~ 2023/03/25(土) の日程で開催される PHPerKaigi 2023 へプラチナスポンサーとして協賛する他、BASE 株式会社に所属する 3 名のエンジニアが登壇します。 PHPerKaigi 2023 とは PHPerKaigiは、オープンソースのスクリプト言語 PHP (正式名称 PHP:Hypertext Preprocessor)を使用している方、過去にPHPを使用していた方、これからPHPを使いたいと思っている方、そしてPHPが大好きな方たちが、技術的なノウハウとPHP愛を共有するためのイベントです。 https://phperkaigi.jp/2023/ 弊社はプラチナスポンサーとして、当カンファレンスに協賛しています。 プラチナスポンサー一覧の左下にBASE株式会社のロゴ PHPerKaigi 2023は、オンラインおよびオフラインでのハイブリット開催となります。 セッションの内容について 02 ( @cocoeyes02 ) 2023/02/03 に約3年ぶりのメジャーバージョンアップデートであるPHPUnit 10がリリースされました。 3年ぶりということもあって、PHPUnit 9からの変更はとても多いです。 例えばPHPのrequireが7.3->8.1へと大きく変わったり、大量のクラスやメソッド、オプションが削除されたりなど・・・ 今回のトークではPHPUnit 10で何が変わったのか、時間が許す限り解説していきたいと思います! 永野 ( @glassmonekey ) 最近注目のWebAssembly皆さん使っていますか?私は仕事ではまだです!! Frontendでの活用を始めとして、バックエンド含めて活用のシーンが広がってきたように感じます。 そんな状況なのでPHPerの私含めて少しでもWebAssemblyと仲良くなれるきっかけを作れたらと考えています。 今回の発表では 以下の内容になります。乞うご期待。 WebAssemblyがどのような技術なのかの紹介 ブラウザ上でPHPを動かすデモ そのために必要なノウハウ Futoshi Endo ( @Fendo181 ) 遠藤です。PHPerKaigi 2023の3日目にLTで登壇します。 タイトルは「PsySHを使った効率的なデバッグ方法について」です。 PsySHはPHPで作られたREPL (Read-Eval-Print Loop) でインタラクティブに変数の中身やクラスのオブジェクト中身を見る事ができます。 bobthecow/psysh: A REPL for PHP 普段PHPでデバッグをする時には var_dump や echo などを使うと思いますが、 PsySH を使う事でより効率的にデバッグする事が可能です。その理由が伝わるようにこの発表では以下の内容でLTをする予定です。 PsySH について簡単な紹介 具体的なインストール方法と使い方について紹介 PsySH を使ったデバッグ方法についてTipsを紹介 最後に さて、ここまで読んでくださったみなさまのために、PHPerチャレンジ用のPHPerトークンを書きます。 PHPerチャレンジはPHPerトークンを探してスコアを獲得し、そのスコアの合計を競う全員参加型の企画です。詳細はPHPerKaigi内でのアナウンスを聞くか、パンフレットをご覧ください。 PHPerトークンは #payment_to_the_people_power_to_the_people になります。 少し長いトークン名になりますが、BASE株式会社のミッションである「Payment to the People, Power to the People.」をトークン名に採用させていただきました。 また、PHPerKaigi 2023 の当日のチケットは下記よりお申し込みいただけます。 https://www.eventbrite.com/e/phperkaigi-2023-tickets-454900217797 それでは、みなさまにお会いできることを楽しみにしております!
初めに こんにちは。フロントエンドエンジニアの竹本です。 入社してそろそろ4ヶ月が経とうとしています。だいぶBASEの開発にも慣れてきました。 この記事では私が社内の静的アセットを管理しているリポジトリ(以降は便宜上 static-repository と呼びます)のNode.jsのバージョンを12から16にあげたら、webpack dev serverの立ち上がりが約12分から約5秒に短縮できた話を紹介したいと思います。 この作業は業務の隙間時間でやったのですが、どのように取り組んでリリースまで持っていったかをお伝えできればと思います。 結論3行 webpack dev serverの立ち上がりが遅かったのはApple シリコン搭載のMacでNode.js 12を動かしていたから。 Apple シリコン搭載のMacでNode.js 15未満を動かすと、rosetta経由になり非常に遅くなる。 Node.jsのバージョンを上げようとしたら、それなりに大変だった。 話の始まり 事の発端は私がBASEに入社して約2ヶ月ほど経ったときの事でした。その頃私はBASE10周年プロジェクトにアサインされ、 10周記念特設サイト の開発・リリースを担当することになりました。と言ってもWebサイト自体の制作自体は別の方が担当されるので、やることといえば成果物に対して既存のビルド処理を通してコンポーネント等を差し込み、リリースに備えて準備を行う程度のものでした。 ※ 余談ですが 10周記念特設サイト はリリース後、 Web Design Clipさんにも取り上げられました。 とても素敵な仕上がりになっているので、よければ一度ご覧になってください。 特設ページは基本的に static-repository で管理されており、静的ページにビルド処理を通して独自のコンポーネントを差し込んだりmetaタグを追加することができるようになっています。 特設サイトのソースコードを受け取った私はそれを static-repository に移して、webpack dev server起動コマンドの yarn run dev を実行、、、しますがローカルサーバーが立ち上がりません。あれ???と思いながら何度か同じコマンドを叩きますが、どうやらローカルサーバーが立ち上がらないわけではなく、 立ち上がりが非常に遅くなっているようでした。 static-repository は静的アセットを管理するだけのリポジトリなので、メンテナンス頻度はあまり高くなく考えられる原因はいくつかありましたが、この時の私は納期が迫っていましたし、立ち上がりが遅いだけでエラー等は起こってなかったのでとりあえず作業を完了させることにしました。10周記念特設サイトは無事にリリースされ反響も大きく、プロジェクトは大成功でした。 それから2ヶ月ほど経って、BASEのフロントエンドエンジニアが有志で集まって負債解消に取り組む frontend-yatteiki という集まりに参加させていただくことになり、そこでずっと気になっていた static-repository 遅い問題に取り組ませてもらうことになりました。 やったこと まずは現状の調査から始めました。 yarn run dev を実行してからローカルサーバーが立ち上がるまでの時間を測定したところ平均して12分くらいかかっていました。遅くなっている原因をざっとコードを眺めて探ってみましたが、 .node-version で指定されていたNode.jsのバージョンが12.14.1と非常に低いことが気になりました。 なので雑にNode.jsのバージョンをLTSである16まで上げるところから始めることにしました。 .node-version を16.18.0に書き換えて yarn install を実行すると以下のようなエラーが出力されました。 1 warning and 1 error generated. make: *** [Release/obj.target/binding/src/binding.o] Error 1 gyp ERR! build error gyp ERR! stack Error: `make` failed with exit code: 2 gyp ERR! stack at ChildProcess.onExit (/Users/XXXXXX/XXX/XXXXXXX/XXXXXX/static-repository/node_modules/node-gyp/lib/build.js:262:23) gyp ERR! stack at ChildProcess.emit (node:events:513:28) gyp ERR! stack at Process.ChildProcess._handle.onexit (node:internal/child_process:293:12) gyp ERR! System Darwin 21.6.0 gyp ERR! command "/Users/XXXXXX/.nodenv/versions/16.18.0/bin/node" "/Users/XXXXXX/XXX/XXXXXX/XXXXXX/static-repository/node_modules/node-gyp/bin/node-gyp.js" "rebuild" "--verbose" "--libsass_ext=" "--libsass_cflags=" "--libsass_ldflags=" "--libsass_library=" gyp ERR! cwd /Users/XXXXXX/XXX/XXXXXX/XXXXXX/static-repository/node_modules/node-sass gyp ERR! node -v v16.18.0 node-sass のビルドでコケているようです。node-sassのバージョンは 実行環境のNode.jsのバージョンに大きく影響を受けます。 なるほど、これがNode.jsのバージョンを上げにくくなっていた原因かもと思いました。しかし static-repository は直接 node-sass に依存してなかったので yarn why node-sass でどのライブラリが node-sass に依存を持っているか調べます。 ❯ yarn why node-sass yarn why v1.22.19 [1/4] 🤔 Why do we have the module "node-sass"...? [2/4] 🚚 Initialising dependency graph... [3/4] 🔍 Finding dependency... [4/4] 🚡 Calculating file sizes... => Found "node-sass@4.12.0" info Reasons this module exists - "base-kit#gulp-sass" depends on it - Hoisted from "base-kit#gulp-sass#node-sass" base-kit が依存している gulp-sass が node-sass に依存しているようです。 base-kit はBASEの社内ライブラリのようですが、今まで見かけた記憶がありません。調べたところ base-kit はフロントエンド開発の便利ツールを集めたライブラリとして過去には存在していましたが、数年前にメジャーバージョンが上がる際に bbq としてUIライブラリに生まれ変わっていました。困ったことに static-repository は base-kit の依存がそこそこあり、その中には base-kit をアップデートして bbq にすると削除されてしまうモジュールもありました。 どうして... ということで、頑張って base-kit への依存を剥がしていきます。 base-kit をアップデートして bbq の最新版にし、 node-sass を使っているところは dart-sass に置き換えていきます。この移行はビルド設定ファイルの変更はほとんどありませんでしたが、webpackのビルド時にSCSSのコンパイルで新しくエラーが出るようになったので、そこも一通り対応していきます。 bbq にアップデートすると消えてしまうモジュールに関してはコード量がそこまで大きくなかったので、コピペでそのまま持ってきます。 その他、軽微な修正をいくつか行なって yarn install を実行するとNode.js 16でインストールに成功しました! yarn install 自体もかなり速くなってました。そのまま続けて yarn run dev を実行するとwebpack dev serverが数秒で立ち上がり、表示崩れ等もない状態でした。 static-repository はdevelop・masterブランチに新しい変更が加わればCIでビルド処理を行なって、成果物を自動的にS3に上げることが役割なので、ビルドが通ることとビルドの成果物が期待通りの状態になっていれば問題ないという考えのもと、ステージング環境で再ビルドされたものを入念に動作確認をして本番リリースしました。 リリースから数日の間はCIでエラーにならないか気を配っていましたが、2回ほどCIが落ちることがありヒヤリとしました。しかし、いずれもNode.jsのバージョンを上げたことが直接の原因ではなく、すぐに安定稼働してくれるようになったのでそこでようやく一安心することができました。 なぜstatic-repositoryが遅くなっていたのか たまたまNode.jsのバージョンアップをしたら動作が爆速になったので、てっきりNode.jsのバージョンが古かったことが遅くなっている原因だと思っていました。しかし、PRを作り始めた時にCTOの川口さんから以下のようなコメントを頂きました。 なんと!思っていたこととちょっと違っていました。 私は業務でしかM1 Macを使っておらず、プライベートでは基本的に最新版のNode.jsしか使っていないため全く気付きませんでした。他の方がIntel Macで試してみたところ、Node.js 12でも快適に動作したとのことだったので static-repository が遅くなっていた直接の原因は Apple シリコン搭載のMacでNode.js 15未満を動かしていた からでした。 後になってから知ったのですが、元々BASEではM1 Macbookを導入する際にCTOや基盤チームの方がM1でも開発できるよう開発環境を整備して下さっていました。BASEの主要リポジトリはその時にNode.jsのバージョンが引き上げられていましたが、更新頻度の低い static-repository は取り残されていたというのがこの話のオチになります。 やってみて得られた知見やBASEのいいところ バージョンアップ対応は溜め込むと大変 今回の事例でいうと static-repository が base-kit に依存しており、 base-kit が node-sass に依存し、 node-sass がNode.jsのバージョンに依存しているという構造になっていました。そのため、Node.jsのバージョンを上げるためにはコードを読み解いて依存関係を理解しつつ、一つ一つエラーを潰していく作業が必要でした。ライブラリ等のバージョンアップをしないでいると古い依存関係の上に新しい依存が作られていくことになるので、改めて日頃から依存ソフトウェアのバージョンを上げていくことの大切さを実感しました。 やらないといけないことはやっていく必要がある Webサービスを提供している事業会社はどうしても新機能の開発や既存機能の改善をしていくことが優先されます。それはユーザーに新しい価値を届けるためにとても大切なことですが、一方でプロダクトをより堅牢に, より速く変えていけるようにすることも同じくらい重要です。ライブラリのバージョンアップはまさにそういった作業の第一歩だと思うので、積極的に上げていきたいなと思いました。 BASEは「いつかやらないといけないこと」にも取り組めている BASEは創業10周年を迎え、会社もサービスも大きくなりましたが同時にやり残し・積み残し作業も数多く存在しています。ですがBASEはサービスを成長させていくのと同時に「いつかやらないといけないこと」についても今取り組んでいこうという空気を強く感じていますし、実際かなり取り組めていると思います。 今回私が参加した frontend-yatteiki ではプレイヤーとしてのフロントエンドエンジニアの他にフロントエンド領域に明るいセクションマネージャーの方や基盤チームの方も参加されており、BASEの負債や開発上の課題について活発に議論が行われていたりプロジェクトとは関係のないPRが出されていたりしています。BASEで責任ある立場にいる方がこういう問題に積極的に取り組んでいることは、開発チームとしてとても良い状態だと思いますし、私自身も何かしら貢献がしたいと思えるようになりました。私が入社する前の事例を見ても入社歴が長くないフロントエンジニアの方がVue.jsのバージョンを上げたりビルドパイプラインを改善したりと自発的に課題解決に取り組んでいる様子がslackから伝わってきて、非常にいい刺激をもらいました。 終わりに 今回は社内リポジトリのNode.jsのバージョンを上げた事例を紹介させていただきました。依存ソフトウェアのバージョンを上げていくことはとても大切です。社内にはたくさんのリポジトリがあり、中にはあまり頻繁にはメンテナンスされていないものもありますが、自分が関わったリポジトリに関しては来た時より綺麗な状態にしていけるよう努めていきたいですね。
はじめまして、2023年1月4日に入社しました遠藤( @Fendo181 )と言います。 所属は Cart Dev というチームでバックエンドエンジニアを担当します。 Cart Dev チームはBASEの決済開発を担当しているチームになり、主にショップオーナー様や購入者の決済、カート機能周りの開発を担当しています。 入社してそろそろ1ヶ月経つタイミングですのでこの記事では初リリースまでに行った事や実際にBASEに入社してから経験した事をご紹介します。 初リリースできるまでに経験した作業内容について 自分がはじめてリリースした機能は、ある処理が完了した際のログを追加する軽微な変更でした。 以下に入社してからリリースするまでに行った具体的な作業内容を時系列順にご紹介します。 (1)GitHubやOneLoginなどの業務で使うアカウントを作成する (2)オンボーディング用のドキュメントを参考に作業内容を確認する (3)BASEでショップを開設しながらサービスの仕様を把握する (4)開発環境を構築する (5)具体的な作業内容をメンターの方と相談しながら実装する (6)PullRequestを作成してDevelopment環境にデプロイする (7)Development環境で検証後に問題なければメンターやチームメンバーにレビューをしてもらう (8)レビュー後にApprovedを貰ったらPullRequestをマージしてStaging環境にデプロイする (9)Staging環境で問題なければProduction環境にリリースする (10)Production環境に動作確認をして問題ないか確認する 上記で紹介した作業以外にも PhpStorm の設定や、アーキテクチャの方針や、ドメインモデル図の紹介だったり細かい作業もありました。 紹介した作業の中で自分が特に掘り下げて説明したい内容は以下の2つです。 (2)オンボーディング用のドキュメントを参考に今後の業務内容を確認する (3)BASEでショップを開設しながらサービスの仕様を把握する オンボーディング用のドキュメントがとにかく充実している オンボーディング用のドキュメントには組織図の紹介からチームメンバーのプロフィール、グループでの活動、開発に入るまでの準備等、作業内容が丁寧に記述されていました。 また、Slackでオンボーディング専用のチャンネルが出来ておりドキュメントを読んでも分からない事があったとしてもチャンネルで質問をなげるとすぐにメンターやチームメンバーからフォローが入り1人で悩むというのが無かったです。 また、オンボーディング期間中は上長と1週間に1回、1on1のMTGで作業の進捗具合を相談する機会があります。 この時に「30days入社モニタリングシート」というのを使って進捗を確認するのですがオンボーディングで想定している作業と実際に行っている作業で大きな差が生じないよう1つ1つ状況を確認しながら相談にのっていただいたのが良かったです。モニタリングシートを使ってのふりかえりを行う事で次の1週間の動きが明確になり安心して業務に集中する事ができました。 このようにオンボーディング用のドキュメントが丁寧にまとまっていたり、30days入社モニタリングシートが用意されている等、BASEでは リモート環境で入社してもすぐに会社の環境に慣れる配慮 がされているのが個人的に素晴らしいと感じました。 オンボーディングについては Owners Marketing チームの竹本 さんが書かれた記事もあるので是非こちらもご覧ください。 devblog.thebase.in BASEでショップを開設しながらサービスの仕様を把握する BASE社内ではこの研修の事を「プロダクト習熟トレーニング」と呼んでいます。 この研修の目的は「新入社員・中途入社・業務委託向けに、BASEのプロダクトに対する理解を深めてもらう。」というコンセプトで用意されています。 最初にBASEでアカウントを作って商品を登録したり、Appをインストールして実際にショップ作成を体験する研修になりますが、作業内容がとにかく細かく書かれております。 以下に実際の作業内容をご紹介します。 商品を登録する。 商品にカテゴリを設定する。 1つの商品ページ内で、種類(Sサイズ、Mサイズ、Lサイズ)を登録する。※サイズごとに値段の変更は不要 登録済みの商品を複製して、別の商品を登録する。 登録している商品を一括で非公開にする。 登録している商品を任意で選択し、同時に削除する。 登録している商品を全削除(一括削除)する。 CSVで複数の商品を同時に登録する。 CSVで複数の商品へカテゴリを同時に登録する。 ... これは一部分で他にも同様なステップが続きます。 自分は空き時間を活用しながら作業してたのですが2~3日程かけて終えました。 この研修の素晴らしい所はただショップを作成して終わりではなく作成しながら「改善したい所も書く」というのがあり研修を通じて サービス利用者側から当事者側への意識 に変わりました。 開発業務外で経験した事について 次に開発業務外でBASEに入社して良いと思った文化や制度についてご紹介します。 Uniposで褒め合う文化について BASEでは Unipos という従業員同士が感謝したい事やお礼を伝えたい時に少額のインセンティブを贈り合うことができるサービスを活用しています。 自分が機能を初リリースする際にもこのサービスを使ってメンバーからポイント貰い嬉しかったのですが、相手への感謝の気持ち気軽に伝えられるのが個人的には素敵な取り組みだと感じました。 メンターランチ制度を使って他部署の方と交流する メンターランチ制度とはBASEに入社された方がいち早く会社に馴染んでいただけるようランチ代の補助する制度になります。 詳細は BASE Book でもご紹介していますのでご覧ください。 basebook.binc.jp 普段仕事していると自分が所属しているチームメンバーとの交流がメインになるのですがこの制度を使う事で他部署のエンジニアやグループマネージャーの方と交流できるきっかけになり良かったです。 まとめ 自分がBASEに入社して初リリースするまでに経験した内容をご紹介しました。 オンボーディング用のドキュメントが充実している事やメンターランチ制度が揃っているなどBASEではリモートで入社してもすぐに組織に馴染んで開発に集中できる環境が整っていると感じました。 またこの記事では紹介できなかったのですが頻繁に社内で読書会が開催されたり、ブロク記事や勉強会への登壇を推し進めるチャンネルがあったり組織の中で活発にインプットとアウトプットに取り組んでいる事も素敵だと感じました。 この記事を読んでBASEに興味を持った方は Youtube 、 BASE Book でも事業内容や現在取り組んでいる内容についてご紹介していますのでご覧ください。 この記事を読んでBASEに少しでも興味を持っていただけると幸いです。 読んでいただきありがとうございました。 binc.jp
はじめに この記事は BASE Advent Calendar 2022 の25日目の記事です。 CTOの川口 ( id:dmnlk ) です。 毎年技術ブログチームに勝手に組み込まれています。 タイトルと画像が一致してないのはデザインテンプレに合わせづらかっただけなので気にしないでください。 BASEでのエンジニアリングマネージャーについて エンジニアリングマネージャー(以下EM)は各社によって定義が分かれていることと思います。 どこに責任を持ってもらうか、という点が異なっており下記エントリーがまとまっていてわかりやすいです。 yigarashi.hatenablog.com BASEにおいてはEMは主にピープルマネジメントとデリバリマネジメントに責任を持ってもらっています。 ピープルマネジメントには採用も含んでいたりするのではないでしょうか。自分のチームの補強はEM自らが主体で採用していくということですね。 テクノロジーマネジメントはテックリードとCTOの僕がマネジメントしている構造となっています。プロダクトマネジメントに関しては、VPoP率いるチームが持っています。 EMがエンジニアのキャリアとしてどう捉えられているか 最近ではようやくEMがエンジニアキャリアと1つとして道筋になってきていますが、どうしても技術を伸ばすことを諦めてしまうといった捉え方をされることを聞くことが多いです。 実際のところ、BASEのEMが最先端の技術を検証したりバリバリとプロジェクトのコードを書くということは行っていません。 そういう点を見聞きしてしまうとEMはエンジニアのキャリアから外れてしまうという印象が出てしまうということなのだと思います。 ですが自分はそうは思っていません。 自分は人や組織はシステムアーキテクチャの1つというか同じであると考えています。 人というコンポーネントをどのように配置し、どのように相互作用してアウトプットを増やして開発をスケールさせていくかを考える必要があります。 人間はとてもグローバル変数が大きいのでいつでも同じアウトプットが出るものではそこも考慮する必要があります。 これら複雑な要素をうまくコントロール、ハックし、BASEという1つの大きなシステムアーキテクチャを運用していくことは疑いようもなくエンジニアリングといえるでしょう。 組織をシステムアーキテクチャと捉えたときのEMの役割 上記の事を踏まえたとき、EMの役割は何になるかと言えば所謂テックリードやシステムアーキテクトになるのではないでしょうか。 チームをリードしアウトプットを改善していくことが求められます。 時にはメンバーにハードなコミュニケーションをしてでもアウトプットのブロッカーをなくしていく必要もあります。 従来のやり方だけでは問題がある場合には、今までチームで取り入れていない技術要素(例えばスクラムの導入など)に取り組むこともあるでしょう。 チームという単位のマイクロサービスのようなもの(あくまで比喩です)をEMが運営し相互作用しそれら全体の設計や流れをコントロールすることがCTOたる自分の重要な責務の1つであります。 おわりに これからのキャリアに悩んでいるエンジニアの方にはEMにあまりネガティブな印象を持ちすぎず、新しいエンジニアリングに取り組むという気概を持ってエンジニアリングマネジメントにチャレンジして欲しいと思っています。 そして改めてここでいうことではないですが、BASEのEMの皆様は自分達がシステムアーキテクト、テックリードとしてチームというシステムをよりよく運用していけるように頑張ってください、よろしくおねがいします。 今年もBASEアドベントカレンダーをご覧いただきありがとうございました。 2023年もこのブログを積極的に更新していく予定ですのでご覧いただければ幸いです。
はじめに この記事は BASE Advent Calendar 2022 の25日目の記事です。 devblog.thebase.in はじめまして、BASE株式会社で執行役員 VP of Productをしている神宮司 ( id:h7jin16 )と申します。 メリークリスマス!アドベントカレンダーも最終日です。皆さま仕事納めはできたでしょうか? BASE株式会社は今年で10周年を迎えたアニバーサリーイヤーでした。自身もBASE株式会社で働き始めて9年経ちます。今回は9年間の社会人経験を経て大切だと思ったことを4つ紹介させてください。 個人的なものなのでお役に立てるかは分かりませんが読んでいただけると嬉しいです。 想像力は大切 ユーザーさんが抱える課題に対しての想像力だったり、誰かとコミュニケーションをするときの想像力だったり、何かを計画するときの想像力だったり。とにかく生きていくうえで想像力は一番大事だと感じています。 想像力の欠如によって誰かを傷つけてしまうことや不要なアクシデントを招くこともあり得ます。さまざまな人のことを想像して適切な行動ができる人になりたいです。 常に意識を向けて日々を過ごす 職業柄自身が体験したことに対して「いい体験」 or 「悪い体験」のラベルを脳内で貼って過ごしています。 例えば、電車に乗ったとき、タクシーに乗ったとき、食事をしたとき、歯を磨いたとき、ボタンを押したとき...etc。なぜ自分は「いい体験」だと感じたのか、なぜ「悪い体験」だと感じたのか。 誰かと同じものを見ていても意識を向けている事柄によって受け取れる情報は人それぞれ違います。 信頼関係を築く 信頼があるから期待され、その期待に応えることでさらに信頼をされる。そんなループによって新たな機会を得ることができます。 信頼は一朝一夕では築くことができませんが失うことは簡単です。日々の所作によって信頼を築くこともできれば失うこともできます。自身も完璧には程遠いですが少しでも信頼を築けるように過ごしていきたいです。 アウトプットが重要 情報化社会なのでインプットの機会は得やすいです。知らないことがあったらAmazon、Google、SNS、ChatGPTに聞けば知ることができます。すごく便利で有り難いですが、個人的なくせとして、アウトプットよりもインプットのほうが楽なのでインプットに逃げてしまいがちです。 アウトプットするのは本当に辛く、解決しなければいけない面倒なことがたくさん起こります。しかし、アウトプットをしなければ何も起こりません。インプットはアウトプットのためにあります。 アウトプットをしなければ得られないインプットもたくさんあり、それこそが重要だったりします。なので意識的にアウトプットの機会を増やしていきたいです。 おわりに 読んでいただきありがとうございます。 今年からBASE DESIGNERブログも始めています。デザインチームもいろんな情報を発信しているので覗いてみてください note.com 今後も個人・スモールチームの経済活動をエンパワーメントしていくために精進します。BASE株式会社は次の10年に向かってより進化していきます。一緒に次の10年を作れるかたを探しているのでご興味あればぜひご応募いただけると嬉しいです。 binc.jp 引き続きBASE株式会社をよろしくお願いします。良いお年を!
はじめに この記事は BASE Advent Calendar 2022 の24日目の記事です。 devblog.thebase.in はじめまして。岡部( @rerenote )と申します。2022年6月にエンジニアリングマネージャーとして入社し、8月からPay ID Dev Groupでマネージャーを務めています。今回は購入者向けショッピングサービス「Pay ID」の開発組織について、マネージャーとして私が考えていることも少し織り交ぜながら紹介していきます。実用性というよりはパッション多めの内容でお送りします。 「Pay ID」と「Pay ID Dev Group」 ショッピングアプリ「BASE」とID決済サービス「PAY ID」を統合・刷新して2021年11月30日に提供を開始した購入者向けショッピングサービスが「Pay ID」です。「ネットショッピングの体験をより良くする」ことをミッションに掲げ、購入者が好きなショップや好きなモノとつながり続けられる関係構築の支援、ストレスフリーな決済体験の両方を提供するべく企画、開発、運用を行っています。統合前の2つのサービスの歴史があるため会員数こそ多いものの、現在の形になってからは1年強と歴史は短く、サービスとしてはまだまだ作り込みが必要という段階にあります。 Pay IDの開発組織である「Pay ID Dev Group」はPay IDのミッションを技術で実現するための組織です。具体的にはPay IDのスマートフォンアプリ、決済サービス領域の開発、運用を行っています。iOSエンジニア、Androidエンジニア、バックエンドエンジニア、フロントエンドエンジニア、エンジニアリングマネージャーが所属しており現在は約20名という規模です。 Pay IDのプロダクト開発スタイル プロダクト開発は主にプロダクトマネージャー、デザイナー、エンジニアでチームを組んで進めています。これから事業を伸ばしていくぞという段階にあるため、きっちり分業しています!ということはやっておらず、それぞれの専門領域で素案をつくり、チームで議論をしながら仕様や設計を決めていくというやり方をとっています。 「スクラムです」とか「アジャイルです」というような表現を用いていないのは、プロダクトに合った開発スタイルを試行錯誤しながらチームで発見していくこともプロダクト開発の一部だと思っていること、また、次で述べる特徴もあり、全チームこのやり方で進めています、とすることはないのかなという私の考えに基づいています。 システム運用についても安心して使っていただけるように、どういう体制でどのように実現していくかを設計して実行していく必要があってまだまだ未着手のことが多い。本当にこれから育てていくプロダクトとチームなんだなぁと痛感することが多いです。 開発組織運営視点でのPay IDのおもしろさと難しさ Pay IDというサービスは性質の異なる要素を内包しているため、異なる要素同士がいい感じに協調して1つの事業としてまとまりを出すことを意識して組織設計や採用要件等を決めています。サービスに対する解像度をできる限り高めた上で要素分解し、共通すること、共通しないことに分けた上で複数のチームに分割し、チームごとに味付けを変えていくイメージです。性質の異なる要素については下記のようなものがあると考えています。 「購入者」と「ショップオーナー」 Pay IDは購入者向けのサービスですが、実はPay IDのユーザーは購入者だけではありません。Pay IDでお買い物ができるショップは、ネットショップ作成サービス「BASE」で作成された自社ECのショップであり、ショップオーナーもユーザーです。プロダクトに機能という形で新しい価値を追加していく際には「購入者」「ショップオーナー」という違う立場と視点を持っているユーザーの両方を想像しながら取り組む必要があります。BtoCとBtoBの2つのビジネスモデルが同居しているようなイメージです。 「ショッピングサービス」と「決済サービス」 決済サービスは「メリットがある、便利だからこれを使おう」という理由が主になってくるもの。ショッピングサービスは「こういう買い物ができるからここで買おう」という理由が必要になってくるもの。特にPay IDでは「好きなショップ、好きな商品とつながる」ことを大事にしており「楽しくショッピングしてほしい」という想いと、「ストレスフリーに決済できるようにしたい」という想いがあり、目的が違うものが同居しています。 「スマートフォンアプリ」と「システム」 私自身の過去のエンジニア時代の肌感覚によるものなのでふんわりとしており伝えるのが正直難しいですが、感じていることをそのまま書いてみます。スマートフォンアプリを開発する際は、複数の機能群を有しながら1つのまとまった世界観を表現するように作るような感覚。システムについては機能群そのものを表現しており、それ自体が1つの世界を表現する感覚というよりは、複数のものが1つの船に乗っていますという感じ。あくまで個人の感覚ではあるのですが、このような違いを感じています。 Pay ID開発組織の現状とマネージャーとして考えていること サービス・プロダクトもこれからだし開発組織もまだまだこれから成長するよ、という段階です。 ネットショッピングの体験をより良くするために改善、変化を積み上げながらアプリやシステムを育てていく ユーザーを取り巻く環境の変化にアンテナを張りながら、長く愛されるサービスになるようプロダクトをメンテナンスしながら育てていく 上記を継続的に実行していくために、仕組みやカルチャーを自分たちの手で作っていく過程にあります。開発スタイル同様、課題解決についても試行錯誤を繰り返しながら前に進み続けることをしている状況です。 マネージャーとしての個人的な想いとしては、サービスや事業が成長することはもちろんですが「作り手が楽しいと感じながら開発をしている」というのも大切にしたいというのがあります。楽しさを感じるポイントは人によって異なるので実現が難しいことではありますが、「持っている力を駆使しながらなんかいい感じにうまいことやる」のがマネージャーとして求められることなので、1つ1つ試行錯誤しながらチームもサービスも変化させていければと思っています。 また、Pay IDのプロダクトチームについても社内では比較的規模が小さく、開発組織同様これから成長させるぞー、とやっている状況です。このような記事もありますので、あわせて読んでいただけると嬉しいです。 devblog.thebase.in note.com さいごに ほんの一部ではあるのですが、私個人の考えていることも織り交ぜながら、Pay ID開発組織の紹介をさせていただきました。歴史が短い分、課題も多いですが、1つ1つ向き合いながらグループ自体もなんかいい感じになるようやっていくのでどうぞよろしくお願いします! 今回紹介したPay ID Dev Groupでは現在エンジニア(iOS、Android、バックエンド)を募集中です!興味あるかも?と思った方はぜひ一度お話を聞きに来ていただけるととても嬉しいです!! A-1.Pay ID_バックエンドエンジニア / BASE株式会社 募集一覧 / BASE株式会社 募集一覧 / BASE株式会社 明日はアドベントカレンダーの最終日です。 CTOの @dmnlk とVP of Productの @7jin16 の記事が登場する予定です。乞うご期待ください!
はじめに はじめまして.経営戦略室の林田(@Linda)と申します. こちらは BASEアドベントカレンダー の23日目の記事です. 本記事では、今年1月に立ち上がったCEO鶴岡(@yt)直下のチームである 経営戦略室(Corporate Strategy Unit;略してCSU)について、立ち上げ時からの活動と、進める中で意識していたポイントを紹介したいと思います! 経営戦略室(CSU)とは 一般的には「経営企画」と呼ばれ、企業の中長期の経営戦略の策定や、新規事業の創出検討などを行う組織機能・職種に分類されますが、実際の業務分掌や組織上の位置づけは各社様々です. 立ち上げ当初、初期メンバーとして参画した岩田(@joe)や鶴岡とともに、「そもそも経営戦略室、何をしようか??」の議論から始めました. 侃々諤々の議論を行い、 経営戦略室は、「BASEをみんなで"より速く”、"より遠く”」へ導く「CEOの拡張機能」 として、目指す方向を定めました. <出所: 経営戦略室作成> ”より速く”、”より遠く”へ向かう先≒CEO機能としてコミットするものは何か? 色々なステークホルダーの方がいらっしゃり、沢山の観点がありますが、1つと言われれば 「ミッション」である「Payment to the People, Power to the People.」の実現 です. <出所: コーポレートサイト > ミッションの実現が全てで、これ以外は極論全て手段です. この立場に立つと、極端なことを言えば事業もプロダクトも、KPI管理も組織も全てが手段です. その時々で、ミッション実現に向けて解決すべき優先度の高い経営イシューは何か? これを中長期観点で考え抜き、アプローチ(打ち手)を検討します. この打ち手候補には、最善解なのであれば心持ちとしては全ての選択肢が含まれます. 極論、経営戦略室が開発をやるべきなら開発をする、営業活動が必要ならする、採用活動をすべきなら採用活動を率先して進める. 限られた経営資源を踏まえ、中長期的な観点も考えてミッション達成へ向けた最善手だと判断すれば、論理的にはこれらの手段も取り得ます. しかし、 BASEには、ミッションに共感する各領域のプロフェッショナル・スペシャリストの仲間がたくさんいます. 1つの組織機能でできることは物理的に限界がありスケールが難しく、経営戦略室単体で閉じる・依存する傾向にある打ち手候補が最善手になることは少なく、 「中長期的なスケーラビリティ」が判断軸 の1つに入ることがほとんどです. ミッションの実現に向けて、 マクロ環境や未来・将来を考えて、つまずきそうなものがあれば先回りしてその障壁を特定し、取り除きにかかる. その障壁を取り除くために、必要な経営機能の獲得や習慣のインストールに資する活動、それらがスケールする仕組み・ルールを考える. 最終的には、各経営機能が有機的に連携し、優先度の高い経営イシューを特定し、解決に向けて自発的に推進・協議され、数多くの打ち手候補の中から最善手が打たれるPDCAが回る状態を目指す. 経営戦略室の最終目的は「経営戦略室がなくなること」 だよね、と立ち上げたばかりではありましたがメンバー間でも話をしています. これが経営戦略室チームです. 今年1年の振り返り チームの方向性を決めた4月以降 高橋(@Nao.takahashi)や米田(@aipon)もチームに加わり、 今年一年で色々な取組・活動をしてきましたが、本記事ではその一例として3つ簡単に紹介します. 【① 各部門との協働検討推進】 まずは「仲間を知り、共に走る活動」から始めました.BASEの組織は、経営戦略室以外に ネットショップ作成サービス「BASE」を管掌するBASE事業に加え、 購入者向けプロダクト「Pay ID」や決済・金融領域のプロダクト「BASE BANK」・「PAY.JP」を担うNEW Div.、 全社のサービス情報セキュリティを担うIT Strategy Div. グループ全体のコーポレート機能を担うCorporate Div. が存在しています(22年10月時点).各部門のマネージャー中心に議論を行い、その内容を元に各経営課題の抽出を行ったり、解決に向けたアプローチの検討案を一緒に考えたりしてきました. <出所: BASE会社紹介資料 > 【② 経営会議のガイドライン設計】 経営会議は、全社の重要事項の意思決定機関の1つであり、まさに経営イシューが議論される重要な機能です. BASEでは、経営の意思決定のプロセスの可視化やその姿勢として議事録を原則公開しているのですが、 どうすればよりよい意思決定につながるか、会議の在り方自体を経営陣で議論し、ガイドラインを定めました. 例えば、資料は事前提出&参加者は前もって資料を読んで会議に臨むこと、と記載されており、 まだまだ試行錯誤中ではありますが、これにより質が高まってきていると感じています. *内容イメージ; 推奨アジェンダや会議参加に関するスタンス等が記載されています. <出所:経営戦略室作成> 【③ 中長期経営戦略の検討推進】 CEO機能の最重要テーマといっても過言ではない中長期経営戦略の策定・具体化、にも足元取り組んでいます. 各種現状を踏まえて、 ミッション・行動指針のレベルから、改めて経営陣で意味解釈やマインドを揃える その上で、これからのマクロ環境に関する見立ても立てながら、ミッション実現に向けたBASEグループ全体の企業戦略を議論する 上記を踏まえて、各プロダクト戦略やその実現に必要な組織ケイパビリティ獲得に向けた方針を議論する といったようなプロセスを経ながら、経営陣を中心に議論を重ねて検討推進を行っています. 進める中でチームとして意識していたポイント 経営戦略室チームとして検討を進める中でメンバー間で、 "チームとしてのマインドは揃っているか?" については、とても意識していました. 「ミッション」・「経営課題」・「事業戦略」・「組織」など抽象的な論点になりやすいトピックであるからこそ、 検討を進める際に、判断軸・議論の軸がブレないように、 些細な疑問点も、その内容や考え方自体のマインドのすり合わせ を行うようにしていました. 「マインドをすり合わせるためのTips」 として2点取組を紹介します. 【① チームミッションに紐づいた年間ロードマップと足元のOKR *1 設計】 BASEでは、クオーターごとに設定するOKRを活用しながら組織運営を行っているのですが、 足元のOKRがチーム方針に沿っているか、年間の活動方針に照らしたときにどの位置づけになっているか のすり合わせを各クオーターで行うことで、 期中に想定内容や進捗にGapが生じた際も、大方針・目的から逸れないような軌道修正が行える ようにしていました. <出所:経営戦略室作成> 【② 備忘メモチャンネルを活用した情報共有】 "普段の生活・仕事の中で生まれる些細な気になる点にこそマインドを揃えるヒントが有る” との考えのもと、そのチャンスを逃さないように、Slackの専用チャンネルを作り、 チャンネルのレスポンス義務なしで(投稿ハードルを下げる) 気になったニュースや、「これ議論したいな」と思った事項を備忘として投稿し、 その内容を日々のMTGや定例などで一気に共有して消化 をしていました.ちょっとした工夫と運用であるのですが、マインドも揃うし情報共有もできるし、おすすめです. 終わりに;僕たちの信じる未来 下記グラフはクリエイターエコノミー市場規模の将来予測ですが、 これからますます個人の力が経済的にも大きくなっていくことが予測されています. <出所: 三菱UFJリサーチ&コンサルティング株式会社 > 22年12月11日、 BASE株式会社は創業10周年 を迎えることができました. これからの10年も、ミッションである「Payment to the People, Power to the People.」の実現に向けて、 ひとりひとりに眠る、想いが、感性が、才能が。 世界中の、必要な人に届くように。 そこから生まれる、作品に、アイデアに、活動に。 正当な対価を、受け取れるように。 ペイメントを、世界中の人へ解放する。 世界のすべての人に、 自分の力を自由に価値へと変えて 生きていけるチャンスを。 あたらしい決済で、あなたらしい経済を。 そんな世界の実現を信じて、個人やスモールチームをエンパワーメントする存在で有り続けたいと思っています. 以上、チーム取組紹介でした! 明日は、岡部(@rerenote)さんの記事が公開予定です!お楽しみに! *1 : OKRは、Objectives and Key Resultsの略称で、GoogleやFacebookなどシリコンバレーの有名企業が取り入れたことで近年注目を集めていると言われている組織の目標の設定・管理方法のひとつです.