フロントエンドチームの右京です。サービスの利用者向けには BASE U にて告知いたしましたが、2020 年 11 月 15 日をもって BASE は Internet Explorer 11 (以下 IE11) のサポートを終了しました。サポート終了と聞くと基本的にはネガティブな印象になりがちですが、ここでは主に開発者に向けて、サポートを終了することによって広がる新しい未来の話をしたいと思います。 ショップのデザインを進化させるであろう 2 つの技術 IE11 サポート終了後に新たに利用できる技術の中で、特に注目しているのは「Web Components」と「CSS カスタムプロパティ」です。 developer.mozilla.org developer.mozilla.org どちらも名前を聞くことが増えてきていて、すでにご存知の方も多いと思います。簡単に言えば前者は独自のタグを作って提供できる機能、後者は CSS で使える変数だと思ってもらえるとイメージしやすいのではないでしょうか。 HTML 編集とショップデザイン これらを活用できる背景には BASE が提供している「HTML編集」という App の存在があります。この機能はショップのデザインをかなり自由に編集できる機能で、 デザインマーケット のベースとなるものともなっており BASE の発展とは切っても切れない関係です。その自由度の高さから多くのオーナーズに利用していただいているのですが、一方で機能の動作保証や技術的サポートが難しいという問題がありました。 機能を提供し、保護するための Web Components HTML 編集が提供している、BASE のショップを構築するための条件や変数を BASE Template と呼びます。これについて詳しく知りたい場合は、以下のドキュメントを参照してください。 はじめに · Developers この中でも「商品の名前」を取得するための {ItemTitle} のようなタグで問題が起こることはほとんどありません。しかし例えば {AppsReviewTag} は、そのタグをレビュー機能を実現するための比較的大きめの HTML と JavaScript に置き換えて動作するタグとなっています。このタグはいわゆるコンポーネントのような扱いとなるのですが、これは現状多くのブラウザで動作をさせるため、必要な HTML、JavaScript、CSS に置き換えるような素朴な実装となっています。(例のコードはわかりやすくしたもので、実際に配信されるものではありません。) // HTML 編集で記述されたコード < div class = "review" > {AppsReviewTag} </ div > // 実際にショップとして配信されるコード < div class = "review" > < div class = "base-review-container" > < div ...> .... </ div > </ div > < script > .... </ script > </ div > これによって特に多く起こる問題が「意図しない破壊」です。スコープの存在しないものに BASE が開発したものを後付けするような形になるため、コードに予期せぬコンフリクトが発生するケースがあります。例えば、 BASE 側の改修によって HTML 編集で作成されたショップのデザインと CSS がコンフリクトしデザインが崩れてしまったり、他の箇所の JavaScript の実行エラーによって一部の機能が停止してしまったことがありました。結果としてオーナーズ、BASE 共に問い合わせやクレームに繋がってしまいます。 // 意図せず class が衝突してしまった! < div class = "review" > < style > .review { padding : 40px ; /* 二重に padding が適用されてしまい、デザイン崩れの原因に */ } </ style > < div class = "review" > < div ...> .... </ div > </ div > < script > document . querySelectorAll ( '.review' ) . ... // 本来想定していない要素も対象に </ script > </ div > これらの問題を解決する方法として Web Components、 特に Shadow DOM への期待が大きくなっています。Shadow DOM はカプセル化された DOM ツリーやスタイルを使用できるため、HTML 編集が書かれたコードと BASE が提供しているコードがお互いに干渉しづらくなります。これを利用することで、提供側利用側に関わらず安定した機能の開発、追加が実現できるようにしていきたいと思っています。 また、BASE のショップ以外への BASE の機能の追加のようなことも考えられます。将来的に以下のようなコードを埋め込むことで、どこからでも BASE の商品を購入できる機能が提供されるかもしれません。 < base -order itemId= "1234567890" ></ base -order > CSS カスタムプロパティによるデザインの変更 CSS カスタムプロパティについては 2 通りの活用方法を考えています。 1 つは先ほど紹介した Web Components での機能提供のデザイン面を補助するような形での利用です。Web Components に機能を隠蔽していくと安全性が高まる一方で、これまで比較的容易に行えていたスタイルの上書きによるデザイン調整が行いづらくなってしまいます。機能の安定性ももちろんですがショップやテーマにあったデザインを提供できる必要もあるため、この隙間を埋めるための方法として CSS カスタムプロパティ経由で多くのスタイルを変更可能にできないかと考えています。 2 つ目は実際に BASE のショップ運用している方でないと分かりづらいかもしれません。 デザインマーケット で販売されている多くの素敵なテーマは、さらに細部をカスタムできる「デザインオプション」を提供しています。 デザインオプション · Developers このデザインオプションを本当に細かく用意してくださるテーマデザイナー様も多く BASE としても非常に嬉しいのですが、どうしてもその数に圧倒されてしまうようなケースも存在します。そこで、こだわり度にあわせて段階的な設定を CSS カスタムプロパティをベースに導入できないかと考えています。例えばですが「デザインオプション」で設定できるものは大まかなカラーのみに絞り、細かなカラー調整については個々に CSS カスタムプロパティを設定できるような機能です。 他にもカラーセットのような機能も考えられます。現行のものでも一部のカラーについてはテーマ間で設定を引き継げるようになっているのですが、これをより汎用的な仕組みとすることでテイストを維持したまま様々なテーマを試せるなど。これらはもちろん BASE だけで実装できるものではなく、テーマデザイナーの協力も必須なものです。 まだまだできることはたくさん 今回は特に HTML 編集やショップデザインに大きく関わるものについて言及しましたが、もちろん他にも BASE がもっと使いやすくなるような改善も実施されていきます。 IE11 のために妥協していたユーザーインターフェイスの調整 管理画面のパフォーマンスの向上 そして、開発のスピードアップ IE11 のサポートを終了し、開発にブーストのかかった BASE の今後にご期待ください。そしてそんな開発を一緒にやってみたいメンバーも常に募集しております。 open.talentio.com
自己紹介 こんにちは。BASE株式会社のフロントエンドチームの谷口です。 本日は、BASEのフロントエンドで使用している日付ライブラリについてお話しします。 BASEの日付ライブラリについて BASEでは、frontendという領域が出来始めた当初、最もメジャーな日付ライブラリである moment.js を使用していました。 その後、 デザインコンポーネントの開発 など、frontend領域が成長していく中で より使い勝手の良い別の日付ライブラリが検討され、 date-fns が採用されました。 現時点で、ほぼ全てのコードがdate-fnsに移行済みです。 date-fnsについて date-fnsについて少し説明すると、公式にもありますが下記のような特徴が上げられます。 moment.jsや day.js がDateオブジェクトをラップして扱うのに対し、純粋な関数を必要な分だけ読み込んで使用することが出来ます。 こちらの ディレクトリ を見ると、180以上の機能が用意されており、全て関数をexportしている事がわかります。 date-fnsは値を不変に保つことが可能です。 これはmoment.jsと比較すると下記のような違いが見られます。 //moment.jsの場合、addを呼び出す度に元の値が変更され、同じ結果が得られません。 //コンソールに警告こそ表示されますが、この動作が予期せぬバグを生み出す可能性があります。 const today = new Date (); const momentToday = moment(today); momentToday.add( "day" , 3); console.log(momentToday.toDate()); // Sat Nov 07 2020 11:17:47 GMT+0900 (日本標準時) momentToday.add( "day" , 3); console.log(momentToday.toDate()); // Tue Nov 10 2020 11:17:47 GMT+0900 (日本標準時) //date-fnsの場合、元の値を変更することはありません。 const threeDaysTime = addDays(today, 3); console.log(threeDaysTime); // Sat Nov 07 2020 11:17:47 GMT+0900 (日本標準時) const sixDaysTime = addDays(threeDaysTime, 3); console.log(sixDaysTime); // Tue Nov 10 2020 11:17:47 GMT+0900 (日本標準時) また他のライブラリと依存しておらず、関数を呼び出す度に新しいDateオブジェクトが返ります。 関数自体にも副作用が無いため、テストツールや他のライブラリに組み込むことも容易です。 bundleサイズも使用する言語やwebpackの設定により異なりますが、比較的軽量です。 出典: https://bundlephobia.com/ TreeShakingをサポートしています。 TypeScriptとFlowどちらにも対応しています。 ドキュメント も充実しており、サンプルコードも豊富なので、使い方に困るということも少ないでしょう。 また近頃、moment.jsがメンテナンスモードになるという主旨の 記事 が公開されました。 その移行先候補の1つとしてdate-fnsも記載されており知名度も高いライブラリです。 出典: https://www.npmtrends.com/ date-fnsのバージョンアップ 上記の経緯で採用されたdate-fnsですが、BASEでは、実装当初のv1.30.1 からアップデートされていなかったため、今年の3月にv2.0.0にメジャーアップデートしました。 v2.0.0の開発にはおよそ 2年の歳月 がかけられており、 中には 破壊的変更 も含まれていたため、いくつか修正する必要がありました。 v1.30.1 -> v2.0.0の主な破壊的変更点 下記が関数名の変更などを除いた主な変更箇所です。 (サンプルコードは公式より抜粋しています) 主要な関数は文字列を許可していたが、日付のみ指定になった。 文字列を使用したい場合はparseISOで変換して使用する必要があります。 // Before v2.0.0 addDays( '2016-01-01' , 1) // v2.0.0 onward addDays(parseISO( '2016-01-01' ), 1) Unicodeのフォーマットが変わりました。 以前まではmoment.jsの仕様を模倣していた 経緯 がありましたが、その他の多くの言語に習って、より普遍的な物に変更されました。 後方互換用のオプションが用意されていますが、今後このオプションが削除される可能性も高いので、可能な限り変更した方が良いでしょう。 // Before v2.0.0 format( new Date (), 'YYYY-MM-DD' ) //=> 2018-10-283 // v2.0.0 onward format( new Date (), 'yyyy-MM-dd' ) //=> 2018-10-10 format( Date .now(), 'YY-MM-dd' , { awareOfUnicodeTokens: true } ) //=> '86-04-04' format関数は明示的にフォーマット形式を指定する必要があります。 // Before v2.0.0 format( new Date (2016, 0, 1)) // v2.0.0 onward format( new Date (2016, 0, 1), "yyyy-MM-dd'T'HH:mm:ss.SSSxxx" ) 日数の変換はparse関数に全て委任していましたが、parseは引数を必須とし、それぞれの用途に合わせた関数が用意されました。 // Before v2.0.0 parse( '2016-01-01' ) parse(1547005581366) parse( new Date ()) // Clone the date // v2.0.0 onward parse( '2016-01-01' , 'yyyy-MM-dd' , new Date ()) parseISO( '2016-01-01' ) toDate(1547005581366) toDate( new Date ()) // Clone the date 最後に 日付という性質上、変更箇所は多岐に渡りましたが、破壊的変更があったにも関わらず アップデートの難度はそこまで難しいものではありませんでした。 これは、date-fnsがDateを引数として渡すだけ、というシンプルな使い方であるため、修正すべきコードも比較的読みやすかったおかげだと感じています。 moment.jsがメンテナンスモードになる中、移行候補の1つとしてdate-fnsを検討してみていかがでしょうか。
こんにちは。BASE BANK 株式会社 Dev Division にて、 Software Developer をしている東口( @hgsgtk )です。 BASE BANK Dev での開発では、クラウドインフラの構成管理に、 Terraform を利用しています。 世の情報をたくさんキュレーションしている CTO の @dmnlk さんに、手軽に CI に組み込めそうなセキュリティチェックツールがあることを教えてもらったので、導入してみました。 CTO氏のキュレーションメディアで紹介された tfsec を早速試して良さそうだった https://t.co/bl67dlW2Ub https://t.co/vAkTOVagec — Kazuki Higashiguchi (@hgsgtk) August 21, 2020 このブログの公開日は 2020/10/30 ですので、導入してから約 2 ヶ月強経ちました。導入・運用をつづけた経験から、いろいろ tfsec 自体の変化や、運用したことで学べた AWS セキュリティプラクティスをご紹介します。 目次 目次 TL;DR tfsec とは 始め方 クラウドの認証キー・権限付与が必要ないため導入しやすい GitHub Actions で始める 既存の指摘は tfsec:ignore でいったん Fixme issue にする tfsec の指摘から AWS におけるセキュリティプラクティスを学ぶ Amazon CloudFront の推奨 SSL/TLS Policy Amazon ECR のイメージスキャン機能の有効化 Amazon S3 のバケットロギング AWS Key Management Service のキーローテーションの有効化 Amazon Elasticsearch Service のデータ保護 ノード間通信の暗号化 保管時の暗号化 Redis 用 Amazon ElastiCache のデータ保護 In-Transit Encryption (TLS) At-Rest Encryption その他 aws_security_group_rule' should include a description for auditing purposes aws_cloudfront_distribution' does not have a WAF in front of it おわりに TL;DR Terraform のセキュリティ静的解析 tfsec はクラウドの認証キー・権限付与が必要ないためすぐに試すことが出来る tfsec 自体の開発も頻繁にコミットされており日々進化を遂げている tfsec を使い続けることで学んだ AWS セキュリティプラクティスをいくつか紹介する tfsec とは tfsec は、Terraform ファイルを静的解析しセキュリティイシューとなるような点を指摘してくれるツールです。 A static analysis security scanner for your Terraform code. Discover problems with your infrastructure before hackers do. www.tfsec.dev AWS・Azure・GCP といったクラウドベンダーをサポートしています。また、秘匿情報の混入がないかといった特定ベンダーに関わらない一般的なセキュリティチェック事項も備えています。 開発はメンテナー・コアコミッターの方々によって頻繁に行われています。チェック項目の新規追加はもちろんのこと、先ほど紹介した https://www.tfsec.dev というウェブサイトを公開したり、tfsec 自体のパフォーマンスチューニングや カスタムチェック 作成のサポートなど、日々新機能が追加されています。また、筆者自身いくつか PR を提出していますがそれに対してもすぐに反応いただきメンテナー・コアコミッターの熱量の高さを感じます。 始め方 クラウドの認証キー・権限付与が必要ないため導入しやすい tfsec が始めやすい特徴として、当該クラウドの認証キー・権限などが不要な点です。たとえば、 terraform plan をするようなツールだと、AWS の場合 IAM を発行する必要があります。しかし、本ツールは *.tf ファイルの内容の静的解析を行うだけなので、これらがいりません。 AWS でのインフラ構成管理を Terraform でやる場合、 Terraform に対してそれなりに強い権限を付与するため、その権限管理をどこでやるかは論点になりがちです。それを考えなくていいのは、とても始めやすい利点だなと感じます。 GitHub Actions で始める 私の所属するチームでは、 GitHub Actions で導入をはじめました。 公式の GitHub では、 triat/terraform-security-scan が紹介されています。しかし今回は、GitHub の Pull request(PR) へのコメントがすぐに実現できる点で、 reviewdog が公開している reviewdog/action-tfsec を使用しました。 github.com 本アクションを使った設定方法は例えば次のような yml ファイルです。 name : tfsec on : [ pull_request ] jobs : tfsec : name : tfsec runs - on : ubuntu - latest steps : - name : Checkout uses : actions /checkout @v2 - name : Terraform security scan uses : reviewdog /action - tfsec@master with : github_token : $ {{ secrets.github_token }} reporter : github - pr - review # Change reporter fail_on_error : " true " # Fail action if errors are found filter_mode : " nofilter " # Check all files, not just the diff flags : "" # Optional これにより、次のように指摘内容が GitHub の PR のコメントで見れるようになります。 ReviewDogによるPRへのコメント ちなみに、最近 GitHub に Unchanged files with check annotations という Beta 版の機能がついて、PR での変更差分外のファイルに対するコメントも反映されるようになりました。 "Unchanged files with check annotations" によるPR差分外のコメント tfsec は、Release によって新たなチェック項目が増えたりします。チェック項目が増えた際に、それに引っかかる内容が Terraform の記述に含まれていないかを継続的にチェックするにあたって、便利な機能だなと個人的に感じています。 github.com 既存の指摘は tfsec:ignore でいったん Fixme issue にする GitHub Actions に入れると、多かれ少なかれ、 Error / Warning レベルの内容が指摘されるかもしれません。導入にあたりすべてを直してからというのも新規に生まれるセキュリティの穴を塞げなくてもったいないので、弊社の例では、最初に tfsec:ignore というマーキングで既存の指摘を無視する設定をしていきました。 resource " aws_ecr_repository " " hoge " { # tfsec : ignore : AWS023 # Fixme above it Fixme で残しつつ、随時解消していく方法をとっていきました。 tfsec の指摘から AWS におけるセキュリティプラクティスを学ぶ 実際に tfsec を使い続けてさまざまな指摘によって、 AWS におけるセキュリティプラクティスを学びました。それらの学びをおすそ分けします。具体的には次の内容を紹介します。 Amazon CloudFront の推奨 SSL/TLS Policy Amazon ECR のイメージスキャン機能の有効化 Amazon S3 のロギングバケット AWS Key Management Service のキーローテーションの有効化 Amazon Elasticsearch Service のデータ保護 Redis 用 Amazon ElastiCache のデータ保護 その他 ひとつひとつ見てみましょう。 Amazon CloudFront の推奨 SSL/TLS Policy tfsec では aws_cloudfront_distribution' defines outdated SSL/TLS policies (not using TLSv1.2_2018) という指摘項目があります。これは、以下の issue で追加された CloudFront のチェック観点です。 github.com この issue 当時のベストプラクティスでは、 TLSv1.2_2018 が推奨されておりました。しかし現在は、 AWS Console に表示されていますが、 TLSv1.2_2019 が推奨されるセキュリティポリシーとなっています。 「そもそも TLSv1.2_2019 はどう違うの」という疑問を持たれた方(かつての自分ですね)は、クラスメソッドさんの次のブログの解説がとてもわかりやすいのでおすすめです。 dev.classmethod.jp resource " aws_cloudfront_distribution " " example.com " { # (省略) viewer_certificate { acm_certificate_arn = " certificateのarn " cloudfront_default_certificate = false minimum_protocol_version = " TLSv1.2_2019 " ssl_support_method = " sni-only " } ) もともと、 TLSv1.2_2018 ではない場合 Error と指摘されていましたが、PR を提出しリリースいただきました。もし TLSv1.2_2019 にあげても Error になる場合は、tfsec のバージョンを 0.27.0 >= に上げてみてください。 github.com Amazon ECR のイメージスキャン機能の有効化 こちらは、同僚の前川さんに対応いただきました。 aws_ecr_repository' defines a disabled ECR image scan という指摘を受け対応したものです。ECR image scan は、2019 年 10 月 28 日に公開された ECR image に対するイメージスキャンの機能です。 aws.amazon.com 他のツールでは、 trivy や dockle などがあげられます。 ECR Image scan を有効にするには、 aws_ecr_repository.image_scanning_configuration を設定します。 image_scanning_configuration は、Terraform 2 系の場合は 2.34 から、 3 系の場合は 3.10 から使用可能です。 resource " aws_ecr_repository " " hoge " { # (省略) image_scanning_configuration { scan_on_push = true } } Amazon S3 のバケットロギング aws_s3_bucket does not have logging enabled と指摘された場合、S3 のバケットロギングの検討が必要です。 S3 では AWS開発者ガイド:Amazon S3 サーバーアクセスのログ記録 で解説がある通り、サーバーアクセスに対するログ記録機能が提供されています。このロギングを有効にしておくとセキュリティやアクセス監査の観点で役に立ちそうです。 resource "aws_s3_bucket" "public-usecase-bucket" { # (省略) logging { target_bucket = aws_s3_bucket.access-logs.id # logging bucketを指定 target_prefix = "logs/" } } resource "aws_s3_bucket" "access-logs" { # (省略) acl = "log-delivery-write" } S3 のアクセスログバケットを作成する際には、acl を log-delivery-write にします。 discuss.hashicorp.com log-delivery-write は、AWS があらかじめ定義した既定 ACL と呼ばれるものの 1 つです(既定 ACL については、 AWS開発者ガイド:アクセスコントロールリスト (ACL) の概要 をご参照ください)。 LogDelivery グループはバケットに対する WRITE および READ_ACP アクセス許可を取得します。 ロギングバケット自体の ACL を考える際にはこの既定 ACL を使用するのが便利です。 以前は、ロギングバケット自体にも aws_s3_bucket does not have logging enabled という指摘が入り tfsec:ignore マーキングで回避する必要がありました。しかし、tfsec に対して PR を提出し解消いたしました。S3 バケットのロギングバケットの場合、当該指摘をしないように修正されています。 github.com AWS Key Management Service のキーローテーションの有効化 これは、同僚の @budougumi0617 さんが新規 KMS Key を構築時に指摘され、対応いただいたものです。AWS Key Management Service(以降、AWS KMS と略します)には、 カスタマーマスターキー ローテーション という機能があります。 AWS KMS は自動的に有効にした日から CMK(Customer Master Key) を 365 日後にローテーションし、その後は 365 日ごとに実行します。 docs.aws.amazon.com resource "aws_kms_key" "sample_key" { description = "機密情報の暗号化に利用" enable_key_rotation = true # 自動キーローテーションを有効にする } 作業としては、 enable_key_rotation = true の設定だけです。その設定をしてから 365 日後に自動でローテーションされます。 Amazon Elasticsearch Service のデータ保護 こちらは、同僚の前川さんが新規 Amazon Elasticsearch Service (以降、Amazon ES と略します)構築時に指摘され対応いただいたものです。Amazon ES は、データ保護におけるセキュリティ上の機能として「ノード間通信の暗号化」・「保管時の暗号化」という2つのオプションを備えています。 ノード間通信の暗号化 Amazon ES のドメインは、デフォルトでは VPC 内のノード間トラフィックは暗号化されませんが、ノード間通信の暗号化を有効にすることで VPC 内のすべての通信で TLS 1.2 暗号化が有効になります。 docs.aws.amazon.com この設定をしていないと、 Resource 'aws_elasticsearch_domain.es' defines an Elasticsearch domain with plaintext traffic (missing node_to_node_encryption block). という指摘を受けます。 具体的には次のようなコードによってノード間通信の暗号化の設定が可能です。 resource "aws_elasticsearch_domain" "es" { elasticsearch_version = "6.3" # (省略) node_to_node_encryption { enabled = true # true にすることで有効化する } } しかし、 AWS開発者ガイド: Amazon Elasticsearch Service のノード間の暗号化 にある通り、これは既存ドメインに対しての設定のつけ外しはできないため、既存の Amazon ES ドメインに対しては別のドメインを作成する必要があります。 また、elasticsearch_version も 6.0 以降が求められます。既存リソースに対して作り直しのコストを書けるのはしんどいという判断したら、tfsec:ignore マーキングするとよいでしょう。 保管時の暗号化 Amazon ES ドメインでは、AWS KMS を使用してインデックスやログ・アプリケーションディレクトリのデータなどを保管時に暗号化する機能が提供されています。 docs.aws.amazon.com Terraform では encrypt_at_rest という記述で指定します。 resource "aws_elasticsearch_domain" "my_elasticsearch_domain" { domain_name = "domain-foo" encrypt_at_rest { enabled = true # 保管時のデータ暗号化を有効化 } } しかし、こちらも既存ドメインでは有効にできません。また、特定インスタンスタイプの場合はサポートしていないこともあります。 docs.aws.amazon.com R3 インスタンスタイプは、保管時のデータの暗号化またはきめ細かなアクセスコントロールをサポートしていません。 サポート対象外の場合 tfsec:ignore マーキングすることになりますが、このような暗号化の検討を指摘によって考えられるのは tfsec の良い点ですね。 Redis 用 Amazon ElastiCache のデータ保護 こちらも Amazon ES における「ノード間通信の暗号化」・「保管時の暗号化」と類似したセキュリティプラクティスが存在します。前者を「In-Transit Encryption (TLS)」、後者を「At-Rest Encryption」にて設定します。 In-Transit Encryption (TLS) tfsec からは Resource 'aws_elasticache_replication_group' defines an unencrypted Elasticache Replication Group (missing transit_encryption_enabled attribute というメッセージで指摘されます。 Amazon ElastiCache には、ネットワーク転送時の暗号化オプションが用意されています。 docs.aws.amazon.com 具体的には、 transit_encryption_enabled というオプションを true にしておくことで設定可能です。 resource "aws_elasticache_replication_group" "my-resource" { # (省略) transit_encryption_enabled = true } こちらの設定は、Redis の対応バージョン(3.2.6, 4.0.10 or later)や対応可能なノードタイプが限られるといった 制約条件 を事前に確認する必要があります。 また、暗号化の実装によるバックアップオペレーション・ノード同期オペレーションの実行パフォーマンスが低下する場合があることを 開発者ガイド にて示しています。 なお、既存のレプリケーショングループの場合は新しいレプリケーショングループを作成する必要があります。こちらの方法についても、 開発者ガイド にて具体的な手順が説明されています。実際に読者の中で気がついて検討をしたい方がいらっしゃれば、是非ご覧になってください。 At-Rest Encryption tfsec からは Resource 'aws_elasticache_replication_group.bb-prd-auth' defines an unencrypted Elasticache Replication Group (missing at_rest_encryption_enabled attribute) というメッセージで指摘されます。 Amazon ElastiCache には、データの暗号化オプションが用意されています。 docs.aws.amazon.com 具体的には、 at_rest_encryption_enabled というオプションを true にしておくことで設定可能です。 resource "aws_elasticache_replication_group" "my-resource" { # (省略) at_rest_encryption_enabled = true } こちらも、「In-Transit Encryption (TLS)」と同様の制約事項・考慮事項があります。 セキュリティ観点とパフォーマンス観点のバランシングは自身のアプリケーション要件に沿って検討が必要ですが、tfsec によってセキュリティ観点での指摘を純粋に受けられるのは設計上の利点でしょう。 その他 その他、少し細かいですが管理上大事な内容を紹介します。 aws_security_group_rule' should include a description for auditing purposes Security group の INBOUND / OUTBOUND ルールには、説明(description)を設定できますが、監査上は設定することが推奨されます。 resource "aws_security_group_rule" "huga" { # (省略) description = "BASE Office" } aws_cloudfront_distribution' does not have a WAF in front of it tfsec の v0.30.0 にて追加されたチェック項目です。 docs.aws.amazon.com WARNING レベルの指摘なので、要件上神経質になる必要がないユースケースでの CloudFront の利用であれば tfsec:ignore マーキングで対応可能です。 おわりに tfsec の導入と、その指摘項目から AWS のセキュリティプラクティスを紹介しました。 今回は紙面の都合上紹介しておりませんが、ちょうど 2020 年 10 月に一気に開発が進んでいるのが カスタムチェック です。JSON 形式でルールを指定することで自分たちにとってのルールを tfsec のチェック内に導入できます。こちらもまた別の機会に紹介いたします。 かんたんに使用開始できるので、ちょっとセキュリティに関心・不安があるけど何も出来ていないという方がいらっしゃれば、試してみてはいかがでしょうか。
BASE の Service Dev にて主に決済周りのバックエンド開発をしている翠川( @midori44 )です。 昨年は PayPal決済の導入 のプロジェクトでメインエンジニアとして携わらせていただきました。 今回は決済周りの開発をしていく中で、社内の開発環境を整えた話をします。 ローカル開発環境での課題 BASEでは現在、 BASEかんたん決済 として6つの決済方法を提供しています。 日々の機能開発をしていく中で、すべての決済方法において各機能が正しく動作するかを確認するために、ステージング環境や社内検証用のQA環境だけでなく開発者のローカル環境でも決済をテストできるようになっています。 新機能のリリース時にはもちろん本番環境で実際の決済を通して動作確認するわけですが、開発中のテストの度に本番相当の決済をするわけにはいかないので、各決済代行会社様のほうで用意していただいている検証用サーバーやsandbox環境に接続してテストすることになります。 基本的にはそれで問題ないのですが、キャリア決済に関してだけはちょっと他の決済とはフローが異なることから、ローカルでのテスト決済ができない状態になっていました。 キャリア決済のフロー キャリア決済では、購入者は一度カートを離れて決済代行サービスのほうで購入手続きを完了します。そのため、決済が確定したかどうかはwebhookで受け取る必要があるのですが、外部にある決済代行サービスは開発者のローカル環境にあるwebhookサーバーへアクセスできません。 もちろん、外部アクセスできるhttpサーバーを立ててリモートフォワードなどをすれば可能ですが、開発用の個人マシンでそこまでするのはリスクが高く現実的ではありません。 ということで、キャリア決済の動作確認をしたいときは共用の検証環境で確認するという方法で長らく運用されていましたが、やはり不便に感じる声が多かったのでDocker上で動く決済代行サービスのモックサーバーを作って解決しました。 外部サービスのモック化 弊社のローカル開発環境はDockerで構築されています。Docker Composeの設定ファイルはGitHubで管理しており、カートが動いているwebサーバー、ショッピングアプリ用のAPIサーバー、データベース用のDBサーバー……等々、各種サーバーをコマンド1つで立ち上げることができます。 今回は、その中の1つのコンテナとしてキャリア決済用のモックサーバーを立ち上げられるように準備します。 適当なwebサーバーを用意して、実際の決済代行サービスと同じレスポンスを返すモックサーバーを作ります。今回は購入中のリダイレクト先としてブラウザからアクセスするため、正常系だけでなく異常系もテストできるように、画面上の操作によって意図的にエラーを起こせるようにしておきました。 モックサーバーのサンプル画面 純粋なAPIサーバーの場合は、異常系のテストをしたいときは『特定のリクエストを渡された場合にはエラーを返す』という実装が一般的かと思います。 たとえば PayPal のsandbox環境では、リクエストヘッダーに PayPal-Mock-Response を渡すことで任意のエラーを受け取ることができるようになっています。 https://developer.paypal.com/docs/api-basics/sandbox/request-headers/ Docker Composeに定義を追加して、用意したモックサーバーをコンテナとして立ち上げられるようにします。今回のモックサーバー構築で注意したいのは、購入者に確認画面を表示させるためのブラウザ経由でアクセスと、裏でwebhookサーバーへ通知を飛ばすためのコンテナ間通信の2つの通信が発生することです。 弊社のDocker環境では本番と同じように任意のホスト名かつSSLでアクセスできるようDNSやリバースプロキシを通しているため、 docker-compose.yml で extra_hosts を設定してモックサーバーからwebhookサーバーへのコンテナ間通信のときにもリバースプロキシを通すようにする必要がありました。 最後に 外部サービスのサーバーを丸ごとモック化することで、一通りの動作確認をDockerネットワーク内で完結させることができました。 今回はローカルでの動作確認が最後までできないことからのモック化でしたが、外部サービスに対する動作確認(こちらからのリクエストに対して想定したレスポンスが返るかどうか)と、自サービス内の動作確認(正常レスポンスもしくはエラーを受け取ったとき正しく処理されるか)を分けて考えるためにも、適切なモック化は役に立つかと思います。 BASEでは開発環境の整備や中長期的な技術基盤の改善を担っていくエンジニア、および120万ショップの決済を支えていくエンジニアを募集しています。 binc.jp
この記事について コロナウイルスによる社会不安の影響でこの半年でリモートワークの機運が特に都心部を中心に大きく高まってきました。 つい先日ヤフー株式会社が全社テレワークへの移行を正式発表したことは記憶に新しいです。 BASEでもコロナウイルスの感染拡大に伴っていち早くリモートワークの制度を構築し(2020年2月には全社的にリモートワークを開始)、 その制度は現在でもまだ運用されています。 また、世の中の動向やニーズの高まりもあり、リモートワークへの関心の高まりは採用の場面でも感じられるようになってきています。 我々も各種求職者の紹介サービスを利用していますが、そういったサービスではリモートワーク可・不可という選択肢しか選べない場合が多く、 結局面接に来ていただいた方に、BASEでどのようなリモートワーク制度が取られているか、今後どうなっていく予定か、 そういった内容を毎回口頭でお伝えする形になっています。 そこで、毎回のように質問を受けるのであればいっそ記事にして公開し、 現場からみたBASEのリモートワークをお伝えしたい、というのがこの記事の趣旨になります。 あなたは誰 私はBASEのフロントエンドチームでエンジニアリングマネージャーをやっている松原( @simezi9 )です。 マネージャーになったのは2020年7月からです。それまではエンジニアとして働いていました。 なので、BASEがリモートワークを導入する上でどういう議論が行われていたかを直接耳にしたわけではありませんし、 当初は1メンバーとして会社の決定に従って行動する立場でもありました。 そして今ではその制度を運用する立場となってこの記事を書いています。 BASEでのリモートワークの位置付け まず最初にBASEのリモートワークに対して結論だけを述べると、 「BASEではリモートワーク(以下、WFH = Working From Home)は現状可能ですが、フルリモートで働きつづけていく可能性を積極的に模索することは現時点では想定していない。リモートとオフラインのバランスを探りつつ、サービス運営に最も最適な形を模索していく」 ということです。 これについては月並な表現かもしれませんが、対面でもしくは物理的に一緒に働くことで生まれる連帯感やコミュニケーション、文化といったものをBASEでは大事にしたいという思いがあるためです。 大前提としてBASEではよいプロダクトを送り出し、ユーザーの皆様をサポートするという点を第一に考えています。 そしてよりよいプロダクトを作る、品質を高めるという点において、中で働く人間の深いコミュニケーションや文化の醸成といったものが必要不可欠であると考えています。 そしてそういった関係を構築することは、WFHだけでは現時点では難しそうだという判断をしているためです。 コロナ禍におけるBASEの流れ 具体的にBASEにおいて、WFHがどのように運用されてきたか、またその中で自分が具体的にどのように振る舞ってきたかを紹介します。 WFH移行初期(2〜5月ころ) 全社的な動き BASEではコロナウイルスの感染拡大に伴い比較的早い段階でWFH制度が整備され、2月中旬〜下旬にはほぼ全社のメンバーがWFHを開始しました。 いままでは基本的にWFHのための制度はなく出社が前提であったBASEでこれだけ早期に移行できたのは情シスのメンバーの努力の賜物でした。 それらの仕組みの整備が進められていくとともに、社内的にコロナウイルスと働き方のあり方をどのように定義するのかという内部資料が用意され、 都の発表する警戒レベルなどと照らし合わせながら定期的に運用がアップデートされています。 社内で運用されているガイドライン 自分の動き この時期は自分はまだただのエンジニア職であったので基本的に家で作業をしていました。 3月頭と4月頭にチームに新メンバーが入社してきてくれたので、その顔合わせのために最初だけ2〜3日会社に行った以外は出社はありませんでした。 もともと家の作業環境を無意味に整えるのが大好きな性分だったので、WFH開始時には会社の情報共有ツールに謎のエントリを投下してはしゃいだりしていましたし 作業的には特に大きな問題はなく移行できたと思っています。 当時のハイテンションで書いた謎のエントリ群 ただ、フロントエンドエンジニアという仕事柄、作ったものを定期的にデザイナーやディレクターに直接見せて相談しつつ微調整をする、 といったことのコミュニケーションコストが高くなってしまったため仕事の効率という意味ではなんとも言えない部分があったことは否定できません。 WFH移行中期(6~8月頃) 全社的な動き 世の中的には少しずつ以前のような活動を取り戻す取り組みを始めた企業もあらわれはじめた時期だと思いますが、 BASEではWFHで一切出社しないメンバーが大半でした。 一部の、オフィスでないと仕事が難しいメンバーだけは出社していましたが、エンジニアは数名の方を除いて家で仕事をしていました。 オフィスの利用自体を禁止しているわけではなく、「オフィスを使うほうが都合が良ければ使って良い」というような柔軟な運用であったため、 育児などの家庭の都合で家だと作業が難しいようなエンジニアが出社をしていました。 業務都合で出社を要請されたエンジニアは基本的にはいなかった記憶があります。 自分の動き 私自身にも8月に自分が携わった比較的大きい機能のリリースがあったり、 7月にエンジニアからエンジニアリングマネージャーへの配置換えなどのイベントがありましたが、 リリースもマネージャー研修もzoomを利用してリモートで行われたため特に出社することはありませんでした。 現在(2020年9月〜10月) 全社的な動き 都の警戒レベルも少し下がってきたために、オフィスを深いコミュニケーションのできる場所・会社の文化を生む土壌として捉え、 適切なタイミングで活用していこうという機運が高まっています。 例として、一部のチームでは高度な業務知識が必要な場面でドメインモデリングのために週に一度出社して仕様を煮詰めていたり、 マネージャー陣が今後の作業のアサインや組織の構成を考えるために毎週出社してミーティングをする、といった具合です。 個人の事情は考慮されていますので、どうしても出社できないという方に強制したりはしていませんし、全社的に出社日があったりもしません。 ただチーム単位で出社日を決めるといった試みが見られるようになってきました。 また業務外のところでも、最近では新メンバーの歓迎会なども行われていました。 (BASEでは広いフリースペースがあり、そこに感染対策の衝立などが用意してあるためそれを使ってパーソナルスペースを確保した上で開催しています) 歓迎会の様子 家ではなんだか仕事がはかどらないというメンバーの自発的な出社も少しづつ増えてきています。 現在BASEでは社員が約140名ほど在籍していますが、20名前後がオフィスに出社しているようです。 自分の動き 私もマネージャー会議のために毎週金曜日は出社しています。 また、現在メンバーとの1on1を毎週30分行っていますが、BASEでは3ヶ月に一回OKRで個人の目標設定をする機会があるので、そのタイミングでの1on1ではメンバーに出社してもらって対面でちゃんと話すということを行いました。 リモートで満足なコミュニケーションを取り切れていなかったという批判はあるかとは思いますが、自分が実際にオフィスであって会話することによって得られる情報量や充実感というのは、オンラインミーティングだけでは補いきれないものであるなと感じました。 折角金曜に出社するのであればということでMtgなどの用事をなるべく金曜日に固めたりするなどの工夫をしています。 突発的な雑談の時間なども多くとっており、金曜は定常業務よりもコミュニケーションを優先する日、と自分の中ではちょっとした割り切りをしていたりします。 これから コロナウイルスの感染拡大は着地点が見えず、冬が近づきまた感染拡大が発生するのではないかという想定もあります。 そんな中でwithコロナという言葉が表しているように、リスクとメリットの落とし所を探る動きが続いていくものと思われます。 WFHへの考え方もそのうちの1つであると思います。 あくまで現時点での予測ですが、BASEでは急に「来月から全員出社必須」というようなことにはならなさそうではあります。 ただし流れとしては なるべく出社の機会を大切にしていく 、という路線であることだけはまず確実です。 出社することによる不便を極力なくすための整備も進められています。 例えばリモートでのミーティングが増えたことで会議室が枯渇気味になってしまい、急に出社するメンバーが増えると耐えられなくなってしまいそうなので zoomでの会議をするための個室スペースの導入が検討されていたりします。 最後に 長くなりましたが、コロナウイルスの流行は社会構造を良くも悪くも大きく変化させました。 また世の中の働き方の在り方も大きく再考されるきっかけにもなりました。 会社がオフィスを捨てフルリモートに移行する話や、個人的に東京を離れ近郊に移り住みリモートワークをするといったような話も珍しくはなくなってきました。 ワークライフバランスという意味では、自分自身の生活もリモートによってよくなった点がいくつもあります(通勤がなくなった時間で自炊を始めたり、ジムに行ってみたりと精神的な余裕が増えた) そうはいいながらも、BASEでの働き方は社会情勢を見極めつつ柔軟に運用されていくことが当面続きそうになっています。 それはオフィスを完全に離れるということはせず、同じ空間で働くことの価値を大切にしながらリスクとのバランスをとることで実現されていく、ということです ある意味でリモートでのコミュニケーションだけで充分だという人にはBASEという会社は合わないかもしれませんし、 リモート疲れしてきてそろそろ出社してちゃんとコミュニケーションとりながら仕事をしたいという方には合っているかもしれません。 もしBASEでのそんな働き方に興味がありましたらカジュアル面談という形で社内のお話をさせていただく機会を用意しているので、ぜひ応募いただければと思います。 採用情報 | BASE, Inc. 採用情報-フロントエンドエンジニア 採用情報-Webアプリケーションエンジニア
こんにちは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が大好きになりました。 まだまだ先輩デザイナーの背中は見えないし、甘えてばかりの日々ですが、一刻も早く恩返しできるように日々努力していきたいです。これからも頑張ります!