TECH PLAY

BASE株式会社

BASE株式会社 の技術ブログ

574

はじめまして、BASEでSREに所属している浜谷です。現在は主にAWSを使用したインフラ構築と運用を担当しています。 そこで今回は前回好評だったBASEビール部部長が語ってくれた「 Yahoo!の近傍探索ツールNGTを使って類似商品APIをつくる 」のインフラ環境の構築についてお話をしようかと思います。 1. 背景 BASEでは機械学習の環境以前に今本番で何が動作しているのか、又その全体を把握するにはAWSのコンソールにログインして調査する方法しかありませんでした。 AWSの運用をしているとよくある事かと思います。 そんな中BASEではシステム全体構成図の見直しやサーバの一覧を自動化したりとインフラの見える化を進めています。 そこで次はインフラの構成管理を行っていこうといった流れがあり、まずはData Strategyチームの環境をTerraformで構成管理しようと相成りました。 2. 機械学習の環境 環境をサクッと説明するとS3に画像がアップロードされたら、SNSにイベントを送付します。 SNSからSQSやLambdaに振り分けて情報を蓄積し、蓄積したデータを元にECSのDockerで機械学習した結果をAPIで返すといったインフラ環境となります。 類似商品APIって何と詳細が気になった人は BASEビール部部長の記事 を読んでみてください。 3. そもそも構成管理は必要? 運用をしていく為に構成を把握する事は必要不可欠です。 ただ私自身構成管理ツールの必要性をあまり感じていませんでした。 というのはSIerの出身なので設計書、手順書、運用のドキュメントは納品物なので時間を掛けて作るのは当たり前でした。 SIerのエンジニアはoffice製品でのドキュメント作りや成果物の承認に時間を割くことが多く、その上構成管理のツールまで必要なのって感じている人は少なくないと思います。 またドキュメントでの構成管理は構築を始めるまでに時間が掛かるのは当然といった考え方が前提としてあります。 しかし、BASEの行動指針の一つに「MOVE FAST」があります。 このMOVE FASTを実現するためには、時間が掛かるのは当然といった考え方を捨てる必要があります。 そこで構成管理ツールは必要不可欠なのです! 構成管理ツールを使用するとインフラをコードで管理できるので設計から構築までを一気通貫に実現できます。 4. なぜTerraformなの? 現在BASEではAWSをメインに利用しているので、AWS CloudFormationの方が良いかもしれません。 機械学習の環境においてGCPのBigQueryを使用する場面が今後発生してくるかと考えています。 その際にマルチプラットフォームに対応した構成管理ツールを選ぶ必要がありました。 5. コードでのインフラ管理 AWSを管理コンソールで構築しているとGUIベースで確認するか、ドキュメントベースで環境を把握する必要があります。 しかし、Terraform等の構成管理ソフトを使用するとコードベースで管理できます。 VPCをTerraformでコード定義すると以下のようになります。 resource "aws_vpc" "ds-image-processing-vpc" { cidr_block = "10.1.0.0/16" tags { Name = "ds-image-processing-vpc" } # We explicitly prevent destruction using terraform. Remove this only if you really know what you're doing. lifecycle { prevent_destroy = true } } コードで管理することでGitHubを利用した管理が出来ます。 GitHubはアプリエンジニアだと日常的に使用しますが、インフラエンジニアにとっては少し敷居が高く感じます。 私もBASEに入社するまでは殆どGitHubは使用していませんでしたが、今では普通に使用してレビューなどの履歴も残すことが出来てとても便利に感じています。 今まではインフラ構築のレビューをシステム構成図や設計書ベースでのレビューをしていたので、別途レビュー票を起こしたり等の手間が大幅に減りました。 またインフラ構成の変更をAWSのコンソールでを漏れなくチェックするのは非常に困難です。 しかし、GitHubを使用することで差分の確認をすることで、何を変更したのかも一目瞭然です。 6. 実際にTerraformを使ってみよう! それではいよいよ実際にTerraformを使用してみましょう。 今回はハンズオンとして、RDSのAuroraとEC2のLinuxインスタンスを実際に作ってみます。 ①まずはTerraformを実行出来る環境の準備をします。  Terraformのダウンロード(URL: https://www.terraform.io/downloads.html )   ※バージョンは適時ダウンロードしたファイルに読み替えてください。  ダウンロードしたファイルを展開して、環境変数にパスを通す。 $ mv terraform_0. 11 .4_linux_amd64.zip /usr/ local /bin $ unzip terraform_0. 11 .4_linux_amd64.zip $ ls -l terraform  ※実行権限があることを確認 $ env | grep PATH  ※PATHに/usr/ local /binが通っていることを確認 $ mkdir -p < 作業ディレクトリ > $ cd < 作業ディレクトリ > ②GitHubにサンプルを用意しましたので、ダウンロードします。  GitHubのリポジトリ: https://github.com/baseinc/Hands-on-Terraform  Terraformのドキュメント: https://www.terraform.io/docs/providers/aws/ $ git clone git@github.com:baseinc/Hands-on-Terraform.git $ terraform init $ vi terraform.tfvars  必要に応じて以下の内容を書き換えてください。 aws_access_key = "<AWSのアクセスキー>" aws_secret_key = "<AWSのシークレットキー>" aws_region = "ap-northeast-1" main_aurora_root_user = "<auroraへのアクセスユーザ>" main_aurora_root_password = "<auroraへのアクセスパスワード>" external_ip = "<EC2にアクセス出来るIP>" host_ssh_key = "<EC2にアクセスする際のキーペア名>" ③準備ができたので、Terraformを実行するだけです。 実行前の動作確認(DryRun): $ terraform plan Plan: 20 to add, 0 to change, 0 to destroy. ------------------------------------------------------------------------ Note: You didn't specify an "-out" parameter to save this plan, so Terraform can't guarantee that exactly these actions will be performed if "terraform apply" is subsequently run.  上記の様に「20 to add」と表示されればOKです。  20個のリソースがコマンド一つで作成されます。 実行: $ terraform apply Plan: 20 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes  「yes」と回答します。 aws_iam_role.db-main-aurora-monitoring: Creating...  リソースの作成が開始します。 ④リソース作成完了までは少し待ちます。 aws_rds_cluster_instance.db-main-aurora-instance.0: Still creating... (12m50s elapsed) aws_rds_cluster_instance.db-main-aurora-instance[0]: Creation complete after 12m57s (ID: db-main-aurora-instance-0) Apply complete! Resources: 20 added, 0 changed, 0 destroyed.  これでAWS上にAuroraとLinuxのインスタンスが立ち上がりました。  どうですか、サクッと作れてしまいましたね。  リソースが出来たかどうか、実際にAWSコンソールにログインして確認してみましょう! 6. リソースを作った後は。。。 こんなに簡単に作れてしまうと、次から次へとリソースを作ってしまいますね。 そして放置なんてことになったら、AWSに多大な貢献をしてしまうことになりかねません。 ですので不要になったらきちんとお片付けを実施します。 削除 : $ terraform destroy コマンドを実行して削除完了と思ったら。。。。 Error: Error running plan: 1 error(s) occurred: aws_route.db-vpc-route-external: aws_route.db-vpc-route-external: the plan would destroy this resource, but it currently has lifecycle.prevent_destroy set to true. To avoid this error and continue with the plan, either disable lifecycle.prevent_destroy or adjust the scope of the plan using the -target flag. あれ?なんでだろう。。。エラーが出てしまいます。 理由は削除保護が有効になっていたからです。 VPCやDB等は間違えて消してしまうと想定外の影響が出てしまう可能性がある為、簡単に消せない様に削除保護 prevent_destroy = true をリソースに定義していました。 ただ、今回は消してしまいたいのでリソース上の定義を全て prevent_destroy = false に変更して再度実行してみましょう。 Do you really want to destroy all resources? Terraform will destroy all your managed infrastructure, as shown above. There is no undo. Only 'yes' will be accepted to confirm. Enter a value: yes 「全てのリソースを削除しますが、良いですか」と聞かれます。 「yes」と回答します。 … aws_subnet.db-vpc-subnet-d1: Destroying... (ID: subnet-0bae4cb4032d56f93) aws_subnet.db-vpc-subnet-a1: Destroying... (ID: subnet-0a9d2118812674f12) aws_subnet.db-vpc-subnet-c1: Destruction complete after 0s aws_subnet.db-vpc-subnet-d1: Destruction complete after 1s aws_subnet.db-vpc-subnet-a1: Destruction complete after 1s aws_security_group.db-main-aurora-security-group: Destruction complete after 2s aws_vpc.db-vpc: Destroying... (ID: vpc-0790adf505d9e6ac3) aws_vpc.db-vpc: Destruction complete after 0s Destroy complete! Resources: 20 destroyed. 今度は消えましたね。 また必要になったら、 $ terraform apply で作り直しましょう。 まとめ Terraformを使用することで新規作成から削除までコマンドで簡単に出来るようになりました。 今後、既存の本番環境のTerraform化や新規にプロダクトを開発している子会社のBASE BANKもTerraformを利用したりしているので、また機会があれば続きを書ければなぁと思います。
アバター
こんにちは!BASE Product Division サーバーサイドエンジニアの東口( @Khigashiguchi )です。主にEコマースプラットフォーム「BASE」の決済領域の開発や、 BASE BANK というBASEの子会社にて 金融事業の立ち上げ を行っています。 さて、2018/8/7(火)に、ランサーズ、ReBuild、BASEの3社でエンジニア向けの勉強会「 レガシーコード改革!UT/CIでWebサービスの技術的負債を解消する取り組み 」を開催しました。 www.wantedly.com そこで「 PHPバージョンアップと決済テストを支えたユニットテスト 」というタイトルで発表させていただきました。 「レガシーコードを取り扱うためにどのようなユニットテストを書いていったか」について実体験ベースでの取り組みと得られた課題について話しています。 参加者の方からも、「 実体験ベースでの知見が参考になった 」といったフィードバックもいただけました。 登壇資料 この発表は、 PHPカンファレンス関西2018 にてLT発表させていただいた、 テストを書いたことがないエンジニアがテストを書けるようになるまでやったこと の詳細版として、以下のポイントについて言語化させていただきました。 テストがないコードに対して、どういう考え方でテストを書いていったか チームとしてどうやってテストを広めようとしたか 結果としてどのような課題があったか 実際にコードレベルでの説明にまで落とし込んでいるので、同じ課題を持つ方にとって一つの有益な知見として参考になれば幸いです。 また、今回はイベントタイトルが「 レガシーコード改革!UT/CIでWebサービスの技術的負債を解消する取り組み 」というものなので、「 レガシーコード 」をテーマとした発表になりました。 そのため、「レガシーコード」というテーマで発表するに当たり、主に下記の2点の書籍を改めて読み直して発表のコアとなる部分の言葉をお借りさせていただいています。 www.shoeisha.co.jp www.shoeisha.co.jp とても参考になるので、今回の資料を入り口にそちらもご参考にしていただければと思います。 まとめ ランサーズ、ReBuild、BASEの3社でエンジニア向けの勉強会「 レガシーコード改革!UT/CIでWebサービスの技術的負債を解消する取り組み 」を開催しました。 レガシーコードを扱うためのユニットテストの考え方と書き方について話しました。
アバター
はじめまして、BASEビール部部長の氏原です。BASEのData Strategy Groupで機械学習エンジニアをしています。 今回初登場ということで、暑いときにいいサワーエールのお話でも......といきたいところですが、ここは開発ブログということなので仕方ありません。開発のお話をしましょう。 現在私は商品の画像に基づいて、その商品に似た商品を類似商品として提示するAPIの開発を行なっています。今回はこのAPIをYahoo!さんの NGT(Neighborhood Graph and Tree for Indexing) を使って作成したことについて書いてみようと思います。 背景 BASE株式会社はネットショップ作成サービス「BASE」を運営しています。ここで作成されたショップはそれぞれ別のWEBサイトとして公開されていますが、ショッピングアプリ「BASE」では作成されたショップを横断して商品を検索し購入することができます。しかしショップの数は公称で50万店舗、非常に多くの商品がありますのでユーザーさんが興味を持つであろう商品をいかにして探しやすくするかはサービスにとって喫緊の課題と言えます。その取り組みの一環として、私は商品詳細ページにある関連商品の改善を目的に類似商品APIの作成を行っています。 全体の概観 類似商品APIは以下の3つの構成要素で成り立っています。 画像の特徴量抽出 新しい商品画像がサービスに登録された際に特徴量を計算して保存する 特徴量のindexing 関連商品として出す商品の画像を選別して近傍探索用のindexを作成する API 検索元商品の画像から近傍の画像を探索しその画像に対応する商品を類似商品として返す ではそれぞれについて解説していきましょう。 画像の特徴量抽出 BASEには毎日結構な量の商品が新しく登録されていきます。既存の商品の画像を差し替えたりすることもあります。それらの新しい画像の特徴量は随時計算しておかないといけません。 特徴量抽出の全体構成 BASEでは商品画像をS3に保存しています。S3ではファイルが登録されると、そのことをイベントとして通知できます。特徴量抽出ではそれを利用して以下のようにシステムを組んでいます。 S3, SNS, SQS S3で画像が登録されると、そのイベントをまずSNSに投げます。そしてSNSはそのイベントをそのままSQSに投げます。 一旦SNSを通しているのは、画像登録を契機に何かしらの処理を行いたいという要望は今後他にも出てくることを想定しているためです。SNSであればsubscriberを増やせばイベントをbroadcastできます。 こうしてS3に登録された画像はイベントとしてSQSに溜まっていきます。 ECS SQSに溜まったイベントを取りに行くのがECS配下で稼働しているServiceです。ここではSQSからイベントをpollingして、取得したイベントから画像を取得して一枚づつ特徴量を計算してDBに保存していきます。ECSはAuto Scalingと組み合わせればSQSが溜まってきたときにServiceを増やすのが簡単です。 画像の特徴量 みなさん、画像の特徴量といえば何を思いつきますか?SIFTとかHOGでしょうか。最近ですとDeepLearningでしょうか。今回、画像の特徴量の抽出にはMobileNetを利用しました。 いちからMoblieNetを作るのではなく学習済みモデルをそのまま利用しました。 Kerasのやつ ですね。ホント楽になりましたね。 from keras.applications.mobilenet import MobileNet model = MobileNet(weights= 'imagenet' , include_top= False , input_shape=( 224 , 224 , 3 ), pooling= "max" ) include_topはFalseにしてクラス分類のネットワークは外して特徴量を抽出する部分だけ使います。画像はもう単純に224×224にリサイズして使います。これで224×224のRGB画像からfloat32の1024次元のベクトルが得られます。 from keras.applications.mobilenet import preprocess_input from keras.preprocessing import image import boto3 import keras.applications.mobilenet import numpy as np import io # S3から画像を取ってくる s3 = boto3.resource( 's3' ) img_object = s3.Object(bucket, object_key) response = img_object.get() # 画像を読み込む img_data = io.BytesIO(response[ "Body" ].read()) img = image.load_img(img_data, target_size=( 224 , 224 )) # numpyのarrayにしてMobileNetの前処理をする x = image.img_to_array(img) xs = preprocess_input(np.array([x]) # 特徴量を計算する vec = model.predict(xs).flatten() 特徴量を保存するDB 上で得られた特徴量はDBに保存しておきます。 今回特徴量を保存するのにはAuroraを利用しました。1024次元のfloat32のベクトルを保存するのに容量あまり気にしないでもいい場所が欲しかったためです。でもRDSとか単にベクトル保存する場所としては機能過多ではあります。必要な機能を考えると単なるKey-Value Storeでいいんですが、ここは今後も要検討です。 特徴量のindexing 画像登録に連動してDBに特徴量を保存できるようになりましたが、サービスで使うにはある画像の特徴量vectorの近傍にあるvectorがどれなのかを知ることができるようにしなくてはいけません。これを実現するために今回は NGT を利用しました。 NGTとは Yahoo!さんの説明をそのまま引用させていただきます。 NGTは任意の密ベクトルに対して事前に登録した(同次元の)ベクトルから最も距離が近いベクトルの上位数件(k件)を高速に近似k最近傍探索(k-Nearest Neighbor Search)するためのソフトウエアです。 高次元ベクトルデータ検索技術「NGT」の性能と使い方の紹介 超高速に近傍のベクトルを探せるソフトです。本当に超高速です。350万件の1024次元のベクトルを登録してみたところ、メモリを15G程度食いますが近傍1000件取ってくるのに数十msくらいしかかかりません。これならキャッシュを併用すれば十分使えると判断しました。 python wrapperもあるので使うのも簡単です。 index作成の全体構成 ECS Taskを利用したバッチ処理でNGTのindexを作成しています。 ECS indexの作成は日次バッチで行うのでCloudWatch Eventをdailyで投げるようにして、ECSがそれを受け取ってTaskを実行するようにしました。 TaskはAuroraからindexingする特徴量を取得してNGTに登録します。このとき全部の特徴量を使うのではなく、古い商品は登録しないなどある程度の取捨選択をしています。 NGTはpython wrapperを使ってこんな感じです。(適当に簡略化してます) from ngt import base as ngt ngt_index = ngt.Index.create(b "any/where/you/want/to/save/index" , 1024 ) # 結果は大きいのでサーバーサイドCursorつかう conn = MySQLdb.connect(..., cursorclass=MySQLdb.cursors.SSCursor) cursor = conn.cursor() cursor.execute(......) # 画像の特徴量とかとってくる # 大きくて全部持ってこれないから一個づつ処理 for row in cursor: image_id, vec = row oid = ngt_index.insert_object(vec) # NGT内でのobject idと画像のIDの紐付けは自分で覚えておく必要あり ... # indexの作成 ngt_index.build_index(num_threads= 8 ) S3 作成されたNGTのindexはS3に保存しています。indexは毎日作成され、ある程度の期間保存して古いものは捨ててます。 API NGTのindexが日々作成されるようになりましたので、今度はそれを利用する部分を用意しましょう。 API提供部分の全体構成 構成としてはAPI Gatewayを入り口としたECSの二段構えになっています。 これは類似商品を取得するという機能と類似画像を取得するという機能を分離させておくことで、類似画像APIを利用した他の機能の開発を簡単にするためです。例えば、現在BASEの商品の画像検索APIも開発中ですが、これはこの仕組みにそのまま乗っかっています。 類似商品API ここは以下のような役割を受け持ちます。 API Gatewayから商品IDを受け取る 商品IDを対応する画像IDに変換する 画像IDを類似画像APIに投げ、類似画像のIDを受け取る 類似画像のIDを対応する商品IDに変換する 類似商品のIDをAPI Gatewayに返す やってることはシンプルです。 構成のところには出ていませんが、毎度類似画像APIを呼ばなくてもいいようにElastiCacheを設置して、類似画像APIを呼ぶ前にそっちを確認しています。 類似画像API ここはNGTの薄いwrapperになってます。やっているのは画像IDや画像の特徴量そのものを受け取り、近傍の画像のIDを返すだけです。 ここはindex作成が終わったときに新しいindexを読むように再起動されます。この再起動はECSの仕組みを使って複数動いているECS Serviceを少しづつ再起動させていくことでサービスとしては無停止で行われるようになっています。 実際にどう変わるか では、構築したAPIで類似商品がどの程度改善したかみてみましょう。 この洋服の関連商品は以前のロジックだと以下のようになってました。 うん、服ですらないですね。 正直どうしてこれらが関連商品に上がってきたのか謎です。名前だろうか。 で、それが今回のAPIで以下のように改善しました。 おお!服だ! ......まあそれだけで感動できるほど前のが悪すぎたという話もあります。 雰囲気もなんとなく似てますかね。ファッション系は概ね良い感じに類似商品を出せるようになりました。 まとめ 私の所属しているData Strategyチームは最近できたばかりで、まっさらなAWS環境を渡してもらってインフラ含めて一から類似商品APIを構築するというなかなか楽しい経験をさせてもらいました。まだまだ精度を上げたいところではありますが、そこそこ良いものができたのではないかと思っています。 実際関連商品のタップされる率は今までの2倍ほどに伸びており一安心というところです。 今回構築した類似商品APIでは今のところ画像しか見ていません。そのため少々コンテキストから外れたものが出てくることもあります。そこで現在商品のタイトルや説明も考慮するようにAPIをアップデートしようとしているところです。もっと精度を上げて、私がいいビールを探せるように......いえ、ユーザーさんがいい商品をみつけられるようにこれからも頑張ります。 開発した成果は、ショッピングアプリ「BASE」で見ることが出来ます。個別の商品を見るビューをスクロールして「関連する商品」をぜひご覧下さい。 iOS https://itunes.apple.com/jp/app/base-beisu-guo-nei-zui-da/id661263905?mt=8 Android https://play.google.com/store/apps/details?id=in.thebase.base P.S. 長くなるんで省きましたが、実は今回作ったAPIのAWSの構成管理はTerraformで書いて1発で構築できるようにしています。その話はまたの機会にしたいと思います。
アバター
こんにちは!BASE Product Division サーバーサイドエンジニアの東口( @Khigashiguchi )です。主にEコマースプラットフォーム「BASE」の決済領域の開発をしています。 さて、この度、BASE株式会社は7月14日(土)に開催された「 PHPカンファレンス関西2018 」にシルバースポンサーとして協賛いたしました。 私は当日スポンサー担当として参加し、前日に開催された「 PHPカンファレンス関西2018非公式前夜祭 」と合わせて2夜連続でLT発表してきました。 また、同じくBASE Product Divisionの田中( @tenkoma )も本編の懇親会にてLT発表いたしました。 PHPカンファレンス関西2018 2018.kphpug.jp PHPカンファレンス関西は、大阪・梅田のグランフロント大阪で開催され、全国のPHPerが集結したイベントになりました。 メイン会場の様子 BASEは、シルバースポンサーとして協賛いたしましたので、オープニングにてBASEを紹介していただきました。 発表内容 本編 本編では、「 テストを書いたことがなかったBASE入社前から現在に至るまでテストに対してどういう取り組みを行ってきたか 」をぎゅっと5分に詰めて話しました。 LT発表中の様子 内容を詰めたので、ある意味「LTっぽく」スピード・テンポ感重視のプレゼンではありましたが、要点と随所のポイントは無事伝わったようで「一部実践してみよう」という反応をいただけたので良かったです。 懇親会 こちらは、先ほどご紹介した田中( @tenkoma )の発表です。 CakeFest2019 というCakePHPにフォーカスしたカンファレンスの候補地に日本が入っており、 「みんなで日本開催に投票しよう!」 という話をしました。 懇親会LTの様子 7月30日まで投票中 なので私もこのブログが書き終わったら投票します! 非公式前夜祭 非公式前夜祭では、 PhpSpreadsheet というライブラリを扱う上でトラブルシューティングについて話しました。  非公式前夜祭での様子 「PHPでExcelを扱ったことがある方」が参加者の方に多かったので、 「あるある」 という共感をいただきながら、ラフに話させていただきました。 まとめ PHPカンファレンス関西2018にスポンサーし、せっかくの大阪遠征なので張り切って2夜連続LTにチャレンジしてみましたが、充実感があって楽しかったのです。 ただ、個人的な反省としては両日資料完成が発表直前になるくらい追い込まれたので資料準備はより計画的にしないとです。 もし来年参加される方はチャレンジしてみてはいかがでしょうか。 続きは8/7 (火)の勉強会で 今回、PHPカンファレンス本編で5分に詰め込んだテスト関連の話を15分に伸ばした詳細版を、8月7日(火)に開催するエンジニア向け勉強会にてお話しします。ランサーズさん、ReBuildさんにもお越しいただき、CIや技術的負債を解消する取り組みについてお話ししていただきます。 ご興味のある方はぜひ下記のページよりお申込みください。 base.connpass.com
アバター
こんにちは、BASEのDesign Groupに所属している 北村 です。 現在は主にプラットフォームとアプリのデザインを担当しています。 BASEのデザインチームはここ数年で一気に人が増え、社内でも大所帯の部署へと成長しました。今回は、BASEのデザイナーが日々の開発でどんなことを行い、どんなことを考えているのかについてご紹介したいと思います。 1. BASEのデザイナーの役割 プロジェクトの共通認識を作る仕事 BASEでは仕様検討の段階からデザイナーが入り、プロジェクトの担当者と一緒に開発要件を詰めていきます。ときには箇条書きの要件書からワイヤーを起こし、UIをアウトプットしていきます。画面デザインが先にあると、メンバー同士のコミュニケーションがスムーズになり、かつ他部署との認識合わせも円滑になるため、BASEの開発フローでは まずデザインありき という文化が浸透しています。また単純に、先にデザインがあると実際の画面をどう作っていけば良いのかチームの皆で把握しやすい、という利点があります。 プロジェクト内で共通認識となるアウトプットを担うのが、BASEのデザイナーの仕事のひとつです。 BASEにおけるデザイナーの責任 BASEでは基本的に、プロジェクトにアサインされたデザイナー本人がデザインクオリティのチェックを行います。 さらに、担当デザイナーが自分で画面のUIを実装することも多いです。最近はフロントエンドエンジニアも増えたので分業が進んではいますが、例えば細かなインタラクションの実装やUIの改修などはデザイナー自身が積極的に行っています。 画面のUIを設計するだけでなく、最終的なUXの担保まで担うのが、BASEのデザイナーの責任範囲になります。 2. BASEのデザイン思想と、大切にしていること 「お母さんも使える」という共通言語 BASEには社内全体の共通言語として「 お母さんも使える 」という思想が存在しています。 これは、BASE創業当時から変わらない哲学で、代表取締役CEOである鶴岡の強いポリシーであり、「BASE」の重要なコンセプトです。 というのもこのコンセプトは、「BASE」のサービス立ち上げのストーリーにまつわります。鶴岡の母は、大分の商店街で洋品店を営んでいますが、「ネットで服を売ってみたい」と鶴岡に相談があったので、楽天のような大手のECモールを使ってみるよう勧めましたが、使い方が難しくてできないと母から返ってきます。 その際に鶴岡は、母と同じような悩みを持っている人が世の中にたくさんいるのではないかと感じ、「BASE」の開発を始めた、という背景があります。 お母さんのために、良くも悪くも「機能をつけない」 便利だけれど使い方が難しい機能よりも、いかにクリック数を少なくして、簡単にショップを開設・運営してもらうかが最優先事項になります。 4、5クリックしなければならない機能より、2、3クリックで完了する機能を開発・提供する。たとえば、ユーザが一番使用する管理ページには、あえて機能をつけないなど、設計については、当初から「ユーザの手間を減らすための開発」を意識していました。 現在、BASEチームには13人ほどのエンジニアがいますが、新しい機能ができてもチーム内で「この機能は、お母さんたちには使えないのでは」となったら、たとえ便利そうな機能でもリリースしていません。 出典: お母さん目線で作ってみたら、「BASE」はシンプルなサービスになった BASEではプロダクトの開発中、あらゆる場面・文脈で「 お母さん 」という単語が出てきます。「これって複雑すぎてお母さんは使えないよね」や「この説明、お母さんに伝わるのかな?」など、議論の主語となることがとても多いです。 複雑な仕組みだったとしても、お母さんも使えるくらい簡単なサービスとして提供するのが、プロダクトを作るときに最も大切にしている思想です。 誠実さを大切にしている、BASEのデザイン思想 「お母さんも使える」を実現するために、デザイナーで作成したデザイン思想があります。 誠実であること あらゆるユーザに寄り添える、柔軟な拡張性 価値を最大化させる新しいショップ体験 「お母さんも使える」親しみやすいサービス 簡単じゃないものを簡単に BASEのデザイナーはなによりも「誠実」さに重きをおいています。 例えばユーザが何かものを売りたいと思ったときに、今までだとハードルが高くて気軽にできなかったものを、誰でもできるようにするのがインターネットの力で、BASEはそのインターネットのポジティブな力を信じてサービスを作っています。 一方で、インターネットがインフラとして広まっていく上で負の側面もあり、伝え方次第では誤った情報が多くの人に広まってしまったり、誰かを傷つけてしまうことがあったりします。 そういった意味で、デザインの役割は非常に重要です。多くの人に影響を与えるインターネットというインフラ上でサービスをデザインする以上、誠実さを忘れてはいけない、という思想を大切にしています。 3. デザイン思想を実現するワークフロー では実際に、2 のデザイン思想を実現するために行っているワークフローをご紹介したいと思います。 BASEにおけるデザインのフロー PMやディレクターから機能要件がくる 要件・仕様を元にデザイナーがワイヤー、またはプロトタイプを起こす 起こしたデザインを「 UI/UXミーティング 」でレビューする 実装に入る 週2回おこなわれるUI/UXミーティング BASEでは週に2回、UI/UXミーティングという場が設けられています。 このミーティングでは、各デザイナーそれぞれが担当しているプロジェクトのUIをレビューしてもらいます。 (プロジェクトの粒度によってまちまちですが)鶴岡、PM、ディレクター、プラットフォームデザイナー、アプリデザイナー、フロントエンドエンジニア、CSが一堂に会し、デザイナーの作成したUIを見ながらみんなで議論し合います。 他のデザイナー目線でのUIに対するダメ出しも含め、ビジネス視点からの要望や、実装に対するツッコミ、全体のUXへの指摘など、多角的な意見が入ります。もちろん「そもそもその機能って必要なの?」という意見が出ることも多々あります。そこをまとめて取捨選択するのもデザイナーの役目です。 たとえ途中で仕様が変わろうとも プロジェクトのメンバーだけでは把握できなかったより大きなユーザ体験が、UI/UXミーティングでの議論で見えてくる部分もあります。先日公開されたエンジニアの 日比野 、 柳川 の記事でも書かれていましたが、BASEではプロジェクトを進行してゆくなかで「ちゃぶ台返し」が起こるポイントがしばしば発生します。 デザイン目線でいうと、例えば 「簡単じゃないものを簡単に」が満たされてない 「親しみやすさ」が満たされてない 「価値を最大化させるショップ体験」が満たされていない 「お母さんも使える」が満たされてない この部分の踏み込みが甘く、議論が充分でないままプロジェクトが進んでしまった時に、UI/UXミーティングで指摘を受けることも多いです。 これはBASE全体にデザイン思想が浸透しているからこそ起こる議論で、たとえもう一度仕様を練り直すことになったとしても、より良いものを作る努力は惜しまない、納得するまで議論する、というBASEの「SPEAK OPENLY」のあらわれだと思っています。 まとめ BASEのデザイナーは裁量が多く、担う範囲も広いですが、開発の上位レイヤーから関われる環境というのはやはりやり甲斐があります。 誠実にサービスを作る、というBASEのデザイナーが大切にしている思想に共感してくださった方、一緒サービスを作りましょう! デザイナーを随時募集しています! jobs.binc.jp
アバター
こんにちは、Back-end Engineer の田中 @tenkoma です。ショッピングアプリ 「BASE」向けAPIの開発を担当しています。 去る6月16日に福岡で開催された「 PHPカンファレンス福岡2018 」に参加してきました。当日は一般参加でしたが、前日に開催された 非公式前夜祭 リジェクトコン で発表してきたのでブログでもご紹介します。 BASEのPHPアプリケーションは2018年5月にようやくPHP7化が完了しました。 アップデートプロジェクトの中でユニットテストしやすくするためにテストスイートをカスタマイズしたので、発表で3つほどをTipsとして紹介しました。 紹介した3つのTipsについてこの記事でも説明します。 Tips 1. assertSame() で配列のdiffを出力できるようにする PHPUnit 7 で assertSame() は 配列のdiff を出力できる ようになりました。CakePHP2アプリ(データ形式として配列を多用する)で使えるとありがたいのですが PHPUnit 7 の利用は難しそうです。そこで、配列のdiffを出力できるように移植してみました。以下のように出力されます。 SampleTest.php <?php App :: uses ( ' ExtendTestCase ', ' ExtendTestSuite.TestSuite ' ) ; class SampleTest extends ExtendTestCase { public function testAssertArray () { $ actual = [ ' User ' => [ ' id ' => 1 , ' name ' => ' Taro ' ]] ; $ expected = [ ' User ' => [ ' id ' => ' 1 ', ' name ' => ' Taro ' ]] ; $ this -> assertSame ( $ expected , $ actual ) ; } } 出力 There was 1 failure: 1) SampleTest::testAssertArray Failed asserting that Array &0 ( 'User' => Array &1 ( 'id' => 1 'name' => 'Taro' ) ) is identical to Array &0 ( 'User' => Array &1 ( 'id' => '1' 'name' => 'Taro' ) ). --- Expected +++ Actual @@ @@ Array &0 ( 'User' => Array &1 ( - 'id' => '1' + 'id' => 1 'name' => 'Taro' ) ) テストが失敗したときかなり原因がわかりやすくなるので、すぐにPHPUnit 7にアップグレードできない場合は以下のコードを実装すると便利です。 assertSame ExtendTestSuiteConstraintIsIdentical.php Tips 2. テストスイート向けにユニットテストを書く setUp() , tearDown() などに記述したコードをどうテストするか、という話で test for test cycle(setUp/tearDown) #1 のようなテストコードを書きました。 スライドの最後で、CIで複数のPHPバージョンでテストした話をしましたが、そのためのCircleCIの設定は .circleci/config.yml のようになっています。 Tips 3. runkit, php-timecopのコードをIDEで補完するためのスタブ PhpStorm組み込みのスタブファイル に無い runkit , php-timecop のようなPHP拡張のコードを補完できるようにするものです。以下のリポジトリを git clone してIDEの include_path に追加してお使いください。 tenkoma/php-stubs-mighty-magic カンファレンスレポート 以下はカンファレンス当日・非公式前夜祭後夜祭のレポートです。来年も開催されるらしいので、参加したい方の参考になれば幸いです。 前日に福岡入り (6月15日・金) 非公式 PHPカンファレンス福岡2018前夜祭リジェクトコン PHPカンファレンス福岡を楽しむには前日入りが必須。13:30頃に福岡空港に到着しました。 このときまだリジェクトコンの資料が仕上がっていなかったので博多駅近くにとったホテルで資料の手直しをしました。 リジェクトコンの会場であるLINE Fukuoka株式会社と同じビルの1Fで知り合いの方と一緒に食事を取り、19:00 に会場到着しました。 以下、発表前の現場の様子です。 会社に報告しないといけないので写真撮ってる pic.twitter.com/amuPYMhBaX — Koji Tanaka (@tenkoma) 2018年6月15日 発表順は1番目。印象に残るよう GitHub Username Shirt を着て発表しました。 #phpconfuk_rej @tenkoma さんー! pic.twitter.com/l0xKtavLKp — 青ごへいもち (@blue_goheimochi) 2018年6月15日 カンファレンス本編より多い同時3セッション。だれも聞きに来なかったらどうしようと思いましたが、多くの人に聞いていただけたようです。 PHPカンファレンス福岡2018 当日 (6月16日・土) PHPカンファレンス福岡2018 PHPカンファレンス福岡は去年初参加でした。そのときは前日午前2:00くらいまで懇親会に参加した結果当日1時間以上遅刻してしまいましたが、今年は午前10時に間に合いました。 「PHPカンファレンス福岡2018」は同時2セッションです。2つの会場は両方とも席に余裕がある感じで出入りがしやすかったです。 参加したセッションについて紹介します。 MySQLで画像 を扱うメリット・デメリットと障害・解決事例 資料: MySQLで画像 を扱うメリット・デメリットと障害・解決事例 - Speaker Deck 以前実装してみたことがあり、メリット・デメリットについて実感したので、さらに学ぼうとおもい参加。 発想としては思いつきがちですが、適用するメリットの大きいケースは限られそうですね。 ログの設計してますか?PSR3とログ設計の話 資料: ログの設計してますか?PSR3とログ設計の話 - Speaker Deck 何をログに残せば良いかで迷うことが未だにあり、周辺知識を強化したくて参加。ログのリスクの部分を一番集中して聞いてました。 Event Sourcing,CQRS For PHP Application 資料: Event Sourcing,CQRS For PHP Application - Speaker Deck 複雑化するサービスのための設計パターン、アプリケーションとミドルウェアの組み合わせ例紹介。扱うデータやトランザクションが増えたり、集計分析などのシステムがあると必要とされそうに思いました。 Testing Live!!! 資料: Testing Live!!! 実際のWebサービスに対して探索的にテストを行い、問題を探すデモでした。5分という短い時間でアプリケーションに潜む不整合が見つかり、会場がすごく盛り上がってました。 PHP 5.3 + CakePHP1.3 バージョンアップ報告 資料: PHP 5.3 + CakePHP1.3 バージョンアップ報告 - Speaker Deck 去年、同じくPHPカンファレンス福岡で発表された計画の現状報告。BASE もCakePHPを利用しているので、気になりました。 物理層のこと、時々でいいから、思い出してください。 資料: 物理層のこと、時々でいいから、思い出してください。 - Speaker Deck システムの物理層というより物理インフラ構築運用について面白おかしく紹介。失敗談が聞いていて面白すぎました。 その他 スポンサーブースも参加者に足を運んでもらえるようAsk The Speakerコーナー(セッション後に発表者に直接質問できる場所)とコーヒーが用意されており、いつ行っても賑わっていました。 翌日 (6月17日・日) いっぱいご参加頂けて嬉しい限り! #phpconfuk_after #fusic pic.twitter.com/CEMKSoHJit — せいけ しろー (@seike460) 2018年6月17日 非公式 PHP Conference Fukuoka After Hack!! 去年同様、株式会社Fusicのセミナールームで開催されたので参加しました。参加者各自で自由に作業しながら、発表したい人が自由に発表するようなゆるやかな集まりでした。 僕は前夜祭で発表した内容のコード tenkoma/extend-cakephp2-testsuite-example の準備をしていたのですが、飛行機の都合で2時間ほどしか参加できませんでした。 来年もし開催されるなら、絶対フルで参加できるように調整します! まとめ 非公式前夜祭 リジェクトコンで発表しました PHPカンファレンス福岡、フルで楽しむなら前後のイベントもチェックしてみるのがオススメです。
アバター
こんにちは、BASEのPayment Engineer Groupに所属している 柳川 です。 先日BASEではショップコインという新機能をリリースしました。ショップコインの説明を簡単にすると、BASEをご利用いただく各ショップさんが、独自にショップで使えるコインを発行することで、ショップさん独自の経済圏を作れる機能です。詳しい説明は こちら をご覧いただけると幸いです。 私はこの機能の開発でサーバーサイドエンジニアとして設計、開発、リリースを行いました。 今回は開発者ブログの記事ということで、開発していて気がついたことをまとめてみたいと思います。 事前情報 プロジェクトの特徴 修正範囲がでかい 新規コード+既存の決済コードに手を入れる 端的にいうと新しく決済方式を作るということ 開発量に対して実装者が少ない サーバーサイドエンジニア:1人 デザイナー:2人 私の特徴 大規模開発をしていたSIer出身。 プロジェクトの情報と私の特徴から、SIer時代の開発経験をうまく活かせば、上手にプロジェクトを回せるのではとうっすら考えながら開発に挑むのでした。 やったこと UMLを書いた 開発が始まる前に、自分の中で以下のことを確認したいと考えUMLを書きました。 ヒト モノ コト カネ このあたりのことを詰めると、実装の漏れが防げると考えてのことでした。 SIerからスタートアップに転職してからは、関係者の人数が少ないことや、スピードが求められることからこの工程を省くことも多かったのですが、今回はそうも言ってはいられない物量であると考えてSIer時代の知識を引っ張り出してきました。このとき書いたUMLが、人に設計を共有する上でも役に立ちました。少人数で開発していると、開発中の内容がブラックボックスと化してしまうきらいがありますが、その点を少なからず軽減できたのではないかと思います。 また図に起こすことで、エンジニア以外も直感的に機能の把握が行えたようです。弊社がドキュメント管理ツールとして使用している DocBase にて PlantUML の記法が使用できるため、そちらを使用してUMLを記述しました。文章でダイアグラムの作成ができるので、通常のドローイングツールに比べ、あとからの変更が非常に容易でした。おすすめです。 設計書を書いて設計書のレビューをした 転職後はあまり行ってこなかった、設計書自体のレビューをしました。 小さな機能開発であれば 頭の中や手元のメモで設計→実装→コードレビュー→リリース この流れで、進めて大きな問題はないように思います。 しかし今回は開発量の多さが懸念されたため、SIer時代を思い返して、設計書をある程度書いて、なおかつ設計書のレビューもしようと考えました。致命的な指摘等炙り出せたので、本当にやってよかったと思いました。 ちゃぶ台返しポイントを積極的に作った SIer時代の経験を思い出して辛いのが大幅な手戻り、いわゆるちゃぶ台返しというやつです。 残念ながら自社プロダクトの開発でもちゃぶ台返しは起こります。大切なのはいかにちゃぶ台返しのインパクトを少なくして、プロダクトのクオリティの向上に活かすか。 ちゃぶ台返しは敵ではなく、味方なのです。 今回はちゃぶ台返しへの対抗手段として、いろいろなところで細かくちゃぶ台返しを起こさせるという作戦を取りました。 設計書のレビュー 複数回のコードレビュー 出来ている場所までをデプロイして操作してもらいながらのレビュー 上記のように開発期間中に数々のレビューをはさみました。 ちゃぶ台返しの回数こそ多くなったような気はしますが、結果的に工数が収まった上でクオリティを上げられたのではないかと思います。ポイントとしてはSlackでレビューを依頼をするだけではなかなか見てもらえないので、必要と思うタイミングで必要な人には明確に時間を取ってもらいレビューを行うことです。他力本願は駄目! リリース前にQAプロセスを入れられたこと 今回少人数での開発、かつ開発量が多かったこともあり、明示的にQA期間を設け、リリース前の検証を行いました。機能の開発に関わっていないメンバーの新鮮な目で、QAをおこなってもらうのは、実際にバグが潰せるのはもちろん、精神的にも大きな助けとなりました。 うまくやれなかったこと リリースの単位がでかくなってしまった この 発表資料 を読みながら反省したのですが、リリースの単位がでかくなってしまったのは反省点かなと思います。後で確認する範囲がでかくなるだけなので、できるだけ細かく早く出すべきだったと思います。ただすぐには本番稼働しないコードを本番に組み込むのも影響確認とロールバックという点でどうだろう、というのはあるので難しいところかなとも思います。 リリース前の忙しい時期がうまく回らなかった 開発自体は、少ない人数でも段取りをしながら進めることが出来たのですが、リリース直前に立て込んでくると、開発作業とそれ以外作業の帽子をかぶり直すことが出来ませんでした。特にリリース前のQA作業を行うことと、バグを修正することを同時に行うのが厳しかったです。リリース直前に忙しくなることがわかっているなら、極力帽子をかぶり直すことなく進められるように、人をアサインしてもらうなどで準備するべきでした。 開発範囲が少ない場合は、できるだけ一人でやったほうがスピーディーに進められますが、ある程度開発範囲が大きくなると、各人が各ロールに分かれた体制を作ることに強みが出てくるのだろうなと思いました。このあたりは今後の課題かなと思います。 また、自分が今何に集中すべきかを客観的に考えるのが大切だと感じました。テンパらない。 まとめ 大きめの機能開発を、主導する立場として担当させていただき、非常に勉強になりました。まるごと任せていただけたからこその気付きが多かったように思います。特に設計書を作る、開発プロセスを明確化する等のSIerで培った技術が役に立ったのはいい経験でした。 SIer時代は、最初から決まりとしてあった開発の手順に窮屈感を感じることもありましたが、実際になんのために行うのかということを考えて、開発中の課題と照らし合わせていくと、力となる部分は無数にあるなと感じました。 当たり前ですがSIerでもスタートアップでもアプリケーションを作るという上では同じです。アプリケーション開発の道具として使えるソフトウェアの開発手法を、積極的に取り入れていくべきだと感じました。すべての開発工程が最初に描いたとおりに進んだわけではありませんでしたが、それも含めいい経験でした。忙しく開発作業を終えたあとは、知識の吸収が早い気がするので、振り返られなかった分をしっかり振り返って、学ぶべきものを見定め学んで、次に活かしたいです。日々勉強。 最後に BASEでは、様々な経験を活かしながら一緒に未来を作っていく仲間を募集しています。前向きかつ自由にやっていけるのは間違いない環境です。 ご興味を持たれた方は以下の採用情報から! jobs.binc.jp
アバター
こんにちは、CTOの藤川です。 これまでエンジニアの肩書において、エンジニア専門職の上級職としてリードエンジニアという役割を設定しておりました。 リードエンジニアと言うと、世間の見方としては「技術力に優れたエンジニア」というやや漠然とした役割と想像しているのではないでしょうか? Webサービス開発における「技術力」とは 「良いサービス」とは 「良いサービス」を提供するために、エンジニアに求められるスキル Webサービス企業におけるエンジニア属性:「テック」と「サービス」 「テックリード」と「サービスリード」の役割 リードエンジニア テックリード サービスリード 「サービスリード」とは、その一文字を直す作業に意義、喜びを感じられること 一緒に良いサービスを作りませんか? Webサービス開発における「技術力」とは そもそも「技術力とは何ぞや?」というのが曖昧なことが多いです。 というのも、私共が担っているビジネスは、Webサービスを提供しています。Webサービスは24時間365日運用されていますので、必要な技術も多岐に渡ります。毎日新機能を開発していますし、継続的かつ安定的に運用していく必要がありますし、セキュリティ要件は日々変わっていきます。 僕らはコンピュータサイエンスの力の恩恵を受けつつ、特には恩返しを試み、サービス実現としてのソフトウエアエンジニアリングを推し進め、ユーザーさんに使い続けていただくサービスを継続的に開発運用していくことが求められます。 我々の場合は、フリーミアムなECプラットフォームですから、多くのショップオーナーさんのビジネスや生活を支えることを生業として、結果として生まれた流通総額(GMV)という成果に連動してお給料をいただきます。 また、サービスそのものは外部環境に合わせて変化していくことが必要ですので、それをスピーディーに推進する力がエンジニアには求められます。Webサービスで何もしないのはビジネス的にもセキュリティ的にも退化を意味します。常に時代の変化にアンテナを張り、技術を用いて変化を生み出していきます。また、そのような技術的問題点を一切感じさせることなくユーザさんには安心して使っていただけるように良いサービスとして提供していく必要があります。 「良いサービス」とは (Photo by WOCinTech Chat ) ここで言う、良いサービスとは、 サービスクオリティ (目的に対しavailableではなく、usefulであること。) プロダクトクオリティ(UIを通じた高い品質のサービスを安心、安定して使えること) サイト信頼性 (変化と継続) スケーラビリティ (何が起きても困らない) セキュリティ などで構成されます。 「良いサービス」を提供するために、エンジニアに求められるスキル これらを元に私共が提供するサービスを実現することに関して、エンジニアに求めるスキルについて軽く想像するだけでも、結構たくさん思いつきます。 Webアプリケーションの技術開発力(PHP等のサーバサイド言語、JS、動画アプリケーション) よいWebサービスを作るサービス開発力(UI/UX、ビジネスフロー、サービスを実装に変える力) HTML5、iOSやAndroidアプリケーションのアプリ開発力(主にパフォーマンス、安定性、OSの知識等) Webフロントエンド、iOSやAndroidアプリケーションのUI開発力(クリエイティビティの実現、UI安定性) サーバインフラの実現力、DevOpsの開発力、AWS等のクラウドの知識 セキュリティをしっかり維持する力、もしくは過去の問題の発見力 サービスの継続的運用に関するコミットメントを持てる力 (なにげに、これは特殊技能だと思います) 機械学習やAIなどを実現する技術力、統計的知識 変化するフロントエンドをキャッチアップし、クリエイティビティと結びつける構築力 要件をチームにわかりやすく翻訳する翻訳力、ドキュメント力 未来に向けたアーキテクチャ設計、変化を実現する力(これはスキルだけあってもできない) プラットフォーム開発力、外部パートナーを巻き込むAPI開発力など プロジェクトマネジメント、アジャイル等工程設計力と実践力 テストやQAなどプロダクトクオリティを実現する方法論に長けていることと、チームメンバーを引っ張る力 PHPそのもの、フレームワークそのものの成長性維持に貢献する知識、人脈、コミットメント、コミュニティ活動ができる力 Webサービス企業におけるエンジニア属性:「テック」と「サービス」 ここに挙げた通り、一つのWebサービスの成長に必要なスキルへの関心について、一人のエンジニアがすべて満たすのは現実的に不可能です。 Webサービスのエンジニアに期待される能力のわかりやすい事例として、深夜に起きていること(障害などではなくアラートなど)の適応力は、何より我々のビジネスそのものへの関心がなければ、到底できるものではありません。「このアラートは今は気にしなくても大丈夫」の一言をSlackに投げるためのバックグランドにある技術知識と当社のサービスの経験こそがWebサービスのエンジニアとして求められる部分です。 もちろんやることはそれだけではないですから、エンジニアそれぞれ特技にあわせて役割を定義し、貢献、成果を評価できる体制をつくり、その総体としてエンジニアチームを構成していくことになります。それに必要な貢献を期待できる能力に、投資的にお給料を先払いするのに必要な肩書を上級技術職として割り当てていくことになります。 それに必要な能力を抽象的にまとめていった時に、Webサービス企業のエンジニアに求められる能力属性には「テック」と「サービス」という括りがあることにたどり着きました。 テックのスキルが優れているだけで良いサービスが作れるほどWebサービスは甘くありません。一方で、良いサービスを作るためにはテックの適応力は不可欠です。また時間軸と共に変化していく技術に対する適応性、応答性は、テックのスキルが優れている人材が得意とする分野です。 「テックリード」と「サービスリード」の役割 今回、テックとサービスにおける理想像をまとめて、それらを達成している模範となるべきエンジニアを「リードエンジニア」と定義し、更に細かい属性として、「テックリード」と「サービスリード」という肩書を定義しました。 Webサービス企業のエンジニアはテックへの適応力とサービス開発力は不可分です。しかし、その人の魅力の出自はテックなのかサービスなのか、どちらに立脚するかで肩書を変えています。今回、その役割定義を行いました。 その定義が以下になります。まずは、リードエンジニアの役割です。 リードエンジニア 事業に配属され、事業の中での開発やサービス運営をリードする以上の成果を期待されたロール。 サービスの継続的発展を実現するための技術力や、BASEのサービス哲学を具現化するためのサービス開発力などを兼ね備え、圧倒的な主体性でサービスの成長に取り組む模範となるべき役割を担う。 「圧倒的な主体性」こそがリードエンジニアにとって重要なポイントです。 そして、テックリードです。 テックリード 高い技術力を持ち、時代の変化を読みながら、適切な技術を、適切なタイミングと適切な方法で自社サービスに取り入れ、スケーラビリティの実現や高いセキュリティを通じてサービスの進化に寄与することが期待される。サービスの継続的進化を担い、メンバーの技術的成長の模範となる役割 「適切な技術を、適切なタイミングと適切な方法」を模索することを強く求めています。技術変化の激しい業界だからこそ、タイムラインに日々流れてくるような素敵な技術ありきではないということです。また、チームに変化を生み出すスキルがテックリードには重要です。それが「サービスの継続的進化を担う」という部分に期待されています。 該当職種はWebアプリケーションエンジニア、フロントエンド(Web、App問わず)に加えて、SREのようなDevOpsエンジニアや技術基盤を担うアーキテクトなども想定しています。 そして、今回追加したのがサービスリードです。 サービスリード BASEのサービス哲学を熟知し、高い顧客体験を実現するサービスを開発することで、体験の質を通じたサービス信頼性を実現する。 顧客に支持され続けるサービスの継続的発展に寄与し、サービスづくりの模範となる役割。 当社のサービスでビジネス要件をサービスとして設計する際に、ユーザーへのベネフィット実現を前提としてすべてを再構築する必要があります。つまり「本当にその要求はユーザベネフィットが提供できるのか?プロダクト側で全部洗い直せ」という工程が必要なのですが、そのあたりのアレンジをエンジニアという役割の中で期待できる人材がサービスリードです。 例えば、ついつい受託出身だと(僕自身がそうなのですが)、ビジネス要件は実現すべき前提条件として盲目的に受け入れてしまいがちですが、そのまま無理やり実装したところで戦闘力のある良いサービスが提供できないのであれば、すべての話をひっくり返さなくてはいけないかもしれません。そこへのサービス思考力が「高い顧客体験」の実現には不可欠です。その視座を元に高いプロダクトクオリティを実現することがサービスの継続的発展に繋がります。 また、顧客ニーズに耳を傾け、時には己の判断で即座に修正を行える信頼というのも必要です。その修正の粒度や判断力が顧客ニーズや会社のOKR達成に対して不適切であれば、その行動を誰かがマネジメントする必要があります。例えば大技主義のアーキテクトであったり、スキルが高いがゆえに過剰に作り直したくなる病などを持っている人は、サービスリードには適していません。目の前で困っている人、その裏側にいる人を想像し、適切な粒度の修正を行うという判断力は、テックを中心とした思想とは少し違う価値観が求められることが多いようです。 この役割は基本的にはWebアプリケーションエンジニアやフロントエンド(Web、App問わず)などを想定していますが、もしかしたらフロントエンドを担うデザイナー職もこの範疇に入るかもしれません。(デザイナーとデータサイエンティストは違う役割構造を定義することになるとは思いますが) 「サービスリード」とは、その一文字を直す作業に意義、喜びを感じられること サービスリードという肩書は検索してみると、いくつかのWebサービス企業の記事で見つかり、参考にさせていただきました。 しかしながら、なかなか一般的なエンジニアの評価スキルとして見えないことが多いです。世の中の判断軸が技術偏重とまでは思いませんが、技術系メディアが書籍等を作るのに必要なテクニカルな部分にアテンションが集中しやすいというのがあるのかもしれません。テックへの貢献は、GitHubで言うPublicリポジトリにおける貢献や活躍が多くインターネットで共有されています。サービスへの貢献は、主に企業内のPrivateリポジトリへの隠れた貢献であることで、なかなか共通基盤としての技術者評価に結びつきにくく、Webサービスを作ることはコードさえ書ければ誰でもできるんじゃないか?と、その質やコミットメントの部分を無視されてしまい、当たり前の行動のように見えてしまうことで適切に言語化されていないというのがあるように感じています。 サービスで実現したい哲学(その機能は何のためにあるのか、何を実現したいのか)を顧客が所有する仕事に慣れている受託の方やSIerの方で、僕の面接を受けている人であれば聞いている方もいらっしゃるかもしれませんが、「その一文字を直す作業に意義、喜びを感じられること」がWebサービスに従事するエンジニアに求める部分です。今回、その模範となる役割がサービスリードそのものです。今回テックリードとサービスリードの肩書を持つエンジニアができましたが、当社のエンジニアはテックリード職であってもサービス属性は実はすごく高いです。そもそも、それが見えないと採用していませんから、テックリードとサービスリードは敵対しない概念だと書いたとおり、その人の魅力はどこが主軸か?で分けています。 一緒に良いサービスを作りませんか? この2つの概念は敵対するものではなく、両立が望ましいわけですが、そうは言っても、その人の得意技として技術変革を主軸に活躍する人もいれば、技術は手段としてサービス実現に活躍する人もいるわけで、その両属性をチームとして評価しますよ!というのが今回のテックリードとサービスリードというリードエンジニアの属性化に繋がっています。今後はそこをしっかり明確化していくことで、サービスづくりをしたいエンジニアももっと増やしていきたいと思っています。 この両者の人材がバランスよく融合することで、サービス全体のクオリティが実現できるというのが、この記事に書いてた論点です。それぞれの属性を強みとしたエンジニア、それぞれ、ちゃんと高く評価してるんですよという当社にご興味を持ってくださったお方がいらっしゃいましたら是非、お話しましょう。 採用情報はこちらから! jobs.binc.jp
アバター
こんにちは。BASE で Design Group に所属している 三佐和 です。主に ネットショップ作成サービス「BASE」 のフロントエンドを担当しています。 背景 BASE のデザインチームはここ最近で人数が急激に増え、活動が活発になってきており、その中のプロジェクトの一つとして、現在スタイルガイドの刷新に取り組んでいます。 しかし、人数が増えていく一方で、コーディングのルールの統一をコードレビューや個人の裁量に任せていたり、マークアップからリリースするまでに時間がかかってしまうことが問題になってきていました。 そこで、新しいスタイルガイドでは、デザイナーやエンジニアの作業工数を短縮し、より効率よく開発を進めるために、コーディングルールの整備とリグレッションテストを導入することにしました! やったこと stylelint を使ってコーディングルールを管理 BackstopJS でテストを行うことでデグレを防ぐ 前提として、 nodejs や yarn などの一般的なフロントエンド開発環境が整っているものとします。 stylelintを導入 stylelint を使って、これまで個人の裁量で保たれていたコーディング規約への準拠を機械的に行えるようにします。 導入 stylelintをインストール その他必要なプラグイン等をインストール stylelint-scss (SassのSCSS記法のためのプラグイン) stylelint-order (プロパティをアルファベット順に並び替えるプラグイン) stylelint-config-standard (CSSのコーディング規約集) prettier-stylelint (コードフォーマッターprettierとstylelintを組み合わせて使用する) yarn を使ってインストールします。 $ yarn add -D stylelint stylelint-scss stylelint-order stylelint-config-standard prettier-stylelint 設定 既存のコーディングルールに合わせて、 .stylelintrc を設定していきます。 BASE の場合はプロパティをアルファベット順にソートしたかったので、 stylelint-order を使用したりしています。(私はいままで abc の歌を歌いながら順番にプロパティを並べていました........) // .stylelintrc { " parser ": [ " css " ] , " plugins ": [ " stylelint-scss ", " stylelint-order " ] , " extends ": [ " stylelint-config-standard ", " ./node_modules/prettier-stylelint/config.js " ] , " rules ": { " indentation ": 4 , // インデント " order/order ": [ " custom-properties ", " declarations " ] , // アルファベット順でソートする " order/properties-alphabetical-order ": true , // アルファベット順でソートする " length-zero-no-unit ": true , // 値が「0」なら単位を省略する " number-leading-zero ": " always ", // 小数点の頭の「0」は省略する " color-hex-length ": " short ", // HEX形式のカラーコードは3文字で表記する " shorthand-property-no-redundant-values ": true // ショートハンドでプロパティを書く } } 設定ができたら、 package.json の scripts にコマンドを追加して、 yarn lint-sass で実行できるようにします。 // package.json // ... " scripts ": { " lint-sass ": " prettier-stylelint --quiet --write src/sass/**/* " } // ... 実際の使用方法 まずは思うがままに sass(scss) を記述します。 . btn--submit { color : $white ;  background-color: $green ; border : none ; } めちゃくちゃですね!でも大丈夫です、lint を実行すると... $ yarn lint-sass こうなります。 . btn--submit { background-color : $green ; border : none ; color : $white ; } 完璧ですね!もう歌は歌わなくても大丈夫になりました! 結果 常にコーディングルールを意識する必要がなくなったので、マークアップのスピードも上がりました! 2. BackstopJSを導入 BackstopJS を使って、戻りが発生しないよう、動作チェックする仕組みを作ります。 導入 BackstopJSをインストール stylelintと同様に、yarn を使ってインストールします。 $ yarn add -D backstopjs backstop.json にオプションを設定し、スナップショットを撮る スナップショットを使ってテストする 設定 backstop.json に必要なオプションを設定していきます。 // backstop.json { " viewports ": [ { " label ": " sp ", " width ": 320 , " height ": 480 } , { " label ": " pc ", " width ": 1024 , " height ": 768 } ] , " scenarios ": [ { " label ": " reference ", // スナップショットの名前 " url ": " テストするURL ", " hideSelectors ": [] , " removeSelectors ": [] , " selectors ": [ "# test - sandbox " // スナップショットを撮影する部分 ] , " readyEvent ": null , " delay ": 500 , " misMatchThreshold " : 0.1 , " onBeforeScript ": "", " onReadyScript ": "" } , { " label ": " test ", // スナップショットの名前 " url ": " テストするURL ", " hideSelectors ": [] , " removeSelectors ": [] , " selectors ": [ "# test - sandbox " // スナップショットを撮影する部分 ] , " readyEvent ": null , " delay ": 500 , " misMatchThreshold " : 0.1 , " onBeforeScript ": "", " onReadyScript ": "" } ], " paths ": { " bitmaps_reference ": " ./backstop_data/bitmaps_reference ", " bitmaps_test ": " ./backstop_data/bitmaps_test ", " compare_data ": " ./backstop_data/bitmaps_test/compare.json ", " casper_scripts ": " ./backstop_data/casper_scripts " } , " engine ": " phantomjs ", " report ": [ " CLI ", " browser " ] , " cliExitOnFail ": false , " casperFlags ": [] , " debug ": false , " port ": 3001 } 設定ができたら gulpfile にタスクを追加します。 // gulpfile.coffee // ... exports.backstopref = () => connect.server( { root: './build' , livereload: true } ) backstopjs( 'reference' ).then () -> connect.serverClose() exports.backstop = () => connect.server( { root: './build' , livereload: true } ) backstopjs( 'test' ).then () -> connect.serverClose() // ... そして、 package.json の scripts にコマンドを追加して、 yarn backstop-ref で参照用画像の作成、 yarn backstop-test でテストが実行できるようにします。 // package.json // ... " scripts ": { " backstop-ref ": " gulp backstopref ", " backstop-test ": " gulp backstop " , } // ... 実際の使用方法 はじめに、テストの元データになる参照用の画像を作ります。 $ yarn backstop-ref BackstopJS は、この画像をもとに比較テストを行ってくれるので、予期せぬ変更を行ってしまった場合にテストが失敗し、それに気づくことができます。 試しに、このボタンの border-radius を 8px から 0px へ変更してみましょう。 そしておもむろにテスト実行用のコマンドを叩きます。 $ yarn backstop- test // ... compare | ERROR { requireSameDimensions: false , size: isDifferent, content: 0.32%, threshold: 0.1% } : reference bbq_reference_0_test-sandbox_0_sp.png compare | ERROR { requireSameDimensions: false , size: isDifferent, content: 0.32%, threshold: 0.1% } : test bbq_test_0_test-sandbox_0_sp.png compare | OK: reference bbq_reference_0_test-sandbox_1_pc.png compare | OK: test bbq_test_0_test-sandbox_1_pc.png report | Test completed... report | 2 Passed report | 2 Failed report | Writing jUnit Report report | Writing browser report report | jUnit report written to: ~~/backstop_data/ci_report/xunit.xml report | Resources copied report | Copied configuration to: ~~/backstop_data/html_report/config.js COMMAND | Executing core for `openReport` openReport | Opening report. report | *** Mismatch errors found *** COMMAND | Command `report` ended with an error after [ 0.51s ] COMMAND | Error: Mismatch errors found. at ~~/backstopjs/core/ command /report.js: 113 : 17 at < anonymous > :null:null COMMAND | Command ` test ` ended with an error after [ 5.371s ] COMMAND | Error: Mismatch errors found. at ~~/backstopjs/core/ command /report.js: 113 : 17 at < anonymous > :null:null [ 15 : 02 : 59 ] ' backstop ' errored after 5.38 s 差分が発生したので、テストが失敗し、レポート用の HTML が出力されました。 これを開いてみると、差分のある箇所がピンク色になっています!分かりやすいですね! 結果 作業を開始する前にスナップショットを作成しておくことで、行った作業でのデグレに早く気づいたり、防ぐことできるようになりました。 まとめ 今回、stylelintやBackstopJSを利用したことで、実装者の負担が以前よりも軽くなりました! 実装者が増えても差分が生まれにくく、デザインの一貫性を保つことができる仕組みを考え、引き続きスタイルガイドを作成していきたいと思います。また同時に、それらをメンテナンスしやすい環境も整えていきたいと思います!
アバター
こんにちは!BASE Product Division サーバーサイドエンジニアの 東口 です。主にEコマースプラットフォーム「BASE」の決済領域の開発をしています。本ブログでは、PHPerKaigi 2018での登壇記事等も書いています。 devblog.thebase.in BASEのサーバーサイドの多くはPHPで書かれているので普段触る機会の多い言語はPHPなのですが、先月からGoを書きたい有志が集まって定期的にGo言語勉強会を行っています。 きっかけ 初めたきっかけは2018年4月15日に開催された Go Conference 2018 Spring でした。スポンサー企業のラインナップや実際に会場の熱気に触れて、改めてGo言語の勢いや実用性を強く再認識しました。それまでGoを書きたいと思っていたこともありカンファレンスに参加していた同僚と勢いで始めることを決めました。 学生版goconやろうとしている方に刺激を受けて「Goならわかるシステムプログラミング」社内読書会を勢いで作った #gocon — Kazuki Higashiguchi (@hgsgtk) 2018年4月15日 やり方 対象書籍として、 『Goならわかるシステムプログラミング』 を進めていくことにしました。この書籍を選んだ理由は、Goという言語自体の書き方ではなくGoを使って目的のあるコードを書ける点でした。また、個人的にPHPを触ってると意識しにくい低レイヤの仕組みについて知っておきたいという意図もありました。 Go Conference 2018 Spring の翌週から毎週1回2時間定期的に時間を取って実施しています。 集まってやるということで発表の時間を作ろうかという検討もありましたが、身内でやる分にはまずは各自好きなペースでもくもく進めていく方法で進めることにしています。 また、読書会中の会話や詰まったときの内容をGo言語について話すslackの #golang チャネルにて話しています。ここで各自詰まったところについて話していたりしているので後続の人がそこを見て参考にできるという利点が有りました。 良かったこと 学習のペースメーカーになる 定期的に時間をとることで途中で止まりがちな本の写経をする習慣ができ、週一回Goを触るペースメーカー的な存在になっています。 議論ができる 全員が同じ書籍をベースにやっているので、「このページで使われている関数の内部実装がどうなっているか」等、一人で進めているとスルーして先に進めがちな箇所について疑問を深掘りする機会になっています。 Goに触れた経験のあるエンジニアが増えた 本読書会を期に、「実はGoやりたかった」というエンジニアがGoを書き始めました。 元から社内slackに #golang チャネルというGo言語について話すチャネルがあったのですが参加者が7人くらいで更新頻度もあまり高くありませんでした。 しかし、読書会を通じてGo言語に触れたエンジニアが増え#golangチャネルに人が増えGoの話題について話す機会が増えました。Go言語のイベントの共有や「MySQLドライバをGoで書いてみたら面白そう」といった、こういうチャレンジをしたら面白そうと言った会話がslackでされています。 まとめ プロダクションでGoを採用している箇所はスポット部分に限られるので、この読書会を通じてGoをプロダクション環境や趣味のプロダクトに適用するきっかけになればと思っています。 読書会やもくもく会といった勉強会を始める際どういう風に運営するかみたいなことを考えて止まってしまうかもしれないですが、やってから考えるくらいの気持ちで始めてみてはいかがでしょうか?
アバター
iOSエンジニアの 大木 です。 日々の開発で、ちょっとした微修正でメソッドを追加・削除すると、差分コンパイルが効かずビルド10分待ちとなり、開発効率の低下が問題となっていました。それを解決するためEmbedded Frameworkを導入したところ、差分ビルドが成功し1-2分になったというお話です。 私が入社したのは、2017年の2月でした。そして、アプリはもともとObjective-Cで書かれていて、Swiftコードの占める割合は10%以下だったようです。それから1年近くで、90%以上Swiftコードに置き換えました。 その時点で、ビルドにかかる時間の長さが目立つようになり、ちょっとした不具合の調査や微調整しているだけなのに10分近く待たなければいけないケースが目立つようになってきました。 問題としては以下の2つがありました。 1つのメソッドを追加しただけなのに、何故か10分近くかかるため、微調整するのに不向き タイプミスしたので一旦途中キャンセルして修正し再ビルドしたが、差分ビルドが効かず10分待ち 前提 日々の開発で行うDebugビルドを対象としています。そのため、AdHoc配信などでビルドする場合のケース(Archive)はCircle CIでおこなっているため特に対象にしていません。差分ビルドが効くようにして開発効率を改善していきます。 環境 MacBook Pro (15-inch, 2016) macOS High Sierra(10.13.4) Xcode 9.2 Swift 4.0 Swift:Objective-Cの比率は、9:1 ビルド対象のSwiftファイルは約850ファイル 一般的なビルド設定やSwift-Objective-Cのブリッジングに対する改善はすでに行なっていた New build systemを使っている 改善の流れ ビルド時間計測 ビルドが遅くなっている原因コードを探して修正する これ以上速く出来ない? コードをモジュール単位に分割 差分ビルドが効くようになり、開発効率改善! ビルド時間計測 パイク: Cプログラミングに関する覚え書き にもある通り、推測するのではなく、どこで時間がかかっているか計測してみます。 XcodeのBuildSettingsの OTHER_SWIFT_FLAGS に -Xfrontend -debug-time-function-bodies を追加すると、閾値以上のビルド時間がかかっているメソッドを、Xcode上でWarningレベルで報告してくれます。 ちなみにBASEアプリでは、App Extensionsを使用していることもあり、設定の抜け漏れを防ぐため、XcodeのGUI上ではなく、 xcconfig ファイルで設定しています。 // Debug.xcconfig #include "Shared.xcconfig" #include "DebugPlugins.xcconfig" SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) DEBUG; // 計測用フラグ OTHER_SWIFT_FLAGS = -enable-bridging-pch -Xfrontend -debug-time-function-bodies -Xfrontend -debug-time-compilation -Xfrontend -warn- long -function-bodies= 200 -Xfrontend -warn- long -expression-type-checking= 200 ; GCC_PREPROCESSOR_DEFINITIONS = $(inherited) DEBUG= 1 ; 計測結果が含まれるビルドログはXcode上で全ては見えないのと、出力されたファイルを読み解く時間が惜しいという場合は、 BuildTimeAnalyzer-for-Xcode を使うとよいでしょう。 ビルドが遅くなっている原因コードを探して修正する さて計測結果を眺めてみたところ、注文内容と支払い情報を送信するためのHTTPBodyの生成structを返す処理で10秒前後ビルドにかかっていました。 その処理は、Structに (String, Any) のタプルの配列で必要なパラメーターをセットしているのですが、型情報がわからないままなため時間がかかっていたようです。 そこで、一旦変数に格納することによって、型推論が効くようになり、ビルド時間も大幅に改善しました。 diff --git a/CartClient.swift b/CartClient.swift index 9e2b4c060..93a882f19 100644 --- a/CartClient.swift +++ b/CartClient.swift @@ -42,6 +42,11 @@ class CartClient: APIClient { case .checkout(paymentType: let `type`, payment: let payment, cart: let cart): let orderRequestInfo = cart.orderRequestInfo + // 一旦変数に格納して型情報を用意する + // 住所とメールアドレスは必須なのでforce unwrappingで取り出しても問題ないはず + let familyName = payment.shippingContact!.name?.familyName ?? "" + let givenName = payment.shippingContact!.name?.givenName ?? "" + let tel = payment.shippingContact!.phoneNumber?.stringValue ?? "" return Parameters([ ("payment", type.paymentMethod), @@ -49,14 +54,14 @@ class CartClient: APIClient { ("item_id", orderRequestInfo.itemId), ("shop_id", orderRequestInfo.shopId), ("variation", orderRequestInfo.variationId), ("amount", orderRequestInfo.amount), - ("last_name", payment.shippingContact!.name?.familyName ?? ""), - ("first_name", payment.shippingContact!.name?.givenName ?? ""), + ("last_name", familyName), + ("first_name", givenName), ("postal_code", payment.shippingContact!.postalAddress!.postalCode), ("state", payment.shippingContact!.postalAddress!.state), ("address", payment.shippingContact!.postalAddress!.city), - ("address2", payment.shippingContact!.postalAddress?.street ?? ""), - ("tel", payment.shippingContact!.phoneNumber?.stringValue ?? ""), - ("mail_address", payment.shippingContact!.emailAddress ?? ""), + ("address2", payment.shippingContact!.postalAddress!.street), + ("tel", tel), + ("mail_address", payment.shippingContact!.emailAddress!), ("version", appVersion())]) default: break 改善結果は以下の通りです。 コンパイル時間 内容 9323.63ms 元のコード 265.4ms(-97%) 追加する値を一旦変数に保存(Optionalのまま) 16.6ms(-99.8%) さらにNonOptionalにして保存 他にも修正していくらか改善しましたが、劇的な改善には至りませんでした。 if boolValue = true { のような比較をやめて if boolValue { に変更して中身の判定を行う 条件に一致したコレクションの要素を取得するメソッド filter() を使うだけで条件を満たせるのに compactMap() 使って余計にビルド時間がかかっていた。 100ms以内に収まり喜んだのもつかの間、再度ビルドすると200ms以上時間がかかってしまう問題もあり、これ以上は誤差でしかないと考え修正を打ち切りました。 これ以上速く出来ない? Swiftコードコンパイル時間短縮も大事なのですが、最初に述べた 差分ビルドが効くようにして開発効率を改善 達成するのが第一の目標です。 考えてみると、全てのソースファイルをアプリケーションターゲットでビルドするのは無駄です。APIからデータを取得するコードやデータモデルなどは、最初に定義してしまえばほとんど修正することはありません。 モジュールとして切り出せば、関係ないコードのビルドはFramework側で行うことになり、ビルド時間の大幅な改善が見込めそうです。 iOSには、Cocoa Touch Frameworkとしてコードを共有する仕組みがあります。さらに、Embedded Frameworkという仕組みを使ってXcodeのワークスペースに直接組み込むこともできます。 コードをモジュール分割 Embedded Frameworkを使って、コードをモジュールとして分割していきます。 レイヤー化アーキテクチャー等で、各々理想のアーキテクチャーはあると思いますが、ビルド時間の解決に使うことにします。 iOS SDKにのみ依存し単体で動作する共通コード アプリで定義したデータモデルやAPIクライアントコード等、複数箇所で利用し変更が頻繁に発生しないコード 上記両方に共通していえることですが、設定ファイルの読み込みが必要な部分はアプリケーションターゲット側で読み込み、その結果オブジェクトをフレームワーク側で定義したデータモデルに変換して渡すようにした方がテストもしやすいですし、後々依存関係のエラーで悩む必要も無くなります。 また、再利用可能にすることを考えると、APIのエンドポイントやストレージのパスなども、アプリケーションターゲットから渡すようにした方が良さそうです。 最終的には下記のようにモジュール分割しました。 UIExtensionKitとAppKitという名前のフレームワークを作成し、アプリケーションターゲットはそれをインポートして使うようにしました。 frame "Application Target" { [AppContext] [App] } package "UIExtensionKit" { [Extensions] } package "AppKit" { [AppContext Interface] [Registory] [Data Structures&Logics] } [App] . [AppContext] : Init [App] ... [Extensions] : Use [AppContext Interface] <|.. [AppContext] : Implement [Registory] *- [AppContext Interface]: DI [Data Structures&Logics] . [Registory] : Use [App] . [Data Structures&Logics] : Use 図のApplication Targetというのはアプリケーションのエントリーポイントとなるターゲットです。アプリを起動する場合はこのターゲットを起動します。 UIExtensionKitは、iOS SDKでのみ実装してアプリの業務ロジックは含まないそれ単体で動作するコードです。カラーパレットの定義やViewコンポーネントが配置されているセルのIndexPathを取得する便利メソッドなどがあります。 AppKitは、アプリで定義したデータモデルやそれらを操作するビジネスロジックなどを含みます。 APIリクエストのクライアントだったり、APIのレスポンスを加工したりローカルのストレージにシリアライズしたデータを保存したりするコードがあります。 結果 改善結果は以下の通りです。差分ビルドの結果は、 UIViewControllerに viewWillAppear(_:) を追加してビルドした結果です。 コンパイル時間 ビルド種別 内容 494.4s<約8分> フルビルド 分割していない元のプロジェクト 247.055s<4分8秒> フルビルド フレームワークを使ってモジュール分割したプロジェクト 232.8s<3分52秒> 差分ビルド(成功時) 分割していない元のプロジェクト 86.924s<1分27秒> 差分ビルド フレームワークを使ってモジュール分割したプロジェクト まとめ 差分ビルドが失敗してビルドに時間がかかるという場合は、Frameworkを使ってモジュール分割してみたら改善できたというお話でした。これによって、無駄に残業して仕事をすることもなくなり、効率よく開発できるようになったと思います。 おまけ(モジュール分割に関して) モジュール分割に対応するためには、技術的な課題がいくつかありそれを解決しなければなりません。 ざっと挙げますと アプリケーションターゲットでしか使えないもしくは実体が存在しないオブジェクトやメソッドが存在し、Frameworkやテストターゲットから利用したい場合に簡単にアクセスできそうにない フレームワーク内のコードを動作させるには、アプリケーションターゲットに配置した設定ファイルを読み込む必要がある Objective-Cで書かれた広告や解析SDKを利用する場合、複数のモジュールでインポートすることができない 今回の場合フレームワーク側は、一方的に利用される側なので、何らかの方法でこういった依存関係を解消する必要があります。 それには、依存関係逆転の原則(DIP)という方法を使いこの問題を解決しました。フレームワーク側にAppContext Interfaceという抽象インターフェースを定義することにより、アプリケーションの詳細に立ち入らず依存関係のエラーを防ぐことができるようになりました。 フレームワーク側に用意する抽象インタフェースの例は、下記のようなコードです。 これを、アプリケーションターゲットやテストターゲットが実装すれば、フレームワーク側は抽象インタフェースを通して処理を行えるようになりました。不必要にSDKをインポートして依存関係のエラーになることもありません。APIのエンドポイントも渡すようにすれば、切り替えのたびにフレームワーク側をビルドし直す必要もありません。 // AppKit.frameowrk public protocol AppContext { var apiConfig : APIConfig { get } var tracker : Tracker { get } var legacyImageSliceFetcher : LegacyObjCImageSliceFetchable { get } var bundleResolver : BundleResolvable { get } var keychainResolver : KeychainResolvable { get } var realmContainer : RealmContainer { get } var legacyAPIBridging : LegacyObjCAPIBridging { get } var appConfig : AppConfig { get } var traits : Traits { get } var userDefaultsResolver : UserDefaultsResolvable { get } var activity : Activity { get } } public enum TrackerActions { case setUser(userId : String ?) case error(Error) case errorWithAdditionalUserInfo(Error, userInfo : [String: Any] ?) } // FabricのCrashlyticsはFrameworkの中に重複してリンクできないので、アクションを通じて処理を行わせる(処理の詳細実装自体はこのフレームワークを利用する側にある) public protocol Tracker { func dispatch (action : TrackerActions ) } フレームワークを利用する側(アプリケーションターゲットやテストターゲット)は、下記のようにこのインタフェースを実装すれば良いことになります。 // アプリケーションターゲット import AppKit final class AppContext : AppKit.AppContext { var apiConfig : AppAPIConfig = APIConfig() // [...] } // テストターゲット import AppKit final class MockAppContext : AppKit.AppContext { var apiConfig : AppAPIConfig = MockAPIConfig() // [...] } フレームワーク側で解決できない依存関係は、利用する側で抽象インタフェースを実装することにより解決できるようになりました。 しかしこの実体をどう渡せば良いのでしょうか? 下記のようなコンテナをフレームワーク側に用意し、それを利用するようにすればどこからでも呼び出せるようになります。 public struct Registory { private static var context : AppContext ! public static func setContext (_ context : AppContext ) { self .context = context } static func resolve <D> (keyPath : KeyPath <AppContext, D> ) -> D { return context[keyPath : keyPath ] } } これでフレームワークの外側から必要な処理を行えるようになりました。 参考文献 パイク: Cプログラミングに関する覚え書き 実践ドメイン駆動設計 (Object Oriented SELECTION) ヴァーン・ヴァーノン var a = Array.from(document.querySelectorAll("pre.code")); a.forEach(function (pre) { if (pre.attributes['data-lang'].value) return; var xhr = new XMLHttpRequest(); xhr.open("POST", "https://plantuml-service.herokuapp.com/svg"); xhr.onload = function () { if (xhr.status === 200 && pre instanceof HTMLPreElement) { pre.parentNode.replaceChild(xhr.responseXML.documentElement, pre); } } xhr.send("@startuml\n" + pre.innerText + "\n@enduml"); });
アバター
(BASEオフィス内の光景) 初めに こんにちは!BASEでBack-end Engineer Groupに所属している 菊地陽介 です! 今年度からBASEでは世のエンジニアに興味を持ってもらおうと、積極的に技術ブログを発信していこうという運びとなりました。本記事を読んで少しでも興味を持って頂けましたらぜひ 私まで ご連絡ください! さて、私はRedashエヴァンジェリストとしてRedashを社内に普及させましたので、その話について書こうと思います。「Redashって何?」、「Redashサーバってどうやって立てるの?」、「Redashの便利機能は?」などの疑問については先に素晴らしい記事がたくさんありますので、そちらを参考にされてください。 この記事では、Redashをどのように社内に普及させたのかということについて述べたいと思います。 背景 私がBASEに入社したのは、今からちょうど一年前の2017年4月でした。 当時は何か新機能をリリースしても出しっ放しで、効果があったのかなかったのかの検証が十分になされておらず、次のアクションに活かせていないなと感じていました。日々、「なんだか知らないけど今日は数値が良いような気がする」といった漠然とした感想を持つだけでした。 ちょうど、前職でRedashを導入したことで社内に良い影響を与えることができたという成功体験があったので、BASEにも導入して普及させようという運びになりました。またRedashを導入することは、数値分析をしやすくなること以外にも様々な効果が期待できるので本記事でご紹介します。 Redashを導入するメリット Redashを導入することで享受できるメリットは多々あるのですが、特に私が一押しのメリットは下記になります。 非エンジニアがエンジニアに依頼していたデータ抽出が不要になる このようなお互い不毛なやりとりけっこう多く行われているのではないでしょうか。 カスタマーサポートのRさん(以下Rさん): 「ショップAの商品情報一覧が欲しいのですが、データを抽出してもらえないでしょうか?」 頑固エンジニアのHさん(以下Hさん): 「はい、どうぞ」 〜3時間後〜 Rさん: 「ショップBの商品情報一覧が欲しいのですが、データを抽出してもらえないでしょうか?(さっき頼んだばかりだし頼みづらいな、、)」 Hさん: 「はい(またかよ)、今忙しいのであとで渡します」 〜3時間後〜 Rさん: (依頼してから3時間経ったけどまだ忙しいのかな、それとも忘れてるのかな、リマインドした方がいいのかな、、、。あー、めんどくせええ。) それがRedashが普及するとこんなふうになり、業務効率化がはかれます。 Rさん: 「ショップAの商品情報一覧が欲しいのですが、データを抽出してもらえないでしょうか?」 Hさん: 「Redashに任意のショップの商品情報一覧を取得できるクエリを用意したので、これからは自分で抽出できます。」 〜以降〜 Rさん: 「ショップBの商品情報一覧が必要だな。Redashでさくっと抽出しようっと。あー気を遣う必要がなくて楽チン。」 Hさん: 「前まで頻繁にきてたデータ抽出依頼がこなくなったからコーディングに集中できてハッピー。」 BigQueryの高額請求に怯えなくてよくなる BigQueryはクエリが処理したデータ量に応じて課金されるため、うっかり 月に150万溶かす という恐れがあります。それ故に気軽にクエリを叩けないという人も多いのではないでしょうか。私もその一人でした。 しかしRedashでは、強制的にBigQueryのコスト上限設定を適用できるため、不用意にコストのかかるクエリを叩く心配がなくなるのです。 ちなみにこれが前職でRedashを導入した理由でした。 Redash普及のためにやったこと Redashが導入された当初、BASEのslack上にRedashで作ったグラフをアップしたりしてその素晴らしさを共有しようと努めました。しかしみんなの反応は薄く、兼ねてよりRedashに興味を持っていた一部のメンバーが使うだけでした。 世の中には便利なツールがたくさんあるにも関わらず、社内全体に普及するようなツールは少ないように感じています。そもそも新しいツールが普及しない理由としては下記のようなものが挙げられると思います。 そもそも存在を知らない 存在は知っているけどなんだか難しそう 一部の人しか使ってないから使えなくても大丈夫 そこで私はマーケティング理論で有名な「キャズム理論」に思いを馳せ、どうやってキャズムを超えるか考えました。 キャズム理論を応用する 消費者(社員)は下図の5つのグループに分類でき、アーリーマジョリティー層まで普及させることができれば新商品や新サービスは急激に市場に浸透していくと言われています(これはイノベーター理論というやつ)。 (出典: 【キャズム理論】マーケティングの深い溝を乗り越えるには? より引用) しかし、アーリーアダプター層とアーリーマジョリティ層の間(エンジニアと非エンジニアの間)には簡単に超えられない深いキャズム(分かり合えない価値観)が存在し、そこをどうやって超えるかというのが新技術(Redash)が普及するかどうかの大きなポイントになります。 (出典: 【キャズム理論】マーケティングの深い溝を乗り越えるには? より引用) そこで私は、いかにキャズムを超えるかというところに注力しようと心に決め、各部署のコアとなるメンバー(アーリーマジョリティ層)に売り込みにいくことにしました。 ちなみに私が思い描いたイノベータ理論の層と社内のグループの対応表は下記になります。 層 社内のグループ イノベーター層 元からRedashに興味を持っていたメンバー アーリーアダプター層 エンジニア アーリーマジョリティー層 Customer SupportやMarketing、経理・財務のリーダー レイトマジョリティ層 Customer SupportやMarketing、経理・財務のメンバー ラガード層 Customer Experienceのメンバー どのようにRedashを売り込んだか 私は他部署の人がRedashのメリットを最も享受できるのは先に述べた↓であると考えていました。 非エンジニアがエンジニアに依頼していたデータ抽出が不要になる ですので最もデータ抽出を依頼する頻度が高いCustomer Supportのコアメンバーに、定番のデータを抽出するクエリを全て用意して売り込みに行きました。 やはり普段データ抽出依頼にストレスを感じていたようで、すぐにRedashを利用することのメリットを理解してもらえました。同様に普段の業務の中でマーケも法務経理もエンジニアへのデータの抽出依頼が度々発生していたので、各部署のコアメンバーに同じ切り口で売り込みにいき、布教活動に勤しみました。 その後は、私が何も働きかけなくても自動的に社内のあらゆるメンバーに普及していきました。「キャズムを超えた」と感じた瞬間でした。 まとめ Redashが普及した後は「新機能をリリースしたら必ず効果検証しよう」という意識が根付きました。今ではより質の高い効果検証をするためにはどうすれば良いかということをみんな意識するようになり、組織として一段階レベルアップしたなと感じています。他にも「非エンジニアがエンジニアに依頼していたデータ抽出が不要になった」などの業務効率の改善をはかることができ、Redashエヴァンジェリストとしてはやりきったなという思いです。 今回はキャズム理論を応用させてRedashを社内に普及させたかということについて書きましたが、これは他にも応用が効くと思いますので参考にしていただければと思います。 おまけ 社内で新たに一ヶ月で登録されたクエリの数と累積数 Redash普及率80% Redashのアカウント開設数を調べたら80でしたので、BASEチームが約100人であることを考えると普及率は約80%でした。
アバター
こんにちは。 ショッピングアプリ「BASE」 のiOSアプリを担当している 竜口 です。 背景:あの改修の効果測定用のログ、送られてる? ショッピングアプリ「BASE」内で、施策の効果測定やKPIの経過観察で様々なログを使用しているのですが、細かい改修などで特定のログが送られない事象があり、効果測定が出来ずに多部署の作業が止まるということがありました。 そこでアプリ(今回はiOSのみ)でログが正しく送られていることを保証するために、ログのテストをするようにしました。 全体の流れ 次のことをしました。 EarlGreyでUITestを実装 テストの中で送られるログをMockに保持 テスト完了後、Mockにあるログの有無を確認 テストをCircleCIで自動化 これで改修によるログの影響を保証出来るようになります!! 1. EarlGreyでUITestを実装 EarlGrey Reference は、Googleが作っているiOSのUI automation test フレームワークです。 書き方は、簡単で以下の例の場合 UIButton.accessibilityIdentifier に特定のIDを指定して、テストでは selectElement で指定したIDの要素を取得し、要素の有無の確認、要素をタップ等できます。 class ViewController : UIViewController { override func viewDidLoad () { super .viewDidLoad() button.accessibilityIdentifier = "BTN" } } class UIAutomationSpec : XCTestCase { func testTapButton () { EarlGrey .selectElement(with : grey_accessibilityID ( "BTN" )) // 要素を指定 .assert(grey_sufficientlyVisible()) // 存在するかを確認 .perform(grey_tap()) // 指定した要素をタップする } } 2. テストの中で送られるログをMockに保持 UITest内でログを送る際に、Mockにログを保存する処理を追加します。 class ViewController : UIViewController { @IBAction func didTouchUpButton (_ sender : UIButton ) { LogManeger.send(log : Log (name : "tap_button" )) } } struct LogManeger { static func send (log : Log ) { isTest { LogMock.store(log) // Mockに保存 } // Logを送る } static func isTest (_ doForTest : () -> Void ) { #if DEBUG if ProcessInfo.processInfo.environment[ "XCTestConfigurationFilePath" ] != nil && enabledUITest { doForTest() } #endif } } 3. テスト完了後、Mockにあるログの有無を確認 テスト開始前に保証するログを指定して、終わった段階でログが揃っているかを確認する。 class UIAutomationSpec : XCTestCase { override func tearDown () { super .tearDown() LogMock.removeAll() } func testTapButton () { LogMock.addExpect(Log(name : "tap_button" )) // 期待するログを指定 EarlGrey .selectElement(with : grey_accessibilityID ( "BTN" )) .perform(grey_tap()) XCTAssert(LogMock.verify(), "Logが揃っていません。" ) // ログが揃っているか確認 } } 4. テストをCircleCIで自動化 実装したテストをCircleCIで動かすようにして、変更があってもログが送られることを保証できるか確認できるようにしました。 なかでもハマったところがいくつかありましたので紹介します。 ローカル環境では通るけどCircleCIでは通らなかった 一番長く戦った凡ミスです。 ローカル環境で実機確認してテスト通るのに、CircleCIで行うと通らないし何故か画面が真っ黒になっていました。 原因は、ローカル環境とCircleCIで実行している環境が違うので、UITestの結果が環境に依存する場合、結果が変わってしまうことでした。 CircleCIは、どこかの場所でこちらが指定したOS,端末のSimulatorで初回インストールとして起動されテストしています。 なのでローカル環境で確認する時に、CircleCIの環境を揃える必要があり、今回のようにローカル環境で実機確認していると結果が変わる場合があります。 テスト通らなかったのはわかるがなぜ通らなかったのかわからない CircleCIでテスト通らなかった際に、どこの箇所で通らなかったのかはわかりますが、どの画面でなぜ通らなかったかはわかりません。 なので EarlGrey.setFailureHandler(handler: ) で通らなかった時のErrorMessageとその画面のスクショをSlackに送るようにしました。 まとめ まだカバーしてる部分は一部重要機能のみですが、テスト導入し今の所ログの不具合も起こらず、何よりUIの保証も最低限できるので安心して開発できるのが良いです! BASEを日本一のサービスに成長させる仲間を募集しています! BASEでは、Web、アプリ、SRE、データ解析など幅広い職種を募集しています。 ご興味を持った方、カジュアルな面談もできますので、一度オフィスに遊びに来てみませんか? base.ac
アバター
こんにちは、BASE株式会社 BASE Product div サーバーサイドエンジニアの東口です。主にサービスの決済部分とPHP・CakePHPのバージョンアップをしています。 CakePHP2.10.9のリリースに対して、 Koji Tanaka さんと Kazuki Higashiguchi がcontributeいたしました。 Release 2.10.9 · cakephp/cakephp · GitHub 自分自身は、BASEに入社してからCakePHPを仕事で使い始めて半年、初のコントリビュートでした。備忘録としてコントリビュートに至った経緯を残していきます。 何をしたのか Release 2.10.9 · cakephp/cakephp · GitHub を引用すると下記のBugFixを行いました。 CakeTestCase::getMockForModel() now correctly handles secondary connections. github.com だいたいの流れ きっかけは、テストコードを書いていた際になぜか意図しない挙動をすることに同僚が出くわしたことでした。 実際に起きていたことはIssueに書いた内容ですが、テストケース内で、メインではないDBに接続するModelをmockするメソッドを使用した際に下記のエラーが発生していました。 MissingConnectionException: Database connection "Mysql" is missing, or could not be created. Issueを出すところまで、既にプルリクを何度も送っている同僚の Koji Tanaka さんにざっくり教えてもらいながらやりました。おおまかな流れは以下です。 調査 いけそうな修正方針決める Issueを出す 機能修正する テストを修正する Pull Requestを出す マージしてもらう 今回は、既にテストコードが書いてあり通っていたのでなぜ通っているのかという原因調査が少し大変でした。 マージされた phperkaigiの裏でこつこつ出してたcakephp本体へのcontributeが通った^-^ — kazuki.higashiguchi (@Khigashiguchi) 2018年3月10日 今回のバグの原因調査にあたり、中のコード読んだりデバッグログを仕込んだりしているうちにCakePHPの中身が見えてきたのが良かったです。 最後に 今回のcontributeはちょっとしたBug Fixでしたが、今後も自社が使っているOSSが発展していくようコントリビュート頑張っていきます! エンジニア募集中 BASE株式会社では、OSSにコントリビュートしていきたいエンジニアの方募集中です! jobs.binc.jp
アバター
BASE Back-End Engineerの田中 ( @tenkoma )です。アプリケーションのPHPアップデートなどを担当しています。 3/14 (水)に開催された技術勉強会ヒカ☆ラボにて、アプリケーションで利用しているPHP/CakePHPアップデートの取り組みについて発表しました。 【 ヒカ☆ラボ 】【Laravel5、CakePHP3など】ベンチャー企業のリアルなPHP事情 : ATND サービスの裏側の話であり、今まで特に公開はしていませんでしたが、機会をいただいたのでこれまでの取り組みを振り返ることにもなると思い、発表することにしました。 BASEのPHPアプリケーションは2016年末までほぼPHP 5.3で動作していました。2017年にPHP/CakePHPのアップデートを推し進めるプロジェクトが立ち上がり、アプリごとに段階的にアップデートをリリースしています。 今回の発表では何を・どの順番でアップデート作業したかをお話しいたしました。同様のプロジェクトを検討中、実施中の方の参考になれば幸いです。 登壇資料 BASE の PHP アプリ アップデートについて // Speaker Deck エンジニア募集中! BASE株式会社ではモダンな開発環境をつくっていくエンジニアを募集しています。 jobs.binc.jp
アバター
こんにちは、BASE株式会社 BASE Product div サーバーサイドエンジニアの東口です。主にサービスの決済部分とPHP・CakePHPのバージョンアップをしています。 下記の記事でも公開いたしましたが、BASE株式会社はPHPerKaigi 2018にプラチナスポンサーとして協賛いたしました。 devblog.thebase.in また、私自身もLTを採択いただいたので、スポンサー担当者兼LTスピーカーとして参加いたしました。 PHPerKaigi 2018 phperkaigi.jp  PHPerKaigi 2018は今年初開催のPHPエンジニアのためのカンファレンスです。 TrackA・Bの2つレーンがあり、TrackAがトーク、TrackBはコミュニケーション中心の企画が行われていました。   トークが1レーンだったこともあり、みなさんレベルの高い厳選されたトーク内容でした!また、TrackBで行われた「Interactive Round Table」等のコミュニケーションの場もとても盛り上がっていました。 会場の様子 TrackAを行っていたメイン会場の雰囲気です。 TrackAの様子 スピーカーが登壇する場所には豪華なバックパネル 会場には、PHPerKaigi 2018とスポンサー各社のロゴが乗ったバナーが設置されていました。 会場バナー また、参加者全員にカンファレンスのハンドバッグが配布され、弊社は5周年ノベルティ・ステッカー・チラシの3つを配布させていただきました。 5周年ノベルティ・ステッカー・チラシ LTの内容 私も恐縮ながら「レビューをもらいやすい細かいプルリクの切り分け方」というタイトルで発表させていただきました。 発表中の様子 普段、やっている人は無意識のうちにやっているけどそれに対するノウハウが無いなと感じていたので、改めて整理したという内容です。 スポンサー担当をしてよかったこと ここからは、私個人が申込から当日まで一貫してスポンサー担当をしていてよかったと思うことです。 カンファレンスに対する主体的な達成感がある スポンサー担当者として参加すると、 カンファレンス成功 = スポンサーをしたことの成功 になるので、主体的に取り組むことになると思います。 当日までのスポンサー準備も含めて、カンファレンスが無事終わった際に「やり遂げたぞ!」という達成感がありました。もちろん、運営されているスタッフの方々の大変さに比べれば大変さはそこまでですが、一人の参加者として参加していた時とは違う気持ちの良い達成感が有りました。 ディレクションの経験になる カンファレンスのスポンサー窓口をされている方とのやり取りや配布物などの準備の段取り、制作が必要であればデザイナーチームとの連携が必要になります。カンファレンス当日に向けてToDoを整理して進行していくため、普段開発のみの方であればディレクターと呼ばれるような方が行っているお仕事を体験できます。 最後に 今回は、記念すべき第一回開催にスポンサーとしてPHPerKaigi 2018に貢献出来たことを光栄に思います。 引き続き、PHPコミュニティの発展に貢献していきます。 エンジニア募集 BASE株式会社では、PHPerを募集しています! jobs.binc.jp
アバター
Androidアプリエンジニアの鈴木 ( G_devi ) です。 今まで何回かDroidKaigiに参加はしていたのですが、今回の DroidKaigi2018 は初めてスタッフとして参加させていただきました。 その中で、運営・進め方・情報管理・当日の動き・臨機応変な対応など、いろいろとすごいなーとか、このやり方いいなーとか思ったことがあったのでお伝えしたいと思います。(書ける範囲で) すごかったこと・いいなと思ったやり方etc... どれが一番とか選べないので順番は特に関係ないです globalチームがある 簡単に言うと、英訳してもらいたい文をここにお願いすると分かる人が翻訳してくれる感じです。 DroidKaigiは海外からも参加者や登壇者が来ますし、グローバルな対応が必要になってくるので何にでも英語が必要となります。 登壇者とのメールのやりとり、アンケートなど全体に投げるもの、海外サービス(Sessionizeなど)への質問など英語を用いるところはたくさんあるのですが、担当している人が必ずしも英語ができるわけではありません。(自分もできません) slackの専用のchannelで英訳できる人のグループ(@english)宛に、こんな用途でいつまでにお願いしたいという感じで投げると、誰かがシュッと英訳してくれるという初めて見たときは感動するような流れ! 何よりみんなslackを使い慣れているので引用など諸々見やすく投げるし、感謝と謝罪もキッチリしているし、緊急度と重要度をみんながある程度把握しているため流れがいい。 こんなに素晴らしい流れができてる企業とかないんじゃないか?と思ったくらいです。 こういうのほしいなーという話が出たら誰かが作り始める 多分、いろいろ作られてたとは思うけどとりあえずパッと思い出したのは一つ。 github issueのMilestoneからもうすぐ期限が来そうなものをまとめてslackに投げて教えてくれるというもの。 全体で見ると結構な数のissueが作成されてるうえ、期限遵守しなくてはいけないものもあるため非常に見やすく気づきやすく素晴らしかった。 恐らくスタッフの大半が簡単なスクリプトを書いてシュッと投げるくらいのものはそれほど手間なくできると思うので、誰かに作業が集中してしまわないのが素晴らしい。まあ、忙しい人ほど自分で作ってちゃっちゃと済ませちゃうものな気がするけども。 用語集がある まぁ、当然ですよね? ただこれがちゃんと存在してないと認識のズレや時間のムダにつながるのであることはとても重要だと思います。 用語が増えてきてメンテできずに人によって呼び方が違うものとか増えてくる現場にいた経験をするともう。。。 リアルタイムKPT KPTを雑に書き込めるchannelがある。 確かに、思ったことはその場ですぐに記載したほうがいいですね。 DroidKaigi本番中もちょくちょく書き込まれていて、みんな結構slackのチェック頻度が高かったりもあるので、それを見て参考にもできるしとても良かったと思いました。 今更ながら、何でよくあるKPTの集まりでは時間区切って思い出しつつ書き出すことをするのだろうと。。 あのやり方だと後でこれもあったなと思うことが結構あるんですよね。 当然ながらslackに書き込んで終わりではなく、後で別途まとめると思いますが。 担当ごとに書き込むためのissueもありますし。 当日のインカム運用 当日はスタッフ全員がインカムをつけて緊急時の案内や共有などを行っていた。 slackでいいじゃんと思っていたが、結構動き回ってるうえ一般の人よりチェック頻度が高いと言ってもやはりリアルタイム音声連絡の便利さには敵わないものがありますね。 特に参加者から質問などを受けて自分が分からないときなどは急ぐ必要があるので非常に良かったです。 正直、撤収の途中からインカムを外したら不安になるし聞きたいことあるときに不便だなと思いました。 去年は全員がつけていたわけではなかったようなので、うまく改善がされていってるんだなという印象も受けました。 ただ、どうしても聞き取りづらいというのはよくあるので、いずれgoogle glassをつけて追加でも文字でも見れるようになるといいな〜。 2段階認証 当然だがキッチリしている。 当然ながら外に出せない情報もあるので重要なところですね。 何よりまだ設定していない人に対するリマインドがしっかりしていてよかったと思います。 最新情報の重要性の理解度 みんながみんな、情報が最新であることの重要性を強く認識しているため古い情報を見てズレたことをしてしまうという状況がほぼなかったと思う。 特に、セッションの司会や補助の割り当ては当日中にもちょくちょく更新されたので全員が最新情報をきちんと確認する必要があったが、通知もしっかりしていましたが問題なくみんなチェックしていたようでスムーズでした。 あとは、マニュアル類も都度更新されたりするのでそのチェックも重要でしたがデジタル主体の人が多いとなんと楽なことかと。(やはり便利なので印刷したものもありましたが) とりあえず手軽にgoogle docsは便利ですよね。 スタッフ用アプリ なんと、スタッフが利用するアプリも作られていたのです! マニュアル類へのリンク、Slack起動、Twitterで#DroidKaigi検索、各自の行動予定表、各ルームの進行中・休憩中表示の切り替え、そして何よりプッシュ通知でみんなへの連絡事項が文字で送られてくるというのは便利でした。(ちなみに最後の通知は打ち上げ会場についてでしたw) 半分くらい(?)はスタッフ初参加なようなので、このようにこれを開けばなんとかなるというものがあると迷わずに便利に動けて素晴らしかったです。 各種マニュアルの完成度 各種マニュアルの完成度がハンパないです! 上にも書いたように初めての人が多いというのもありますが、とりあえずこれを見れば大体のことは迷わずできるというレベルで作成されていました。 当日のことだけでなく、準備や撤収に関してもマニュアル化されているので非常に動きやすかったです。 しかも、こういうことも必要ではないかという話が出るとすぐに更新されて通知がくるのがまた素晴らしかったです。 いろいろな面で見習いたいところ。 責任の所在が明らか 全体、そして各担当の責任者が明確で(状況によって変わったりもありますが)その人に質問すれば大体何とかなるという状況。 もちろん質問だらけにならないようにいろいろ記載されているものがあるのですが。 何か発生した際の線引(これはやる。やらないなど)がすぐに分かるというのは素晴らしかったです。 まぁ、これもエンジニアらしく反応速度が早いからうまく回ってるというのもありますが。 やばい問題が起こらないように、そして確実に間に合わせるためにきっちりと内容を把握している責任者がハンドリングしているのは素晴らしかったです。 責任者が自分の担当範囲をキッチリ把握している。できない場合でも周りがフォローできるという体制は普通なようでなかなかできてなかったりしますからね。 受付アプリまで作られている ついに1000人規模になったDroidKaigiですが、その人数の受付を回すとなるとものすごく大変なのは目に見えている。 参加者が提示したQRコードをスタッフの受付アプリで読み取ることによってスムーズな受付が可能だった模様。 "模様"というのも、自分は受付時に別の作業をしていたので現場は見ていないもので。。。 ただ、この辺も前回の反省を踏まえて作るという流れがいいですね。 何より特別な機器を用いなくてもスマホのカメラで可能であり、そのアプリをシュッと作れる人たちというのが強い。 ミーティングはハングアウトでも参加可能 スタッフもほとんどの人が普段の仕事をしているうえで夜に集まるので、どうしても参加できない人もいる。 また遠方の人もいるので、行くことはできないけどハングアウトで参加できるというのはすごく便利。 あと、議案・議事録もしっかりしているため参加できなかったとしてもある程度はきちんと把握できるようになっていました。 (自分もいろいろあってあんまりミーティングの場に行けなかったので非常によかった) 直接会って話すというのも重要なのですが、普段テキストベースでのやり取りに慣れている人が多いのもあり、議事録のチェックでも情報格差がそれほど発生しないようになっているのは非常によかったです。 経緯はともかく結果はしっかりとどこかに明記されているので。 そして、それほど回数も時間も確保できるわけではないのでミーティングのための準備もしっかり行われており、極力無駄な時間を使わないようにしていたのが素晴らしかったです。 これも非常に見習っていきたいところです。 急遽対応すべきことが発生したときの流れが良い 1000人もの人を動かすと、予期できなかったことなどが発生し急遽対応を入れたりします。 うまく人を流すために誘導を配置する必要がでてきたなど。 その作業タイミングで手が空いていそうな人をみつけ簡単に流れを説明するだけで動けるのは非常に良かったです。 何か分からないことがあればインカムで聞けますし。 エンジニアだからとは必ずしも言えないですが、ある程度自分で考えて行動できる人が多かったように思えます。 オープニング動画がかっこいい!!! これはしびれた (まぁ、自分は準備でウェルカムトーク出てないし終わってから見たんですが) www.youtube.com その他感想 ひたすらに物理作業がツライ!!! 普段座ってばかりいる自分なので、、前日の電源を机に配置してテープで足をひっかけないように留めていく作業で疲労困憊。 セッションの司会補助で立ち続けてるだけでも脚がプルプル。 撤収作業で疲労困憊。 最初のほうは緊張もあり相当疲れました。 やはり体力は必要だなーと。 朝が早い! と言っても、8:50厳守なので一般的に見たらそんなに早くはないのですが。 自分は朝に弱すぎるうえ、疲労困憊なので本当に心配でした。。 現地が西新宿で家が池袋なので結構近いのに本気で現地近くに泊まろうかと考えていました。 けど、参加者も泊まる人多いでしょうし、そんな近くに宿泊施設が多そうに見えなかったので断念。 少し歩けばいくらでもあるだろうけどそれなら帰っても変わらないかなーと。 最終的に知り合いに電話で起こしてもらうというリスクヘッジをして何とか乗り切りました。 スタッフの顔と名前が分からない。一致しない。 自分がミーティングにあまり参加できなかったというのもありますが、当日結構みんな初めましてという感じが多かったです。 slackやtwitterのアイコンや表示名は分かるけども実際の人と結びつかないというのはよくありますよねー。 人が増えてくると会社でもそうだったりしますよねー。 とはいえ、それでもうまく回るような感じではあったのですが、やはり顔と名前が一致するとだいぶやりやすくはなると思います。 (覚えるの苦手なんですが。。。) あと、みんなほとんどslackの表示名で呼んでいるのですが、どう読むのか分からなかったりw スタッフ打ち上げ会場に人権(ネット接続環境)がなかった… ほぼネット前提であるAndroidのイベントスタッフの打ち上げにこの状況は驚きましたねw 地下だったのもあり電波がほぼ届かず、現地WiFiもなかったです。(あったとしてもこれだけアクティブな人が80人?くらい集まってたらパンクするでしょうが…) まだ外部と連絡とる必要のある人もいたでしょうしせめて繋がる環境だったほうがよかったのでは?とは思いました。 何より自分が欲しかった。。。w 最後に 個人的に非常に為になり、参考になり、楽しかったです。 他にも良かったと思うところはたくさんあるのですが、とりあえずパッと思いつくところを書きました。 やってみたい人や組織運営に悩んでる人なども一度スタッフとして参加してみると為になるかと思います。 元の仕事や準備など諸々で時間がなくアプリ開発のほうには関われなかったのが残念だったので、来年は多少手を付けられるといいなと思いました。 スタッフのみなさん、登壇者のみなさん、そして参加者のみなさん、ありがとうございました!! (文字だけで寂しいのでスタッフ名札写真でも載せようと思ったら無くしてしまったようだ…泣)
アバター
こんにちは、BASE株式会社 エンジニアの東口です。主にサービスの決済部分を担当しています。 この度、BASE株式会社は、 PHPerKaigi 2018 にプラチナスポンサーとして協賛いたします。 phperkaigi.jp PHPerKaigi(ペチパーカイギ)は、現在PHPを使用している、過去にPHPを使用していた、これからPHPを使いたいと思っているエンジニアが、技術的なノウハウを共有するためのカンファレンス(イベント)です。 BASEは、サーバーサイドの大部分をPHPを使って構築しているため、この機会を通してPHPのコミュニティ発展に貢献できればという想いから協賛を決めました。 私自身も レビューをもらいやすい細かいプルリクの切り分け方 | PHPerKaigi 2018 というタイトルで発表いたします。 カンファレンス当日は、皆様にノベルティを配布させていただいたり、弊社エンジニアも参加いたしますので、ぜひお気軽にお声掛け下さい。 イベント概要 日時 2018年3月9日(金)〜3月10日(土) 場所 練馬区立区民・産業プラザ Coconeriホール 主催 PHPerKaigi 2018実行委員会 (実行委員長: 長谷川智希 / @tomzoh) 公式HP: https://phperkaigi.jp/2018/
アバター
はじめまして、2017年9月に入社したBack-End Engineer の田中です。アプリケーションが使うPHP/CakePHPのバージョンアップを担当しています。 BASE ではサーバーサイドアプリケーションの大部分が CakePHP2 を使って構築されています。 日常的にCookbookやCakePHPコアのコードを読んでいて、時々typoや不具合を見つけてはプルリクエストを送っています。 PHP 7.2 でテストスイートをパスさせる 修正もしたので、PHP7.2 でも動くはずです。 CakePHPユーザーの方で、ドキュメントにtypoを見つけたことはありませんか? ドキュメントへの貢献についてのページ を読むと、まずはメールを送る必要があるようなことが書いてあり面倒そうに思えますが、実際のところプロジェクトがGitHubに移行してからはいきなりプルリクエストを送っても問題ないようになっています。この記事ではドキュメントをPCで修正してプルリクエストを送る方法を説明します。 この記事の内容は2018/02/08にランサーズ株式会社で開催された CakePHPクックブックを直してみよう勉強会 - connpass で解説した内容に多少の修正を加えたものです。 CakePHP のドキュメントを直す CakePHP Cookbook 日本語ドキュメント はボランティアベースで翻訳されています。 翻訳率はかなり高いですが、typoや読み取りづらい部分が見つかることがあります。 CookbookはGitHubでホストされているので、GitHubアカウントさえあれば、修正してプルリクエストすることができます。以下の記事をご覧ください。 3分でできるCakePHP公式ドキュメントの誤訳を直す方法 - Qiita こちらの方法だと、PCにリポジトリをコピーしなくてもよいので、簡単に修正依頼できますが、表示確認ができません。 マークアップやサンプルコードを含めて修正するときは、表示確認したくなります。 その場合はローカルPCで作業する必要がありますのでその方法を説明します。 目次 リポジトリをコピーして作業を始めるまで テキストを修正してローカルビルドする プルリクエストを作成する 補足 リポジトリをコピーして作業を始めるまで 事前の準備として git インストールとSSH鍵の設定が必要です。以下の記事が参考になります。 monsat.hatenablog.com 準備が終わったら、 Cookbook 用のリポジトリにアクセスします。 github.com ページ右上にある Fork ボタンを押しましょう。 そうすると、自分専用のリポジトリが作成されます。 github.com 次にリポジトリをローカルPCにクローンします。 [your-name] はあなたのGitHubアカウント名に置き換えてください。 $ mkdir -p ~/src/github.com/cakephp $ git clone git@github.com:[your-name]/docs.git ~/src/github.com/cakephp/docs 常に最新のソースファイルから作業に着手するために、オリジナルのリポジトリを upstream として登録しておきます。 $ git remote add upstream git@github.com:cakephp/docs.git 最後にDocker をインストールします。ドキュメントをビルドするために必要な環境を簡単に構築できるようになっていますので、手元のPCにインストールしてください。 Docker Store から、お使いのPCのプラットフォーム向けインストーラをダウンロードして、インストールしてください。 https://store.docker.com/search?type=edition&offering=community テキストを修正してローカルビルドする まずは、手元でドキュメントをビルドして、ブラウザで確認してみましょう。以下のコマンドを実行します。 $ cd ~/src/github.com/cakephp/docs $ docker build -t cakephp/docs . $ docker run -it --rm -v $(pwd):/data cakephp/docs make html-ja 2行目の docker build ... でビルドに必要なツールをインストールして、3行目の docker run ... でビルドします。 生成されたWebページは build/html/ja ディレクトリ以下にあります。 build/html/ja/index.html をブラウザで開くと生成されたドキュメントを確認できます。 次にドキュメントのソースを修正します。今回はCakePHP3 Cookbook で見つけたtypoを修正してみましょう。 *1 upstream/3.0 *2 からブランチを作成します。 # オリジナルのリポジトリの状態をローカルに取得します $ git checkout 3.0 $ git fetch upstream $ git merge upstream/3.0 $ git checkout -b fix-ja-console Switched to a new branch 'fix-ja-console' ソースを開いて修正します。ドキュメントソースの reStructuredText形式 に対応しているエディタを使うのがよいでしょう。以下はPhpStormでの例です。 直したらビルドします。 $ docker run -it --rm -v $(pwd):/data cakephp/docs make html-ja 2回目以降は docker build 不要です。 表示が確認できたらコミットします。英語である必要がありますが、typoなら 「Fix typo」でOKです。 $ git commit -am '[ja]Fix typo' プルリクエストを作成する あとは、ブランチをプッシュして、プルリクエストをつくるだけです。 $ git push origin fix-ja-console cakephp/docs: CakePHP CookBook を開くとプッシュしたブランチが表示されるので「Compare & pull request」を押し、「Create pull request」を押すとプルリクエストが作られます。 *3 github.com あとはマージしてもらえるのを待ちましょう。 補足 日本語以外の版もビルドしたい場合は以下のコマンドを実行します。 # 英語 $ docker run -it --rm -v $(pwd):/data cakephp/docs make html-en # すべての言語 $ docker run -it --rm -v $(pwd):/data cakephp/docs make html エンジニア募集 BASEではECプラットフォームを一緒に作ったりCakePHPにコントリビュートしたいエンジニアを募集しています! 採用情報 | BASE株式会社 *1 : typo程度ならローカル作業不要ですが、修正箇所を見つけてないので… *2 : 3系の最新版のドキュメントでも 3.0 ブランチを更新していきます *3 : 2コミット以上のプルリクエストだと、プルリクエストのデフォルトタイトルがブランチ名になってしまうので、「[ja]Fix typo」などに変更しておきます
アバター
CTOの藤川です。今回、デブサミにお誘いいただいて登壇させていただくことなりました。 初日 2/15の13:05~13:50の回でE会場とのことです。 BASE社におけるフィンテックへの取り組み 今回お話しようと思ってるプレゼンテーションに類するお話に、以前、情報処理学会の学会誌にフィンテックについての寄稿をさせていただいたことがあります。 フィンテック:3.フィンテックスタートアップのビジネスモデルFintech:3. Business Model of Fintech こちらではさすがに自社の自慢話をするのは難しかったので、freeeさん、マネーフォワードさんのアカウントアグリゲーションのビジネスから始まり、何が重要か?という部分でメルカリさんの事例を挙げさせていただきました。 まだ、当時はメルカリとフィンテックの繋がりというのはあまり着目されていなかったタイミングでの寄稿だったと思っています。 メルカリさんの例で書いていたのは、要はポイント経済圏のことなわけですが、フィンテックと呼ばれるサービスは、Webサービスを通じなんらかしらの経済合理性や集客力を金融事業に結びつけていく試みですので、その部分を抽象化して、沢山の方々のビジネスに対する共感をいただくことは可能だと思います。 なので、そこについては聴講者の方々には、絶対に損をさせないようにしますってのがまず大前提として。 (我ながらタイトルがいまいちでしたね。BASEのPRみたいなタイトルにしてしまったし、何か特別なことをやってるようなタイトルにしてしまった。それでもお申込みが満員のようで感謝です。) もう一つは、確かにBASEのPR面の野望はありまして、採用面接をしている時に、無料ECのプラットフォーム事業者という認識はあっても、フィンテック企業だという認知はほとんど得ておらず、しっかり面接でお話することで、我々の狙いを理解いただくことで会社に興味を持っていただくということが多いです。 逆を言えば、1時間、話をしなければ、我々の魅力を知っていただけてないということになり、それでは転職市場に対しても強烈な機会損失をしていると考えられます。 その部分の認知を変えたいというのもあります。 無料EC自体は、これまで沢山の会社がやってきていますし、ショッピングカートのUIのパラダイムもずっと変わっていないし、敵と思わしき企業はビジネスが完成された会社ばかりで、ある意味、ECプラットフォーム市場はコモディティ化していいると言っても過言でないでしょう。 なのに何故、今更ECなの?となるわけですよね。 わかります。 SNSやゲームなどのネットワーク性が前面に出ているサービスと比べても、ただのツールという感覚が強いのかなと思います。そもそも決済やEC業界が好きだという人でなければ、あまり魅力的なサービスのように見えない部分もあります。 一方でEC業界の玄人のおじさん達に言わせると「こんなビジネススキームで儲かるわけがない」となるわけです。 BASEのサービスデザインにおいて、無料ECという仕組みは情報発信プラットフォームの一つであり、BASEという名前からもなんとなく感じ取れるかもしれないですが、インターネット的な世界を作りたいという社会変革を目指したグランドデザインの方にビジネスとしての主眼があります。 会社としての理念が、「価値の交換をシンプルに。世界中の人々が最適な経済活動を行える社会へ」という抽象概念で語られているのは、そこにポイントがあります。 何故、BASEは無料でいいのか?という部分にこそ、他社の有料サービスが考えているビジネスモデルとは違う思想が存在しており、それこそがフィンテック企業として注目いただいている肝になっております。 僕が面接で使うメタファは、銀行で通帳を作る時の「口座維持手数料」って無料ですよね?それ単体だと銀行だって赤字ですよね?BASEも同じなんですよ、というところなんですが、当然我々は銀行ではないのですから、Webサービス企業としての「BASE」がビジネスとして成立するための世界観を、どううまく伝えられるか、そんなあたりにチャレンジしていきたいと思います。(書いててプレッシャーが...) 要は、フィンテックベンチャーの肝は「ただの家計簿アプリ」「ただのフリマアプリ」「ただのネットショップ構築サービス」「ただの決済サービス」ではないんですよ!、、、、ってところなんで、その辺の整理をしていけたらいいし、そのプレゼンテーションを通じて、フィンテックへの魅力を伝えられて、聴講者の方のビジネスにメリットを提供できれば幸いです。 あ、HRの方で採用ページを作ったそうなので、是非見てみてください! jobs.binc.jp
アバター