TECH PLAY

Wedding Park/ウエディングパーク

Wedding Park/ウエディングパーク の技術ブログ

206

こんにちは。新卒2年目エンジニアのダテです。 今年も4月半ば〜7月にかけて新卒エンジニア研修を実施しました。 今年は、新卒研修の定義〜内容を考え直すリニューアルプロジェクトを行いました。 今回はその研修リニューアルプロジェクトの裏側をPMを努めた自分からお話したいと思います! 目次 研修の目的を再定義 目的や基礎知識の細分化 昨年までの研修と細分化した目的の比較 変更点の紹介 まとめ 研修の目的を再定義 研修内容をリニューアルするにあたり、最初に行ったのが研修での目的を再定義することです。 昨年までは「新卒エンジニアの即戦力化」を目的に研修が行われていました。 今回も、「即戦力化」という点は引き続き研修の目的として考えていました。 ただ、新卒がどのような状態になっていれば「即戦力」なのかがフワッとしていたので、「即戦力」の状態をプロジェクトメンバーで話し合い、決まった内容を研修の目的として再定義しました。 再定義した研修の目的は下記の2つになります。 エンジニアとしての基礎知識を獲得できていること 配属先チームにて、開発工数3人日程度の案件に対して不安なくチャレンジができる状態 研修の目的のうち、案件に対する不安は技術に対する不安と通ずる要素が大きいため、 今回の研修リニューアルでは「エンジニアとしての基礎知識を獲得すること」に注力 していくことに決めました。 目的や基礎知識の細分化 続いて行ったのが、上記で定めた研修目的の細分化です。 研修の目的として定めた「エンジニアとしての基礎知識」のままでは抽象的だったため、研修内容を考えられる粒度まで「基礎知識の細分化」を行いました。 細分化は「 ここまで知っていれば案件に取り組める 」という軸で、弊社で利用している各言語、プロダクトを運営していく上で必要な知識(セキュリティ、パフォーマンス等)それぞれで行いました。 細分化の作業は、プロジェクトメンバーに加えて、各技術において専門的な知識を持っているエンジニアにもヒアリングを行ったりしながら総力戦で進めていきました。 以下は細分化を進めている時の表の一部です。 各技術の基礎知識を細分化したことで、それまでふわっとしていた研修のゴールイメージがぐっと具体的になりました。 また、個人的にも細分化したものをすべて理解できているか?と当時の自分を振り返る機会にもなりましたのでプロジェクト的にも、個人的にもとても重要な時間だったと思います。 昨年までの研修と細分化した内容の比較 細分化作業を終えたのち、具体的に研修内容を考えていくフェーズに入っていきました。 今回の研修リニューアルは 昨年までの良い点を残しつつ、変えたほうが良さそうな部分を重点的に変える方針 で進めていきました。 理由としては、上記の細分化作業をする中で、「ここらへんは昨年までの研修でしっかりと教えてもらっていたな」というシーンが多く見られたので、全てを変えるよりも良いところは残しつつ変えるべきところを変えたほうが良い効果が期待できると考えたからです。 昨年までの各エンジニア研修の内容と細分化した内容を一つ一つ照らし合わせて、 「変えた方が良さそうなところ」「昨年までの研修でも十分だけど、変えたらもっと良くなりそうなところ」 を洗い出し、プロジェクトメンバーでどのような研修内容にすればよいかを話し合っていきました。 変更点の紹介 今回は上記の比較のもと、大きく変更したものを2つ紹介したいと思います! 1つ目は オンライン教材の利用 です。 今回、PHP(Laravel), Go言語, MySQLといった弊社で利用している言語の研修でオンライン教材の ドットインストール を利用しました。 ドットインストールは数多くの言語をサポートしており、基本的な言語知識に関するレッスンに加えて、webサービスを開発できるレッスンも用意されています。 ドットインストールを採用した理由も、 弊社で利用している各言語のレッスンが体系的に用意されていた からです。 加えて、各レッスンの最初に 開発環境のセットアップについて丁寧に説明されている点 も採用した理由になります。 開発環境のセットアップについては、毎年時間を取られることが多く研修担当者からも「苦労した」という声が上がっていたので、学習の質を担保しつつ、担当者の負担を軽減することができるのは大きなメリットがあると考えました。 2つ目の変更点は チーム開発の前倒し です。 昨年までチーム開発研修前に行っていたWedding Parkサイトの改善提案を行う研修をなくしました。Wedding Parkは15年以上運営している大規模サイトのため、小さな変更でも影響範囲が大きくなります。 そうすると、期間や技術などの問題で改善提案が小規模になってしまうことがしばしばありました。 そこで、チーム開発研修を前倒しして、学んだ言語の基本を最大限活用して自由に開発を行うことで、学びの質の最大化を図りました。 チーム開発研修の全社向けのプレゼン会では、全社から拍手喝采をもらうほどのアウトプットをしてくれました! チーム開発での学びについて 新卒が執筆してくれる記事 も公開してます! まとめ 今回は、今年の研修をどのように作ったのかの過程の話をしました。 研修リニューアルプロジェクトの過程で一番良かったと感じているのは「 基礎知識の細分化 」の過程です。 細分化したことで今年の研修を考える上で昨年と比較がしやすくなったのはもちろんですが、 細分化した基礎知識は来年以降の研修を変えるとなった時にも使える 定義ができたと思いますし、 若手エンジニアが自分の技術を見直す軸 にもなったと思います。 ただ、技術はどんどん進歩していくので都度更新しながら、弊社における「基礎知識」を定義し続けられればと思います!  
アバター
こんにちは。新卒1年目エンジニアのririです。 私は新卒研修の一環で5月から約3ヶ月間、合同開発に取り組みました。 今回は、企画・仕様フェーズに焦点を当てて、やってよかったこと・苦労したことをまとめました。これから企画・仕様書作成にチャレンジする!という方の参考になれば幸いです。 目次 新卒合同開発について 企画書作成 仕様書作成 おまけ:サービス名 まとめ 新卒合同開発について まず、新卒合同開発とは何かについて説明します。 入社して基礎的な研修を受けた後、新卒クリエイターチーム(エンジニア2人、デザイナー1人)で、約2ヶ月間合同開発を行いました。お題は、 Googleスライドで管理している社員のプロフィール(自己紹介&仕事紹介)をシステム化する というものです。コンセプトを0から練り、4日間で企画書作成・決裁、3日間で仕様書作成・決裁を行いました。 企画書作成 どんな方向性で、何を実現するのか?それは本当に仕事としてやる意義があるのか? という点をまとめ、決裁をもらうために企画書を書きました。具体的には、与えられたお題をもとに、背景の整理、実際に作るシステムのコンセプトと全体像、想定効果を盛り込みました。 やってよかったこと  1. アンケートを実施し、現状の課題感を把握した 社員の方々に使い心地・使う頻度、感じている価値などをアンケートすることで、 現状の課題を具体的に把握 することができました。また、企画書プレゼンの際にも、 明確な根拠を持って「やる意義」を示す ことができました。 2. そのサービスが使われた先、どんな状態になっているのか?まで想像した 「今この課題があるから、解決します!」で終わらず、 「課題解決することで生み出される価値とは何か?」 まで考えました。 今回は、システム化することで利便性を向上し、その上で「社員が誰かとの共通点を見つけにいくことを促し、心の距離を縮めることができる」という価値の創造を目指しました。それをプロダクトのコンセプトとして落とし込むことで、納得感のある企画書になりました。 (企画書の一部※一部改変して掲載) 3. 企画提案時には簡単なプロトタイプを作成し、イメージを具体的に伝えた 企画書では提案した背景やコンセプトだけでなく、簡単なプロトタイプを作成し、現時点で考えているシステムの全体像も伝えました。その結果、機能を実現する上で考慮すべき点など現実的かつ具体的なフィードバックをもらうことができました。 苦労したこと 1. 事実と仮説の切り分け 現状を整理するためにアンケートを実施したものの、その結果からわかる事実と仮説の切り分けが難しかったです。 事実 :数値でわかること(数・割合) 仮説 :事実をもとに、本当はどうあって欲しいのか?を推測すること 話し合いを進める中で認識の違いに気づき、先輩ディレクターに質問することで解決できたため、認識が揃った状態で議論を進めることができました。悩んだら とりあえず先輩に聞いてみる! がオススメです。 2. 今あるモノの良さを、どうシステム上で残すか? プロフィールスライドに関しては「利便性はイマイチだけど、社員が自由にアレンジできる」という特徴があり、そこに社員の個性が表れていました。 企画の決裁においては、 入力形式が決まっているシステム上では、操作の自由性・社員の個性が失われてしまう負の側面も考慮しなければならない、 という点をご指摘いただきました。 作って終わりではなく、使ってもらって初めて価値が生まれます。システムによる制約があっても 「こんなのだったら自然と見たくなる、楽しくなるもの」 を徹底分析しました。 最終的に、プロフィール表示画面にスライドショー形式のコーナーを作り、「使いたい!他の人のも見たい!」となるような仕掛けを作りました。 (企画書の一部※一部改変して掲載)   仕様書作成 企画の決裁をいただいた後、仕様書作成に向けてシステムの細部を検討しました。 研修期間中、新卒クリエイター同士一番密度濃く議論したのは仕様書作成のときでした。 やってよかったこと 1. 仕様書で説明する項目について、あらかじめ共通認識を合わせる 今回は分担して資料作成することになったため、検討事項に漏れがないよう、以下の項目を設定してチーム内で認識を合わせました。 表示条件 …その画面・対象が表示される条件 処理条件 …考えられる処理とその条件 入力項目/表示項目 …入力フォームの項目/表示される項目の形式などを定義 押下アクション …ボタンや入力欄などのアクションを定義 テスト観点 …どのようなことをテストするか(画面単位で記しました) その結果、「このページではこの項目に触れているのに、他のページでは触れてない」といった漏れが少なく済みました。 2. 指摘箇所の差分をわかりやすく表示 フィードバックをもとに仕様を修正した際は、変更前・変更後を比較しやすい資料づくりを心がけました。仕様書のページ数も多かったため、前回どんな指摘を受けて、どんな変更をしたのか?をわかりやすくまとめてよかったです。 苦労したこと 1. 膨大な検討項目を短い時間でまとめきること 仕様を決めるにあたって検討すべき項目がたくさんあり、話し合いながら資料に落とし込むことが大変でした。後の開発フェーズでも実感したのですが、以下の項目は特に、この段階で十分に検討しておくべきだと思います。 画面遷移とURL 数値(年、入力文字数)の閾値 表示順、表示件数 センシティブな情報への配慮 入力値のバリデーション(どんな値・条件を許容するのか) 機能の優先順位(実装の優先度をコンセプトに基づいて決める) また、今回は仕様書の更新を怠っていたことが原因で、開発中にチーム内で再議論する…ということがかなり多く、時間のロスでした。仕様書は常に最新の状態に!ということは今後しっかり意識したいです。 2. 仕様の伝え方 チーム内の議論で共通認識を合わせることに注力した結果、他者に伝える際に視点の切り替えができていませんでした。 言葉のわかりやすさ・全体像の把握のしやすさ・画面・機能を説明する順番は、伝える前に改めて確認する と良いです。細かい仕様を効率よく伝え、決まった時間内で十分に検討してもらうためにも、伝える際の配慮は非常に重要だと感じました。 おまけ:ネーミング 先輩方のアドバイスのもと、サービスのネーミングにはかなりこだわりました。思いのほか時間を費やしてしまったのですが、その分思いのこもったネーミングにできました。 同期のデザイナーが「 ワクワクしながら使ってもらう 」という要素をプラスしてロゴ・サイトデザインを作ってくれたこともあり、どんどん愛着が湧き、私自身ワクワクしながら開発できました! (サービスのロゴ) まとめ 新卒1年目エンジニアが初めて企画・仕様書を作成する中でやってよかった・苦労したポイントをまとめてみました。 企画・仕様書は設計・開発で迷った際の指針となる資料 で、非常に重要なものだと実感しました。妥協せず、チーム内でがっつり議論したことで、その後の開発では共通認識を持ち、 都度コンセプトに立ち返りながら開発 することができました。 また、クリエイターとして企画段階から考え、開発に挑むことができた経験は非常に貴重だったと感じています。 結婚の幸せへ、まっすぐに進めるデジタルを。 弊社の中期ビジョンです。「アナログな仕組みをデジタル化する」にあたり、今あるモノを受け入れてもらう形に変えることの大変さを実感しました。単純ではない、だからこその面白さがあるのだと学びました!
アバター
こんにちは!エンジニアの久保です。 2021/9 より AWS Lambda の動作環境として、Arm/Graviton2 プロセッサが選択できるようになりました。 AWS Graviton2 プロセッサを搭載した AWS Lambda 関数 – Arm で関数を実行し、最大 34% 優れた料金パフォーマンスを実現 これまでは X86 プロセッサだけだったのですが、Arm/Graviton2 を選択することで低コストで高パフォーマンスを実現できます。弊社でも現在 X86 で動作していた Lambda を Arm での動作へ置き換えを進めています。 今回は Lambda を Arm プロセッサで動作させる場合の SAM テンプレートをご紹介します。 SAMテンプレートを書き換え Arm プロセッサで動作可能にする SAM テンプレートの template.yml を次のように書き換えて Arm プロセッサで動作するようにします。 具体的には2点を変更しています。 Architectures を X86_64 から arm64 へ変更する Lambda Insights を有効にしている場合は、Arm に対応したものへ変更する AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > sam-app Sample SAM Template for sam-app # More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst Globals: Function: Timeout: 3 Tracing: Active Layers: # - !Sub "arn:aws:lambda:${AWS::Region}:580247275435:layer:LambdaInsightsExtension:25" - !Sub "arn:aws:lambda:${AWS::Region}:580247275435:layer:LambdaInsightsExtension-Arm64:2" Api: TracingEnabled: True Resources: HelloWorldFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: CodeUri: hello-world/ Handler: app.lambdaHandler Runtime: nodejs16.x Architectures: # - x86_64 - arm64 Events: HelloWorld: Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api Properties: Path: /hello Method: get Outputs: # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function # Find out more about other implicit resources you can reference within SAM # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api HelloWorldApi: Description: "API Gateway endpoint URL for Prod stage for Hello World function" Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" HelloWorldFunction: Description: "Hello World Lambda Function ARN" Value: !GetAtt HelloWorldFunction.Arn HelloWorldFunctionIamRole: Description: "Implicit IAM Role created for Hello World function" Value: !GetAtt HelloWorldFunctionRole.Arn 必要に応じて CI を書き換えます。 Lambda 関数内で使っているライブラリがアーキテクチャに依存しない場合は、CI を変更する必要なく動きます。 一方で、アーキテクチャに依存するライブラリを使っている場合(たとえば、libvips を使う node.js の sharp など)は、次の対応が必要です。 CI の実行環境を Arm へ変更する 異なるアーキテクチャでもビルドできるようにする 一般的には前者の方法が選ばれますが、場合によっては CI は X86 の環境環境しか用意していない場合もあるでしょう。 今回はこのケースに該当したため、X86 の CI でビルドを試します。 異なるアーキテクチャ(ArmをX86)でビルドできるようにする X86 の環境で Arm 向けのビルドを行うには sam build --use-container を使って、Dockerコンテナでビルドする方法が一般的です。しかしながら --use-container オプションが使えない場合があります。 例えば、セルフホストで動作させている GitLab CI などの場合です。設定によっては、Pipeline を Docker コンテナ上で実行していたりします。この場合 Docker コンテナ内で Docker build するには dind (Docker in Docker)とよばれる仕組みを使います。 ところが、今回の環境では dind で sam build --use-container を動かすことができませんでした。 そもそも Arm 用のビルドが必要なのは、npm の sharp で使われている libvips を Arm でビルドされたバイナリにする必要があるためです。SAM を使わずに npm で install する場合、公式では npm install --arch=arm64 --platform=linux sharp でインストールせよ、と紹介されています。 Cross-platform そこで SAM を使った場合に内部で実行されている npm install でこれらのパラメータを指定してみました。 具体的には環境変数を設定してから sam build を実行します。 export npm_config_arch: "arm64" export npm_config_platform: "linux" sam build 補足事項として、環境変数に npm_config_xxx と設定した場合、 npm install --xxx のパラメータとして渡されます。 Environment Variables npm_config_arch, npm_config_target_arch, そして npm_config_* 環境変数について まとめ 今回は Lambda を Arm プロセッサで動作させる場合の SAM テンプレートをご紹介しました。 Arm プロセッサを利用することでコストを抑えた Lambda の利用が可能になります。ぜひご活用ください。
アバター
こんにちは、エンジニアの久保です。 弊社では 2022/4 にリリースされた AWS Lambda の関数 URL(AWS Lambda FunctionURLs) を使って Lambda の開発を進めています。前回の記事では、AWS SAM で関数 URL を有効にする方法を紹介しました。 AWS SAM で AWS Lambda の 関数 URL を利用してみました 現在、社内で運用中の AWS Lambda + Amazon API Gateway で構成される WebAPI についても関数 URL を使った構成へ変更を進めています。 今回は、API Gateway と 関数 URL(FunctionURLs)を併用する場合の SAM テンプレートを作成しましたのでご紹介します。 関数 URL を利用した場合、ペイロード形式は API Gateway Version 2 となるため構成によっては注意が必要です。 クライアントが関数の URL を呼び出すと、Lambda は、まずこのリクエストをイベントオブジェクトにマップしてから、関数に受け渡します その関数の応答は、Lambda が関数 URL を介してクライアントに返信する HTTP レスポンスにマッピングされます。 このリクエストとレスポンスのイベント形式は、Amazon API Gateway ペイロード形式バージョン 2.0 と同じスキーマに従います。 リクエストとレスポンスのペイロード なお、前回利用した SAM の hello-world テンプレートの場合、API Gateway Version 1 の形式になっています。 もしも API Gateway と関数URLのどちらも利用したい場合は、API Gateway を HTTP API に設定するとよいでしょう。以下にテンプレートの例を示します。 利用ケースとしては、「開発の際にローカル環境では sam local start-api を使って動作確認したい」などが考えられます。 AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > sam-app Sample SAM Template for sam-app # More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst Globals: Function: Timeout: 3 Tracing: Active Api: TracingEnabled: True Resources: HelloWorldFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: CodeUri: hello-world/ Handler: app.lambdaHandler Runtime: nodejs16.x Architectures: - x86_64 Events: HelloWorld: Type: HttpApi # More info about API Event Source: https://github.com/aws/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlesshttpapi Properties: Path: /hello Method: GET FunctionUrlConfig: AuthType: NONE Outputs: # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function # Find out more about other implicit resources you can reference within SAM # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api HelloWorldApi: Description: "API Gateway endpoint URL for Prod stage for Hello World function" Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" HelloWorldFunction: Description: "Hello World Lambda Function ARN" Value: !GetAtt HelloWorldFunction.Arn HelloWorldFunctionIamRole: Description: "Implicit IAM Role created for Hello World function" Value: !GetAtt HelloWorldFunctionRole.Arn HelloWorldFunctionUrl: Description: "Function URLs endpoint" Value: !GetAtt HelloWorldFunctionUrl.FunctionUrl まとめ 今回は、Lambda で API Gateway と 関数 URL(FunctionURLs)を併用するケースの SAM テンプレートをご紹介しました。ぜひご活用いただければと思います。
アバター
こんにちは。フォトウエディング・前撮りのクチコミ情報サイト「Photorait (フォトレイト)」のエンジニアリングマネージャーをしている武田( @takedajs )です。 弊社では「エンジニアのやりがい」と「技術力」の向上を目的とした技術推進委員会という組織をエンジニアリングマネージャーとテックリードが中心となって運営しています。 今回は技術推進委員会が運営している 「WP HACK DAY」 の第3回目を開催したので紹介します! 目次 WP HACK DAY とは? 当日の様子 参加者からのフィードバック 最後に WP HACK DAY とは? WP HACK DAYは、ウエディングパークエンジニアチームの技術力向上と一体感醸成のための1dayハッカソンです。 第1回目テーマ Slackを活用して、社内の誰かの仕事を便利にする仕組みをつくる! 第2回目テーマ 開発の課題解決やタスクの効率化、技術検証など、やりたいけど出来ていないこと 今回実施した第3回目では 「業務課題を解決するプロダクト開発」 をテーマに実施しました! WP HACK DAY #3のルール ・ 参加者:エンジニア(今回は2部署のエンジニアが参加) ・ 3人1チームで1日(約7時間)で取り組み、夕方に成果発表会(デモ実施必須)を実施 ・ 事前に当日開発するものを検討し、実装可能か調査 ・ プロトタイプ以上のものを開発 ・ 参加方法はオンライン&オフラインどちらでも可 当日の様子 全体のスケジュール 開会式(9:30-9:40) 各々チーム毎に背景画像を作成して参加してくれました! さあー1日頑張っていきましょうー!朝だからみんなテンション少し低い?w 午前の開発(9:40-12:00) チーム毎に固まってもくもくと開発中! ランチタイム(12:00-13:00) 一人用のピザを人数分用意しました! 注文内容を全員にヒアリングし、なんとか間違えずに注文できたので良かったです 午後の開発、発表資料作成(13:00-17:00) オンライン参加メンバーがいるチームは終始Zoomをつなげて全員で話し合いながら開発! どのチームも開発と資料作成で集中モード 成果発表会(17:00-18:00) 全社向けに成果発表会の開催を告知し、エンジニア以外の方も視聴者として参加して頂きました! 運営が想定していた以上のクオリティのものが発表されていて、Zoomのチャットが「すごい!」「今すぐ欲しい!」など、とても盛り上がりました 発表されたプロトタイプ ・出社管理表 ︎ Slack(ワークフロー)で運用改善 ・チャットボット形式のDocBaseドキュメント検索(Slack連携) ・システム問い合わせの新規ツール作成 ・ コーシー の活性化Slack連携 ・アプリケーション楽々構築で制度運用改善検証 懇親会(18:00-18:30) 最後はチーム関係なくみんなでワイワイ! エンジニア組織全体でざっくばらんにいろいろな話をしながら盛り上がりました! みなさん今日1日お疲れさまでした 参加者からのフィードバック 開催後、参加者に匿名アンケートを実施しました! 全体の満足度(5点満点)平均点は4.6点と高い点数でした。 以下、いただいたフィードバックの一例です。 良かった点 この人数のエンジニアが出社する機会はあまりないので、久しぶりにみんなと集まれて嬉しかった。 第1回目と第2回目は個人開発だったので、今回チーム開発にしたことで前回より会話が増えてハッカソン感があった。 ランチや懇親会があり、ワイワイガヤガヤお祭り感があった。 改善点 業務改善に繋がる良い発表ばかりなので、成果発表会の場にエンジニア以外の方がもっと参加してほしかった。 良い取り組みなので、全社イベントにして他部署のメンバー(エンジニア以外)にも参加してもらい一緒にやるのも良さそう。 レベルの高い発表が多かったので、外部発信力を高めるためにも各チームで会社テックブログへのアウトプットは必須にしても良かった。 最後に ウエディングパークエンジニアチームの技術力向上と一体感醸成のための1dayハッカソン(WP HACK DAY)の第3回目について紹介しました。 3人1チームにすることで他エンジニアの考え方や実装方法を学べたり、ランチや懇親会を開催することでワイワイガヤガヤと盛り上がりながら一体感を強めることができた1日でした。運営の想定していた成果が出せて良かったです。 これからも継続して開催予定なので、今回のフィードバックを活かしてより費用対効果の高いイベントにしていきます。
アバター
こんにちは。結婚指輪・婚約指輪のクチコミサイト「Ringraph」でエンジニアをしているさー( @__south__373 )です。今日は新規事業部署のエンジニアがエンジニア組織の未来について考えて提案してみた話をしたいと思います。 ビジョンを実現するためにエンジニア組織に必要な施策を考えたい 事の発端は今年の2月頃。職種別のチームで、スキルアップをするための取り組みを考えてみようという時間がありました。そこで私たちエンジニアチームが決めたのが、「 ビジョンを実現するためにエンジニア組織に必要な施策を提案する 」というもの。 私の部署は新規事業がいくつか集まっており、普段は担当事業の運用や開発に取り組んでいます。自分の事業に対してはロードマップを考えたりする一方で、部署全体のエンジニア組織としてどう成長していきたいか考える機会はほとんどありませんでした。各事業が伸びているなかでさらに成長を加速するためには、事業を超えてエンジニア組織の未来を語り、課題を解決していく必要があると感じており、これがエンジニアみんなの中で一致していたのでやってみることになりました。 もっと技術的なチャレンジに取り組んでいきたい 私たちは「21世紀を代表するブラダル会社を創る」というビジョンを掲げています。その中で、私たち新規事業のエンジニアは「 サービス愛 + 技術力を持って、新しい付加価値を創出することができる組織 」を目指したいと考えました。 ビジョンを実現するためには、組織として今まで以上にチャレンジを繰り返していくことが必要であり、技術力を高めなければ事業としてやりたいことがシステムがネックになりできなくなってくるのではないかという危機感もあります。ウエディングパークのエンジニアは「 クリトラ 」を行動指針としていますが、その中でもSKILLに当たる部分は、まだまだ伸び代がありもっと技術的なチャレンジをしていく必要があると思っています。 今動いているシステムも現状維持ではどんどん取り残されていきますし、エンジニアとしてビジョン実現に貢献するために、今あるチーム力そしてサービス愛に加えて技術力を持って、新しい付加価値を創出したい。そのためには、技術的なチャレンジができる環境を整える必要がある。そう感じました。 早くて安定したリリースができる仕組みをつくることで技術的なチャレンジができる ではなぜ技術的なチャレンジがしづらい状況になっているのか。理由は大きく2つあると考えました。 1つは影響範囲が増え続けていることに伴うテストコストの増加です。UnitテストやE2Eテストで一部担保している部分はあるものの、基本的には影響範囲を全て人力で確認している状況です。サイト全体に影響がある開発に取り組むコストがとても高くネックになっています。 もう一つは事業を直近伸ばすための開発が優先されがちであるということ。やるべき施策が決まっている中で、プラスの工数をもらって手を加えることが難しいこともあります。 今までは案件を開発してリリースすることに注力しており、開発のサイクルを見直したりリリーススピードまで意識が回っていませんでした。先程上げたような課題を解決するためには、品質とスピード両方を上げることで、早くて安定したリリースができる仕組みをつくる。そうすることで挑戦できる環境を整えることができると考えています。 Four Keysを追いかける 早くて安定したリリースができる仕組みを作るにはどうしたら良いかを考えたとき、Four Keysという指標に出会いました。 Four Keysとは DevOps Research and Assessment(DORA) チームが実施した 6 年間の研究から確立された、ソフトウェア開発チームのパフォーマンスを示す 4 つの指標です。 ・デプロイ頻度 ・変更のリードタイム ・変更障害率 ・サービス復元時間 品質とスピードの両方を上げたいと考えた時、どちらかに注力するとどちらかが疎かになってしまいがちです。なので、この4つの指標を追うことでどちらも改善することを意識しながら進められるところが良いなと思っています。 まずはチームのパフォーマンスを測り可視化する。そしてボトルネックとなっている箇所に対してアプローチをする。これを繰り返すことで技術挑戦できる環境を作っていきます。 おわりに この提案が無事承認され、今は各指標の細かい定義を決めています。そして来月からは実際に計測をしていくので、実際測ってみてどうだったか、どんな施策をやったかはまたの機会にお伝えしようと思います。 今回事業を超えてエンジニア組織の課題をディスカッションすることで、課題の共通認識を持つことができ、そこに対する新しいアプローチを考えることができました。Four Keysを計測し改善することが目的ではないので、技術的なチャレンジをしやすくすることで事業の技術力を上げていく。そしてビジョンを実現する。ここはブラさずに取り組んでいきたいと思います。
アバター
こんにちは。 Photorait エンジニアのヒエイです。 全社エンジニアが参加する開発定例「クリトラ定例」の運営をしています。 「クリトラ」ってなに?については こちら をご覧ください。 四半期末の定例では振り返り会を実施しており、エンジニアの頑張りや活動量を発表しました。 この活動量について プロジェクト毎のリリース数 プルリクエスト(以下、PR)・マージリクエスト(以下、MR)数やコメント数 これらの数値をグラフ化し、前回振り返り時とも比較しつつエンジニア自身の活動量が数値化された発表を見て みんなでわちゃわちゃ盛り上がる会となりました。 今回はこの、「PR・MR数やコメント数」を集計した話を書きます。   どんな発表をしたか 集計したデータをグラフ化し、以下を発表しました。 月毎のPR・MR数やメンバー毎のPR・MR数 メンバーのレビューコメント数 レビューに対する平均コメント数   集計対象と集計内容 ウエディングパークでは、GitHubとGitLabを活用しています。何故二種類あるのかはここでは説明を省きます。 GitHubとGitLab双方から以下を集計させます。 PR・MR数 メンバー毎のPR・MR提出数を出します。 この集計により、月毎やプロジェクト毎のコードレビュー依頼数も見えてきます。 PR・MRに対する開発メンバーのコメント数 先述の通りPR・MRに対するコメント数を集計します。 つまり、コードレビューに対してどれぐらいコメントをしたかを出します。 PR・MRへのレビューアサイン数 PR・MRにアサインされた数を集計します。 コードレビューにアサインされた数を出します。   APIエンドポイント GitHub API、GitLab APIの以下のエンドポイントを利用します。 エンドポイント GitHub GraphQLを使います。 https://api.github.com/graphql https://docs.github.com/ja/graphql/reference/queries GitLab 弊社のGraphQL APIのバージョン都合上 REST APIを利用します。 https://docs.gitlab.com/ee/api/merge_requests.html#list-merge-requests https://docs.gitlab.com/ee/api/discussions.html#merge-requests   GitHub集計 Organizationに紐づくリポジトリからPR一覧、PR作成者、レビューアサインメンバー、コメント一覧を取得します。 { organization(login: "Organization名") { repositories(first: 100) { edges { node { name pullRequests(first: 10, after: null, orderBy: {field: CREATED_AT, direction: DESC}) { pageInfo { endCursor } edges { node { createdAt author { login } assignees(first: 10) { edges { node { login } } } comments(first: 100) { edges { node { author { login } body } } } } } } } } } } }   GraphQLなのでまとめて取得できるのが便利です。集計自体はスクリプト側に任せます。 PR数やコメント数も制限をかけてリクエストしているので、良しなにページネーションさせて細かくリクエストさせます。 GitLab集計 こちらはREST APIを利用だったので、スクリプト織り交ぜて載せます。PHPで取得。 $date = '2022-04-01T00:00:00+09:00'; $url = "https://{GitLabドメイン}/api/v4/merge_requests?created_after=%s&per_page=100&scope=all&page=%s"; // 日付に制限をかけて取得させる $mrUrl = sprintf($url, $date); $headers = [ "Authorization: Bearer {トークン値}", ]; page = 1; // apiリクエストをする例 while ($mrList = $this->request($mrUrl, $page)) { foreach ($mrList as $mrValue) { $authorName = $mrValue['author']['username']; // author(MR作成者)ごとのMR数をインクリメントさせる例 $this->incrementAuthor($authorName); if (!empty($mrValue['assignee'])) { $assigneeName = $mrValue['assignee']['username']; // assignee(レビュー者)ごとのMR数(レビュー依頼数)をインクリメントさせる例 $this->incrementAssignee($assigneeName); } $mr = [ 'prjId' => $mrValue['project_id'], 'mrIid' => $mrValue['iid'], 'authorId' => $mrValue['author']['id'], ]; // この部分は以下で解説 $this->sumComment($mr); } $page ++; }   コメント部分は別で取得しなければならず、ソース上の $this->sumComment($mr) 部分の取得は以下のような形です。 private function sumComment($mr) { $mrDiscussionUrl = "https://{GitLabドメイン}/api/v4/projects/%s/merge_requests/%s/discussions?per_page=100"; $path = sprintf($mrDiscussionUrl, $mr['prjId'], $mr['mrIid']); $page = 1; // apiリクエストをする例 while ($discussions = $this->requestPath($path, $page)) { foreach ($discussions as $comments) { foreach ($comments['notes'] as $note) { // システム(CIによる投稿など)による内容ならスルー if ($note['system']) { continue; } // 投稿者がMR作成者ならばスルー(レビュー依頼者によるコメントは除きました) if ($note['author']['id'] == $mr['authorId']) { continue; } $authorName = $note['author']['username']; // レビューコメントした人ごとのコメント数をインクリメントさせる例 $this->incrementCommenter($authorName); } } $page ++; } }   GraphQLを使ったGitHub集計も上記のようなスクリプトで集計させています。   集計したものを発表 数値は簡単にスプレッドシートにまとめてグラフ化しました。グラフは先述の通りです。 この発表をし、前回より増えたねーなどの声も上がったり、レビューに対して沢山コメントしてくれる人、PR数が多い人など、人によって数値の差が大きく、面白い発表になりました。 そして多い少ないが分かるだけでなく、 レビュー時に沢山コメントしてくれるメンバーが、隅々までコードを見てくれる点や分かりやすいコメント内容だったという声が上がったり PR数が多いのは、どの粒度でコードレビューを出しているか、それによるコードレビューのスピード感やリリース数などの相関関係も見えてきたり 今度PRを覗いてみよう、と話が発展することもありました。   単純な数値の発表から、生産性を考えたり、レビュワーに感謝を伝えるきっかけにもなったりと発見が多い発表になりました。   というわけで今月末も振り返り会を実施します。 集計発表が楽しみです。  
アバター
エンジニアの久保です。 2022/4 に AWS Lambda の関数 URL(AWS Lambda FunctionURLs) がリリースされました。この機能を使うと、Lambda を使った WebAPI を作成する際に必要だった Amazon API Gateway が不要になります。 今回はこの関数 URL を AWS SAM(AWS Serverless Application Model)から利用してみました。 作業環境 AWS SAM CLI は次のバージョンを利用しています。 % sam --version SAM CLI, version 1.51.0 プロジェクトの作成 sam init でプロジェクトを作成します。 今回はおなじみの hello-world テンプレートを利用しています。 % sam init \ --runtime nodejs16.x \ --dependency-manager npm \ --app-template hello-world \ --tracing \ --name sam-app Cloning from https://github.com/aws/aws-sam-cli-app-templates (process may take a moment) このとき作成される SAM のテンプレート template.yml は以下のようになっています。 AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > sam-app Sample SAM Template for sam-app # More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst Globals: Function: Timeout: 3 Tracing: Active Api: TracingEnabled: True Resources: HelloWorldFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: CodeUri: hello-world/ Handler: app.lambdaHandler Runtime: nodejs16.x Architectures: - x86_64 Events: HelloWorld: Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api Properties: Path: /hello Method: get Outputs: # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function # Find out more about other implicit resources you can reference within SAM # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api HelloWorldApi: Description: "API Gateway endpoint URL for Prod stage for Hello World function" Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" HelloWorldFunction: Description: "Hello World Lambda Function ARN" Value: !GetAtt HelloWorldFunction.Arn HelloWorldFunctionIamRole: Description: "Implicit IAM Role created for Hello World function" Value: !GetAtt HelloWorldFunctionRole.Arn 関数 URL(Function URLs)を有効にする それでは、関数 URLを 有効にしてみます。 template.yml の Resources → HelloWorldFunction のセクションに FunctionUrlConfig を追加します。 Resources: HelloWorldFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: CodeUri: hello-world/ Handler: app.lambdaHandler Runtime: nodejs16.x Architectures: - x86_64 Events: HelloWorld: Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api Properties: Path: /hello Method: get FunctionUrlConfig: AuthType: NONE FunctionUrlConfig については、 ドキュメント に詳細が書かれています。 今回は特に認証なしでアクセスできるようにしたいので、 AuthType: NONE を設定しています。 また、作成された関数URLを確認できるように、Outputsのセクションで以下のように HelloWorldFunctionUrl を追記します。 Outputs: # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function # Find out more about other implicit resources you can reference within SAM # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api HelloWorldApi: Description: "API Gateway endpoint URL for Prod stage for Hello World function" Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" HelloWorldFunction: Description: "Hello World Lambda Function ARN" Value: !GetAtt HelloWorldFunction.Arn HelloWorldFunctionIamRole: Description: "Implicit IAM Role created for Hello World function" Value: !GetAtt HelloWorldFunctionRole.Arn HelloWorldFunctionUrl: Description: "Function URLs endpoint" Value: !GetAtt HelloWorldFunctionUrl.FunctionUrl デプロイして動作確認 それではデプロイして動作を確認してみましょう。 まずはビルドします。 % sam build 続いてデプロイします。 % sam deploy \ --template-file template.yaml \ --stack-name sam-app \ --resolve-s3 \ --capabilities CAPABILITY_IAM デプロイが完了するとデプロイされたスタックが表示されます。 CloudFormation outputs from deployed stack ----------------------------------------------------------------------------------------------------------------------------------------------------------- Outputs ----------------------------------------------------------------------------------------------------------------------------------------------------------- Key HelloWorldFunctionIamRole Description Implicit IAM Role created for Hello World function Value arn:aws:iam::000000000000:role/sam-app-HelloWorldFunctionRole-114EYP0OM26CS Key HelloWorldApi Description API Gateway endpoint URL for Prod stage for Hello World function Value https://jlw92sp9w4.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/ Key HelloWorldFunctionUrl Description Function URLs endpoint Value https://rwu4uvcrsa5yxsecf3dliu2fpu0vmrty.lambda-url.ap-northeast-1.on.aws/ Key HelloWorldFunction Description Hello World Lambda Function ARN Value arn:aws:lambda:ap-northeast-1:000000000000:function:sam-app-HelloWorldFunction-Ynj767nxr0Xw ----------------------------------------------------------------------------------------------------------------------------------------------------------- Successfully created/updated stack - sam-app in ap-northeast-1 動作確認 それでは実際に動かしてみます。 API Gateway のエンドポイント hello-world テンプレート に最初から含まれている API Gateway のエンドポイントに接続してみます。 % curl https://jlw92sp9w4.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/ {"message":"hello world"} 関数 URL(Function URLs)のエンドポイント 次に、今回追加した関数 URL のエンドポイントに接続してみます。 % curl https://rwu4uvcrsa5yxsecf3dliu2fpu0vmrty.lambda-url.ap-northeast-1.on.aws/ {"message":"hello world"} API Gateway のエンドポイントと同様に動作しました! 今回の template.yml の最終結果 参考までに、今回利用した SAM テンプレート template.yml の最終結果を以下に記載します。 AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > sam-app Sample SAM Template for sam-app # More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst Globals: Function: Timeout: 3 Tracing: Active Api: TracingEnabled: True Resources: HelloWorldFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: CodeUri: hello-world/ Handler: app.lambdaHandler Runtime: nodejs16.x Architectures: - x86_64 Events: HelloWorld: Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api Properties: Path: /hello Method: get FunctionUrlConfig: AuthType: NONE Outputs: # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function # Find out more about other implicit resources you can reference within SAM # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api HelloWorldApi: Description: "API Gateway endpoint URL for Prod stage for Hello World function" Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" HelloWorldFunction: Description: "Hello World Lambda Function ARN" Value: !GetAtt HelloWorldFunction.Arn HelloWorldFunctionIamRole: Description: "Implicit IAM Role created for Hello World function" Value: !GetAtt HelloWorldFunctionRole.Arn HelloWorldFunctionUrl: Description: "Function URLs endpoint" Value: !GetAtt HelloWorldFunctionUrl.FunctionUrl まとめ 今回は AWS Lambda の関数 URL(AWS Lambda Function URLs)を AWS SAM から利用する方法を紹介しました。 現在社内で進行しているプロジェクトでは関数 URL を積極的に利用しています。 先述の通り、従来の API Gateway + Lambda で構成される WebAPI の場合、Lambda 関数 URL を使った構成へ変更することで API Gateway が不要になります。 弊社の場合、Lambda 関数 URL を利用することで月に $30 ほど節約できるケースがありました。 API Gateway で提供される機能を必要としていない場合は、関数 URL の利用を検討してみてはいかがでしょうか。
アバター
こんにちは、エンジニアのみーや( @miiya387 )です。 Reactのフレームワーク「Next.js」への入門として、公式チュートリアルを何回かに分けてまとめていきます。 今回は4つ目の pre-rendering and Data Fetching です。 それ以前の章を知りたい方は Reactのフレームワーク”Next.js”を触ってみた「アプリ新規作成 / ページ遷移 / スタイル設定」 をご覧ください。 Create a Next.js App Navigate Between Pages Assets, Metadata, and CSS Pre-rendering and Data Fetching Dynamic Routes API Routes Deploying Your Next.js App やってみる 4. Pre-rendering and Data Fetching pre-rendering Next.jsではデフォルトですべてのページにおいてpre-renderingが有効になっています。 pre-renderingにより、ページのHTMLを事前に生成するためクライアントサイドですべてのJavaScriptを実行するのに比べて、パフォーマンスもSEOも良くなります。 生成されたHTMLはブラウザで最低限のJavaScriptを実行し、インタラクティブなページを完成させます。このプロセスを hydration と呼びます。 check That Pre-rendering Is Happening 以下の工程でpre-renderingを確認していきます。 ブラウザのJavaScriptを無効にする その後Next.jsで実装されている こちらのページ にアクセス chromeのJavaScriptを無効にします(手順は こちら ︎ ︎ ) その後、公式で指定があったページ https://next-learn-starter.vercel.app/ にアクセスすると、JavaScriptなしでページのレンダリングができていることが確認できました! これは、Next.jsがページを静的なHTMLとしてpre-renderingしているから、JavaScriptなしでの表示が可能になります。 Next.jsなしで純粋にReactで実装しているページではこうはなりません。 それを確認するために以下のステップでReactのページでJavaScriptを無効にした状態でアクセスするとどうなるのか確認していきます。 JavaScriptが有効な状態で こちらのページ にアクセス その後、JavaScriptを無効にし、再度同じページにアクセス まずは指定のページにJavaScriptが有効な状態でアクセスします。 Reactのアイコンがくるくるしているページが見れますね。 その後JavaScriptを無効にし再アクセスすると以下のようにJavaScriptを有効にしてくださいと表示され、ページのレンダリングはされません。 これでNext.jsと違い、Reactではページのpre-renderingがされていないことが確認できました。 Summary: Pre-rendering vs No Pre-rendering 以下は公式で紹介されているNext.js(pre-renderingあり)とPlain React(pre-renderingなし)の概要です。 Next.jsでは、初回のHTMLの表示がすぐに行われ、その後<Link>などのJavaScriptの実行が必要な一部要素のみ遅延して行われます。 出展: https://nextjs.org/learn/basics/data-fetching/pre-rendering 一方でReactでは、初回表示のものはなく、すべてのReact ComponentがJavaScriptの実行を待ってから表示されます。 普段Reactで開発しているときは、初期描画に時間がかかってしまうのはある程度仕方ないと思っていましたが、Next.jsは基本的に全ページでpre-renderingに対応しているのでその問題は解決しそうですね。 Two Forms of Pre-rendering Next.jsでは以下の2種類のpre-renderingがあります Static Generation : ビルド時にHTMLを事前生成し、その後は1度生成されたHTMLをリクエストごとに再利用されます Server-side Rendering : リクエストのたびにHTMLが再生成されます 出展: https://nextjs.org/learn/basics/data-fetching/two-forms なお、開発モードの環境では、Static Generationであっても、リクエストごとにpre-renderingされます。 Per-page Basis Next.jsではページごとに使用するpre-rendered方式を選ぶことができ、SSGとSSRのハイブリッド構成が可能になります。 ページの特徴に合わせて選択できるので、とても便利ですね!嬉しいです! 出展: https://nextjs.org/learn/basics/data-fetching/two-forms When to Use Static Generation v.s. Server-side Rendering Next.jsでは基本的にSSGを使うことを推奨しています。 一度ページを生成してCDNの利用が可能になるため、パフォーマンス的に有利になります。 例えば、次のようなページにSSGが使えます。 マーケティングページ ブログ投稿 ECサイトの商品一覧 ヘルプページ 一方で、データの更新が頻繁に行われるページやリクエストごとに表示するコンテンツを切り替えたいページではSSRを使うのが適しています。 SSGと比べるとページ表示速度のパフォーマンスは下がりますが、ページを常に最新の状態にすることができます。 または、pre-renderingをスキップしてクライアントサイドでJavaScriptを利用して頻繁に更新されるデータを表示することもできます。 CMSツールのような入力テキストがリアルタイムでプレビューに反映されるページや、ユーザーの志向性に合わせて表示内容を切り替えたいページではpre-renderingをスキップする方が適していそうですね。 Static Generation with and without Data SSGはデータの有無に関わらず利用可能です。 これまで作成したページでは、外部データを取得する必要がなくアプリが本番用にビルドされるときに自動的に静的に生成されます。 出展: https://nextjs.org/learn/basics/data-fetching/with-data しかし、一部のページでは事前にデータを取得しないと、HTMLの生成ができない場合があります。 ビルド時に、画像ファイルを取得したり外部APIをフェッチしたりデータベースにクエリ実行したりなど、、、 その場合もNext.jsはサポートしており、 getStaticProps を使うと事前処理が可能になります。 getStaticPropsはasync関数で、本番ビルド時に実行され、関数内では外部データをフェッチしてページに渡されます。 開発モードでは各リクエストで実行されます。 export default function Home(props) { ... } export async function getStaticProps() { // Get external data from the file system, API, DB, etc. const data = ... // The value of the `props` key will be // passed to the `Home` component return { props: ... } } Blog Data ここでは実際にブログデータをフェッチして追加していきます。 プロジェクトトップに posts ディレクトリを作成します。 作成したposts配下にブログファイル(マークダウン)を追加し、内容を以下にします。 --- title: 'Two Forms of Pre-rendering' date: '2020-01-01' --- Next.js has two forms of pre-rendering: **Static Generation** and **Server-side Rendering**. The difference is in **when** it generates the HTML for a page. - **Static Generation** is the pre-rendering method that generates the HTML at **build time**. The pre-rendered HTML is then _reused_ on each request. - **Server-side Rendering** is the pre-rendering method that generates the HTML on **each request**. Importantly, Next.js lets you **choose** which pre-rendering form to use for each page. You can create a "hybrid" Next.js app by using Static Generation for most pages and using Server-side Rendering for others. 次に、同様にposts配下にssg-ssr.mdファイルを追加し、内容を以下にします。 --- title: 'When to Use Static Generation v.s. Server-side Rendering' date: '2020-01-02' --- We recommend using **Static Generation** (with and without data) whenever possible because your page can be built once and served by CDN, which makes it much faster than having a server render the page on every request. You can use Static Generation for many types of pages, including: - Marketing pages - Blog posts - E-commerce product listings - Help and documentation You should ask yourself: "Can I pre-render this page **ahead** of a user's request?" If the answer is yes, then you should choose Static Generation. On the other hand, Static Generation is **not** a good idea if you cannot pre-render a page ahead of a user's request. Maybe your page shows frequently updated data, and the page content changes on every request. In that case, you can use **Server-Side Rendering**. It will be slower, but the pre-rendered page will always be up-to-date. Or you can skip pre-rendering and use client-side JavaScript to populate data. Implement getStaticProps マークダウンをパースするために gray-matter をインストールします npm install gray-matter プロジェクトトップにlibディレクトリを作成し、以下のposts.jsを追加します。 import fs from 'fs' import path from 'path' import matter from 'gray-matter' const postsDirectory = path.join(process.cwd(), 'posts') export function getSortedPostsData() { // Get file names under /posts const fileNames = fs.readdirSync(postsDirectory) const allPostsData = fileNames.map(fileName => { // Remove ".md" from file name to get id const id = fileName.replace(/\.md$/, '') // Read markdown file as string const fullPath = path.join(postsDirectory, fileName) const fileContents = fs.readFileSync(fullPath, 'utf8') // Use gray-matter to parse the post metadata section const matterResult = matter(fileContents) // Combine the data with the id return { id, ...matterResult.data } }) // Sort posts by date return allPostsData.sort(({ date: a }, { date: b }) => { if (a < b) { return 1 } else if (a > b) { return -1 } else { return 0 } }) } pages/index.jsを次のように更新し、getSortedPostsDataを使ってデータフェッチします。 フェッチしたデータを使うようにHomeコンポーネントも一部書き換えます。 import Layout, { siteTitle } from '../components/layout' import utilStyles from '../styles/utils.module.css' import { getSortedPostsData } from '../lib/posts' export async function getStaticProps() { const allPostsData = getSortedPostsData() return { props: { allPostsData } } } export default function Home({ allPostsData }) { return ( <Layout home> {/* Keep the existing code here */} {/* Add this <section> tag below the existing <section> tag */} <section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}> <h2 className={utilStyles.headingLg}>Blog</h2> <ul className={utilStyles.list}> {allPostsData.map(({ id, date, title }) => ( <li className={utilStyles.listItem} key={id}> {title} <br /> {id} <br /> {date} </li> ))} </ul> </section> </Layout> ) } 更新後、 http://localhost:3000/ にアクセスするとフェッチしたブログデータを使用してpre-renderingできました! getStaticProps Details Fetch External API or Query Database 今回はファイルシステムからデータをフェッチするパターンを posts.js に実装しましたが、外部APIからデータをフェッチすることや、データベースに直接クエリを実行することもできます。 外部APIからデータをフェッチする場合は posts.js を以下のようにします。 export async function getSortedPostsData() { // Instead of the file system, // fetch post data from an external API endpoint const res = await fetch('..') return res.json() } クエリを実行する場合は以下のようにします。 import someDatabaseSDK from 'someDatabaseSDK' const databaseClient = someDatabaseSDK.createClient(...) export async function getSortedPostsData() { // Instead of the file system, // fetch post data from a database return databaseClient.query('SELECT posts...') } getStaticPropsはサーバーサイドのみで実行されるため、JavaScriptのバンドル対象に入りません。 そのため、実行するクエリなどをブラウザに送信することなく実行することができます。 Development vs. Production 先にも記載しましたが、開発モードの場合はリクエストごとにgetStaticPropsが実行されます。 本番では、ビルド時にのみ実行されます。 つまり、getStaticPropsでは、リクエスト毎にクエリパラメータやHTTPヘッダーを指定して、データの動的取得は行えません。 Fetching Data at Request Time ビルド時ではなくリクエスト時にデータをフェッチする必要がある場合は、 Server-side Renderingを使います。 Server-side Renderingの場合は、getStaticPropsの代わりにgetServerSidePropsを使う必要があります。 Using getServerSideProps ブログの例では使わないため実装はしませんが、getServerSidePropsを使うことで リクエストごとのデータフェッチができるようになります。 export async function getServerSideProps(context) { return { props: { // props for your component } } } Client-side Rendering pre-rendering時に事前取得する必要のないデータは、JavaScriptを使ってクライアントサイドでレンダリングすることもできます。 外部データを必要としないページの部分をSSGでレンダリング ページが読み込まれたら、JavaScriptを使用してクライアントサイドで外部データをフェッチし、残りの部分にデータを入力 出展: https://nextjs.org/learn/basics/data-fetching/request-time クライアントサイドでデータフェッチする場合は、React HooksライブラリのSWRをおすすめされています。 ページ表示が終わった後に一部広告を表示する場合などに適していそうですね。ただし、途中で表示項目が増えることでのレイアウトシフトによるUX低下やSEOへの影響は注意しないとなので検証してみる必要がありますね。 まとめ 今回はNex.jsの公式チュートリアルをもとにpre-renderingについて触れてみました。 ページの特性に合わせてSSG, SSRを使いわけができることはとても便利ですよね。 SSGを基本としてクライアントサイドで必要な分だけ後から追加表示するのも魅力的でした。 ここまでのソースは github に上げたので興味のある方はぜひ一緒にNext.jsと仲良くなっていきましょう! 次回は「Dynamic Routes, API Routes」をやってみます。
アバター
こんにちは、エンジニアのみーや( @miiya387 )です。 今回はReactのフレームワークである「Next.js」を公式チュートリアルをもとに触ってみました。 普段の開発ではReactを使用しているのですが、最近フロントエンド関連の記事でNext.jsをよく目にするようになったので、基本的な機能をチュートリアルを通して触ってみて知ったことをまとめたいと思います。 Next.jsとは? Next.jsはReactベースのフレームワークです。 公式の導入部分にて、Reactを使ってWebアプリケーションを開発する際の考慮点を取り上げた上で、Next.jsはそれらをすべて解決してくれると紹介されていました。 主な特徴は以下の8つみたいです。詳細は こちら ︎ ︎ ・An intuitive page-based routing system (with support for dynamic routes) ・Pre-rendering, both static generation (SSG) and server-side rendering (SSR) are supported on a per-page basis ・Automatic code splitting for faster page loads ・Client-side routing with optimized prefetching ・Built-in CSS and Sass support, and support for any CSS-in-JS library ・Development environment with Fast Refresh support ・API routes to build API endpoints with Serverless Functions ・Fully extendable 特に2つ目のSSG, SSRの特徴が気になっていたのでチュートリアルの中で触れられると嬉しいです。 チュートリアルではシンプルなブログアプリの作成を通してNext.jsの基本を学んでいくスタイルです。 Create a Next.js App Navigate Between Pages Assets, Metadata, and CSS pre-rendering and Data Fetching Dynamic Routes API Routes Deploying Your Next.js App 本記事では1~3をまずはやってみようと思います。 やってみる 1. Create a Next.js App Setup 最初のレッスンではNex.jsのアプリケーション作成とページの表示、編集までを行います。 前提 Node.jsがインストールされていること(バージョンは10.13以上) 任意のエディタとターミナルを用意してあること 私は今回 Node.js は v14.15.5 の環境で作業します。 Create a Next.js app 任意のディレクトリ内で以下コマンドでNext.jsアプリケーションを作成します。 $ npx create-next-app nextjs-blog --use-npm --example "https://github.com/vercel/next-learn/tree/master/basics/learn-starter" Run the development server 作成が完了したら、 nextjs-blog に移動してサーバーを起動します $ cd nextjs-blog $ npm run dev > @ dev /Users/XXXXXX/Projects/tutorial_next_js/nextjs-blog > next dev ready - started server on 0.0.0.0:3000, url: http://localhost:3000 event - compiled client and server successfully in 1880 ms (110 modules) Attention: Next.js now collects completely anonymous telemetry regarding usage. This information is used to shape Next.js' roadmap and prioritize features. You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL: https://nextjs.org/telemetry Welcome to Next.js 起動後に http://localhost:3000 にアクセスすると、以下の画面の表示がされました! サクッとここまでこれるのは簡単で嬉しいですね! Editing the Page サーバーを起動したままページの編集をしていきます。 pages/index.js の Welcome を Learn に書き換えてみましょう。 import Head from 'next/head' export default function Home() { return ( <div className="container"> <Head> <title>Create Next App</title> <link rel="icon" href="/favicon.ico" /> </Head> <main> <h1 className="title"> Lean to <a href="https://nextjs.org">Next.js!</a> </h1> ・・・ なんと編集するだけでページの更新なしに編集内容がページに反映されました! すごーい!これが Fast Refresh という特徴みたいです。 単体のエクスポートファイルの更新なら編集のあったファイルのみ、importされているファイルならimportしているファイルもセットでコンパイルして再描画してくれるみたいです。 最近自分の開発環境のjsのトランスパイルが遅くて少々ストレス・・と思っていたのでこれは嬉しい特徴ですね! ほとんどの場合1秒以内に反映されるようです。開発が捗りますね! 2. Navigate Between Pages 次のレッスンではページの追加と、ページ間遷移を行います。 Pages in Next.js pagesディレクトリ内に新しく posts ディレクトリを作成し、 postsディレクトリ内に以下の first-post.js ファイルを新規追加します。 export default function FirstPost() { return <h1>First Post</h1> } http://localhost:3000/posts/first-post にアクセスすると以下の画面が表示され、新しいページが作成できたことが確認できます。 これがページベースのルーティングです。pagesディレクトリの下にファイルを配置するだけで、ページファイルのパスが、アプリケーション上のページのURLのパスに対応しているため、直感的な実装が可能となっています。 ひえー!すごーい! Link Component 続いて、今作成したページへのリンクをindex.jsに追加していきます。 ここでは Link コンポーネントを使うことでclient-side navigationによるページ間の遷移を実装してみます。 pages/index.jsに Link コンポーネントのimportを追加し、h1タグのaタグをlinkタグに置き換えます。 import Head from 'next/head' import Link from 'next/link' export default function Home() { return ( <div className="container"> <Head> <title>Create Next App</title> <link rel="icon" href="/favicon.ico" /> </Head> <main> <h1 className="title"> Read{' '} <Link href="/posts/first-post"> <a>this page!</a> </Link> </h1> 次に、pages/posts/first-post.js を次のように変更し、 トップページに戻るリンクを新しく設置します。 import Link from 'next/link' export default function FirstPost() { return ( <> <h1>First Post</h1> <h2> <Link href="/"> <a>Back to home</a> </Link> </h2> </> ) } ページを確認すると、追加したLinkを使ってページ間の遷移ができるようになりました! Client-Side Navigation Linkコンポーネントによるページ間の client-side navigation は、クライアント側だけでページ表示とURLを変更するため、通常よりも高速なページ遷移が可能となります。 クライアント側だけで遷移が行われていることを確認するために、htmlのcssプロパティを変更してページ遷移をしてみましょう。 ページ遷移しても、背景色の黄色が継続して反映されていることが確認できました。 これはブラウザがページをロードせずにクライアント側のみでページ遷移できているということになります。 Code splitting and prefetching Next.jsはコード分割を自動的に行うため、各ページに必要なものだけをロードするようになっています。 つまり、ページロード時には他のページのソースはロードしないため、複数ページ存在する場合でも高速な読み込みが可能となります。 さらに、本番ビルド時にはコンポーネントがブラウザのビューポートに表示される度に Linkコンポーネントでリンクされたページをバックグラウンドで自動的に prefetch している ため、リンクをクリックするまでにリンク先にコードが読み込まれている状態になり、高速なページ遷移ができるようになります。 ひょえ〜〜〜! 3. Assets, Metadata, and CSS 次のレッスンではページにCSSスタイルを追加します。 Assets Download Your Profile Picture まずは、ブログトップに表示する自身のプロフィール画像をダウンロードします。 publicディレクトリ内に images ディレクトリを新規作成し、ダウンロードした profile.jpg を格納します。 Unoptimized Image 通常のHTMLでは以下のように画像を追加します <img src="/images/profile.jpg" alt="Your Name" data-mce-src="/images/profile.jpg"> しかし、この場合、画像の最適化や遅延読み込みなどは手動で設定する必要があります。 Image Component and Image Optimization Next.jsの場合、imgタグを拡張子た Image コンポーネントが用意されており、画像の最適化や遅延読み込みなどを自動で行うことができます。webpにも対応しているとか。 Using the Image Component Next.jsは、ビルド時にイメージを最適化する代わりに、ユーザーの要求に応じてオンデマンドで画像を最適化します。 画像はデフォルトで遅延読み込みされるため、ブラウザのビューポート外の画像の影響でページ速度が低下することもなく、常にレイアウトシフトを回避するように描画されます。 詳しくは こちら ︎ ︎ 便利すぎて怖い・・・・・・・ import Image from 'next/image' const YourComponent = () => ( <Image src="/images/profile.jpg" // Route of the image file height={144} // Desired size with correct aspect ratio width={144} // Desired size with correct aspect ratio alt="Your Name" /> ) このコードは後ほど使うらしいのでまだファイル追加せず先に進みます。 Metadata Head コンポーネントを使ってページのメタデータを追加します。 Adding Head to first-post.js import Link from 'next/link' import Head from 'next/head' export default function FirstPost() { return ( <> <Head> <title>First Post</title> </Head> <h1>First Post</h1> <h2> <Link href="/"> <a>Back to home</a> </Link> </h2> </> ) } http://localhost:3000/posts/first-post にアクセスすると指定した通りページタイトルが変更されていることが確認できました。 Third-Paty JavaScript 通常のHTMLでは、サードパーティスクリプトの追加は次のようにscriptタグを使用して行います。 <Head> <title>First Post</title> <script src="https://connect.facebook.net/en_US/sdk.js" /> </Head> この方法でスクリプトを含めると、同じページでフェッチされた他のJavaScriptコードに対していつロードされるかが明確にわかりませんし、読み込みによりページのレンダリングをブロックしていて、ページコンテンツの読み込みが遅れる可能性があります。 Using the Script Component Next.jsでは Script コンポーネントを使うことによって、スクリプトの読み込みや実行を最適化することができます。詳しくは こちら ︎ ︎ import Link from 'next/link' import Head from 'next/head' import Script from 'next/script' export default function FirstPost() { return ( <> <Head> <title>First Post</title> </Head> <Script src="https://connect.facebook.net/en_US/sdk.js" strategy="lazyOnload" onLoad={() => console.log(`script loaded correctly, window.FB has been populated`) } /> <h1>First Post</h1> <h2> <Link href="/"> <a>Back to home</a> </Link> </h2> </> ) } strategyでlazyOnloadを指定しています。これにより、ページ表示速度を向上できます。 onLoadでは読み込み完了後の処理を指定できます。今回は読み込みが完了したことをコンソール出力します。 http://localhost:3000/posts/first-post にアクセスするとコンソール出力ができていることが確認できました。 また、Networkで読み込み順を確認したところ、first-post.js の後に sdk.js が読み込まれていることも確認できました。 CSS Styling pages/index.js にはすでにいくつかのスタイル指定があります。 styled-jsxというCSS-in-JSライブラリを使用しており、Reactコンポーネント内でCSSを記述できるようになります。 Next.jsにはstyled-jsxのサポートが組み込まれていて、読み込むファイルの拡張子を .css から .sass に変更すればSassの読み込みも可能になります。 Layout Component ここでは、すべてのページで共通で使用するレイアウトを作成していきます。 プロジェクトトップに components ディレクトリを作成し、 layout.js を追加します。 export default function Layout({ children }) { return <div>{children}</div> } 次に first-post.js で作成した layout.js をimportし、一番外側に追加します。 import Link from 'next/link' import Head from 'next/head' import Script from 'next/script' import Layout from '../../components/layout'; export default function FirstPost() { return ( <Layout> <Head> <title>First Post</title> </Head> <Script src="https://connect.facebook.net/en_US/sdk.js" strategy="lazyOnload" onLoad={() => console.log(`script loaded correctly, window.FB has been populated`) } /> <h1>First Post</h1> <h2> <Link href="/"> <a>Back to home</a> </Link> </h2> </Layout> ) } Adding CSS 実際に Layout コンポーネントにスタイルを追加してみます。 components/layout.module.css を作成し、Layoutコンポーネントに追加します。 .container { max-width: 36rem; padding: 0 1rem; margin: 3rem auto 6rem; } http://localhost:3000/posts/first-post にアクセスすると、スタイルが適用されたことがわかります。 クラス名が layout_container__fbLkO になっているのは、cssモジュールの機能で一意のクラス名を生成しているからです。 これでクラス名の衝突を気にする必要がなくなります。 Global Styles ここでは、グローバルに適用できるCSSスタイルを作成します。 cssモジュールはページ単位のスタイル指定に役立ちますが、すべてのページにスタイルを反映させたい場合は、以下のように指定します。 まずはすべてのコンポーネントに共通する最上位のコンポーネントを pages/_app.js として新規作成します。 export default function App({ Component, pageProps }) { return <Component {...pageProps} /> } Restart the Development Server pages/_app.js を追加する場合は、開発サーバーを再起動する必要があります。 // Ctrl+c で起動していたサーバーを一度停止します $ npm run dev Adding Global CSS プロジェクトトップにstylesディレクトリを作成し、global.cssファイルを追加します。 html, body { padding: 0; margin: 0; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; line-height: 1.6; font-size: 18px; } * { box-sizing: border-box; } a { color: #0070f3; text-decoration: none; } a:hover { text-decoration: underline; } img { max-width: 100%; display: block; } http://localhost:3000/posts/first-post にアクセスすると、スタイルが適用されていることがわかります。 global.css は pgaes/_app.js 以外のファイルでのimportはできないので注意しましょう。( 公式 ) Polishing Layout ここまで作成してきたレイアウトファイルを改善していきます。 Update components/layout.modle.css layout.module.cssを次のように変更します。 .container { max-width: 36rem; padding: 0 1rem; margin: 3rem auto 6rem; } .header { display: flex; flex-direction: column; align-items: center; } .backToHome { margin: 3rem 0 0; } Create styles/utils.module.css styles/utils.module.cssを次のように作成します。 .heading2Xl { font-size: 2.5rem; line-height: 1.2; font-weight: 800; letter-spacing: -0.05rem; margin: 1rem 0; } .headingXl { font-size: 2rem; line-height: 1.3; font-weight: 800; letter-spacing: -0.05rem; margin: 1rem 0; } .headingLg { font-size: 1.5rem; line-height: 1.4; margin: 1rem 0; } .headingMd { font-size: 1.2rem; line-height: 1.5; } .borderCircle { border-radius: 9999px; } .colorInherit { color: inherit; } .padding1px { padding-top: 1px; } .list { list-style: none; padding: 0; margin: 0; } .listItem { margin: 0 0 1.25rem; } .lightText { color: #666; } Update components/layout.js layout.jsを次のように変更します。 import Head from 'next/head' import Image from 'next/image' import styles from './layout.module.css' import utilStyles from '../styles/utils.module.css' import Link from 'next/link' const name = 'mi-ya' export const siteTitle = 'Next.js Sample Website' export default function Layout({ children, home }) { return ( <div className={styles.container}> <Head> <link rel="icon" href="/favicon.ico" /> <meta name="description" content="Learn how to build a personal website using Next.js" /> <meta property="og:image" content={`https://og-image.vercel.app/${encodeURI(siteTitle)}.png?theme=light&md=0&fontSize=75px&images=https%3A%2F%2Fassets.vercel.com%2Fimage%2Fupload%2Ffront%2Fassets%2Fdesign%2Fnextjs-black-logo.svg`} /> <meta name="og:title" content={siteTitle} /> <meta name="twitter:card" content="summary_large_image" /> </Head> <header className={styles.header}> {home ? ( <> <Image priority src="/images/profile.jpg" className={utilStyles.borderCircle} height={144} width={144} alt={name} /> <h1 className={utilStyles.heading2Xl}>{name}</h1> </> ) : ( <> <Link href="/"> <a> <Image priority src="/images/profile.jpg" className={utilStyles.borderCircle} height={108} width={108} alt={name} /> </a> </Link> <h2 className={utilStyles.headingLg}> <Link href="/"> <a className={utilStyles.colorInherit}>{name}</a> </Link> </h2> </> )} </header> <main>{children}</main> {!home && ( <div className={styles.backToHome}> <Link href="/"> <a>← Back to home</a> </Link> </div> )} </div> ) } Update pages/index.js index.jsを次のように変更します。 import Head from 'next/head' import Layout, { siteTitle } from '../components/layout' import utilStyles from '../styles/utils.module.css' export default function Home() { return ( <Layout home> <Head> <title>{siteTitle}</title> </Head> <section className={utilStyles.headingMd}> <p>[Your Self Introduction]</p> <p> (This is a sample website - you’ll be building a site like this on{' '} <a href="https://nextjs.org/learn">our Next.js tutorial</a>.) </p> </section> </Layout> ) } http://localhost:3000/ と http://localhost:3000/posts/first-post にアクセスすると、それぞれスタイルが変更されたことが確認できました。 まとめ この記事ではNext.jsのチュートリアルを半分やってみるところまでを記載しました。 ずっとReactを使ってきたので記述方法など同じで理解しやすかったですし、Next.jsは標準サポートしている機能が多くとても便利という印象です。 もう少し触ってみてからReactとの違いをまとめておけると今後のためのインプットになりそうな予感がします。 ここまでのソースは github に上げたので興味のある方はぜひ一緒にNext.jsと仲良くなっていきましょう! また後日残りの半分もやってみて記事にしたいと思います。
アバター
こんにちは!ウエディングパークのエンジニアのほんぼです。 今回はアウトプットの苦手意識を克服するために行った「Advent Calendar in バレンタイン 2022」についてお話させていただきます。 先にまとめを言うと、アウトプットの苦手意識が改善され、さらに他のメンバーのナレッジまでインプットできた最高のイベントとなりました。 目次 そもそもAdvent Calendarとは Advent Calendar in バレンタイン 2022 でやったこと やってみてよかった点 やった結果 まとめ そもそもAdvent Calendarとは Advent Calendarはクリスマスまでの日数をカウントダウンするために使われていたカレンダーです。 12月1日からはじまり、25個ある「窓」を毎日1つずつ開けて中に入っている小さなお菓子やプレゼントを楽しむもので、 近年このカレンダーにならい、インターネット上において定められたテーマに従い参加者が持ち回りで自身のブログやサイトに記事を投稿する企画が多く実施されています。 そこで、今回はこのAdvent Calendarに習って1ヶ月間の期間を用意しアウトプットに苦手意識のあるメンバーでアウトプットを毎日出し続けるというイベントを行いました。 ※行った時期が1/17~2/14とクリスマスと全く関係ないですが、アウトプットすることに早いも遅いもないという精神で走りきりました Advent Calendar in バレンタイン 2022 でやったこと 今回は以下のような内容で行いました。 実施期間:1/17~2/14 メンバー:アウトプットに課題を感じている5名 アウトプット内容:ディレクターやクリエイターが学べること全般 アウトプット方法: * 社内のナレッジベース(DocBase)に投稿 * 毎週アドベントカレンダーチームのミーティングで読み合わせを行う 1営業日につき1つのアウトプットを出したかったので、自分以外で4人のメンバーを集めて1人週1回投稿することにしました。 通常業務の中でアウトプットに課題を感じていると言っていたメンバーに直接声をかけてチームを組みました。 担当サービスや入社年次、職種がバラバラなメンバーが集まったので、記事内容も十人十色でとても良かったです。 また、週一で共有ミーティングを設けることでお互いのアウトプットをスムーズにインプットすることができました。   ▼参加メンバー ほんぼ(ウエディングパーク担当エンジニア・4年目) Sさん(QA担当ディレクター・5年目) Tさん(Webつく担当エンジニア・2年目) MIさん(リングラフ担当エンジニア・1年目) MAさん(ウエディングパーク担当ディレクター・1年目)   やってみてよかった点 チームで行うことでやらなければという気持ちが芽生えた 自分もそうですが、個人でアウトプットをしようと思っても中々行動に移すことができないものかと思います。 理由としてはアウトプットはインプットしたものを誰かに伝えるために整理する時間と労力が必要だからだと思います。 開発を進めるとインプットはできてもアウトプットの工数確保ができず、後回しになってしまいます。 しかし、今回チーム戦にすることで他の人もやってるから自分もやらなければという良い責任感が生まれました。 アウトプットを評価してもらい、モチベーションが向上した 個人でアウトプットを行なっていても評価が見えないことが多々あります。 そうなると、アウトプットするモチベーションが下がり、アウトプットしようとする気持ちが減っていきます。 そこで、今回は1週間に一度集まって、投稿した記事を読み合う場を設けました。 その結果、お互いの記事内容を知ることできるだけでなく、褒め合うことでモチベーション向上にも繋がりました。 自分の中で生まれていたアウトプットの敷居の高さを下げられた 若手によくあるつまずきポイントとしてアウトプットの質に問わられすぎて発信ができなくなってしまうことがあります。 そこで今回は1週間いに1つという期限を設けることでアウトプットする習慣をつける意識をしました。 その結果、アウトプットの容量を掴み、アウトプットしやすい環境が生まれました。 やった結果 Advent Calendarをやる前とやった後でアウトプットのスキルは大きく改善することができました。 また苦手を感じていたメンバー全員がやってよかった・次回も参加したいと回答してもらったので とても良いイベントにできたのではないかと思います。 まとめ 当初Advent Calendar in バレンタイン 2022はアウトプットの苦手意識をチームで改善できればと思い行いましたが、 結果として苦手意識改善だけではなく、他のメンバーのナレッジまでインプットできた最高のイベントになったかと思います。 アウトプットは相手に適切な内容を伝えるため、自分の中で理解させる必要があります。 そのため、インプットしただけの状態よりもしっかりとした理解に繋がるので、 この記事を読んで興味を持った人は是非試してください!
アバター
こんにちは。結婚指輪・婚約指輪のクチコミサイト「Ringraph」でエンジニアをしているさー( @__south__373 )です。 先日、これから約一年かけて取り組んでいくRingraphシステムのロードマップを作成したので、内容の宣言と共にどうやって作り上げたのか紹介したいと思います。 Ringraphが掲げている合言葉 本題に入る前に、今回のロードマップを決める判断材料の一つとなった、チームが掲げている合言葉をご紹介させてください。 Ringraphでは”指輪探しの「代名詞」になる”という意義目標を掲げて日々サービス運用をしています。そんなサイトに育てていくため、開発チームでは合言葉を決めています。 ふたりの一歩目にワクワクを 指輪探しはこれから結婚をする、結婚を決めたカップルが最初の一歩目を踏み出すイベントです。そんなイベントが思い出に残る素敵なものとなるよう、楽しくわくわくしながら指輪を探せるようなお手伝いをしたいという想いを込めています。 なぜロードマップを作ろうと思ったか さて、ここからが本題です。 エンジニアは通常の運用開発をすると共に技術的な挑戦が求められます。技術的な改善や新しい取り組みは特に方針があったわけではなく、エンジニア自身がこのサイトに必要だと思うこと、かつ挑戦してみたいことをリストアップし、3ヶ月ごとに取り組むものを決めるというやり方をしていました。 この運用で半年ほど進めていった中で、徐々にある思いが大きくなっていきました。事業としては年間単位で計画を立ててそこに対し達成のプロセスを考えていくのに、技術の面に関しては少し行き当たりばったりな感じがするなと。 そこで一度システム面でも年間のロードマップを作ってみたいという提案を事業責任者にしたところ快く承諾してもらえました。 進め方 1. 何に注力するか決める まずはもともとリストアップしていたやりたいことリストの中から、サイトとしてやっていくべき優先度が高いものをピックアップすることにしました。 フレームワークの一新や新しい技術導入など色々ありましたが、普段の運用の中でもサイトの速度がたびたび課題に上がっていたこと、「ふたりの一歩目にワクワクを」を叶えていくためにも速度改善は本腰を入れる必要があると感じたことから速度改善に注力したいということはすぐに決まりました。 2. まずは現状把握 改善の目標を決めるため、New Relicで現状把握を行いました。 サイトの表示は2-3秒が望ましいとよく言われますが、いくつかのページでその指標を超えていることがわかりました。 次に、サーバーサイドとフロントエンドにかかっている時間をそれぞれ出し、どのフェーズをどれぐらい改善する必要があるのかを数値化しました。 3. どうすれば達成できるかブレスト 数値化してみたところ、サーバーサイドを約50%、フロントエンドを約28%削る必要がありそうでした。 もともとリストアップしていた改善項目やLighthouseの指摘事項などを参考に、サーバーサイドとフロントエンドでやれそうなことをそれぞれ洗い出し、工数を出した上でどんな順番で着手していくかを決めました。 4. 関係者と壁打ち 2割共有が大事だとよく言いますが、はじめてやってみることだったので頻繁に事業責任者に共有することを意識し、方向性がズレていないことを確認しながら進めました。 ブレストの段階では、エンジニアマネージャーや一緒に開発をしているメンバーに共有をしてアドバイスをいただいていました。その結果、最終的に約一年間かけてこんなことをやりたいです、工数くださいという段階でスムーズに内容承諾をいただけたと思っています。 5. 自チームや全社エンジニアに共有 最後に、決めた内容を営業を含めたチームのメンバーと全社エンジニアに向けて共有しました。 宣言することで期待値が上がって応援してくれる人が増えたり、こんなことができるんじゃないかというサポートがいただけたり良いことしかないなと思ったからです。あとは純粋に自分へプレッシャーをかけるためでもあります。 やってみて 前々からやりたいと思っていた速度改善だったのですが、新しい開発に工数を割くことが多くなかなか着手するのが難しい領域でした。 今回、事業メリットとも絡めて今コミットしていくべきという認識を擦り合わせられたことで、注力プロジェクトとして取り組むことが決まりました。 採用いただけたことが嬉しい反面、ここからがスタートであり、現時点で構想している改善だけではおそらく達成が難しいと感じています。プロジェクトを進めていく中で、内容をブラッシュアップしながら達成まで頑張っていきたいと思います。 さいごに ウエディングパークでは、一緒に技術のウエディングパークを創っていただける仲間(エンジニア)を募集しています。 興味のある方はぜひ一度気軽にお話ができたら嬉しいです! 【クリエイターズ大解剖】エンジニア編 https://www.wantedly.com/companies/weddingpark/post_articles/349428
アバター
こんにちは!前撮りなど結婚写真の撮影スタジオ・サロンを検索できる情報サイト「 Photorait 」のメインデザイナーをしています、かおりん( @PANbooooo )です。 2020年の10月から1年間、「アウトプットを意識する」ということを心がけて、外部への発信等を進めてきました。今回は、この1年間での学びや得たものなどを紹介したいと思います。 クリエイターのアウトプットの参考になれば幸いです。 アウトプットを意識した理由 リモートワークという働き方になってから、チームメンバーや他部署の方、他社の同業者の方に自分自身が起こしたアクションを知ってもらう場が少なくなったと思いました。実際に、「デザイナーって何をやっているの?」という声を聞くことも多くなりました。「このままではいけない!自分自身をどんどんアピールしないと!」と考えた私は、自己アピールのために、アウトプットをしていくことを決めました。 アウトプットのために取り組んだこと まず、アウトプットを心がけてから、どんなふうにアウトプットをしていくのか、使うツールやその頻度などの詳細について決めていきました。 そして、自分に3つのルールを課しました。 ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ・Qに1本、クリエイターブログに記事を投稿する  結果→1年で5本投稿 ・Qに1回、LT会に登壇者として参加する  結果→1年で6回登壇 ・月に2本、社内情報共有ツールにナレッジを投稿する  結果→1年で32本投稿 ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー ー LT会については、毎週月曜日に connpass で勉強会やイベントを探し、自分自身が登壇できそうなイベントがあったら、申し込みをするようにしました。ここでは「勢い」がとても大事だと思い、登壇内容が決まっていなくても、とりあえず申し込みボタンだけはその場で押すようにしていました。 こうやって「登壇しないといけない環境」を自ら作り、自分で自分を追い込むことで、振り返ればこの1年で6回ほど登壇をさせていただきました。 アウトプットを意識して得たこと アウトプットを意識してからたった1年ですが、得たものはとても多かったです。 その中で、特に感じた3つの「得たこと」を紹介したいと思います。 1:物事への理解がさらに深くなる 登壇資料の作成時やブログへの執筆時に、「どうしてそう思うのか?」や「なぜこの作業をしたのか?」など、自分自身の行動や想いについて疑問を投げ、答えを導き、他者へわかりやすく伝えるための「情報」に変換していくことで、物事への理解がさらに深くなっていき、視野を広げる事ができました。 2:色々な人からフィードバックをもらえるようになった LT会では「自己流のデザインの勉強法」や「開発のウラ話」「チームでおこなったワーク」など、様々な内容のものを各イベントで発表させていただきましたが、他の参加者の方から「このワーク、もっとこうすると面白そうですね」や「あそこをこうやって変えるのおすすめですよ」などの、新たな視点でのフィードバックを頂く事があり、すごく勉強になりました。 3:創ったものを知ってもらう機会が増えた これは必然的なことですが、自分自身が開発に携わったサービスなどについて、外部へどんどんアウトプットをすることで、知ってもらう機会が増えました。特に、LT会への参加はその効果が大きく見られ、LT会で登壇させていただいた後にTwitterでイベントのハッシュタグを検索すると、「Photorait使ったことあります」や「今度使って見よう!」などの嬉しいお言葉を頂く事が出来、サービスの宣伝にも繋がったと思います。 さいごに 今後も「アウトプットを意識する」ということは心がけつつ、アウトプットの形を変えていきながら、またさらに新しいものを得られればと思います。 また、この1年に参加したLT会などは他社のイベントのものがほとんどであったため、自分たちでLT会を開き、アウトプットの場をどんどんと作っていければと思います。
アバター
こんにちは、SRE エンジニアの綿引です。 今回は Amazon GuardDuty を取り上げたいと思います! 弊社でも GuardDuty は導入しているのですが如何せん確認が億劫になりがちです、、 そこで今回以下を記事にしようと思います! GuardDuty の概要 検知結果を Slack に通知する方法 同じような悩みを抱えている方の参考になれば幸いです。 因みに対象の方は以下のような方でしょうか。 GuardDuty を有効にしているが毎回マネージメントコンソールから確認している or 放置してしまっている GuardDuty をまだ使用していない Amazon GuardDuty とは Amazon GuardDuty は AWS 環境や AWS アカウントに対する不正な動作や攻撃を検知してくれる脅威検出サービスです。 特徴を簡単にまとめると以下です。 以下のログなどを取得・分析して攻撃と思われる操作を検知してくれる AWS CloudTrail イベントログ Amazon VPC フローログ DNS ログ ログの分析には機械学習を用いている 使用方法はマネジメントコンソールから GuardDuty を開き 有効化 するだけ 機械学習を用いて通常時とは異なる挙動や、攻撃や脅威を検知してくれるなんて素敵なサービスですね。 試しにどんな情報を検知するのか、検証用の AWS アカウントを作成して確認してみました。 色々検出してくれたのですが、その一例が以下です。 Amazon S3 ブロックパブリックアクセスの無効化 EC2 への ブルートフォースアタック IAMUser がいつもと違う API を発行した S3 や EC2 、IAM など様々なサービスで怪しい動きを検知してくれ、頼りになりそうです。 料金 続いて 料金 ですが、以下は東京リージョンの料金になります。 AWS CloudTrail 管理イベント分析 4.72 USD/100万イベント AWS CloudTrail S3 データイベント分析 – 最初の 5 億イベント/月 : 1.04 USD/100万イベント – 次の 45 億イベント/月 : 0.52 USD/100万イベント – 50 億を超えるイベント/月 : 0.26 USD/100万イベント VPC フローログと DNS ログ分析 – 最初の 500 GB/月 : 1.18 USD/GB – 次の 2000 GB/月 : 0.59 USD/GB – 次の 7,500 GB/月 : 0.29 USD/GB – 10,000 GB/月を超えた場合 : 0.17 USD/GB 料金はイベント数や使用量によるので少しわかりづらいですが、だいぶ安い金額になっております。 GuardDuty の検知結果を Slack に通知する Slack 通知には以下のサービスを使用します。 GuardDuty CloudWatch Events SNS Chatbot(対象の Slack アカウントと連携済みの想定) IAM Role Slack SNS・Chatbot・IAM Role に関しては CloudFormation で作成します。 イメージはこのような形です。     尚、SNS トピックの サブスクリプション には Chatbot だけでなく、メールも送信するように設定を入れております。 では早速設定をしていきましょう。 Slack のチャンネルID と ワークスペースID を取得する まずは Slack のチャンネルを作成します。既存のチャンネルに通知したい場合は新規の作成は不要です。 チャンネル名は任意ですが、私は [# note-aws-guardduty] にしました。 次に Slack の [SlackチャンネルID] と  [ワークスペースID] を取得します。これはCloudFormation にて Chatbot を作成する必要になります。 確認方法としては以下です。 SlackチャンネルID Slack のアプリを起動 通知したいチャンネルの [Copy link] をクリック 貼り付け結果の /archives/ の後の文字列がチャンネルID https://XXXXXXX.slack.com/archives/YYYYYYYYYY      ←  この Y の部分 ワークスペースID AWS マネジメントコンソールより Chatbot を選択 [接続済みクライアント] の Slack アカウントを選択 [ワークスペースの詳細] に記載   CloudFormation にて SNS・Chatbot・IAM ロールを作成・設定する 続いて SNS トピック・Chatbot・Chatbot に付与する IAM ロールを CloudFormation で作成・設定します。 以下が CloudFormation の yaml ファイルです。 AWSTemplateFormatVersion: "2010-09-09" Description: GuardDuty to Slack # Slack のワークスペースIDとSlackチャンネルIDを入力 # Slack のワークスペースは事前に作成しておく Parameters: TargetWorkspaceId: Type: String Default: XXXXXXXXX # 先ほど取得したワークスペースIDを記載 TargetChannelId: Description: "note-aws-guardduty" Type: String AllowedValues: - "XXXXXXXXXXX" # 先ほど取得した SlackチャンネルID を記載 Resources: # GuardDuty用のSNSトピックの作成 GuardDutyForChatbotTopic: Type: AWS::SNS::Topic Properties: TopicName: GuardDuty-for-Chatbot-topic Subscription: - Endpoint: XXX@XXXXXXXXXXXX # 通知を受けたいメールアドレスを記載 Protocol: email # GuardDuty用のChatbotの作成 ChatbotForGuardDuty: Type: AWS::Chatbot::SlackChannelConfiguration Properties: ConfigurationName: GuardDutyAlertChannel IamRoleArn: !GetAtt ChatbotIamRole.Arn LoggingLevel: INFO SlackChannelId: !Ref TargetChannelId SlackWorkspaceId: !Ref TargetWorkspaceId SnsTopicArns: - !Ref GuardDutyForChatbotTopic ChatbotIamRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: chatbot.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: chatbot-iam-policy PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - cloudwatch:Describe* - cloudwatch:Get* - cloudwatch:List* Resource: - "*"   CloudWatch Events を設定する 最後に CloudWatch Events を設定して、GuardDuty と SNS を連携します。 マネジメントコンソールより CloudWatch を選択し、[イベント] → [ルール] → [ルールの作成] をクリックします。   ルールの作成では以下の項目を入力していきます。 イベントソース : イベントパターン サービス : GuardDuty イベントタイプ : GuardDuty Finding ターゲット : SNS トピック トピック : GuardDuty-for-Chatbot-topic(先ほどの CloudFormation で作成)     これで全ての設定が完了しました。 GuardDuty で異常を検知すると以下のように Slack とメールが通知されます。   最後に 今回は GuardDuty の検知結果を Slack に通知する方法を記載しました。 GuardDuty を含め Config や CloudTrail などセキュリティ系のサービスは即時チェックしたいので、できればチャットに飛ばしたいという思いからやってみましたが、上手くいってよかったです。 次は他のセキュリティ系のサービスでのチャット連携と、terraform での作成などもやっていきたいと思います。
アバター
こんにちは。エンジニアのなりです。 今日は普段のお仕事についてご紹介をしたいと思います。 その前に、まずは簡単に自己紹介をさせていただきます。 私は2015年に新卒でウエディングパークに入社をしました。入社から2020年9月までは、 結婚準備クチコミ情報サイト 「 ウエディングパーク 」 のサービス開発に携わり、その後新規事業の フォトウエディングの決め手が見つかるクチコミサイト 「 Photorait 」 の開発を担当しております。 大規模なサイト開発のためエンジニアの人数も多く担当領域もしっかり分かれているウエディングパークの組織と、立ち上げからの日が浅くエンジニア数名で明確な担当分けをしていないフォトレイトの組織を経験しました。 組織規模の違うサービス開発に携わった経験を踏まえて、今回は主に新規事業であるフォトレイトのサービス開発のご紹介をいたします。   どんなお仕事してる? まず、一番メインの業務である開発についてご紹介します。 私は、主にフォトレイトの自社広告商品の新規開発を担当しています。 自社広告とは、サイト内にバナー等を配信できる純広告、掲載内容をよりリッチに見せることが出来るオプション商品のことを指します。 私が最近開発した商品は、このオプション商品のひとつ「こだわりハイライト」です。 フォトレイトでは、フォトスタジオを検索する際にエリア絞り込みだけでなく、様々なこだわりでも絞り込む事が可能です。 こだわりの例としては、「海で撮影出来る」や「マタニティプランがある」などです。 今回の商品は、こだわりで検索した際に、その検索条件に沿った情報を全面に出した専用ページへ誘導し、ユーザーが欲しい情報をすぐに届けることができる、といった内容になっています。たとえば「スタジオで撮影したい」を選択すると、検索画面から選択したスタジオの情報ページは、スタジオで撮影したお写真や、スタジオで撮影するのにぴったりなプランが特集されたページへ遷移できる、ということです。 各こだわりごとに、フォトスタジオさんがおすすめしたい情報を入稿できる管理画面を開発し、それが表示される検索画面等を開発しました。   このような商品をつくる過程では、プログラムを書くだけでなくディレクターや営業メンバーと一緒に、自社広告の新規商品や機能アップデートのアイディア出しにも参加します。 そのアイディア出しにエンジニアも参加することで、「絶対にこの商品はユーザーやクライアントに喜んでもらえる」と確信を持てる商品づくりができるので、開発もモチベーション高くやりがいを持って「早く届けたい」という気持ちで取り組むことができます。   開発以外では、どんなことしてる? 開発以外では、私は組織づくりの取り組みをしていることが多いです。 どうしたらビジョンに真っ直ぐ突き進める強い組織になれるか?やりがいを持ってポジティブに働ける環境を作るには?コミュニケーションが円滑にとれる関係性を築くには何が必要か?、そんなことを議論してアクションする仕事が好きでした。 例えば、 ・部署の組織課題をメンバーが当事者意識を持って解決する「おためしマネージャー」というミッション ・フォトレイトの未来をつくる「 イノP会議 」の運営 など、部署やチームの組織づくりには積極的に参加しています。   どんなときにやりがいを感じる? お仕事紹介の中でも少しご紹介しましたが、やはりユーザーや業界の方々に役に立てた瞬間が一番嬉しく、やりがいを感じる瞬間です。 少数のチームだからこそ、営業メンバーとは頻繁にコミュニケーションをとる機会があります。クライアントがどんな課題を抱えているのか、どんな機能があったら嬉しいか、そのような情報を逐一教えてもらうことが出来ます。そんな課題に、エンジニアとして商品開発で携わり、機能をリリースして、結果が出てくれたときには、とても嬉しいです。 あとは、身近な友人が自分の携わるサービスを使ってくれているのも嬉しいです。「式場(またはフォトスタジオ)を探してるんだけど、ここどうかな?」という相談で送ってもらうURLがウエディングパークやフォトレイトということもよくあります。そうやって、私の会社と知らない友人が自然と使ってくれているところを知ると、やってて良かったなと思います。   今後チャレンジしたいこと サービス開発のより上流工程に携わっていきたいと思っています。 6年前、「結婚を、もっと幸せにしよう。」という経営理念に共感して、入社を決めました。そこへの思いは常に強く持っています。 価値観が日々変化し続ける状況の中で、「結婚」が豊かで幸せな瞬間で溢れ続けるためには、変化を恐れずに今必要とされる「結婚」の形を探し続けることが大切だと思います。サービスづくりを通じて、幸せな結婚を追求することで社会に貢献していきたいです。  
アバター
ウエディングパークのメディア運営チームでマネージャーをしている小山です。 この記事では私の経験からウエディングパークのマネージャーの仕事ややりがい、大切にしていることを主に学生の方に向けて紹介したいと思います! プロフィール 2014年に新卒エンジニア2期生としてウエディングパークに入社し、サーバーサイドエンジニアとして「Wedding Park」の広告商品のアップデートやカップル向けのコンテンツ開発、姉妹サイトの運営など幅広く担当する機会に恵まれました! 組織づくりやメンバーの成長を通してチームの技術力を高め、事業や業界に貢献したいと考え入社3年目からマネージャーに役割が変わり、約5年経過しました。   どんな役割? ウエディングパークのエンジニアマネージャーの役割は 「プロダクトと人に向き合い、組織成果を最大化させる」 ことだと考えています。 エンジニアマネージャーの役割範囲は会社によって様々だと思いますが、 ウエディングパークでは、エンジニアリングやプロダクトのマネジメントと同時に組織づくりに貢献することが求められます。 自分たちがつくるプロダクトへの愛着を持てる人、「人」が好きな人にはもってこいの役割です!     開発マネージャーとしての役割 戦略づくり 中長期的な技術戦略やプロダクトのバージョンアップや保守など、技術にまつわる様々な戦略立案や実行のファシリテートを行います。 例えば、注力技術を定めエンジニアメンバー全員で推進する戦略を立てることや、オンプレミスで運用していたプロダクトのAWS移行などを実現しました。 また、みんなの考え方を一致させて技術推進を加速させるために行動指針づくりなどの取り組みも行っています。 ウエディングパークのクリエイターが大切にしたいこと|ウエディングパークの『ン』。|note ピープルマネジメント エンジニアのみんなが最大限に能力を発揮できる環境をつくるために1on1でコンディションの確認、キャリアビジョンのすり合わせなどを行います。 強みを伸ばすことを基本的な考え方として、活躍の場をアレンジしたり成果をわかりやすく全社に伝える工夫を考えて実行します。 プロジェクトマネジメント ウエディングパークでは年次、役職に関係なく役割に適したメンバーがプロジェクトマネジメントを担当していますが、 エンジニアマネージャーは技術導入やリプレイスなどのプロジェクトの推進役を担うことが多くあります。 エンジニアとしての実装経験を基にメンバーと最適なプランを構築しながらプロジェクトを成功に導きます。     全社マネージャーとしての役割 活性化 ビジョンにむかってみんながイキイキと活躍できる環境を作るために担当チーム以外のことにも目を配り組織カルチャーの浸透を図ります。 ウエディングパークでは全社が集まるイベントが多くありますが、その場の運営を行うこともあります。 バードビューで組織づくりをする意識が大切です。 採用 新卒・中途採用にも積極的に関わります。 会社全体で自分たちの仲間は自分たちで集めるという文化があるので、エンジニアのみんなにも協力をしてもらいながら未来のウエディングパークを一緒に創っていくミッションとして力を入れています。 自分が採用に関わったメンバーが入社後活躍している姿を見るのがとても嬉しい瞬間です! 大切にしていること エンジニアリングで事業成果を最大化させるために、ブライダル業界の理解や社内の他の職種の活動を理解することがとても大切です。 様々な方面に関心を持って技術の活かし方を提案できる人材になりたいと考えています。 もうひとつ強く意識しているのは、マネージャーはあくまでも役割であるということ。 マネージャー業務の性質上ものごとの優先順決めや評価など、いくつかの権限を委譲されています。 これは、メンバーが良い仕事をするための手助けや、生産性を上げる仕組みを整えるために使うべきであるということを絶対に忘れてはいけないと考えています。 やりがい・おもしろさ プロダクトを通してブライダル業界に貢献し、人々の幸せを創っていく開発の仕事はとても充実感があります。 メイン事業である結婚準備クチコミ情報サイト「Wedding Park」は10年以上運営しており、webメディアとしてはかなりの歴史があります。 歴史ある大規模サービスをエンジニアリングで守りながら進化させていくこと、 DXやAI、ビッグデータ活用のような新規性の高い技術で業界にイノベーションを起こしていくこと。ひとりの力では絶対になし得ないことをビジョンに共感した仲間と一緒にカケザンで実現していくマネージャーの仕事は毎日とても刺激的です。 「マネージャーと聞くと技術と距離ができるのでは?」 と思う方も多いと思いますが、そんなことはないと考えています。 確かにマネージャーに求められる仕事は開発以外にも多岐にわたるため、自ら手を動かす時間は物理的に減ることになりますが プロフェッショナルなメンバーと一緒に戦略を考え実行する過程で多くの技術的インプットがあります。 私自身、一緒に仕事をするテックリード(技術選定や技術推進、チームの技術底上げなどを行ってるエンジニア)と技術戦略を考える中で発見があり知識を絶えずアップデートさせてもらっています。 より技術を見ているプロフェッショナルと、より組織を見ているマネージャーが一枚岩で仕事をすることで、技術活用のアイディアが 広がり新しい価値を生みだせるはずです。 マネージャーとしてはまだまだ修行が必要な身ですが、みんなで切磋琢磨しながら組織も個人も成長させていきたいと思います!!
アバター
はじめまして、エンジニアのしげです。 今日はウエディングパークが提供しているクライアント向けツールを開発するエンジニアの仕事内容を紹介したいと思います。 まず僕の自己紹介をさせていただきます。 僕は2017年に新卒でウエディングパークに入社しました。入社してから花嫁のための結婚式準備レポート 「ハナレポ」 やオンライン接客支援ツール 「フェアつく online」 の開発に携わり、2021年2月からDX推進室へジョインし、 AIパトローラー の開発を開発リーダーとして担当しました。 今日はAIパトローラーの0→1開発で自身が初めて開発チームを牽引した経験について紹介しますので、これからチーム開発を始める人の参考になれば嬉しいです。 普段の業務について まずはじめに僕が所属しているDX推進室について軽く紹介させていただきます。DX推進室はウエディング企業のDX支援強化を目的に2020年に設立された部署になっており、2021年7月にAIパトローラーというサービスをリリースいたしました。 DX推進室でのエンジニアの業務はAIパトローラーの運用開発や監視がメインなのですが、それだけではありません。 インフラ環境の技術改善や技術キャッチアップをするMTG(毎週) 部署の目標や全体進捗を確認するMTG(毎週) 開発の進捗確認や開発課題について議論するMTG(毎日) DX業界についてランチ時間を使ってキャッチアップする会(不定期) 職種混合の新機能提案合宿(不定期) など、技術的な挑戦やDX業界のキャッチアップをしており、コミュニケーションも活発な部署になっています。 ↑先日の合宿の様子 運用開発ではAIパトローラーへの機能追加を行ったりより使いやすいデザインへ変更したりなどをしているのですが、これは実際にクライアントからいただいた声がもとになっている部分もあるため、「クライアントにより良いものを届けたい」という想いで開発に臨むことができます。 0→1開発でチームを牽引するためにやったこと 共通の開発ルールの設定 ここでは開発リーダーとして開発を進めるにあたってどんな工夫をしたかについて話をしたいと思います。 工夫した点1つ目は開発ルールを初めに決めたことです。 AIパトローラーの開発チームは僕の他にもエンジニアが複数いました。ウエディングパークサイトの開発であればすでにあるコードを参考にすることもできるのですが、今回は0→1開発だったため参考にするものがなく、また、初めから開発メンバー全員が開発方針について同じ認識をしているわけではありませんでした。 そこで開発に着手する前に、チームで実装方針についてディスカッションする時間を作りルールを決めました。そうしたことで実装に着手してからメンバーごとの実装が違う、といったことがなくスムーズな開発につながったと思います。また、このファイルを変更したら共有する、コードレビュー依頼はこの単位で出すなど開発の進め方についても決めることができたので、認識ずれやレビュアーの負担が大きくなったりということも起きずに進められました。 ↑開発ルールの一部 全体の開発に関わる実装は優先度を上げ自分で対応 工夫した点2つ目は開発全体に影響するタスクを積極的に対応したことです。AIパトローラーではDockerを使った開発をしており、データベース構築やデータの生成もLaravelの機能を使って簡単にできるようにしていました。しかし開発規模が大きかったため、途中でテーブル構造やDockerfileの設定変更など予定外のタスクが発生することがありました。そういったタスクの優先度を上げ、開発リーダーの僕が対応することで、他のメンバーの開発スケジュールになるべく影響を与えずに、サービス全体がどういった状態になっているのかを常に把握しながら進めることができたと思います。 メンバーとの1on1を実施 工夫した点3つ目はエンジニアメンバーとのコミュニケーションを増やし開発フォローを徹底したことです。開発当時は全員フルリモートでの勤務だったため、メンバーが今何をしていてどんな状況なのかがオフラインで仕事をするときに比べて見えづらい状態でした。また今回初めて一緒に仕事をするメンバーもいたため、コミュニケーションが取りにくいのではないかという懸念がありました。そこで毎日実施していたチーム全体のMTG以外にも1対1のMTGを毎日設定し、どんな些細なことでも気になることがないかを吸い上げるようにしました。これが結果的に実装の相談や進捗確認だけでなく、チャットで聞くかどうか悩むレベルの質問も拾うことができたりなど、想定以上に効果的でした。 やりがいについて やりがいを感じるのはクライアントからの嬉しい声をフィードバックしてもらったときです。DX推進室は営業サイドと開発サイドの距離がとても近く週1回以上MTGをしており、クライアントからどういった声をいただいたか共有いただいています。AIパトローラーを契約してくださった理由や実際に出た効果を聞くと、作ってよかったなと感じますし、これからの励みにもなります。 また技術的にたくさん学びがあることも魅力の1つだと思います。僕は今までDockerを使った開発も未経験で、AWSの環境設定をする機会もありませんでした。ですがAIパトローラーの開発を通して、開発環境の構築をするためにDockerのキャッチアップをしたりAWS設定はインフラエンジニアと連携をして教えていただいたりとたくさんのことを学ぶことができ、今では改善の提案なども行っています。 今後チャレンジしたいこと より良いものを届けるための技術とアイデアの引き出しを増やしたいです。 AIパトローラーは運用フェーズに入っており、今後はもっと使いやすくするための機能を追加したり、利用してくださったクライアントから頂いた意見をもとに改修をしていく予定です。そういった改修のなかでもプラスアルファの価値を創造し少しでもクライアントの課題解決に繋げることが、DX推進室のエンジニアの役目だと思います。そのためには武器になる技術力をしっかりと身に付け、ウエディング業界とDX業界に常にアンテナを張って取り組みたいです。
アバター
こんにちは!ウエディングパーク新卒1年目エンジニアのダテです。 今回は、研修の集大成として取り組んだ社内アナログ施策のシステム化を通して学んだこと、工夫したこと、今後の課題と感じたことをまとめたいと思います。 エンジニアとしての技術というよりかは、チームの一員として開発に取り組んでの思いをまとめているので、これからチーム開発を行う多くの方に見て頂ける内容になっているかと思います。 目次 取り組んだ施策について 苦労したポイント 技術のこだわりポイント 良かったポイント 改善ポイント システム化を通して大きく成長できたポイント 取り組んだ施策について まずは今回システム化に至った背景とその社内施策についてです。今回システム化した社内施策は「シャッフル座席」というものでした。「シャッフル座席」とは出社時の社内活性化のために提案されたもので、毎朝出社したら座る席をくじ引きで決めるという内容です。 実際に「シャッフル座席」を導入してから普段は関わることの少ない社員の方たちと席が近くなることでコミュニケーションの活性化が起こった一方で、くじを紙で作っていたため「管理が難しい」という課題があがり、これを解決すべく私達がシステム化に取り組みました。 システム化のメンバー構成はディレクターが1人、デザイナーが2人、エンジニアが1人という普段の開発では経験することがあまりないデザイナー2人構成となっていました。 苦労したポイント その1:スケジュール調整 なるべくメンバーの空き時間ができないように、開発スケジュールを敷くのがとても難しかったです。エンジニア1人、デザイナー2人という構成だったので、役割分担と負担の兼ね合いを考えるのにとても頭を使いました。最終的に、ディレクターが中心となって、クリティカルパスを元に3パターンのスケジュールを作りました。「このタイミングでここまで進んでなかったら違うパターンのスケジュールに切り替える」といったように臨機応変に対応できるスケジュールを決められたのはスケジュール通りのリリースができた大きな要因だと思います。 その2:アプリケーション側の環境設定 普段の改修案件ではなかなか触ることのできないデータベース接続の設定、Sentry導入の設定、メール送信の設定など知識が浅かったため先輩に聴きながら1歩進んでは立ち止まるというのを開発序盤では繰り返していました。質問をする度に丁寧に教えてくれる先輩がいてくれたおかげで無事設定をすることができたので本当に感謝しています。また、自分で設定を行うことで設定周りのファイルの理解が深まったのは苦労してよかったポイントでした。 技術のこだわりポイント その1:非同期処理を一切使わなかったこと 非同期処理を使ったほうが情報のリアルタイム性を実現できるというメリットはあった一方で、その実装担当をJavaScriptを初めて触るデザイナーに任せる決断をしていたので、なるべくJavaScriptでの実装負担を軽くする手段を選びました。また、システムを利用できるのが社内に配置している1台のタブレットのみということが仕様で決まっていたので、データの差分が起きにくい状況だったのも非同期処理を使わない選択をした理由になります。 非同期処理を使わない分、1度のリクエストで取得する情報量が増えたのでLaravelでデータベースからデータを取得する際にEager Loadingを使用したりとデータ取得に掛かる負担を最小限に抑えるようにしたのもこだわりの1つです。 その2:データベースに保存するくじ引き結果を14日で削除するようにしたこと くじ引き結果は毎日データベースに保存されていくようにしたため、増えれば増えるほどデータ取得への影響が出てしまう可能性がありました。そうならないようにバッチ処理によってくじ引き結果を定期的に削除する実装を行いました。 保存する日数を14日にしたのはコロナウイルスの感染判別にかかる日数が14日であるため、万が一社内で陽性反応が出た際の接触の指標にできるようにしたかったのが理由になります。(こちらも先輩からのアドバイスあってのこだわりでした。本当にありがとうございます。) 良かったポイント その1:開発タスクを実装イメージができる粒度まで細分化したこと 自分が処理を頭でイメージできる粒度まで落とし込んでタスクを洗い出したことで、実装前から大体の流れをイメージしてすすめることができました。また、タスクの粒度が小さくなったことで工数の見積もりがしやすかったのも良かったポイントでした。加えて、デザイナーにお願いしたJavaScript周りもタスクを細分化していたことで初めてでもキャッチアップがしやすかったと言ってもらえたのが嬉しかったです。 その2:コードレビューの事前依頼をするようにしたこと 今回の開発では4人の先輩方にコードレビューの機会をいただいていたため、適切なタイミングで時間をもらえるかがスケジュール進行のカギでもありました。そのため、コードレビュー依頼日の目途が立ったら、いつまでに依頼ができれば希望日までに見てもらえるかを先輩方に事前に確認することで、タスクの優先度を調整しながら開発を進めることができました。これもスケジュール通りにリリースできた1つの要因だと思っています。 要改善ポイント その1:設計レビューの質が悪かった 0→1の開発であったにもかかわらず、設計レビューに持っていく際に文章と言葉のみで説明しようとしていました。その結果、処理の流れや重要ポイントの説明がうまくできず、先輩の理解力におんぶにだっこ状態の設計レビューをしてしまいました。また、このときは設計レビューの本質を理解しておらず、「実装する前に通らなければいけない門」のように思っていて、変な緊張もしていました。もっと実装における不安点や不明確な点の相談、方向性が間違っていないかのディスカッションをする場としての意識を持って行くべきだったなと今では思っています。また、説明をする際もフローチャートやシーケンス図などを用いた視覚的な説明をするべきだったなとも今では思っています。 その2:タスクの受け渡し時のすり合わせができていなかった リリース後テストの際に1つhotfix対応をしたのですが、修正の原因がデザイナーが作成してくれたモックアップをVIEWファイルに反映する際の分岐漏れでした。これはデザイナーとのすり合わせがしっかり出来ていれば防げたことでした。これはエンジニアとデザイナー間だけにとどまらず、実装方法が変わったときに新たにテスト項目として追加する必要がないかをディレクターとすり合わせる時もそうだし、チームで開発をしている以上、全員で認識をすり合わせておく必要があることを身にしみて実感しました。今回は最後のテストで気がつけたから良かったものの、もし気づけていなかったらと思うとゾッとしています。これからは今回のような社内システムだけではなく、世の中すべての人に使ってもらうメディアに携わるので、この失敗を胸にチームでの認識合わせを丁寧に行っていこうと思います。 システム化を通して大きく成長できたポイント 最後に、今回のシステム化を通して大きく成長できたポイントですが、「報連相」と「タスクの細分化」だと自分では思っています。 「報連相」 これはきっとエンジニア以外の方にも通ずることだと思いますが、関わる人達の「報連相」つまり「進捗、変化、意図を常に共有できているのか」というのは組織で仕事をしていくにあたって重要であり、仕事のスピードにも大きく関わってくると思っています。実際、今回チーム間で進捗や変化の報連相ができていなければ、臨機応変なスケジュール変更ができていなかったと思いますし、先輩へのコードレビュー事前依頼もなかったらスケジュール通りでリリースができていなかったと思っています。当たり前だけれど社会人として必要不可欠なこの報連相をシステム化をとおして学び、以前よりもできるようになったことは大きな成長の1つでした。 「タスクの細分化」 実は、このシステム化をする前の研修で開発タスクの細分化ができておらず、納得の行く結果を得られなくて悔しい思いをした背景がありました。その苦い思いがあったので、今回は細かすぎると言われるくらい細かくタスクを分割したら案の定開発がとてもやりやすかったです。また、細かくタスクを細分化することで実装イメージがつきにくい部分がわかり、そこの相談を先輩に予めしておくといったことにもつながったので、研修前の自分からしたらとても大きな成長だと思っています。今後の実業務においても細かいだろと言われるくらい細分化を行って丁寧な開発をしていきたいと思います。 最後に 今回のシステム化が無事完遂できたのは一緒に進めた同期3人と嫌な顔ひとつせず何でも教えてくれた先輩方がいてくれたこそだと改めて感じています。チームで1つのものを完成させる喜びを実業務に入る前に実感できたのは自分にとって、とても大きな財産になりました。これからはチームウエディングパークとして各メディアの発展に貢献し、全社でこの感動を味わえるように日々尽力していきたいと思います。本当にありがとうございました。 ※今回のシステム化にいっしょに取り組んだデザイナーがまた別の視点でこのシステム化についての 記事 を載せているので、興味がある方はぜひご覧ください!
アバター
こんにちは。ウエディングパークに新卒で入社し、早3年の月日が経ったエンジニアのほんぼです。 私は入社からこれまで、結婚準備クチコミ情報サイト「ウエディングパーク」の運用開発チームのエンジニアを担当しています。 チームのミッションは カップル(以下ユーザー)と結婚式場(以下式場)のマッチ度を高めること で、そのために、サイトのSEO評価を上げるための施策を実施したり、ユーザーにとって使いやすいサービスになるようにUI/UXを改善したりと日々チーム一丸となってサイト運用を行っています。 今回はさまざまな施策の中の一つをピックアップしながらやりがいや業務内容について紹介したいと思います。 もくじ 案件開発業務について 開発業務以外もやってます 組織貢献施策もやってます やりがい 案件開発業務について ウエディングパークでは毎日どのようにすれば、 ユーザーと式場のマッチ度を高める を提供できるかを考えて開発・運用を行っております。 私が開発・運用を行うのは、ユーザーが活用するサービスサイトと、式場が自社の魅力を伝える情報や画像などを入稿・管理する管理画面です。 直近の案件をひとつ挙げると、結婚式場のプランを検索する機能および結婚式場向け管理画面のバージョンアップを行いました。 新型コロナウイルスの影響などで結婚式のあり方が変わってきました。今までは結婚式場が結婚式のプランを入稿する際にプランに紐づくカテゴリを単一でしか設定できませんでしたが、時流に合わせたキーワードを新たに追加できるように変更しました。 (例えば「オンライン配信OK」や「2部制・3部制」など新たなキーワードを用意し、一つのプランに複数選択できるようにしました。) この案件では、式場がこれらの情報を新たに入稿できるように管理画面の機能改修やデザイン変更、ユーザーが活用する公開画面や取得APIの新規作成などウエディングパークの幅広いページやプログラムを触る必要があります。 影響範囲の広い案件でしたが、この機能の追加によって式場は伝えたい情報を深く提供でき、ユーザーはそれを知ることができるようになりました。 この様にユーザーと式場のマッチ度を高める様々な案件を日々開発しております。 開発業務以外もやってます メイン業務は先程述べたような開発を行っておりますが、ディレクターから依頼された案件をただ手を動かして実装するだけはありません。 ウエディングパークのエンジニアは実装だけでなくチーム一枚岩となって案件の企画や実現方法を考えることがあります。 例えば、私のチームでやっている一例としては、「 チーム合宿 」と「 サミット会議 」です。 「チーム合宿」は、チーム全員でアイデアを提案し、ディスカッションすることで案件を作成していくミーティングのことです。 このミーティングにはディレクター・デザイナー・エンジニアが参加し、自ら感じている課題などを提案・実行しています。 合宿の開催方法は、全員で集まって話し合う場合や少人数のチームに分けて行うケースなど毎回様々です。 私が以前、提案した案件は「画像の拡張子を次世代の形に変更し、サイトパフォーマンスを向上させる」というクリエイター目線でページの速度改善の提案です。 この案は無事採用され、案件として実際に動き出しました。 このようにウエディングパークでは職種や役職に囚われず、自ら改善・提案をできるような場がたくさんあります。 そのため、 通常業務の中で感じた課題やアイデアを提案するスキル も求められます。 「サミット会議」は、実施が決定した企画の初期段階でディレクター・デザイナー・エンジニアのチームですり合わせを行うミーティングのことです。これによって、開発が始まる前に実現可能性を高めることができます。 例えば、「その実装には〇〇日かかってしまう」、「この企画の目的が▼▼なら□□の実装がいいかもしれない」など上流工程の段階でクリエイター側から提案をしています。 また、事前にディレクターが実装面で不安に感じているところなどがクリアになるため、お互いが100%理解した上で企画を進めることができ、途中で案件内容がズレるといったリスクを減らすことができます。 この様にエンジニア側からも提案する機会がたくさんあります。 そのため、 チームで一緒にものづくりをすることができ、効果があった際は全員で喜びを分かち合うこと ができます。 組織貢献施策もやってます また、開発以外の組織貢献にも取り組んでいます。例えば、私が提案・実施したのは「SQL講義」です。 実施した背景として、ウエディングパークではデータベースの操作やデータ抽出などは全てエンジニアが対応しております。 そのため、ディレクターがデータベース構造を知る機会が少なく、エンジニアとディレクターの考え方で乖離が生まれていました。(ディレクターが簡単にできそうだと思ったことが、実はDBで複雑な処理が発生してしまうなど) そこで、ディレクターに対してデータベースやSQLについての講義を行うことでエンジニアとの認識のズレを少しでも改善できればと思い、SQLの基礎から社内での活用方法まで、3ヶ月間毎週1時間の講義と毎週30分の質疑応答タイムを設けて開催しました。 結果として参加メンバーのデータベース/SQL知識が向上し、先程述べた「サミット会議」でテーブル構造をベースにした話をするケースやディレクターがSQLを作成したケースが増えました。 この様に 自ら感じた社内の問題点などに関しても意見を言い、実行すること ができます。 やりがい ウエディングパークのチーム開発は案件の企画や定義など上流工程も行うことができます。 ミッションであるユーザーと式場のマッチ度を高める手法に関しては明確な答えがないため、常にチームと相談し、悩み、悪戦苦闘しています。 しかし、その分効果が出たときはチーム全員で喜びを分かち合うことができます。 そのため、 チームでものづくりをしているという一体感 を感じることができます。 また、私のチームはサイトの根幹部分を担う案件がたくさんあるため、開発することは良くも悪くも自分達の力量で今後の会社の成長が決まります。 その責任は大きいですが、その分 挑戦し続けることができるやりがい があります。 新型コロナウイルスの影響で「 結婚式のあり方 」も変化していきました。 今まで通りのやり方では通用しなくなった今、ユーザーが一番使いやすいと思えるようなサービスを追求していく必要があります。 その答えをチームで考え、作成していくことがウエディングパークのエンジニアとして面白さだと強く感じます。
アバター
こんにちは!前撮りなど結婚写真の撮影スタジオ・サロンを検索できる情報サイト「 Photorait 」のメインデザイナーをしています、内田( @PANbooooo )です。 Photoraitでは、今Qに新卒のデザイナーがチームにジョインしてくれました! それに伴い、新卒デザイナーの育成ロードマップを作成しましたので、今回はそのロードマップの作成過程をブログにしたいと思います。 育成ロードマップってなに? 人材育成の大まかな計画のことです。 今回は、「新卒デザイナーが独り立ちをしてプロジェクトを進められること」をゴールとして、「いつまでにどんなスキルを身につけて欲しいのか」、そして「そのスキルを身につけるためには何をすれば良いのか」の部分を掘り下げたロードマップを作成しました。 作成方法 1:身につけて欲しいスキルをピックアップする まずは、「どんなスキルを身につけて欲しいのか」のゴールの部分を決めました。 ゴールの設定に参考にしたのが、以前弊社が開催したイベント「 enjoy!インハウス #14 デザイナー評価と育成 」です。 サイバーエージェントの井上さんがお話ししてくださった、「デザイナーとして成長するために、何年目にどのスキルを持っておいた方が良いのか」の発表がすごくわかりやすかったです。 このイベントで話されていたことが、noteにまとめられていたため、こちらを参考に身につけて欲しいスキルを決めていきました。 2:上記であげたスキルに繋げるための環境を作る ゴールが決まったら、次はゴールに辿り着くまでの過程について考えます。 まずは、ゴールの状態をより深堀りし、「伸ばしたいスキルが身に付く=どんなことができる状態なのか」を「自社チームのデザイナーで言うと・・・」と、自分たちに落とし込んで考えました。 このように落とし込むことで、よりゴールが分かりやすくなり、「できるようになった!」と言う成功体験も感じやすくなると思います。 次に、伸ばしたいスキルや身につけたいスキルをちゃんと得るためにはどんなアクションが必要なのか、何をすれば良いのか、効率的且つしっかりとスキルに繋がるワークや取り組みを考え、環境を用意します。 「◯◯力 デザイナー スキルアップ」などと検索すると、他社のデザインチームが行っている取り組みが書かれたブログや、色々なデザイナーさんのナレッジを見つけることが出来たため、それらを参考にスキルアップワークの内容や環境づくりについて考えました。 3:レビューをもらい、ブラッシュアップする ある程度、ロードマップが作成できたら、他のチームのデザイナーさんに「ゴールとワークの内容が合っているのか」「もっと良いワークがあるか」などを確認してもらいました。 実際に確認してもらうことで「このスキルを高めたいならこの方法もおすすめだよ」と、もっと効率的なワークの内容を教えていただいたり、「このワークをするならこんなところに注意した方がいいね!」などの、自分では思いつかない新たな視点でのご意見をたくさんいただき、ロードマップの精度がより上がりました。 作成する上で気をつけたこと ロードマップを作成していると、「あれも取り入れたい!」「これも取り入れたい!」「こんなワークもやってほしい!」「あの取り組みも力になる!」と、足し算をすることが多くなりますが、途中で引き算を意識的にすることで、コンテンツも詰め込みすぎず、アクションに起こしやすいロードマップを作成することができました。 さいごに ロードマップを作ることで、新卒デザイナーに対し「どうなって欲しいのか」「何ができて欲しいのか」を伝えやすくなりました。 また、デザイナーのスキルの可視化にも繋がり、デザイナーの評価における新しいツール的な役割にもなると思いました。 今後、いつ新卒デザイナーがジョインしても大丈夫なように、常にブラッシュアップして、「良いロードマップ」を保ちたいと思います。
アバター