TECH PLAY

スマートキャンプ株式会社

スマートキャンプ株式会社 の技術ブログ

226

スマートキャンプのエンジニア瀧川です。 弊社では昨年からエンジニア合宿を企画していまして、今年は10月15日から17日までの2泊3日で実施しました! 合宿のテーマや全体感は別記事でまとめるかなと思いますが、3日の限られた時間で1チーム(4人)1つのプロダクトを作り、成果として発表する必要がありました。 この条件だとあまり技術的なチャレンジもできないな...と感じてはいたのですが、どうしてもチーム内でGraphQL触りたい欲求が高まってしまったので、なんとか負荷があまりかからない形で導入できないか調べて見つかったのがPrismaというツールでした! 本記事ではPrismaを試した際のメモ、Tips、所感を書いていきます! (公式でPrisma2がアナウンスされてますが、ほぼ別物なので今回はPrisma1について書いています) (多分最終的な成果物の進捗は、慣れ親しんだツールを使った場合とほぼ同じだったかなと思っています) GraphQLとは Prismaとは インストール 初期化 起動 クエリ Mutation Query Tips Seedを実行する たまにDBをResetする必要がある 所感 GraphQL とは GraphQLとは、Web APIのための規格の1つで、「スキーマ定義」と「クエリ定義」によってサーバとクライアントの通信をサポートします。 「スキーマ定義」で標準化された型付きのスキーマを定義し、それに則ったクエリをクライアントから発行することで、安全で柔軟にデータ取得が行えます。 詳しくは公式ドキュメントなどお読みください。 また、GitHubが外部向けAPIとしてGraphQLを採用しているので、こちらで試すのも良いと思います。 developer.github.com Prisma とは インストールし、GraphQLのスキーマ定義をするだけで、以下ができるようになる便利なツールです。 起動用docker-compose.yml生成 データ管理アプリ(Prisma Admin) CRUDの自動生成(GraphQLサーバの実装) DB(MySQL/PostgreSQL)へのMigration Seed定義 CRUDにアクセスするクライアント(JavaScript, TypeScript, Golang)生成 インストール まず、以下のようにpackage.jsonを定義し、 yarn install などで依存解決します。 package.json { " name ": " prisma-sample ", " devDependencies ": { " prisma ": " ^1.34.8 ", " ts-node ": " ^8.4.1 ", " typescript ": " ^3.6.3 " } } 初期化 Prismaはinitコマンドがあり、それにより必要なファイルを自動生成してくれます。 以下のように yarn prisma init と実行すると、「データベースの接続先をどうするか」「データベースの種類はなにか」「Prismaサーバにアクセスするためのクライアントを生成するか」の質問がでます。 以下では、LocalのDockerでMySQLを新規で起動し、TypeScriptのクライアントを生成するようにしました。 $ yarn prisma init ? Set up a new Prisma server or deploy to an existing server? Create new database ? What kind of database do you want to deploy to? MySQL ? Select the programming language for the generated Prisma client Prisma TypeScrip t Client Created 3 new files: prisma.yml Prisma service definition datamodel.prisma GraphQL SDL-based datamodel ( foundation for database ) docker-compose.yml Docker configuration file Next steps: 1 . Start your Prisma server: docker-compose up -d 2 . Deploy your Prisma service: prisma deploy 3 . Read more about Prisma server: http://bit.ly/prisma-server-overview Generating schema... 25ms Saving Prisma Client ( TypeScript ) at /Users/takigawa.yosuke/projects/personal/prisma-sample/generated/prisma-client/ ✨ Done in 31 .93s. 実行後に以下のファイルが生成されていればOKです。 prisma.yml Prisma全般の設定を記述する datamodel.prisma GraphQLのスキーマ定義 docker-compose.yml Prismaサーバ、DBなど起動用 起動 $ docker-compose up -d $ docker-compose ps Name Command State Ports ---------------------------------------------------------------------------------- prisma-sample_mysql_1 docker-entrypoint.sh Up 3306 /tcp, 33060 /tcp mysqld prisma-sample_prisma_1 /bin/sh -c /app/ start .sh Up 0 . 0 . 0 .0:4466- > 4466 /tcp localhost:4600/_admin でPrisma Admin(Sequel Proみたいなデータ閲覧、アップデートなどできる)にアクセスができます。 ( localhost:4600 でおなじみのGraphQLのPlaygroundにもアクセスできますがPrisma Adminのほうが使い勝手がよさそうです) datamodel.prisma に初期状態で User が定義されているので以下を実行し、Prismaサーバを更新するとPrisma AdminでもUserが確認できると思います。 $ yarn prisma deploy これでほぼ準備は完了です! クエリ 試しにデータ定義を以下のように修正して、「Create」「Read」のクエリを作成してみようと思います。 ユーザの所属する会社を追加する想定でのスキーマ定義を追加します(Company has_many Usersですね) ID! @id でユニークかつインデックス追加をしてくれているようです @hogehoge はPrismaのアノテーションでいくつか種類がありそう 関連定義をする際に、相互に参照定義するほうがクエリを書く際に楽そう datamodel.prisma type Company { id: ID! @id name: String! users: [User!]! } type User { id: ID! @id name: String! company: Company! } ※ datamodel.prisma更新後は、Prismaサーバに yarn prisma deploy で反映してください Mutation 試しに Companyを1つ、Userを2つ生成してみます。 mutation { createCompany(data: { name: "スマートキャンプ", users: { create: [ {name: "瀧川スマ太郎"}, {name: "瀧川スマ次郎"} ] } }) { id } } Prisma Adminでクエリを実装すると、補完がしっかりと効いていてすばらしいですね! createCompany などはPrismaによって自動生成されたものです。 createCompany の ブロック {} はmutation成功時に返却してほしいデータを記述しています。 なので実行後のResponseは以下のように自動付与されたIDが含まれています。 { " data ": { " createCompany ": { " id ": " ck2q06vkc006n07980p4l1av0 " } } } Query 生成したCompanyとUserをすべて取得するクエリを作成します。 query { companies { id, name, users { id, name } } } 結果がこちらになります。 { " data ": { " companies ": [ { " id ": " ck2q06vkc006n07980p4l1av0 ", " name ": " スマートキャンプ ", " users ": [ { " id ": " ck2q06vmf006o07989z7b6e1s ", " name ": " 瀧川スマ太郎 " } , { " id ": " ck2q06vmo006p0798yllvbja7 ", " name ": " 瀧川スマ次郎 " } ] } ] } } このクエリとレスポンスのわかりやすさはGraphQLのメリットの1つですよね。 ちなみにPrismaでは、データの絞り込み用の関数も組み込まれています(使い勝手は少しむずかしいですが...) 例えば「会社名がキャンプを含み、ユーザ名の後方が次郎ではない」のような条件だと以下のようになります。 query { companies(where: { name_contains: "キャンプ" }) { id, name, users(where: { name_not_ends_with: "次郎" }) { id, name } } } このようなPrismaによって生成されているものは非常にたくさんあるので、公式ドキュメントや補完をよくみて慣れていく必要がありそうです。 Tips Seedを実行する 以下のようにTypeScriptのPrismaクライアントを生成し、それを使った seed.ts をts-nodeで実行してやるだけですね。 prisma.yml generate : - generator : typescript-client output : ./generated/prisma-client/ seed : run : yarn ts-node ./seed.ts seed.ts import { prisma } from './generated/prisma-client' async function main () { await prisma.createCompany ( { name: 'スマートキャンプ' } ) } main () . catch ( e => console.error ( e )) $ yarn prisma seed たまにDBをResetする必要がある スキーマ定義で関連を変更したり、Seedを2回実行などがエラーになるため、リセットする必要が出てきてしまいます。 ローカルでは以下のコマンド一発ですが、プロダクションではどのように運用するといいのでしょうか... 怖いですね $ yarn prisma reset 所感 GraphQL自体は、処理がクライアントに寄せられて、必要なデータを都度取得できるのでやりやすさを感じました。 また、型があるので、Prismaのような自動生成するタイプのツールでも補完が効き、導入障壁は低く感じました。 なによりも今回小さなアプリケーションを作成したのもありますが、サーバサイド実装要らなくてフロント実装だけで済んだのは新しい可能性を感じられました...! ただ複雑なデータを取得する場合、それなりにクエリが複雑になるのと、Prismaの仕様、GraphQLの仕様上うまく取得できない条件があったり(知識不足もあると思いますが)難しさも感じました。 (あと、公式ではPrismaとフロントエンドとの間にもう1階層GraphQLサーバかRest APIサーバを挟むのを想定しているようなので、そのあたりも今回は無視した難しさがありますね) またバルクインサートできないとかパフォーマンスチューニングできない、スキーマの変更をした際にresetせざるを得なくなるなど、ツールとしての成熟度はまだまだ低いかなと感じました。 ただ、GraphQL自体伸び始めたところで、ようやくプロダクション導入もちらほら聞こえ始めたので、これから大いに飛躍すると思います。 Prisma2はまた毛色が違って、よりスモールで実用的なツールになっているようなので、そちらも今後追っていきたいなと感じました。 なにはともあれ、GraphQL、Prisma、新感覚でおもしろかったです! 合宿最高でした!
アバター
スマートキャンプのエンジニア瀧川です! 先日、 B2B SaaSエンジニアMeetup - SharingIssues というイベントを弊社で開催させていただきました。 様々なつながりから発表枠も埋まり、参加者も当初想定20人でしたが、 結果40名強 もの方にお越しいただき、とても充実した会だったと感じています。 私も主催者側ではあるものの、発表が面白く聞き入っていたので、 今回は一参加者としてのレポートを公開しようと思います! ちなみにイベントの概要は以下で紹介しています。 定期開催予定なので、ご興味あればチェックいただければと思います。 tech.smartcamp.co.jp 「B2B領域における開発組織作り 〜採用編〜 」スマートキャンプ株式会社 エンジニアリングマネージャー 米元さん 概要 感想 「開発リーダーが結果的にPMと呼ばれるまで」 スマートキャンプ株式会社 PdM 郷田さん 概要 感想 「B2Bサービスを作る上で心がけていること」株式会社マネーフォワード VPoE 渋谷さん 概要 感想 「インターナルマーケティングで織り成すマルチプロダクト開発」株式会社リンクウェル CTO 戸本さん 概要 感想 「B2BSaaS開発におけるモチベーションマネージメント」A1A株式会社 曽根田さん 概要 感想 「B2B製品開発における7つの失敗」株式会社シャノン CTO 堀さん 概要 感想 全体通して ※ メディアに掲載されました!!(2019/11/25追記) 「B2B領域における開発組織作り 〜採用編〜 」スマートキャンプ株式会社 エンジニアリングマネージャー 米元さん speakerdeck.com 概要 自己組織化したチーム + 再現性を目指していた 管理者がいなくても動ける 採用が課題(マネージャーになってから実績0名だった) 要求が高いのか やり方が間違っているのか 有識者にヒアリングしてわかったこと 方向性は悪くない 各方面でやりきるしかない 採用をマーケティングの考えを応用してやりきる Lead Generation 母集団を増やす Nurturing(今回これだけ話す) 志望度を上げる 会社資料公開 開発組織説明資料公開 プロダクトごとの説明資料公開 エンジニアブログ メンバーのことを知ってもらう 全員のストレングスファインダー共有 全員の性格診断共有 体験入社 Closing 採用承諾を得る Onboarding 定着・活躍してもらう ​- まとめ 組織全員で採用に打ち込む とにかく伝える努力 弱みを理解する 感想 採用がうまくできなかったときに、採用の各フェーズで施策を考えて実施した話でした。 B2B企業はプロダクトを目にする機会もすくなく、エンジニアリングについても表にあまり出ないので、採用にも影響していると感じます。 自社ですが、社員のストレングスファインダーの結果なども候補者に伝えているのはとてもおもしろいと思っています。 「開発リーダーが結果的にPMと呼ばれるまで」 スマートキャンプ株式会社 PdM 郷田さん speakerdeck.com 概要 六本木PMでも発表した内容 PdMになりたいエンジニアに向けた実体験を語る発表 新規プロダクトのBiscuetのPdM 開発する中で2度の越境(役割が変わったことを自覚したきっかけ) ​- プロダクトの方針とか明確にする人がいない 採用するか自分がするか -> じゃあやります 成果を残すために開発をしないと決める! 何よりも早く市場に出す! やった施策(重要度と優先度のメトリクスを作って実施) ドメイン知識向上 最小限ってなんだろうがわかりたい Expo, カンファレンス, セミナー 開発メンバーへもTheMODEL勉強会を実施 etc... 感想 プロダクト開発をする中で、必要な役割を自分でやっていったら、それがPdMという役割だったという発表。 ドメイン知識を多く必要とするB2B業界で、早く価値を届けるために、営業のセミナーへの参加、チームへのTheMODELの普及など活動しているのが印象的でした。 「B2Bサービスを作る上で心がけていること」株式会社マネーフォワード VPoE 渋谷さん speakerdeck.com 概要 開発者としてやってよかった取り組みを紹介 BtoB 業務フローに取り込まれているためサービスが止まると仕事が止まる マラソンっぽい開発 120%よりずっと80%開発の方が良さそう そのための取り組み 和英辞典のようなものを作る(社内Wiki) payment allowance family name last name dept_id department_id 表記ゆれを防ぎたい モクモク会 会議室を専有して一緒にやるだけ 声に出せば解決するかも環境を作る やる決定よりやらない決定 がんばろうとしている 10の仕事を終えれば3生まれる 社内の他の取り組み 社内用語集が充実 全社用語集 プロダクト用語集 業界用語集 新卒今さら聞けない用語集 **さんの用語集 歴史オリエン 過去の負債 懺悔とともに未来どうしていきたいかを伝える会 パルスサーベイ & オンボーディングFB 今の課題に気づくため dmemo運用してる 3ヶ月に一回未来組織図会議 この人がこれくらい伸びてくれるはず ポジション変更や採用に活かす 感想 かなり具体的に取り組みを紹介していただきました。 用語集、dmemoなどは、やったほうがいいが運用(追加・更新)が課題となってしまうので、それが社内で定着しているのがすごいと思いました(もう少し詳しく聞きたかった) 過去の負債を風化させないように、プロダクトの歴史オリエンを実施する取り組みは弊社でもやってみようと思っています。 「インターナルマーケティングで織り成すマルチプロダクト開発」株式会社リンクウェル CTO 戸本さん speakerdeck.com 概要 従業員13名 エンジニア6名 ​- 病院を作っている会社 予約最適化、薬リモート購入など プロダクトが複数あり、メンバーのモチベーションも高く、あっちもこっちも手を出す ディストピアトークになる 発散してしまう 原因は個人の意識にプライオリティがない ポジションを取らせようとした どこを誰が担当するか うまく行かない 全部に関わりたい 信念がある 取り組み: インターナル・マーケティングを実施する 社内にもなぜを説明する 取り組み: 「今日一つしかできないならなにをしたい」と問いかける 本人に一番を見つけてもらう 本人のやりたいことにやるべきことを重ねる動き(自発的に) 希望がかぶったら... 採用から意識してるのであまりかぶらない 小さい組織だからなんとかする だれもやらないなら自分がやる 感想 小規模な組織で全員がモチベーション高い状態がマイナスに働く事例は共感できました。 「今日一つしかできないならなにしたい」を問いかけるのアプローチはなるほどと感じました。 余談ですが、スライドのイラストが絶妙で面白い発表でした。 「B2BSaaS開発におけるモチベーションマネージメント」A1A株式会社 曽根田さん speakerdeck.com 概要 B2B Horizontal SaaS どこの会社でもあるだろう業務を提供 Vertical SaaS 業界特化 イメージ B2Cに比べてクリエイティブじゃない 受託多そう 技術チャレンジ少なそう イメージを覆したい Vertical SaaS 情報収集が難しい 購買意欲とか 参考になるアプリケーションが少ない 実業務が難しい ソリューション セミナー ドメインエキスパートへのヒアリング 要望が多い・多様 製造業も多様 ソリューション 課題の追求 AsIs/ToBeシート ストーリーマップ 仮説検証が難しい フリーミアムプロダクト少ない アップデートに慎重(ABテストとかむずかしい) 一度のミスがクリティカル ソリューション PMF ディアルトラックアジャイル ​ 技術チャレンジ B2B SaaSのデータモデリングとか GraphQLにチャレンジ 多言語対応 MicroService BigQuery, TreasureData, DataDog 必要性に応じてチャレンジング ​ 深いドメイン理解 風呂敷を最大に広げた上でのミニマムな設計 未来を描いた技術チャレンジ ​ モチベーションは満たせる 感想 要望が多い、フリーミアムプロダクトが少ないなど、B2Bならではの課題に対して、様々なアプローチを真摯に実施して解消している印象でした。 やりがいを感じ、モチベーションを強く感じているのがとても伝わる発表でした。 各課題に対するソリューションも、業界の成長や技術の進歩などで増えていると感じているので、より一層楽しみな領域なんじゃないかなと思っています。 「B2B製品開発における7つの失敗」株式会社シャノン CTO 堀さん speakerdeck.com ※ 追記:2019/11/06 資料をアップしていただきました 概要 7つの失敗 失敗を踏み抜いてるので共有 顧客ごとにカスタマイズ受けちゃう 売上でると言われるとやるしかないか... 心を鬼にする 課題の突き詰める 開発はたくさん、営業・マーケが少ない 少ないお客さんにフィットさせにいこうとなりがち 製品にフィットするお客さんをコストかけて探すべき 営業が機能の存在意義を説明できない インターナル・マーケティング 目的が重要 営業・マーケ・開発を橋渡しする人が必要かも 目指すアーキテクチャと組織図がずれている Perlモジュール郡これは死ねる リプレイス組織を分けちゃった 組織と技術的なアーキテクチャは似てくる 潜在的に人は組織に準拠する行動を取る 重要な課題を解決してない スコープが広く要望が多様化 言ってるものと欲しいものは違う お金を出してまでほしいかとクライアントに聞くと、いや...となる 掘り下げる 技術的負債に向き合ってない GoogleDriveで検索するとめっちゃある(引き継ぎ資料にも負債が) 小さい負債は開発サイクルに盛り込む 大きい負債はビジネス課題に盛り込む なんでもポリシーを決めるのが大事 自動テストなく年位置ビッグバンリリース 都度リリースがいいよ KPIで全社の意思疎通が図られてない 売上以外にも興味を持って、全社の方向性を知るべき 仕事を見ているが人を見てない エンジニアは人に興味ない(人もいる) 大きいことをするためには人と向き合って投資する その人が会社の方向性と考えがマッチしているか 感想 圧巻の失敗事例集でした。 どの項目もB2B業界で開発をしている人は共感できたのではないでしょうか。 シンプルに失敗と学びを紹介されておりわかりやすく聞けました。 再度いくつかに絞って、発表していただきたいなと感じました。 全体通して どの発表も共感できる内容で、かつ面白い対策をされており興味深かったです。 発表や懇親会の中で、開催のきっかけでもある「B2Bってあまりノウハウが表に出ない」「B2Bはドメインが多様で難しい」といった感覚をみなさん持っていることがわかり、開催してよかったなと感じました。 これからも続けていくことで、B2B SaaS開発でのハマりどころが、ここに来れば解決する場を作っていきたいですね! 次は12月開催を目指しています! ※ メディアに掲載されました!!(2019/11/25追記) Find careersさんに記事にしていただきました! とても読み応えの内容になっていますので是非読んでいただければ嬉しいです! www.findcareers.jp
アバター
スマートキャンプの郷田です。 私は Biscuet(ビスケット) という新規SaaSのプロダクトマネージャーをしております。 Biscuetでは開発プロセスに課題を感じていたため、外部から アジャイルコーチの天野さん をアドバイザーとして召喚し、スクラムの導入を進めています。 そこで今回は、Biscuetチームで先月から導入を進めているスクラムの現状を、たくさんの画像を用いてまとめてみたいと思います! スクラムの役割 開発チーム プロダクトオーナーチーム スクラムマスター スクラム全体像 スクラムのセレモニー PBL(Product Backlog) SBL(Sprint Backlog) 朝会(Daily Scrum) モブプロスペース KPT(Sprint Retrospective) その他 最後に スクラムの役割 開発チーム 開発チームはエンジニアの3人が中心となって開発を進めています。 それぞれがバックエンド、フロントエンド、インフラと、違う強みの持つメンバーとなっています。 各エンジニアバックエンド〜フロントエンドまでの開発は基本的には行うこととしています。 開発チームにはデザイナーを兼務しているエンジニアも所属して、デザインの改修まで開発チームで行えるようにしています。 プロダクトオーナーチーム プロダクトオーナーは、プロダクトマネージャー(私)と、営業&マーケティングのマネージャーの2名体制としています。 2名にすることで開発〜営業までの広い情報を元に意思決定を行えるようにしています。 スクラムマスター スクラムマスターの役割は召喚しているアジャイルコーチの天野さんが担っています。 業務の目的をアジャイルの思想を用いた業務効果の最大化とすることで、スクラムマスターがスクラムだけにとらわれず自由に動けるようにしています。 自社にあわせたスクラムの落とし所を見つけるために密にコミュニケーションをとりながらスクラムの導入を進めています。 スクラム全体像 Biscuetではスクラムの全体像をこの図で表しています。 PBLとSBLの管理に Asana を活用しています。 全社員がAsanaのアカウントを持っている ため、Biscuetのセールスや別プロダクトのメンバーがいつでも見れるようになっています。 スクラムのセレモニー Biscuetのスクラムは1週間スプリントで、月曜日にSprint Review、Sprint Planningを入れています。 スクラムマスターは月曜のみ出社しています。 Refinementは火〜金に30分ずつ実施することで、1週間の内2時間をRefinementに確保できるようにしています。 Sprint Reviewはセールスも含めた全てのプロダクト関係者が出席し、今のプロダクトとこれからのプロダクト方針が共通認識となるようにしています。 PBL(Product Backlog) PBLはプロダクトオーナーチームが管理しています。 SprintごとにAsanaのセクションを切ることで、Sprintのベロシティが自動で合計されるようにしてます。 Asanaのカード内に受け入れ条件やユーザーストーリーを記述する形で利用しています。 PBLのアイテムごとのステータスは、プロダクトの開発状況がエンジニア以外でも理解できるように、リリース状況を表すステータスとしています。(未着手、作業中、リリース済み) SBL(Sprint Backlog) SBLは開発チームが管理しています。 Planningで計画したアイテムは、PBLとは別のAsanaプロジェクトでSBLとして管理しています。 エンジニアは、SBLのアイテムにアサインされ、アイテムごとにGithubのPRを作成する運用としています。 SBLのアイテムごとのステータスは、開発チーム内での共有がしやすいよう、開発状況を表すステータス管理にしています。(未着手、wip、review、merge) 朝会(Daily Scrum) GoogleカレンダーとSBLを見ながら、開発チーム全員のその日の方針を確認するようにしています。 プロダクトオーナーも必ず朝会に参加するようにしており、Sprintに影響がありそうな課題の共有がその場でできるようにしています。 毎回必ずタイマーで15分はかり、超えたらできる限り強制的に終了することとしています。 モブプロスペース 52インチのテレビを昇降付きの台に載せ、3人が同時に使えるサイズの昇降付きの机を開発チームが常に使えるようにしています。 AppleTVを設置し、コネクタの差し替えも不要で画面共有ができるようにしています。 過去モブプロ文化はありませんでしたが、スクラム導入後からモブ業務が徐々に増え、今ではエンジニアの5割以上の時間は、ここでモブ業務をするようになっています。 モブスペース正面の窓からは東京タワーが見えます。 机の上に置いてあるもの Refinementでストーリーポイントを付けるために、プランニングポーカー(mixiさんのノベルティ)を常にモブプロスペースに置いています。 複数人業務での利便性向上のため、ワイヤレスのキーボードとマウスも置いています。 KPT(Sprint Retrospective) Sprint Retrospectiveは、KPTのフレームワークを利用しています。 Keep、Problem、Tryは、それぞれ書く時間・発表する時間で区切り、タイマーで測ってKPTを進めています。 実施が決まったTryは、SBLに乗せて、開発チームが実施できるようにしています。 付箋と水性ペン ディスカッションが捗るように、付箋と水性ペンをポーチに入れてまとめて持ち運べるようにしています。 ディスカッション中に付箋が剥がれると非常にストレスなので、強粘着の付箋を使っています。 その他 スクラムの参考文献 スクラムのフレームワークを実務に取り入れるとぶつかる壁がとても多いため、スクラムガイドとSCRUM BOOT CAMPをすぐに手に取れる場所に置いておき、原則を見返せるようにしています。 オフィスの周りの様子 隣のBOXIL(ボクシル)チームもモブやってます。BOXILチームはスクラムではないため、また別でまとめてくれると思います。 スペースの区切りはキャスター付きホワイトボードを利用しており、ホワイトボードがいつでも使えたり、エリアを広げたい場合はすぐに動かせるようにしていたりします。 最後に 弊社のスクラムはいかがだったでしょうか? スクラムは取り入れたばかりで、現状Sprintも#6(6週間分)しか進んでいないため、今後も改善を繰り返していくことになりそうですが、一旦スクラムでのプロダクト開発が回るようになってきたため、社内外問わずなにかの参考になればと思い現状を記事にまとめてみました。 最終的にはアジャイルコーチの天野さんが居なくてもスクラムが回る自己組織化したチームを目指しているので、今後のスクラムチームの成長がとても楽しみです! 最後に告知ではございますが、B2Bのマネジメントについて弊社meetupでLT登壇させていただきますので、ご興味があれば以下リンクをご参照ください。 smartcamp.connpass.com
アバター
スマートキャンプでエンジニアをしている井上です。 今月の10/29に弊社でエンジニアイベント B2B SaaSエンジニア Meetup - Sharing Issues #1 を開催することになりました! 弊社はBtoBでSaaSを扱う企業として、 なぜこのイベントをやろうと考えたのか 、 イベントを通して実現したいこと をこの記事で紹介しようと思います。 記事を読んでいただき、興味が湧いた方は以下から参加登録していただければ幸いです! smartcamp.connpass.com イベント趣旨 なぜこのイベントをやるのか なぜmeetupなのか 今後やっていくこと 最後に イベント趣旨 以下に該当する方に集まっていただき、B2B業界で働くエンジニアならではの課題や解決方法などを共有して、ディスカッションをする場を提供したいと思います。 B2B業界でエンジニア・デザイナーとして働いている B2B業界に興味がある 同じ業界の情報交換・議論がしたい 正直課題があり困っている 課題解決が好き ...etc 毎回少しずつテーマを変えようと思いますが、今回は マネジメントに関する課題・解決 をテーマに決定しました。 なぜこのイベントをやるのか BtoBの領域ではビジネス職とのやり取りや様々な部署が関わるからこその調整、企業相手だからこそ考慮しなければいけない問題など、BtoCの領域とは少し異なる課題があると感じています。 私達は「良い人のところには、良い情報が集まる」と考えており、イベントという形で情報共有する場を作り育てていくことで、自社エンジニアの成長そしてBtoB業界のエンジニアの生産性向上を目指したいと思っています。 なぜmeetupなのか BtoBといっても業界やプロダクトによって大きく内容がことなるので、参加者それぞれが共有する場、解決する場を作り出していってほしいという意味でmeetupにしてます。 今後やっていくこと どのような人が集まるかにもよるのですが、テーマごとの強いコミュニティに派生させていき、課題はそのコミュニティに聞けば分かる状態にしていきたいです。 例えば持ち寄った課題解決のワークショップなどをイベント内で行い、それぞれ最適な解決策を複数出せるようなものが出来ればと考えています。 最後に これからさらに成長していくBtoB SaaS業界で、エンジニアが課題につまずく事なくよりよいサービスへと伸ばしていける状態を作るため、一緒にコミュニティを育てていければ嬉しいなと思います! 今後ともよろしくおねがいします!
アバター
スマートキャンプのエンジニアインターン生の高砂です! 高砂渉と書いて、たかすなじょうと読みます!(会社ではじょにーと呼ばれてます) 私はスマートキャンプでインターンを始めて半年ほど経ちますが、インターンを始めたばかりの頃、オフィス来客対応に非効率さを感じていました。 そこで、Slack APIとGASを使ってオフィス来客時の手動作業の自動化に取り組みました。 本記事ではどのように考えて、実装と改善をしていったかをお話ししようと思います! 来客対応における課題と要件 来客対応の手順 具体的な課題 作成方針 実装 GASで事前に今日1日の予定を取得 Slack APIで訪問通知取得 GASが対応する予定を検索 Slack APIで予定を通知 Slack botの反響と改善 同僚の反応と追加機能の要望 追加実装、利用、要望、ヒアリングのサイクル 終わりに 来客対応における課題と要件 来客対応の手順 スマートキャンプでは基本的にインターン生がお客さまを会議室にお通ししていました。 お通しする際には「お客さまのお名前」「使用する会議室」「担当者の名前」が必要なのですが、従来では Slackに受付システムのbotから「お客さまのお名前」が通知される お名前に対応する予定をGoogleカレンダー上で目視で探す 見つけたら「使用する会議室」「担当者の名前」を記憶する お客さまを会議室に案内した後、担当者を呼び出す というフローでした。 具体的な課題 上記手順では「目視で探す」「予定情報を記憶する」など間違いが起きやすいのに加え、一度のオペレーションに時間がかかる事が課題でした。 また、会社が成長中で日に日に社員が増えていく為、その負担が増していっているという問題もありました。 そこでこのフローを自動化したいと思い、趣味として取り組みました🙌 作成方針 主に以下のような流れで実装することにしました。 また、実用上の課題として、Receptionistに入力された名前や、カレンダーに入力された名前の漢字が間違っていることもあり、漢字のよみがなを取得できる よみたん というよみがな検索システムのAPIを用いています。 お客様が受付で名前をReceptionistに入力 ReceptionistがSlackに通知するのをGASでキャッチ Googleカレンダーから予定を検索 よみがな検索APIで名前を Slackに通知 実装 GASで事前に今日1日の予定を取得 まずは会議室ごとに複数あるGoogleカレンダーの予定一覧を取得してきます。 この取得時に、 よみたん のAPIを利用し、よみがなも取得しています。 また、この取得には時間がかかるので、業務時間開始1時間前に取得するようにトリガーを設定しました。 yomi-tan.jp コードは以下のようになりました。 var scheduleSheetId = PropertiesService.getScriptProperties().getProperties().sheetId; var spreadsheet = SpreadsheetApp.openById(scheduleSheetId); var calendars = [ CalendarApp.getCalendarById( 'カレンダーID1' ), CalendarApp.getCalendarById( 'カレンダーID2' ), CalendarApp.getCalendarById( 'カレンダーID3' ) ] ; function main() { var scheduleList = setSheet(scheduleSheetId); var today = new Date ( new Date ().toLocaleDateString()); var tommorow = new Date ( new Date ().toLocaleDateString()); today.setDate(today.getDate()); tommorow.setDate(tommorow.getDate()+1); //複数のカレンダーから取得 for ( var room = 0; room < calendars.length; room++) { var lastRow = scheduleList.getLastRow() var events = calendars [ room ] .getEvents(today, tommorow); var scheduleListValues = scheduleList.getDataRange().getValues(); //予定の数だけ繰り返し for ( var i = 0; i < events.length; i++) { var title = events [ i ] .getTitle(); var startTime = events [ i ] .getStartTime(); var endTime = events [ i ] .getEndTime(); var location = events [ i ] .getLocation(); var patternList = [ /.{2}様/g , /.{1}様/g , /.{3}様/g , /.{4}様/g ] var kanaList = '' ; //訪問予定の場合 if ( /様/ .test(title)) { patternList.forEach( function (pattern) { kanaList = arrangeScheduleInfo(pattern, title, kanaList) } ) //訪問予定では無い場合 } else { var kanaList = [ undefined ] } var scheduleInfo = [ title, startTime, endTime, location ] ; scheduleList.appendRow(scheduleInfo); } } } function setSheet(scheduleSheetId) { var scheduleList = spreadsheet.getSheetByName( 'main' ); scheduleList.clearContents(); var scheduleInfoTitle = [ '予定名' , '開始日時' , '終了日時' , '場所' ] scheduleList.appendRow(scheduleInfoTitle) return scheduleList } function arrangeScheduleInfo(pattern, title, kanaList) { var kanjiList = title.match(pattern); try { kanjiList.map( function (kanji) { var kanji = kanji.slice(0,-1); var kanaCandidates = translateIntoKanaArray(kanji); kanaList = kanaList + kanaCandidates + ',' ; } ) } catch (e) { kanaList = kanaList.concat( undefined ); Logger.log( '右記予定名はよみたん不可:' + title) } return kanaList } function translateIntoKanaArray(name) { var apiUrl = 'http://yomi-tan.jp/api/yomi.php?ic=UTF-8&oc=UTF-8&k=k&n=5&t=' + name; var kanaCandidates = UrlFetchApp.fetch(apiUrl); return kanaCandidates } Slack APIで訪問通知取得 実際にお客さまが来社された際、ReceptionistからSlackの特定のチャンネルにメッセージが送られます。 このメッセージに対してSlack APIを反応させ、来客名を取得します。 var scheduleSheetId = PropertiesService.getScriptProperties().getProperties().sheetId; function doPost(e) { var receptedName = extractName(e.parameter.text); var scheduleList = getActiveSheet(scheduleSheetId, 'main' ); searchSchedule(receptedName, scheduleList) } function extractName(receptedText) { var regex1 = / の.+? 様/ ; var regex2 = /から.+? 様/ ; var regex3 = /に、.+? 様/ ; if (regex1.test(receptedText)) { var name = receptedText.match(regex1); } else if (regex2.test(receptedText)) { var name = receptedText.match(regex2); } else if (regex3.test(receptedText)) { var name = receptedText.match(regex3); } name = String (name).slice(4,-3); return name } GASが対応する予定を検索 事前に取得していた予定一覧と照らし合わせて、対応する予定を決定します。 function searchSchedule(receptedName, scheduleList) { scheduleList.forEach( function (schedule) { var now = new Date (); var startTime = new Date (schedule [ 1 ] ); var earlyTime = new Date (startTime.setMinutes(startTime.getMinutes() - 20)); var lateTime = new Date (startTime.setMinutes(startTime.getMinutes() + 20)); if (earlyTime < now && now < lateTime) { nameMatchCheck(schedule, receptedName) } } ) } function nameMatchCheck(schedule, receptedName) { var scheduledNames = schedule [ 6 ] ; if (scheduledNames !== 'undefined' ) { var scheduledNamesList = scheduledNames.toString().split( ',' ); scheduledNamesList.each( function (name) { if (!name) { return ; } else if (name.length === 1) { //1文字は誤判定が多いのでスキップ return ; } else if (receptedName.indexOf(name) === 0) { //名前一致 postSchedule(schedule, name) return ; } } ) } return false ; } Slack APIで予定を通知 決定した予定の内容を通知します。 function postSchedule(scheduleInfo, scheduledName) { var name = scheduleInfo [ 0 ] ; var startTime = scheduleInfo [ 1 ] .toLocaleTimeString().slice(0,-7); var endTime = scheduleInfo [ 2 ] .toLocaleTimeString().slice(0,-7); var place = scheduleInfo [ 3 ] ; var guests = scheduleInfo [ 5 ] ; var message = 'こちらの予定でしょうか: \n ' + name + ' at ' + place + '\n' + startTime + ' ~ ' + endTime; postMessage(message) } function postMessage(message) { var postUrl = PropertiesService.getScriptProperties().getProperties().postUrl; var jsonData = { "username" : "お茶たろう" , "icon_emoji" : ":johnny:" , "text" : message } ; var payload = JSON.stringify(jsonData); var options = { "method" : "post" , "contentType" : "application/json" , "payload" : payload } ; UrlFetchApp.fetch(postUrl, options); } Slack botの反響と改善 これらによって、通知に対して情報を出してくれるSlack botが完成しました。 このbotによって20秒程かかっていた手動での業務が1秒に短縮されました! 同僚の反応と追加機能の要望 反響も予想以上に多く、社員の方々から「お茶たろう(ツールの愛称)の人」と覚えられるまでになりました(笑) それと同時に、更に色んな方から要望を頂けました。 もっと反応率を高めて欲しい 1つの予定に対して複数のお客さまがいる場合も全員に対応して欲しい 担当者をメンション(Slackの呼び出し機能)で呼び出して欲しい 担当者が複数人いる場合、不参加の人は呼び出さないで欲しい 口調を可愛くして欲しい 追加実装、利用、要望、ヒアリングのサイクル その後も新しく貰った要望を基に実装し、実際に使い、それに対する要望を社員からヒアリングするという形式の開発を3ヶ月ほど続けました。 その結果、反応率は高く、社員の要望にも適合した良いプロダクトとなりました🤗 終わりに このbotに込めた想いは、スマートキャンプのPRメディアで話しているので良ければそちらもご覧ください。 スマートキャンプの「来客対応」の非効率を解決!内定者インターン生が開発した ”お茶たろう” に迫ってみた #Ownership #新卒 | .▲.tent
アバター
スマートキャンプのエンジニア入山です。 皆さんは、AWS Lambdaを知っていますか?知らない方でもサーバーレスという単語は聞いたことがあるのではないでしょうか。 Lambdaはいままでプログラムを実行する上で必要不可欠だったサーバを用意(構築・運用)しなくても、実行したいプログラムをLambda関数として作成・登録するだけで、プログラムを動作させることが可能なサーバーレスコンピューティングサービスです。 2014年にサービスが公開されてから着実にアップデートを重ねており、現在では柔軟かつ幅広い用途で利用することができます。 LambdaにはCloudFrontと連携して動作させることのできる Lambda@Edge という機能があり、今回はCloudFront+S3でのSPA構成の際にLambda@Edge(CloudFrontのエッジサーバーで利用できるLambda)を活用した例を紹介しようと思います! AWS Lambda@Edgeとは 活用例1 やりたいこと:オリジンへのリクエストをリダイレクトしたい 実現方法:Origin RequestでURIを変更する 活用例2 やりたいこと:レスポンスヘッダをカスタマイズしたい 実現方法:Viewer Responseでレスポンスヘッダを変更する まとめ AWS Lambda@Edgeとは Lambda@Edgeとは、CloudFrontのBehaviorに設定可能なLambda Functionのことです。 Lambda FunctionをCloudFrontのエッジサーバにデプロイしておくことで、CloudFrontへのアクセス/レスポンスをインターセプトしてLambda関数を実行し、 レスポンス自体を変えたり、二次処理を実行するなど、CloudFrontの動作をカスタマイズすることが出来ます。 処理を差し込む事が可能なのは、以下の4箇所となります。 (公式HPから引用 : CloudFront Lambda@Edge での AWS Lambda の使用 - AWS Lambda ) Viewer Request : CloudFront がビューワーからリクエストを受信した後 Origin Request : CloudFront がリクエストをオリジンサーバーに転送する前 Origin Response : CloudFront がオリジンからレスポンスを受信した後 Viewer Response : CloudFront がビューワーにレスポンスを転送する前 活用例1 やりたいこと:オリジンへのリクエストをリダイレクトしたい Web運用においてリクエストをリダイレクトしたい場面は、少なくないと思います。 SPAでHistoryAPIを利用する場合では、URIに対応したHTMLファイルが存在しないため、ブラウザリロード時などのリクエストがエラーになってしまいます。一般的には、403/404などのエラーページをindex.htmlにリダイレクトすることでこの問題を回避すると思います。 実現方法:Origin RequestでURIを変更する Origin RequestにLambda関数を設定することで、柔軟にURIを書き換え、リクエストをリダイレクトさせることが出来ます。 以下は、index.htmlへリダイレクトするLambda関数の例です。 exports.handler = ( event , context, callback) => { const { request } = event .Records [ 0 ] .cf; const currentUri = request.uri; // URIにドットを含む場合は、アセットへのアクセスとみなしてリライトしない if (currentUri.indexOf( '.' ) !== -1) { console.log(`Don 't rewrite. Uri is ${currentUri}`); return callback( null , request); } const newUri = '/index.html' ; console.log(`Old URI: $ { currentUri } `); console.log(`New URI: $ { newUri } `); request.uri = newUri; return callback( null , request); } ; 活用例2 やりたいこと:レスポンスヘッダをカスタマイズしたい Webページを公開するときのセキュリティ対策などで、レスポンスヘッダをカスタマイズしたいという要望もよくあると思います。 通常であればNginxやApacheといったWebサーバーの設定で対策するのが一般的ですが、SPA(CloudFront+S3)の場合はレスポンスヘッダはカスタマイズし辛いと思います。 実現方法:Viewer Responseでレスポンスヘッダを変更する Viewer ResponseにLambda関数を設定することで、ユーザーへレスポンスを返す直前でレスポンスヘッダを編集することが出来ます。 以下は、X-FRAME-OPTIONSを付与し、クリックジャッキング対策をする関数の例です。 'use strict' ; exports.handler = ( event , context, callback) => { const response = event .Records [ 0 ] .cf.response; const headers = response.headers; /* X-Frame-Options: DENY Content-Security-Policy: frame-ancestors 'none' */ headers [ 'content-security-policy' ] = [{ key: 'Content-Security-Policy' , value: "frame-ancestors 'none'" }] ; headers [ 'x-frame-options' ] = [{ key: 'X-Frame-Options' , value: 'DENY' }] ; callback( null , response); } ; まとめ 今回は、Lambda@Edgeを活用してSPAの動作をカスタマイズする例を紹介しました。 Lambda@Edgeを利用することで、CloudFrontでの配信コンテンツに対して柔軟に処理を行うことができるようになるため、SPAにおけるクライアント運用の利便性を向上させることが出来ます。少しでも皆さんの参考になれば幸いです!
アバター
スマートキャンプでエンジニアのチームマネージャーをしている米元です。 弊社ではエンジニアが中心となってエンジニア採用を進めております。 その甲斐あってか、ありがたいことに最近も入社を決めてくれたエンジニアが何名かおり、少しずつですが仲間が増えてきました。 この記事では弊社がどのようなエンジニア採用フローを行っているかを紹介しようと思います。 想定読者 弊社へ応募している、または弊社に興味を持って頂いているエンジニアの方 他社のエンジニア採用フローに興味あるエンジニアマネージャー、採用担当者 備考 中途採用のフローです 必ずしもこの内容がすべての候補者の方に適用される訳ではありません 基本的にスカウトや書類選考以降について紹介します 採用フローは日々改善しているため、記載した内容と実際のフローが異なる場合があります なぜこの記事を書いたか 主な理由は以下の2つです。 エンジニアが中心となってエンジニア採用の設計・運用をしていることが知られていない 選考フローが不透明な事による候補者の不安を無くしたい この記事で少しでもこれらの事が解消できれば幸いです! 想定読者 備考 なぜこの記事を書いたか 採用フロー 初回面談前の情報共有 カジュアル面談 面接 面接官 面接回数 重視するポイント 質問内容 行動指針「SOCS」 性格診断・SPIの受験 その他の取り組み 期待値のすり合わせ リファレンスチェック オファー面談 内定承諾〜入社後の一定期間 これからやること 心がけていること 自社の魅力を言語化し、正しく伝える オープンであること 入社後に働くイメージをつけてもらう 期待値調整をサボらない 採用基準は妥協しない 改善し続ける 最後に 採用フロー 初回面談前の情報共有 ここからは採用フローを順に説明していきます! 最近の流行りに乗って弊社も会社説明資料をWebで公開しています。 事業内容やVision/Mission/Value、文化、制度、給与テーブルなど赤裸々に掲載していますが、この資料を公開していることを知られていないケースもまだまだ多いため初回面談前のやりとりの中でURLを共有しております。 会社説明資料 speakerdeck.com 初めてお会いする時間は候補者の方にとっても弊社にとっても貴重な時間です。 限られた時間の中で弊社の事をより深く知って頂くため、当ブログを始め以下のような記事・資料も共有させて頂いています。 候補者の志向や興味によっては、より弊社に興味を持って頂くために共有する記事を変える場合もあります。 tech.smartcamp.co.jp note.mu boxil.jp boxil.jp もちろん全部目を通す事は出来ないと思いますので、面談時に一緒に見ながらアイスブレイクをしたり候補者の方からの質問のきっかけになるような使い方をしています。 カジュアル面談 選考要素の無い「カジュアル面談」もエンジニアが担当します。基本的にエンジニアのチームマネージャー(私)か各プロダクトの開発リーダーが担当することが多いですが、希望によってはチームのメンバー数名でお話することもあります。 カジュアル面談では相互に簡単に自己紹介をした後に今回特に話したい事を候補者の方に確認し、それに応じて説明の順番や内容を調整しながら以下の内容をお話します。 会社説明(資料を事前に読んで頂いている場合は質問などがあるかを確認) 事業・プロダクト エンジニアのメンバー エンジニアのカルチャー 利用技術 エンジニア組織の最近の取り組み その後、お互いの詳しい自己紹介や質問などを行うことが多いです。 また、事業やエンジニア組織などの説明に関しても資料(今のところ非公開)を作成しており、誰でも同じ説明が出来るようにしています。 面接 面接の概要は以下の通りです。 面接官 主にエンジニアが担当します 入社後に関わることになるセールスやマーケターなどのエンジニア以外の職種も面接官として参加する場合があります 面接回数 3回が多いですが人によって4回以上になる場合もあり エンジニア面接2回、代表面接1回 遠方の方など来社が難しい場合はリモート面接も可能 希望に応じて1日で複数回の面接も可能 重視するポイント カルチャーマッチを重視しており、技術面が優れていてもカルチャーがマッチしない場合はお見送りとさせて頂く 技術面においてはその時の募集要件を満たしているか、将来的に満たすポテンシャル(学習・思考プロセス)があるかを見る 質問内容 過去の経験を事実ベースで聞く どんなプロジェクトで、どのように考え、どんな行動をとったか等 将来のビジョン、やりたいことなど未来について聞く これらの質問から後述する「SOCS」に当てはめてカルチャーマッチするかを見る 趣味や興味のある技術の話で盛り上がる事も多い 全体的にかっちりとした面接ではなく、雑談のようにラフに話をすることが多いと思います。 また、基本的にはエンジニアチームのメンバーとは選考のどこかで必ず会ってもらうようにしており、面接で話せなかったメンバーは別途ランチや会食(飲み会)を設定したり社内のイベントスペースで軽食を取りながら話す機会を設けています。 行動指針「SOCS」 弊社では4つの行動指針があり、評価規準にも使用されています。 これら4つの頭文字をとって「SOCS(ソックス)」と呼んでおり、主にSOCSを基準にカルチャーマッチするかどうかの判断をしています。 SmartThinking 仮説思考・本質思考 先見性と創造性 Ownership リーダーシップ 主体性 Collaboration 社内・社外共創 Speed 実行スピード 生産性(質/時間) 性格診断・SPIの受験 1次面接後にWebで受験できる性格診断とSPIを受けていただきます。 基本的には業務の得意領域・不得意領域の参考のために使いますが、特に性格診断の方は社内の誰に特徴が似ているかや誰と相性が良いかを把握するためにも利用しています。 ※私が知る限りエンジニアでこの結果を元にお見送りしたことはありません。既存社員でもかなり偏った結果が出ているメンバーもいますが問題無く活躍しています! その他の取り組み 選考フローの中で出来るだけ弊社の事を知ってもらうための活動をいくつか行っています。 面接時だけでなく選考期間中にも連絡をとり、不明点や疑問点があればそれを埋めるための資料や参考記事を送る 面接後のオフィス案内 エンジニア+入社後関わるメンバーとの会食(2次面接以降) タイミングが合えば月1回のピザパへ招待 1日体験入社(選考進んでいる人向け) boxil.jp note.mu 期待値のすり合わせ 最終面接まで進んで頂いた後は条件面の希望確認と、改めて期待値のすり合わせを行います。 候補者の方が弊社でやりたいことができるか、作りたいキャリアが作れるか。また、それが弊社側の想いと一致しているかを確認します。 特に最近はその人向けの入社後の役割や2〜3年後のキャリアイメージの資料を個別に作成し、言葉だけでなく視覚的にもズレが無い事を確認しています。 意外と候補者の方ご自身でも最後の最後まで本当にやりたいことを言語化できていない場合があり、この段階ですり合わせがうまく出来ていない場合は辞退につながっていることが多いと感じています。 リファレンスチェック ミスマッチを無くすため候補者本人の同意のもとでリファレンスチェックを行います。 オファー面談 最後に内定通知と共に条件の提示を行います。来社が難しい場合は面談ではなくメールで完了する場合もあります。 内定承諾〜入社後の一定期間 無事内定承諾して頂いた後は入社までと入社後の一定期間を「 オンボーディング期間 」として、入社後に出来るだけ早い段階で活躍して頂けるようにサポートさせて頂きます。 これに関しては今まさに取り組んでいる最中ですが、例えば以下のような内容を準備しています。 Vision/Mission/Value、ルール・制度、事業、組織など会社全体に関わる説明 業務するうえで必要な情報の共有 業界用語、技術などの研修 他部署のメンバーとのランチ メンターによるフォロー 採用がゴールではなく、入社して頂いた方が活躍することがゴール であるため人事とも連携しながら会社全体でオンボーディングの仕組みを作っている最中です。 これからやること オンボーディング以外にもまだまだ整備できていない事だらけなのですが、今後は以下の2つにも注力していきたいと思っています。 技術試験やシチュエーションテストなどを用いたスキルチェック方法の確立 副業や業務委託から正社員化のフローの確立 特に技術試験は候補者側の負担が大きいわりに方法を間違えると正しい判断が出来ないため、導入には慎重になっています。 今のところ候補者の方の都合がつけば副業や業務委託で一定期間一緒に働く時間を作ることが一番良いとは思っていますが、もし他にも良い方法があるよ、うちではこんなやり方で成果でてるよ、というものがあれば教えて頂きたいです。 心がけていること 今回ご紹介したフローの全体を通して心がけていることをいくつかお伝えしたいと思います! 自社の魅力を言語化し、正しく伝える 人、文化、事業、会社などそれぞれの魅力を言語化しておく 感覚的に思っていることも自分の中で一度整理し、具体例を元にわかりやすい表現で相手に伝わるよう言語化しておく 言語化しておかないと面接官によって内容に一貫性が無かったり、誤った意味で伝わる恐れもある オープンであること 良い面だけでなく悪い面も率直に伝える 入社後のミスマッチだめ、絶対。 入って欲しい人には良いことばかり伝えたくなる・・・でも悪い面を隠しても入社後にバレる 悪い面は一緒に改善してくれる方と働きたい 入社後に働くイメージをつけてもらう カルチャーや雰囲気をあらゆる方法で伝える 仕事で関わる全員と会ってもらう 期待値調整をサボらない 候補者の期待と自社の期待を言語化・視覚化してズレが無いかをすり合わせする 採用基準は妥協しない 人は欲しい・・・でも妥協しない 技術面がよくてもカルチャーがマッチしない人を無理に取るとお互い不幸になる 改善し続ける 候補者の方からのフィードバックや自分達自身の反省をもとに定期的に振り返りを行い、改善し続ける 最後に 細かいところは書き切れていない部分もあるのですが、少しでも採用フローのイメージがついて弊社に興味を持って頂ければ幸いです。 また、今回は主にエンジニアに向けて書きましたが、私と同じようにエンジニア採用を担当されているマネージャー職や人事の方からすると今回の内容は採用活動全体の一部でしかないと思います。 自社への認知を増やす活動や選考に入る前の興味を持ってくれた方へのアプローチ、ATSを利用したデータ分析など他の取り組みも順次進めていますので、どこかでそれらの取り組みについても共有出来ればと考えています。 今回の記事で興味を持って頂いたエンジニアの方はもちろん、エンジニア採用に一緒に取り組んでもいいよ!という方はぜひ一度お話させてください! hrmos.co
アバター
スマートキャンプの郷田です。 先日行われたRoppongi Product Manager Meetup #8 にスピーカーとして参加させていただきました。 本記事では、私がPM(自称)となるまでの発表内容をまとめましたので、ご紹介します。 pm-roppongi.connpass.com 発表内容まとめ 発表の目的 プロダクトと私のタイムライン 1回目の越境 多くの問題と行動意識 実施した施策サマリ 2回目の越境 勉強中の参考書 発表スライドはこちら 最後に 発表内容まとめ 発表の目的 開発リーダーとして振る舞っていた私がいつの間にかPMの振る舞いをしていた話のため、対象者はPMになりたいエンジニアかなと思います。 また、PMの仕事を全く知らなかった私が、泥臭く問題解決に動いていることを紹介しているスライドとなります。 ※ちなみに、主催の pm-roppongi - connpass は「現役プロダクトマネジャー、プロダクトマネジャーを志すエンジニアの集い。」であるため、こちらの内容でマッチしていたようでした。 プロダクトと私のタイムライン エンジニアとしてスマキャンにジョインしていたものの、2018年はスマートキャンプのコーポレートIT立ち上げをしていました。 こちらの採用や業務整理も一通り終わり、2018年12月に開発チームに戻ることになりました。 プロダクトの前身となる社内プロジェクトがすでに動いていたため、1ヶ月ほど開発を行った後に開発リーダーの役割りとしてチーム活動を行っていました。 開発リーダーとなってから、2度の越境の後、現在スマートキャンプではPM(プロダクトマネージャー)と名乗っています。 本発表では、1回目の越境から、2回目の越境までの業務にフォーカスを当てています。 1回目の越境 新規SaaSプロダクトの立ち上げを行う上ではエンジニアリング以外も進める必要があったのですが、これらを対応する人が居ない状況でした。 そこで、上司に相談してもらったFBの結果、私がそれら(いわゆるプロダクトマネージャーの役割り)を行うことと決めました。 多くの問題と行動意識 すでにプロダクト開発の一部が走り出していたこともあり、エンジニア内外ですでに色々問題が起きている状態でした。 それらを、優先度と重要度の4象限に分けて対応すること、私しかできない問題に集中することを意識しながら進めました。 また、「意思決定=自分」となりつつあったため、自身の判断により与える影響が大きくなる恐怖を払拭することも重要でした。 実施した施策サマリ 私が実施した施策はすべて、プロダクト関係者が最大のパフォーマンスを出すためのものとなります。 今思えばプロダクトマネージャーとしては視野が狭いように感じますが、エンジニアがPMになる最初の一歩はそんなものだと思います。 実施した施策の概要は、1項目ずつスライドに分けて書いています。 2回目の越境 外部のアドバイザーの方と定期的にコミュニケーションをとっているのですが、私のやっていたことがプロダクトマネージャーの役割りということを教えていただく機会がありました。 そこから、プロダクトマネージャーについて勉強を進め、現在社内でPMを自称しております。 勉強中の参考書 発表の最後には、現在学習中の本を紹介して、終了となります。 発表スライドはこちら speakerdeck.com 登壇の様子 最後に 感想ですが、プロダクトマネージャーとしてのイベント参加は初で、エンジニアリングだけではない幅広い視点でお話することができ、良い経験となりました。 そして、弊社で同じようにもがき苦しみ、チームと共に成長をしたい仲間を継続して探しているので、この記事に興味を持った方はぜひお話しましょう! hrmos.co
アバター
スマートキャンプのエンジニア今川( @ug23_ )です。 今月3日から6日にかけて 産業技術大学院大学のenPiT2プログラム の一環である、 enPiT2 PBL基礎・夏合宿「アジャイルチームキャンプ」 (以下、夏合宿)に社会人メンターとして参加してきました。本記事ではその参加レポートをお送りします。 会社側には業務として送り出していただきました。任意で受講するenPiT2の受講生たちと直接関われる機会が得られ、直接採用につながらなくても「今の学生エンジニアが求めるもの・流行り」などの情報収集になるし、アジャイル開発を実践していることを伝えられるという会社側へ与えるメリットも説明して最終的には代表OKをいただきました。 enpit.aiit.ac.jp enPiTは 高度IT人材を育成する産学協働の実践教育ネットワーク という題がついており、学生時代のうちから実践的なIT教育を行って社会で活躍できる人材を輩出するというねらいのある文部科学省プロジェクトです。とくに、BizSysDという分野は以下のように位置づけられています。 社会やビジネスニーズに対する実用的なソリューションとしてのビジネスアプリケーションやシステムデザインを自ら提案、開発し、顧客の潜在的要求を満たすことのできる人材育成を目指します。 メンターについては、会の中に TDD+モブプログラミングでワイワイする会 があることやenPiT2の前身であるenPiTの修了生であり、学生メンターとして参加していたこともあり推薦していただいたようです。 tddyyx.github.io 合宿でなにをやったか? 夏合宿自体は9月2〜6日をまるまる使って行われました。 会のざっくりした流れはこんな感じでした。 9/2: アジャイル開発とスクラム・スクラム開発体験ワークショップ 9/3: TDD入門・TDD+モブプログラミングでワイワイする会 9/4-5: スクラムによるプロダクト開発 9/6: 全体ふりかえり 会場はコロニー箱根でした。緑に囲まれていたし、空気がきれいだし建物が円形なので行き来がしやすくて最高でした。(まもなく休止になるようです。悲しい) colony-hakone.com 晴れたり雨がふったりでしたが毎日すごしやすかった! ソフトドリンクが飲み放題でした。辛いジンジャエールが生姜感がすごくておいしかったです。 事前のよびかけで有志の企業のみなさまから差し入れられたお菓子やカップラーメンが毎日適切な量でデプロイされていました。 メンター陣は、参加大学の先生と学生メンター、社会人メンターという構成でした。 1日目: アジャイル開発とスクラム・スクラム開発体験ワークショップ 私は宿の都合で2日目からの参加だったのでいませんでしたが、座学+グループワークが行われていたようです。 グループワークでは、スクラムのプロセスに則って「機能性のあるオブジェクト」を工作していました。 メンターの手が空き始めると勝手にメンターもやりはじめるという自己組織的な環境でした。 (あとで知りましたがターゲットユーザを私にしたプロダクトが作成されていました) 2日目: TDDライブコーディング・TDDyyχ テスト駆動Python や 心理的安全性ゲーム で知られる安井力さんによるPythonを使ったTDDライブコーディングでした。 午後には実践ということで、TDDをみんなでやってみよう!モブプログラミングを体験してみよう、ということで普段の「TDD+モブプログラミングでワイワイする会」のフォーマットに則ってモブセッションを体験してもらいました。 夜はLT会があったり、TDD+モブプログラミングでワイワイする会のメンター陣だけでモブをやったりしていました。写真は Diamond というお題をやりきってドデカなダイアモンドを出して余韻に浸るなどをしました。 3, 4日目: スクラムによるプロダクト開発 初日は工作でスクラムを体験しましたが、3,4日目では実際にコードを書いてチーム開発してもらいました。 テーマは自動販売機。CLIでもWebでもなんでもいいから自動でものを売れるようにする何かを作るという感じ。 スプリント0を行って各チーム思い思いの自動販売機を考えるところから。 プロダクトオーナーとスクラムマスターを決めて開発をはじめます。 途中から「メンタリングするときにスクラムマスターとプロダクトオーナーがパッと見でわかるといいよねー」という話になり、1日目の工作用品にあったお花紙でお花を作っていました。お花をつくるのなんて何年ぶりかなという感じでした。 実益とその場にあるものを活かすという考えが進むと、遊びとメンタリングの境界が薄まって最高に楽しい時間になります。 メンター学生関係なくみんなでワイワイやれていた感じがあります。 Sprint5で最後の最後でデグレードによって機能が動かなくなってしまったチームは「テスト書いておけばよかったな」と漏らす場面もありました。小さい単位で失敗を体験できるのは社会人からしてもなかなか貴重な機会だと思います。 会場のフリースペースにはボードゲームやけん玉など自由に遊べるものをデプロイしていたのですが、この夜は一晩中けん玉に興じる人が多かったです。 5日目: ふりかえり 最終日には全体で集まって5日間をふりかえりました。 まずはタイムラインで振り返り。事実と感情を分けて話しあい、その後チームで成し遂げたいTryをあげます。 最後はみんなで一言ずつ振り返り、解散しました。 他大学との交流がよかった 後期の開発に活かしたい けん玉がたのしかった などの意見がでました。 思ったこと 2日目と5日目での比較ですが、どのチームも1日目とは議論の質が変わっているように見えました。大きい目標を立てるチームになれていることに感銘をうけました。 RSGT2019で楽天の1年目のみなさんが楽天の新卒研修をベースに発表されていましたが、学生はやはり教わった通りにでき、過去の体験に依存せず振る舞えるのでその点が強いなと感じます。例えば1日3回Sprintを回すのは社会人チームでもなかなかできないことだと思います。それを2日で5回やったのは誇っていいことだと思います。 confengine.com 学ぶ場における環境っていいよね、とも思います。チームビルディングのために合宿をやるチームも多いですが、思い切って自由な場でゆとりのある状況にしたほうが学習効果は高まるかもと思いました。このあたりは永瀬先生による設計が大きく寄与している気がします。聞いたら普通に受けたら有料の研修の内容だったようで、enPiTはすごいですね。 スマートキャンプでは? スマートキャンプのエンジニアチームでは週に1度アジャイルコーチの方に来ていただき、ミーティングやふりかえりを見てもらいながら開発プロセスを改善している最中です。 また、私のいるチームでは可能な限り常にモブプログラミングで開発しようという取り組みをやっています。 隣のチームでもモブをやり始めてスペースが足りなくなったのでモブスペースをもう1つ追加しようとしています。 「画面共有しながらでかいディスプレイに画面移してRubyMine使うとMacのファンが回りっぱなしになるよね」という問題もわかったのでmac miniをレンタルしてモブマシンにしてみようか?という話をはじめています。 「こんなプラクティスがあるよ」というのを受け入れて、それに全力で取り組むことでそのメリットを感じ「当たり前になる」という過程を目の当たりにしていてとても楽しいです。 最後に これを書くために写真を確保するため参加者全員で共有しているGoogleフォトのアルバムを眺めていたら「最高の夏だったな」という思いがこみ上げて筆がのりませんでした。ようやくこの時間に書き終わりました…w 学生と関わることはややもすると「こちらから教える」という立ち位置になりますが「眺めて直すべき箇所をよりよくするためのアドバイスをする」「解決のための手段をひとつ教えてみる」というだけで勝手に吸収していくんだなというのを改めて実感しました。そして安全に失敗できる場の大切さを感じました。 教えることで学生から学ぶことも多く、教えるスキルの糧にもなったと感じる1週間弱でした。 スマートキャンプでは「テクノロジーで社会の非効率をなくす」ために、アジャイルに改善を積み重ねながらプロダクトを作っていきたいエンジニアを募集しています。 https://hrmos.co/pages/smartcamp/jobs/005 hrmos.co https://hrmos.co/pages/smartcamp/jobs/0000023 hrmos.co
アバター
スマートキャンプのエンジニア入山です。 近年、ユーザ体験(UX)の優位性からSPA(Single Page Application)を採用しているWebアプリケーションを多く目にするようになりました。 弊社が8月1日にリリースした、インサイドセールスに特化したCRM Biscuet(ビスケット) も、Vue.jsを使ったSPAで構成されたサービスです。 SPAを採用することで多くのメリットがありますが、従来のMPA(Multiple Page Application)とは異なる運用ノウハウが必要になると思います。 今回はSPAをプロダクション運用する上で避けては通れない、リビジョンアップ時のクライアント側の対応をご紹介します! SPAにおけるリビジョンアップ時の課題 リビジョン確認機能の実装方針 リビジョン確認機能の実装 アプリケーションにリビジョンIDを埋め込む リビジョン管理用JSONファイル(revision.json)をS3に配置 JSONファイルから最新のリビジョンIDを取得し、アプリケーションのリビジョンIDと比較 リビジョンIDに差異があればアラートを表示 最後に SPAにおけるリビジョンアップ時の課題 SPAのWebアプリケーションでは、必要なコード(HTML、JavaScript、CSS)を最初にまとめてブラウザに読み込み、ブラウザでできる処理はJavaScriptで完結させることで、サーバとのAPI通信を必要最小限に抑えることができます。 MPAのWebアプリケーションとは異なり、サーバからは必要最小限のデータのみを取得するため、クライアントとサーバが疎結合になることが特徴です。 しかし、クライアントとサーバが疎結合であることにより、リビジョンアップの際には、クライアントが意図的にリロードしない限りブラウザに保持されたJavaScriptファイルが最初に読み込まれたリビジョンのままとなり、クライアント(旧)とサーバ(新)でリビジョンの不整合が発生する可能性があります。 特に大きなシステム修正(DBのカラム変更など)の場合には、リビジョンを合わせないと予期せぬ障害につながる可能性もあるため、運用者が新しいリビジョンをリリースする際には、何らかの方法によりクライアントにブラウザのリロードを促す手段が必要となります。 リビジョン確認機能の実装方針 今回は、CDN(AWSのCloudFront + S3など)でのクライアント配信を例として、以下の手順でリビジョン確認を行うことにしました。 尚、今回は強制リロードではなく画面へアラートを表示させることで、ブラウザのリロードをユーザーに促す仕様にしています。 リビジョン確認機能の実装内容 アプリケーションにリビジョンIDを埋め込む リビジョン管理用JSONファイル(revision.json)をS3に配置 JSONファイルから最新のリビジョンIDを取得し、アプリケーションのリビジョンIDと比較 リビジョンIDに差異があればアラートを表示 リビジョン確認を実施するための実装案は他にもありましたが、以下メリットを考慮して今回のような実装方針にしました。 クライアント側だけでリビジョン確認が完結 リビジョン確認処理にかかる負荷が少ない リビジョン確認機能の実装 アプリケーションにリビジョンIDを埋め込む アプリケーションのリビジョンIDは、柔軟性を持たせるためにビルド時の環境変数(APP_REVISION_ID)から取得し、process.envで参照します。尚、クライアントビルドは、webpackにて実施しています。 クライアントビルド時 export APP_REVISION_ID= " 1.0.0 " yarn install yarn build アプリケーション参照時 process.env.APP_REVISION_ID リビジョン管理用JSONファイル(revision.json)をS3に配置 最新のリビジョンIDを含んだJSONファイルをS3へ配置するようにします。 revision.json {"revisionId": "1.0.0"} JSONファイルから最新のリビジョンIDを取得し、アプリケーションのリビジョンIDと比較 S3に配置したリビジョン管理用JSONファイルを取得し、アプリケーションのリビジョンIDと比較する処理を実装します。 axiosライブラリを利用してAPI通信を行います。(Vueを普段使っているのでVueっぽいサンプルです) src/revisionCheck.vue <script> import axios from 'axios' export default { data () { return { revisionId: null } } , created () { this .getRevisionId() } , computed: { revisionCheck () { // JSONファイルとアプリケーションのリビジョンIDを比較した結果を返す return this .revisionId === process.env.VUE_APP_REVISION_ID } } , methods: { async getRevisionId () { await axios.get( '/revision.json' ).then(res => { this .revisionId = res.data.revisionId } ) } } } </script> リビジョンIDに差異があればアラートを表示 リビジョンIDの確認結果がfalseとなった場合に、アラートのメッセージが表示されるようにします。 src/revisionCheck.vue <template> <div class = "revision-check" v- if = "!revisionCheck" > <div>新機能がリリースされています。ページを更新してください。</div> </div> </template> <script> import axios from 'axios' export default { data () { return { revisionId: null } } , created () { // setInterval関数で定期実行する setInterval(() => { this .getRevisionId() } , 60000) } , computed: { revisionCheck () { // JSONファイルとアプリケーションのリビジョンIDを比較した結果を返す return this .revisionId === process.env.VUE_APP_REVISION_ID } } , methods: { async getRevisionId () { await axios.get( '/revision.json).then(res => { this .revisionId = res.data.revisionId } ) } } } </script> プロダクトでは最終的に以下のように表示するようにしています! ※ setInterval関数については、弊社エンジニアの瀧川が以前記事を書いているので、ぜひ参考にしていただければと思います! tech.smartcamp.co.jp 最後に 今回は、SPAにおけるリビジョンアップ対策について紹介しました。 弊社では、CircleCIでデプロイ作業を自動化しており、リビジョンIDの更新も含めて自動で行われるようにしています! SPAには多くのメリットがあり、近年SPAのWebアプリケーションが増えていますが、実際に構築・運用する場合の情報がまだまだ少ないのが現状です。 リビジョンアップ対策についても実装方法はいくつかあると思いますが、今回紹介した内容が参考になれば嬉しいです!
アバター
スマートキャンプのデザイナー/エンジニアのhaguriです。 弊社では8月1日、インサイドセールスに特化したCRM Biscuet(ビスケット) という新サービスをリリースしました。 biscuet.jp Biscuetでは Vue.js + Atomic Design でコンポーネント設計をしています。今回はその構成と考え方・Biscuetチームでの運用について紹介していきます。 Atomic Design について templatesとpagesについて Biscuetでのルール atoms molecules organisms pages ディレクトリ構成 App.vue components/ plugins/biscuet-materials/ さいごに Atomic Design について Atomic Design とは、コンポーネント単位で設計していくデザイン・開発手法です。 詳しくは以下の記事が分かりやすいので参考にしてみてください。 design.dena.com 簡単に説明すると、以下の画像のように、UIのパーツを5階層の単位で分割して組み立てていくものです。 参照: http://atomicdesign.bradfrost.com/chapter-2/ 1. atoms(原子) 2. molecules(分子) 3. organisms(生体) 4. templates(テンプレート) 5. pages(ページ) Atomic Designは 明確なルールがない、UIを考えるための手法 です。 実際のサービス開発に導入する場合にはこの考え方をベースにして開発チームやデザインチーム内で具体的なルールを実際に決める必要があります。 これらのルールは実際のチームによって異なりますが、この記事ではBiscuet開発チームで設定してみたルールを紹介しています。 templatesとpagesについて Atomic Designを導入しようとすると考えなければいけないのが、templatesとpagesをどうするのかという問題です。 この2つは導入当初以下のように考えていました。 templates : organismsを配置するもので、pagesから送られてきたデータを各コンポーネントに流すもの pages : データを取得してtemplatesにデータを渡すもの わざわざこの2つをわけると複雑性がますと判断し、templatesを廃止しました。 いまでは廃止前に作ったものが一部残っていますが、開発している部分はtemplatesを作らずにすすめています。 Biscuetでのルール Biscuet内では、以下のようなゆるやかなルールを設けています。 再利用性 store参照 同階層参照 プリフィックス atoms ◯ × × b- molecules ◯ × ◯ b- organisms × ◯ ◯ - pages × ◯ × - atoms 定義: これ以上分解できない最小単位のもの 複数コンポーネントからの呼び出しを想定しているため、以下の2点に気をつけています。 store参照をしない 他のatomsを使用しない Biscuetでは、どのコンポーネントで使用されているのかを分かりやすくするために、プリフィックスとして b-card のように b-xxx をつけています。 molecules 定義: 2つ以上のatomを使用したもの moleculesの条件として、以下の3点だけを設定しています。 atomsを複数組み合わせたもの 複数コンポーネントから呼び出す想定があるもの store参照をしない こちらも複数コンポーネントからの呼び出しを想定しているので、atomsと同じようにコンポーネント名に b-xxx をつけています。 organisms 定義: 各ページに特化している最小単位のもの organismsの条件は以下のように設定しています。 atomsとmoleculesから構成されるもの 他のページでの再利用は考えない カードなど、同じ要素をつかって繰り返し表示するようなものはorganismsに置いています。 ただ、organismsはpagesごとにディレクトリごとに分ける構成にしているので他ページでの参照は考えません。 そのページだけで使う要素を組み合わせてorganismsにしています。 例えば カード のように1ページで複数使うようなものはorganismsにしています。 pages 定義: 各コンポーネントを配置して、ページとして成立させるもの 上記で書いたatoms, molecules, organismsを組み合わせて1つの画面を作っていきます。 ディレクトリ構成 実際のディレクトリ構成は以下のようになっています。 src / ├──App.vue ├──main.js ├──components/ │ ├── organisms/ │ │ ├── home/ │ │ │ └── xxxxx.vue │ │ ├── project/ │ │ └── xxxxxx/ │ └── pages/ │ ├── Home.vue │ ├── Project.vue │ └── xxxxxx.vue └── plugins/ └── biscuet-materials/ ├── atoms/ │ ├── BCard.vue │ ├── BIcon.vue │ └── xxxxxx.vue ├── molecules/ │ ├── BInput.vue │ ├── BSelect.vue │ └── xxxxxx.vue └── index.js App.vue 全体に関わるコンポーネントを配置しています。 <template lang="pug"> #app b-toast b-layout sidebar router-view b-modal(modalName="xxx") b-modal(modalName="xxx") </template> トースターやサイドバー、全体に関わるモーダル等を配置しています。 components/ organismsとpagesをおいています。 organismsはページ内の最小単位としているので、基本的にpagesのコンポーネント名でディレクトリを切っています。 plugins/biscuet-materials/ atomsとmoleculesをおいています。 organisms以上とは違い、複数コンポーネントで読み込む可能性があるため完全に分離して以下のようにグローバルのコンポーネント登録をしています。 // index.js const context = require.context( '.' , true , /.vue$/ ) const components = {} context.keys().forEach(contextKey => { const key = contextKey.match( /.+\/(.+)\.vue/ ) [ 1 ] components [ key ] = context(contextKey). default } ) export default { install (Vue) { Object .keys(components).forEach(key => { Vue.component(key, components [ key ] ) } ) } } これをmain.jsで以下のように読み込み、使用しています。 // main.js import BiscuetMaterials from '@/plugins/biscuet-materials' Vue.use(BiscuetMaterials) さいごに 最初はガチガチにルールを決めて、各コンポーネントをどの階層に置くべきかを話し合っていました。 ただ、ルールを決めすぎると判断に迷うことが多くなってきました。現在はシンプルなルールのみを設定することで、以前より共通認識は取りやすくなってきています。 この記事で紹介した方法ははBiscuetというサービスにおいてのルールです。そのためサービスの性質によって変わってくると思いますが、ぜひ参考にしてみてください。 また、本記事の内容は弊社のデザイナーチームによる デザインブログ でも紹介しています。 note.mu デザインブログでは私がデザイナー目線での内容として書いています。こちらもよければご覧ください! note.mu ライター:葉栗 雄貴 / Haguri Yuki(Designer & Engineer)
アバター
スマートキャンプでエンジニアをしている笹原です。 Terraform v0.12がリリースされて数ヶ月経ちましたがみなさんはもう使ってますか? なかなか使えてなかったのですが、ブログ当番になったのをいい機会にアップグレードしてみました! 今回は、アップグレードの手順を紹介したいと思います!! アップグレード前の準備 アップグレード手順を確認する tfenvをインストールする Terraform v0.11.14でアップグレード前チェックを走らせる アップグレード前チェックの対応をする Terraform v0.12へのアップグレード Terraform v0.12をインストールする コードを修正する アップグレードの効用 終わりに アップグレード前の準備 アップグレード手順を確認する Terraform v0.12へのアップグレードは公式のアップグレードガイドに沿ってやっていきます。 アップグレード作業を始める前に一通り目を通しておきましょう! Upgrading to Terraform 0.12 - Terraform by HashiCorp tfenvをインストールする tfenvとは、rbenvのようなTerraformのバージョンを管理するツールです。 GitHub - tfutils/tfenv: Terraform version manager 複数環境でそれぞれ別のTerraformのバージョンを使う際に便利です。 アップグレード作業を途中で止めることもあり得るので、利用しておいて損はないです。 Terraform v0.11.14でアップグレード前チェックを走らせる v0.11.14には 0.12checklist というコマンドが追加されており、v0.12にアップグレードする前に必要な作業を確認することができます。 まずv0.11.14を利用できるようにしましょう。 $ tfenv install 0 . 11 . 14 $ terraform -v Terraform v0. 11 . 14 続いて、必要なプラグインがダウンロードされていることや、tfstateファイルが実インフラ環境を反映していることを確認します。 $ terraform init $ terraform apply そして、アップグレード前チェックを走らせます。 $ terraform 0 .12checklist このチェックによって確認されるのは以下のことです。 アップグレードしておくべきProviderがないか 命名を変更すべきリソースやプロバイダーのエイリアスがないか アップグレードしておくべき外部モジュールがないか アップグレード前チェックの対応をする 私の環境では以下のようなメッセージが出力されました。 $ terraform 0 .12checklist After analyzing this configuration and working directory, we have identified some necessary steps that we recommend you take before upgrading to Terraform v0.12: - [ ] Upgrade provider " aws " to version 2 . 24 . 0 or newer. No currently-installed version is compatible with Terraform 0 . 12 . To upgrade, set the version constraint for this provider as follows and then run `terraform init` : version = " ~> 2.24.0 " 確認項目の1つ目、アップグレードすべきプロバイダーの指摘が入りました。 該当のProviderを利用している箇所でバージョンを最新にします。 provider "aws" { version = "~> 2.24.0" region = "${local.aws_region}" } 変更したら再度、0.12checklistコマンドを走らせましょう! $ terraform init $ terraform apply $ terraform 0 .12checklist Looks good! We did not detect any problems that ought to be addressed before upgrading to Terraform v0. 12 . This tool is not perfect though, so please check the v0. 12 upgrade guide for additional guidance, and for next steps: https://www.terraform.io/upgrade-guides/0-12.html これでアップグレード前の準備が終わりました! Terraform v0.12へのアップグレード Terraform v0.12をインストールする まず、Terraform v0.12を利用できるようにしましょう。 $ tfenv install 0 . 12 . 6 $ terraform -v Terraform v0. 12 . 6 バージョンを上げてからもinitを再度実行します。 $ terraform init ここで、Terraform v0.12と互換性のないシンタックスで書かれているところがあれば、それを知らせるメッセージが表示されるようなのですが、私の環境では表示されませんでした。 ただ、表示されてないからと言って、アップグレード作業が完了したわけではないので、引き続き進めていきましょう。 コードを修正する Terraform v0.12のシンタックスにするコマンドがv0.12には追加されているので、まず、これを使用します。 $ terraform 0 .12upgrade 正常に完了すると以下のメッセージが表示されます。 Upgrade complete ! The configuration files were upgraded successfully. Use your version control system to review the proposed changes, make any necessary adjustments, and then commit. この作業は静的に現在のディレクトリ上のコードのみを変更するようで、 同一プロジェクト内にモジュールとして、別のディレクトリにもコードがある場合には、そちらについても別途実行する必要があります。 $ terraform 0 .12upgrade modules/iam/group $ terraform 0 .12upgrade modules/iam/role また、これで完了ではなく、自動でアップグレードされない部分もあり、そういった部分には TF-UPGRADE-TODO として、コメントがコード上にされています。 私の環境では以下のようなメッセージが有りました。 data "aws_iam_policy_document" "developers_policy" { statement { actions = ["sts:AssumeRole"] # TF-UPGRADE-TODO: In Terraform v0.10 and earlier, it was sometimes necessary to # force an interpolation expression to be interpreted as a list by wrapping it # in an extra set of list brackets. That form was supported for compatibilty in # v0.11, but is no longer supported in Terraform v0.12. # # If the expression in the following list itself returns a list, remove the # brackets to avoid interpretation as a list of lists. If the expression # returns a single list item then leave it as-is and remove this TODO comment. resources = [developer.role.arn] } } v0.10以前では、単一の変数を返したい場合でもリストにしないと変数として解釈されない部分があり、v0.11でもその記法をサポートしていたが、v0.12からサポートしなくなったということです。 リストを返したいのか単一の変数を返したいのかで対応が変わるため、 TF-UPGRADE-TODO となっているようです。 今回の場合は、リストを返したいので、コードはそのままでコメントを削除しました。 ここまで行うと terraform plan でエラーがでなくなりました。 アップグレードの効用 終わりに 今回はTerraform v0.12へのアップグレード作業を紹介しました。 新しい機能についての紹介はしませんでしたが、First-class expressionsなどはスッキリ書くことができるし、他にもv0.12で追加された機能により、運用が楽になることが多々あります。 そういった運用が楽になる箇所については、またの機会に書きたいと思います!
アバター
スマートキャンプのエンジニア井上です! 多くの開発要望がある中で、エンジニアのみでインパクトのある改善をするときにによくあげられるのがサイトの パフォーマンス改善 かと思います。 今回はサイトのスピート計測ツールである、 Google PageSpeed Insightsで使用されているLighthouseのスコア を参考にして、実際に効果があった施策をご紹介します! Google PageSpeed Insightsとは Lighthouseとは Performance項目改善の進め方 実際の対策 レンダリングブロック対応 指摘内容 対策 画像圧縮対応 指摘内容 対策 オフスクリーン画像の遅延読み込み 指摘内容 対策 IntersectionObserver APIとは 実際の実装イメージ 不要なJS・CSS削除 指摘内容 対策 必須のドメインへの事前接続 指摘内容 対策 Resource Hintsとは dns-prefetch preconnect prefetch まとめ Google PageSpeed Insightsとは Googleのスピード計測ツールです。 後述するLighthouseのPerformanceをもとにページごとの評価を採点しており評価項目としては下記の項目があります。 コンテンツの初回ペイント 速度インデックス インタラクティブになるまでの時間 意味のあるコンテンツの初回ペイント CPU の初回アイドル 最大推定 FID developers.google.com Lighthouseとは Google PageSpeed Insight で分析エンジンとして採用されている計測ツールです。 LighthouseのPerformance項目が今回見ていくポイントとなります。 chrome.google.com Performance項目改善の進め方 ローカルでは本番環境と違い、テキストやHTTP2対応などがされていないなどの差分から下記のような問題が起こります。 Pefomanceの点数が違う Pefomanceの指摘点が違う なので、基本的には *本番環境で指摘されているもの** を対応し、ローカルではLighthouseでその指摘事項が解消されているかなどを確認しながら進めていきます。 ただ、単純に項目通りやれば改善するわけではなく、改善するものもあればしないものもあります。 あくまで指摘事項は改善する可能性があることを指摘しているので、あくまで参考として認識しておきましょう。 実際の対策 レンダリングブロック対応 指摘内容 レンダリングブロックはサイトが表示される際に、JSやCSSの読み込みによってレンダリングを待つ状態になり、コンテンツの表示が遅くなる現象です。 主に JSなどがhead部分で読み込まれたり、不要なCSSが多い とこの現象が起こります 対策 JSの対策としては簡単でbodyのあとなどでJSを読み込むようにするのみです。 CSSの対応としては少し難しく対策として不要なCSSをなくす、または初期表示はFirstViewで使用するCSSのみを読み込むようにするなどが考えられます。 他にもloadCSSを使用してレンダリングブロックを回避する例もあるようです。(自分はやったことないですが。。。) 全ブラウザ対応!preload で CSS を非同期で読み込み高速化 画像圧縮対応 指摘内容 単純で画像サイズが大きすぎると読み込みが遅くなり、この指摘がでます。 対策 すべての画像圧縮する処理・バッチを作るなどの対応もありますが、検証としてやるのであればTinyPingなどでWEB上で画像圧縮してアップロードするなどがおすすめです。 tinypng.com オフスクリーン画像の遅延読み込み 指摘内容 FirstViewなどで表示されていない画像の読み込みによって、コンテンツ表示が遅くなることがあります。 対策 対策としてはGoogleが推奨しているIntersectionObserver APIを使ったlazyload対応があります。 IntersectionObserver APIとは 特定のDOM要素が画面内に入っているかどうか、さらにその位置も取得することができるAPIです。 実際の実装イメージ HTML側 < img src = '' data - src = '' 画像のURL ' is-lazyload/> JS側 var observer, targetImgs; // 画像が画面ないに入ったらdata-src属性をsrc属性にセットする observer = new IntersectionObserver( function (images) { return images.forEach( function (image) { if (image.isIntersecting) { image.target.src = image.target.dataset.src; return observer.unobserve(image.target); } } ); } ); // lazyload対象の画像を取ってくる targetImgs = document .querySelectorAll( "img[is-lazyload]" ); // lazyload対象の画像に処理を設定 targetImgs.forEach( function (targetImg) { return observer.observe(targetImg); } ); 不要なJS・CSS削除 指摘内容 JS・CSSなどで使用されていないものが存在する場合に指摘されます。 例としては必要なmodule以外もすべて読み混んでる場合などになります。 対策 こちらはChromeDeveloperConsoleのcovelegeなどで、 使用されているJS・CSSを確認しながらボトルネックを探し ていき削除していく地道な作業が必要になります。 必須のドメインへの事前接続 指摘内容 外部のJSやCSSなどが常に読み込んでるものが多く、その名前解決がキャッシュされていない状態で指摘されます。 対策 Resource Hintsにより事前の名前解決やリソース自体のキャッシュ対応を行います。 Resource Hintsとは Resource Hintsはlink要素を利用したリソース先読みのための仕組みです。 事前に取得すべきリソースを明示することで、先読みやキャッシュが可能になります。 dns-prefetch DNSのキャッシュ行い名前解決の時間を削減します。 < link rel = "dns-prefetch" href = "//example.com" > preconnect DNS の解決に加えて TCP の接続までを確立しておき、すぐにリクエストを行える状態にします。 < link rel = "preconnect" href = "//example.com" > prefetch 主に静的リソースのキャッシュに使用されます。 < link rel = "prefetch" href = "//example.js" > まとめ 今回はLighthouseで指摘されていた項目の対応内容に関して紹介しました。 この内容でよりよいPerformance改善に早くたどり着ければと思います。
アバター
スマートキャンプのエンジニア瀧川です! クライアントサイド(JavaScript)で処理を定期実行したい場合は皆さん使いますよね! そうsetInterval関数です。 ただ何も考えず使ってしまうと色々な問題が起こったり... そこで本記事ではsetInterval関数を使う際の困りごとを挙げて、それをまるっと解消するVue.jsプラグインを作る方法を紹介したいと思います! (今回はVue.jsで実装しますが、特に依存しているわけはないので他のフレームワークをお使いの方も参考にしてください!) まずVue.jsプラグインの雛形を作る 困りごと1 困りごと: ブラウザ(タブ)を開きっぱなしにすると必要以上に実行されてしまう 解決法: Page Visibility APIを利用してアクティブなときにしか処理を実行しない 困りごと2 困りごと: ページ遷移してもsetIntervalが維持されてしまう 解決法: timeId(setIntervalのID)をプラグイン側で一括管理 困りごと3 困りごと: 開発環境(ローカル)で定期実行されるとデバッグなどしにくい 解決法: 環境変数に応じて定期実行しない プラグイン全体 まとめ まずVue.jsプラグインの雛形を作る 今回はVue.jsでsetIntervalのラッパー関数をプラグインとして実装しようと思います。 プラグインは以下のようになります。 src/plugins/SetInterval/index.js export default { install (vue) { vue.prototype.$setInterval = (func, intervalMilliSec) => { const id = setInterval(() => { func() } , intervalMilliSec) return id } } } これをmain.jsなどVue読み込み時に以下のようにインストールすることで実行可能になります。 main.js import Vue from 'vue' import SetInterval from '@/plugins/SetInterval' ... Vue.use(SetInterval) コンポーネント内での実行イメージは以下のようになります! export default { created () { this .$setInterval(() => { // 処理 } , 1000) } } src/plugins/SetInterval/index.js に困りごとに応じた機能を追加していこうと思います! 困りごと1 困りごと: ブラウザ(タブ)を開きっぱなしにすると必要以上に実行されてしまう これがもっともよくある問題かなと思います。 setIntervalは通常ブラウザが起動している状態であれば実行され続けます。 例えば他のタブで別サイトも見ている場合なんかに、裏側で実行され続けると不必要にAPIリクエストを投げ続けてしまう問題が起こります。(タブを複製した場合にその分APIリクエストが流れる...とか負荷がばかにできなくなってきますよね) あと、ページを閲覧しているときだけカウントアップ...なんてこともあるかもしれませんね。 解決法: Page Visibility APIを利用してアクティブなときにしか処理を実行しない Page Visibility APIを利用することで、JavaScriptからページがアクティブかどうかを取得でき、また状態が変更されたイベントをハンドリングすることができるようになります! document.visibilityState が visible の状態が、ページ(タブ)がアクティブな状態となり、その状態のみ関数が実行されるようにしています。 export default { install (vue) { vue.prototype.$setInterval = (func, intervalMilliSec) => { const id = setInterval(() => { if ( document .visibilityState === 'visible' ) { func() } } , intervalMilliSec) return id } } } 困りごと2 困りごと: ページ遷移してもsetIntervalが維持されてしまう Vue.jsなどフレームワークを使っている場合、多くはクライアントサイドでルーティングなど管理していることと思います。 その場合、ページ遷移時にsetIntervalも維持されてしまうので、意図しないページで処理が実行されてしまうことが起こり得ます。 例えば、ログアウトしてログイン画面に遷移させたのに、裏ではAPIにリクエストを投げ続けてしまう...なんてことが起きるかもしれません。 そんなときに当然キャンセル処理を実装すれば解決!となりそうですが、setIntervalのキャンセルは以下のように返り値の timerId をclearInterval関数に渡す必要があり、様々のコンポーネントで好き勝手に呼び出している場合はそれも困難になります。 const timerId = setInterval(() => { // 処理 } ) ... clearInterval(timerId) 解決法: timeId(setIntervalのID)をプラグイン側で一括管理 以下のように各setIntervalのIDをインスタンス変数として保持し、それを使ってすべてをキャンセルするclearAllIntervals関数などを定義しています。 これによって、ページ遷移時のイベントをハンドリングして、setIntervalをキャンセルするなど可能になります! export default { install (vue) { vue.prototype.$intervals = [] vue.prototype.$setInterval = (func, intervalMilliSec) => { const id = setInterval(() => { func() } , intervalMilliSec) vue.prototype.$intervals.push(id) return id } vue.prototype.$clearInterval = (id) => { clearInterval(id) vue.prototype.$intervals = vue.prototype.$intervals.filter(i => i !== id) } vue.prototype.$clearAllIntervals = () => { vue.prototype.$intervals.forEach(clearInterval) vue.prototype.$intervals = [] } } } 困りごと3 困りごと: 開発環境(ローカル)で定期実行されるとデバッグなどしにくい APIの開発をしている際に、別の機能で定期実行でAPIを叩かれて、ログが流れてしまう... みたいなことがありますよね。 解決法: 環境変数に応じて定期実行しない あらかじめ開発環境(ローカル)で VUE_APP_DISABLE_SET_INTERVAL などの環境変数を定義しておいて、その変数が定義されている場合setIntervalを無効化しています。 こうすることで、簡単に切り替えが可能になります! export default { install (vue) { vue.prototype.$setInterval = (func, intervalMilliSec) => { if ( typeof (process.env.VUE_APP_DISABLE_SET_INTERVAL) !== 'undefined' ) { console.log(` [ DISABLE_SET_INTERVAL ] Check environment vars`) return null } const id = setInterval(() => { func() } , intervalMilliSec) return id } } } プラグイン全体 export default { install (vue) { vue.prototype.$intervals = [] vue.prototype.$setInterval = (func, intervalMilliSec) => { if ( typeof (process.env.VUE_APP_DISABLE_SET_INTERVAL) !== 'undefined' ) { console.log(` [ DISABLE_SET_INTERVAL ] Check environment vars`) return null } const id = setInterval(() => { if ( document .visibilityState === 'visible' ) { func() } } , intervalMilliSec) vue.prototype.$intervals.push(id) return id } vue.prototype.$clearInterval = (id) => { clearInterval(id) vue.prototype.$intervals = vue.prototype.$intervals.filter(i => i !== id) } vue.prototype.$clearAllIntervals = () => { vue.prototype.$intervals.forEach(clearInterval) vue.prototype.$intervals = [] } } } まとめ 今回はsetIntervalを使う際に起こる問題を解決するVue.jsプラグインの実装例を紹介いたしました。 解決法を簡単にまとめると以下のようになります。 Page Visibility APIを使う setIntervalをグローバルで管理する 開発モードを実装する こういった細かい問題は、優先度が低く、ボディーブローのようにじわじわコストやリスクとなっていくので、参考になればうれしいです!
アバター
スマートキャンプの今川です。 先日、AWS認定資格の ソリューションアーキテクト - アソシエイト を受けて無事合格してきました。今回は受験対策・受験を経ての感想や覚えておきたいことをまとめました。 AWSの認定資格をこれから取ろうとしている方、興味がある方の参考になれば幸いです。 背景 受験当時の経験・保持資格 受験準備 勉強方法 基本的な進め方 重要項目 ネットワーク系 コンピューティング系 ストレージ系 DB セキュリティ 振り返ってもう少し見ておけばよかったと思うところ 問題集 模試 受験の流れ 結果 資格特典 受けてみて まとめ 背景 ずっと仕事でAWSを触っていて、以前からAWS認定資格には興味があって取りたいな、と思っていたもののきっかけがなくずるずるときていました。 そんな時、部署的に AWSのテクノロジーパートナーになろう という機運が高まり、AWS認定資格保有者が必要だとなり、 チャンスだ! とばかりに手を上げました。 AWS Partner Networkのテクノロジーパートナー - セレクトになるとのことだったのでアソシエイト以上の認定資格が必要でした。社内でソリューションアーキテクトをおすすめされたこともあり、ソリューションアーキテクト - アソシエイトを受験することにしました。 受験当時の経験・保持資格 Webエンジニア4年目 AWSを使い始めて5年目 修士2年から使っているので 情報処理技術者試験: 基本情報・応用情報 JSTQB認定テスト技術者資格Foundation Level ソフトウェア品質技術者資格(JCSQE)初級・中級 好きなAWSのサービス: Elastic Beanstalk 資格試験受けるのは慣れていました。 受験準備 AWS認定資格について調べて、以下のことがわかりました。 コンピュータを操作して受ける試験(いわゆるCBT)なのでテストセンターで受験する テストセンターによっては受験日が結構多く、情報処理技術者試験と違って 割といつでも受けられる CBTなので模試を受けて操作になれておくのが望ましいとのこと その後、ほかの受験体験記を読み漁り未経験でも(通勤時間をフル活用するなどして)1,2週間で受かっていることを見て、2-3週間後を目処に受験計画を立てました。最終的に受験日は上司からはそこまで急かされていなかったため 自分との相談 で決め、3週間後に定めました。 試験申し込みも含め、以下のものを用意しました。 本試験申し込み 模試申し込み 参考書購入: AWS認定資格試験テキスト AWS認定 ソリューションアーキテクト-アソシエイト 問題集サイトの登録: 「AWS WEB問題集で学習しよう」さん 参考書は以下の書籍を購入しました。 AWS認定資格試験テキスト AWS認定 ソリューションアーキテクト-アソシエイト 作者: NRIネットコム株式会社 , 佐々木 拓郎 , 林 晋一郎 , 金澤 圭 発売日: 2019/04/20 メディア: 単行本 選んだ基準としては、割と新しめであったことと、自分が初めてAWSに触ったときに勉強した以下の本と同じNRIネットコムさんが著者であったことが挙げられます。 Amazon Web Services パターン別構築・運用ガイド 改訂第2版 (Informatics&IDEA) 作者: NRIネットコム株式会社 , 佐々木 拓郎 , 林 晋一郎 , 小西 秀和 , 佐藤 瞬 発売日: 2018/03/23 メディア: 単行本 ※自分が読んだときはまだ第1版でした。ハンズオンで覚えられるいい本です。 問題集サイトは以下の「AWS WEB問題集で学習しよう」さんを利用しました。 aws.koiwaclub.com 部署的に必要だったので問題集サイト以外の費用は会社に出してもらいました。いい会社です。 ほかにも技術書が必要になったらすぐに購入してもらえるのでありがたいです。 boxil.jp 勉強方法 基本的な進め方 3週間を目処にしていましたが実際に勉強を始めたのは10日前ぐらいからでした。問題集をざっくり読み、模試を受けて解き直したり、問題集を解きまくって間違えたところを復習しました。 ちなみに無料で受けられるウェビナーやトレーニングなどもありますが、自分はBlack Beltを中心に見ていました。また試験のためにAWSのオペレーションを改めてやるということもありませんでした。実務経験が全ての状態で望んでいます。 実際の方法としては、参考書をベースにiPadにApple Pencilを使ってノートを作るように勉強していましたがだんだんめんどくさくなってきたので問題演習をガンガンしまくり、間違えたところを調べまくったりSlideshareにある資料や公式ドキュメントを読み漁るような流れに切り替えました。 重要項目 出る順とまでは言えませんが、自分が重点的に見た箇所は以下のような感じです ネットワーク系 VPCの構成要素 サブネットの構成要素 セキュリティグループとネットワークACLの違い VPC内に置くサービスとVPC外にあるサービス EC2にアクセスするための要件: つながらないときどこを見るか? オンプレと連携する場合につかえるVPN系のサービスについてチェック コンピューティング系 EC2 AMIとEBSスナップショットの違い S3backedとEBSbackedの違い インスタンスストアの扱い方 Auto Scalingの仕組み Lambda メモリ指定だがメモリに合わせて割り当てられるCPUが増える ストレージ系 S3 ストレージタイプ: STANDARD-IAとかONEZONEとか ライフサイクルポリシーやバージョニングなどの機能 Glacier コスト面で有利なぶん設けられている制限について 取り出し方法による違い EBS ストレージタイプごとのメリット/デメリット EFS EBSを使うべきところとEFSにすべきところのポイント DB Auroraに触れたことがなかったので全体的に確認 DynamoDBがなにできるかについてざっくりしる 20190424 AWS Black Belt Online Seminar Amazon Aurora MySQL from Amazon Web Services Japan www.slideshare.net AWS Black Belt Online Seminar 2017 Amazon DynamoDB from Amazon Web Services Japan www.slideshare.net セキュリティ IAM IAMユーザとIAMロールの違い IAMグループの使い方 振り返ってもう少し見ておけばよかったと思うところ セキュリティ周り KMSや顧客キーの扱い方など Kinesis 問題集 前述の問題集サイトについては、有料登録(ゴールドプラン)すると130セット弱x7問の問題演習ができます。 番号の若いものについては実際の問題形式と近くないですが、100番台ぐらいは結構実際の問題と近いのでおすすめです。こっちの問題集は本試験の難易度と近いですがそこまで込み入った問題は出ません。 模試 ざっくり試験範囲を総ざらいしてから模試を受けました。 結論からすると 絶対に受けたほうが良いです 。CBTに慣れるためというのもありますが、到達度確認としても重要です。 ただし、注意するべきは 模試は本試験より難易度が低め であることです。 模試で80%取れて喜んでましたが、「本試験はもっと難しい」という記事を読んで危機感を覚えました。これより難しいとしたら落ちるかもという恐怖感に駆り立てられましたw 問題はその後残らず、どの問題があっているかどうかもわかりません。そのため全問スクリーンショットをとって保存して見直すのが一般的です。 正解が不明なので、私は厳密に選択肢を1つ1つ検証して消去法をやっていくという手段をとって解き直しました。これにより、各サービスの違いや細かい仕様について押さえることができました。 「このサービスについてよくわかってないな」と思った部分はBlack Belt資料を読んだり、参考書に戻ったり、公式ドキュメントやリリースを読んだりして補完しました。 私は模試を受けるまでSQSにFIFOキューが登場していたことを知りませんでした。本試験でも出たので復習していてよかったです! 受ける中で知らないサービスや知らない機能は特徴や「どう使うのがいいか?」を確認するのをおすすめします。どういう制限があるか?も押さえておきましょう。 受験の流れ 当日はとにかく余裕をもって望みました。夕方受験にしていたので会社を出てテストセンターへ。 テストセンターではすべての荷物を預ける必要があります。スマホはもちろんPCなども電源オフです。ポケットの中身も確認されます。持ち込めるのはロッカーのキー(物理)と身分証、メモ用のホワイトボードです。 顔写真撮影やサインを求められるので応じておきます。 「監視されながら受ける」という話を聞いていましたが監視カメラがあり、パーティションで区切られたパソコン室という感じでした。個別の監視はなく「これで受けてくださいね」という感じ。 メモ用に消せないホワイトボードを渡されます。ネットワーク構成図を書いていました。 空調がうるさくて大変でしたが、防音イヤーマフがあったので着けて受けていました。 出題は65問、制限時間は135分なので1問2分使っても余裕があります。即答可能な問題も十分あるので大分余裕があるはずです。 わからない問題も10問ぐらいありましたが、後で見直す機能があるので利用すると便利です。全体は2回、不安なところは3回見直しました。 余談ですが仕事終わりだし、防音イヤーマフは快適すぎだしで何度かマイクロスリープしていました…。 結果 試験時間が終了し、受験してみてのアンケートに答えると あなたは合格しました 的な表示が出ました。 前回の記事を出した林と135分の試験を終えて受かったことだけを伝えられた私のSlackでのやりとりがこちらです。 翌日夕方にスコアレポートが届きました。最大で5日間かかるときいていましたが結構早かった。 TOEICみたいな得点形式で、100-1000点で表記されますが、900点超えたのでちゃんと勉強した成果が出たことを実感できました。 カテゴリ別のレポートも出ます。パーセンテージは正答率ではなく、点数配分です。全問正解だ!!!とぬか喜びしてしまった。 資格特典 余談ですが、合格すると以下の特典が得られます。 AWS認定試験の模試のクーポンコード AWS認定試験の本試験を半額で受けられるクーポンコード AWS認定の問題を作ることに協力できるワークショップへの参加権(英語が必須らしい…) AWS Certified限定アイテムのショップ(海外発送で送料がめちゃたかい) 受けてみて 問題的には試験前に「試験問題を公開しない」旨の誓約をしないといけないので細かい部分までかけませんが、以下のことを思いました。 問題文が結構わかりにくい部分があるので、英語にして読み直してみたり、ホワイトボードにメモしながら整理するのがよさそう 3層アーキテクチャとか断りなく問題文に出てくるので基本情報ぐらいの知識は根底としてないと大変そう セキュリティポリシーのあるお客さんを想定した質問で「インターネットを介さずにS3とやりとりしたい」とか、「マスターキーをクラウドにアップしてはいけない時」など、セキュリティ系はきっちり押さえておくと得点源にできそう セキュアなアプリケーション構築は問題の26%を占めているので大事 まとめ AWSのソリューションアーキテクト - アソシエイトの合格体験記を書いてみました。 AWSを大分触ってきましたが、EC2とRDSがメインでそれ以外はちょこちょこ、という感じだったので普段触らないところを勉強するきっかけになったと思います。 ソリューションアーキテクトという名前の通り、開発チームやユーザ、顧客に対してソリューションを提供するための構成を考えるスキルが問われるため勉強したことをそのまま実践できそうな感覚がありました。実現のための引き出しが増えたのは嬉しい効果です。 また、基本情報や応用情報の知識はあるのとないのとで勉強のスタート位置が変わる、という実感を得ました。余裕のあるひともない人もはぜひ挑戦してほしいです。まだ秋試験に間に合います。 この調子でほかのアソシエイト資格や、ソリューションアーキテクト - プロフェッショナルにも挑戦したいと思っています。大分難しいでしょうが…。Black Beltの資料にはバッジがいっぱい並んでいるプロフィールが載っているのであれを目指して頑張ろうと思いました。 ここまでお読みいただきありがとうございました。
アバター
UNIXという考え方 スマートキャンプでエンジニアマネージャーをしています林です。 私はエンジニアマネージャーをやっているのですが、エンジニアではありません。 マーケターとしてスマートキャンプに入社し、マーケティングの成果を最大化するためにディレクターの立場でプロダクト改善を行ううちに開発チームのマネージャーになったという経歴です。 tech.smartcamp.co.jp 非エンジニアがエンジニアのマネジメントをするにはエンジニアについて学ばなくてはいけないことが多々ありますが、私が色々と学んできた本の中で、 特に役に立った書籍 を紹介していこうと思います。 「UNIXという考え方」 この本をオススメする対象者と読むメリット この本を読んだ背景 本の内容・構成・読みやすさ 私視点で学びになったポイント3点 ①「スモール・イズ・ビューティフル」 ②大きな一まとまりをつくるよりも、分解した小さなシステムを連携させるほうが応用がきく ③できるだけ早く試作を作成する この本を読んで役立った事 まとめ 「UNIXという考え方」 この本をオススメする対象者と読むメリット 今回ご紹介する本は、私のようなマネージャーだけではなく、 エンジニアと一緒に仕事をする人 なら読んでみるととても参考になる本だと思います。 サブタイトルにある通り、UNIXの設計思想と哲学について解説した本なので特定のOSについて語ったものではあるのですが、そこには良いプログラムとはどういうものなのかという事など、プログラミングについての本質が書かれているように思います。 これらの内容はエンジニアの考え方を理解するのに一役買うと思いますし、想像力を膨らませて応用すれば、エンジニアでなくても自分自身の業務の改善に役に立つ要素が多く見つかると思います。 厚さは1cmないくらいで140ページ程の読みやすいボリュームの本なので、ぜひ読んでみてください。 この本を読んだ背景 この本は、弊社のエンジニアチームのメンバーに勧められて読みました。 私が大好きな経営者に、ミスミグループの社長をされていた三枝匡という方がいます。その方の書籍のなかで、事業組織はなるべく小さくあるべきという意味合いで「スモール・イズ・ビューティフル」という言葉が語られていますが、その話をしている時にこの本を紹介されました。 「エンジニアも同じ考えを重要視している」という文脈で、その詳細が書かれた本として教えてもらいました。 本の内容・構成・読みやすさ この本では、上で紹介した「スモール・イズ・ビューティフル」だけではなく、プログラミングの根幹になるような考え方が様々紹介されています。 本の構成は、まず冒頭で主要な項目の概要の説明があり、次の章から項目のそれぞれについて詳しく紹介していく形になっています。 内容としては、UNIXの考え方として「教義にも匹敵する」と表現される程重要視される9つの項目と、「UNIX文化の一翼を担っている」と表現され、人によっては重要度に差がでるものの重要と考えられている10項目があります。それらの項目1つ1つについて、章やセクションを分けながら詳細に説明がされていきます。 最後にはその他のOSの思想についての説明があります。 このセッションがあることによって、相対的にUNIXについて考える事ができる構成になっていて、非常にわかりやすいですし、興味深く感じました。 構成は非常にわかりやすいですし、文章も著者の経験に基づく事例を交えながらフランクに語られている印象で、肩肘張らず読む事ができると思います。 私視点で学びになったポイント3点 ①「スモール・イズ・ビューティフル」 冒頭で三枝さんが事業組織について同じことを言っているという話をしましたが、この本を読んで、「スモール・イズ・ビューティフル」は真理だなと再認識しました。 小さく分解して考え動かす事はマーケのタスクでも応用可能です。 例えばEFO(入力フォーム最適化)のためのABテストをするとき、フォームの配置の問題、フォームの入力補助の問題、誘導文言の問題、背景色の問題など切り分けてテストすると、どの項目がどれだけ影響を与えるかが明確にわかり改善PDCAを回しやすくなります。 何か施策を考える時に、最小単位に分解できているか?と考える事 は施策の精度をあげるのに貢献してくれます。 ②大きな一まとまりをつくるよりも、分解した小さなシステムを連携させるほうが応用がきく スモール・イズ・ビューティフルに関連する内容ではありますが、 小さな単位で作ると組み合わせでいろんな事ができる というのも真理だなと思います。この内容は、なんとなくそうだと思っていたものが言語化された感覚でした。 私でいうとこれはKPIをメンバー毎に振り分けていく時の考え方に近いと思います。大きくざっくり「みんなでこのKPIをおう」みたいな設定をしてしまうと、役割分担が不明確でメンバーが力をだしきれなかったり、終わった時に評価ができないという問題がおきます。 KPIも適切に分解し、そのKPIを追う人が結果をコントロールできる単位にすることが重要です。そのためKPI設計時に上記の考え方をもっていると、よりシャープに設計ができると思います。 ③できるだけ早く試作を作成する リーンスタートアップなどの書籍によって、今やアーリーリリースの重要性は多くの人が認識している状態だと思いますが、数十年前に既にそれが設計思想として定着していた事は驚くべき事だと感じました。 長く生き残っているものの根本思想はやはり優れている(先をいっている)と感じさせてくれ、そういうものから学ぶ事の重要性を再認識させてくれました。 できるだけ早く試作を作成する事自体は私は常に取り組んでいかないといけない事ですが、タイミングによっては徹底できてない事もあります。この件についてはしっかりと意識し、引き続きやっていきたいと思います。 この本を読んで役立った事 エンジニアを理解するという方向で役立った事としては、『 エンジニアの頭の中がどうなっているか 』を想像しやすくなった事があります。 日々の会話のなかで、「要素を小さく分解してるんだな」とか、「過去のプログラムを組み合わせて活用する事を考えているんだな」とかいう想像がついたり、よく言われる「闇」という状態が何となく想像できたりして、この本を読んだことでよりコミニュケーションがとりやすくなったと思います。 またリファクタリングの重要性や価値についてより理解できるようになるので、その工数を取りたいというエンジニアの要求についても合理的に理解できるなどしています。 根本思想を理解することができると、大枠何が正しくて何が間違っているかが判断できるようになり、そのレイヤーでは 共通認識を持つことができます 。それによるメリットはかなり大きいと感じています。 まとめ この本は、エンジニアの考え方について理解する上で非常に役に立つ本です。 また概念を応用することで、私でいえばマーケティングなど、エンジニアリング以外の業務に役立てる事もできると感じます。 エンジニアを理解する上でも、ご自身の仕事の上でも実用的な本だと思うので、ぜひ一読される事をおすすめします。
アバター
こんにちは。 スマートキャンプ デザイナーの髙松です。 私は今年の1月からスマートキャンプにデザイナーとして入社したのですが、プロダクト部門のエンジニアチームに所属しています。 弊社にはデザイン部署がないというのも理由の1つですが、私の業務の半分は開発が必要となることが主な理由です。 しかし、入社した当時、実務での 私の開発経験は0に等しい状態でした。 この記事では、開発経験0から出発したデザイナーが、エンジニアチームにいた半年で身についたことや、やりきれなかったことなどを書いていこうと思います。 似たような境遇にある方の参考になれば幸いです。 いろいろと0地点からの出発 自分の理想とギャップ 自分の理想 理想と現実のギャップ 初めて見るRuby on Rails デザイン / 開発環境が変化している なにがわからないのか、わからない状態 やったこと 半年で得た学び やってよかったこと エンジニアに学習内容の相談にのってもらう ペアプロをしてもらう 改善点 きっかけを得てから勉強する 業務時間外の学習時間を当てにしすぎない 周囲に助けられた半年間 いろいろと0地点からの出発 いきなりの告白ですが、私は「未経験枠」のデザイナーとしてスマートキャンプに入社しました。 前職では最後の3ヶ月ほどデザイン業務に携わっていたのですが自分がメインの仕事としたかったWebデザインに携われるチャンスが少なく、転職活動を始めたことがスマートキャンプと出会えたきっかけになっています。つまり、 開発どころかデザイン経験もかなり浅いところからの出発 でした。 入社前にいくつかのサービスを使って学んでみたあとの自分のスキルは以下のような状態でした。 デザイン経験 実務 資料デザイン 紙面デザイン / リーフレット / パンフレットなどの社の販促物のデザイン バナー制作 数本 LPデザイン 1本 他 簡単なサイトのデザインとコーディング作業 Daily UI などで個人演習したもの 使用可能なツール Photoshop / Illustrator / XD の基本的な操作 開発まわりの経験 コーディング Progate のHTML/CSS/Sassを1周する HTML/CSS の基礎的な学習本を1冊やってみる 自身がデザインした簡単なサイトのコーディング作業 NewsPicks のワイヤーを起こしてトレースしてみる Github 自分が書いたコードを管理するために使用 add→commit→push→pull することと、branchを切ることができるくらい チームでの開発経験なし!(Gitの意味とは・・!) エンジニアの方はお気づきと思いますが「開発」と言っておきながら、プログラミングは一切できない状態です。(現状もできるわけではありません...。) 昨今、Webデザイナーとエンジニアの境目に立つ人材が多いと言われていますが、そんなハイパー人材などではなく コーディングをかじり出した初心者デザイナー というかんじでした。 自分の理想とギャップ このような状態だったので、身に付けなければならないことは山のようにあります。入社後、数週間が経過したタイミングで自分の理想とギャップを整理してみました。 自分の理想 入社当時から、私の理想は 数値に貢献できるデザイナーになる ことです。 デザインの成果というものは全てを数値に置き換えられるわけではありませんが、それでも数値は1つの結果だと思っています。デザイナー本人だけでなく、関係部署を含めた全員がシンプルに喜ぶことのできるフィードバックです。 私にとってWebデザインが魅力的と思える最も大きな理由の1つは トラッキングができる ことにあります。 つまり、 デザインの数値的なフィードバックが得られる点です。 自社プロダクトを持つ会社にいれば、数値を足がかりに早いサイクルでデザイン改善する経験ができるはずと考えたことも、スマートキャンプに入社を決めた理由の1つになっています。ちなみに入社後に携わったデザイン改善施策は以下のようなものがありました。 例 レイアウト変更による会員登録フォームのCVR改善 ポップアップ実装やレイアウト変更によるリスティングLPの流入改善 メディア記事内に設置されているボタンのCTR改善 理想と現実のギャップ 理想を掲げたのは良いのですが、数値を足がかりにデザインを運用するためには足りないスキルが多くあったため、必要なプロセスをざっくりと書き出してみました。 プロセスだけを見ればシンプルですが、これらを実際に自分の手で行えるようになるには 学習時間と反復機会 が必要になります。 できるようになったことは後ほどまとめますが、苦しめられたポイントについて先に書き出してみます。 初めて見るRuby on Rails スマートキャンプ が運営している ボクシルSaaS はRuby on Railsで実装されています。初めてプロダクトを裏側から見た日にしたことは、自分がさわりたいHTMLとCSSに該当するファイルを探し当てることでした。 Railsではファイル名を利用して呼び出すファイルと読み込むファイルの関係が成り立つなどアプリケーション上のルールがあります。 慣れ親しんだエンジニアには便利なものが初見の者には理解できないブラックボックス になってしまい、自分がデザインしたものを自力で実装する日は本当にくるのか、不安になったことを覚えています。 現在は見るべきファイルを絞ってエンジニアに教えてもらうことで、自分の業務に必要な部分を徐々に勉強することができるようになりました。 デザイン / 開発環境が変化している 例えば、制作から分析までのプロセスを自分が慣れ親しんだツールのみで完結することができれば、追加で学習しなければいけないことは最小限に抑えられます。 一方で、制作ツールなども転職をきっかけに変更する必要があった場合、1つのプロセスを完了させるには ツールに慣れるところから始める 必要がありました。 私の場合の、過去と現在の作業環境の変化を比較するとこのようになります。 過去 現在 デザイン Adobe Figma+Adobe コーディング HTML / CSS Slim / Sass テスト実装 Google Optimize Split※ 分析 ローデータからExcelで成形 クエリを書いてredashから取り出す ※Split ... Ruby on Rails上で動かせるABテストツール 学習計画を立てるときは内容に目が行きがちですが、こういった 環境の変化なども加味して計画を立てるべきだった と今にして思います。 なにがわからないのか、わからない状態 「開発をする」という全く土地勘のない領域では、 今自分がなににつまづいているのかを把握することが難しい です。自分が辿るべき道を見つけて、プロセスを組み立てられるようになるために、初めは人の頭を借りる必要がありました。 このときに、下手にプロセスを組み立てていくよりも 「自分がなにをやろうとしているのか」 を明確にして早い段階で人にヒントをもらうことも大事だと学びました。 もちろん自分で立てた仮説も無駄にはならないので、 自分の頭で簡単にプランAを組み立て、本業のエンジニアにプランBを立ててもらう と、足りなかった考えや自分がもてるスキルで代替可能なプロセスなどを照らし合わせることができます。 やったこと こういった予定外の事態や気づきを得ながら、半年間エンジニアチームのデザイナーとして制作/実施したものを列挙してみます。 コーディングを含めたLPの制作 Railsアプリケーションで動くプロダクトに、動的に内容が変わるページを新設する 検証するデザインの制作〜実装 Rails上で動くABテストツール(Split)を使った、テストの設定 Figma や STUDIO など、新しいツールを使ったデザイン/ 開発 これらの制作は、ただ作ればですごいわけではなくクオリティを上げていく必要もあるので、まだまだ良い品質のものが作れるようになったとは言えません。 また、各場面で必要となるプログラムやクエリなどはエンジニアに書いてもらうなど、 自分にできないと明確にわかるものは切り出して、協力を仰いで制作しています。 半年で得た学び 未だに大きい仕事を1人で完遂することは難しいですが、前章の「できるようになったこと」は半年前の自分には確実にできなかったことです。 しかし、一方で 「これの体得は無理だ...。もう少し成長してからの目標にしよう...。」 となったものもあります。 このような判断も含めて半年間で 「やってよかったこと」と「改善点」 を4つほど挙げてみます。自分と似た境遇の人の一助になれば嬉しいなと思います。 やってよかったこと エンジニアに学習内容の相談にのってもらう なりたい理想像が決まった後、身につけるべきスキルをリストアップして何人かのエンジニアに見てもらいました。今では恥ずかしい限りですが「Railsを理解して書けるようになる」といった大きすぎる目標もそこには含まれていました。 見上げている山が大きすぎて頂上が見えず、高すぎる目標を書いていたと思います。 1人のエンジニアにはっきりと 「短期目標に掲げるのは無理だと思う。それはなぜか。」 を説明してもらい、 自分がやりたいことの難易度と工数を一緒に見積もってもらいました。 さらに、業務での活用頻度も合わせて優先順位の整理をしてもらい、自分がはじめに何をできるようになるべきか、整理することができました。 ペアプロをしてもらう サイトTOPのような繰り返しの要素が多いページを実装するとき、その処理を行うコードをエンジニアに書いてもらったことがあります。そのときに初めてペアプロをしてもらったのですが、 どのような仕組みで処理を行うか説明を聞きながら書いてもらうと、格段に理解が深まります。 説明をしてもらう過程で「よくわかってなかったけど、あそこのコードはこういう意味だったのか...!」など 副産物 を多く得ることもできます。個人でも、本やカリキュラムを通じて体系的な勉強をすることはできるかもしれませんが、実務で出てくるコードの理解には人の説明を受けることが、開発場面においても重要なんだな...(小並)と感じました。 デザイナーがそこまでコードを理解をしておく必要があるのか賛否はあると思いますが、開発をしないデザイナーにとってもコードを理解しておくことにはメリットがあると思います。 デザイナーは最後まで修正をしたい生き物です。 開発が完了したあとに「修正したいけどコードがもはや暗号」という状態を回避したい箇所は、ペアプロで一緒に作ってもらうことで事前に理解を深めておくと、いざという時にササッと直せたりします。 改善点 きっかけを得てから勉強する できないことが複数把握できている場合、同時平行で学習を進めようとしたり、新しい技術の使用場面がくる前に勉強をしておきたいという気が働いていたのですが、これは 結果的に効率が悪い方法になってしまいました。 個人的に、技術を身に着けるにはインプットする学習時間と反復練習が重要だと考えているのですが、 実務での反復練習ができないインプットは次のインプットに押しやられて抜け落ちてしまいます。 必要以上に先回りをしようとしたり、網羅的な理解を優先しようとせず、 学習の必要が生まれた場面で必要なことだけをインプットし、反復の機会を業務中に持つ ことが一番効率の良いやり方だったように思います。 業務時間外の学習時間を当てにしすぎない 学習計画を立てていた頃は、業務時間外や休日に勉強をしよう!と考えていたのですが、期限のないまま努力を続けることは自分には不向きでした。 「できないこと」という大きい山を切り崩すには 「長期的に少しずつ学習を継続する」か「短期間で一気に1つを学習しきる」などのペース配分 を意識すべきだったなと思います。 日々の業務中でも「できないこと / わからないこと」に対峙している中で、業務後や休日も同じことを繰り返しているとやる気と効率が低下してしまいます。 次の半年は、プライベートな時間を当てにするのではなく、業務時間を通じていかに効率良くインプットして反復する時間を持てるか、を考えるようにシフトしようと思います。 周囲に助けられた半年間 長々と書いてしまいましたが、半年間デザインと開発業務に関わっていく中で多くのことを経験させてもらいました。その中での発見や反省が、記事を読んでくれた方のお役に少しでも立っていれば幸いです。 開発未経験かつデザイナーである自分が、開発チームの1人として多くの業務に携われているのは、エンジニアをはじめとする周りの協力的な社員のおかげでもあります。社員同士の連携や、どんな質問も受け入れてくれると思える環境があってこそ、実務を通しての学習というのは成り立つものだとわかった半年でした。 この記事を読んでくださった方が少しでもスマートキャンプに興味を持ってくだされば嬉しいです! smartcamp.co.jp スマートキャンプ株式会社にはデザインブログもありますので、ぜひそちらもチェックしてください!↓↓↓↓↓ note.mu
アバター
スマートキャンプでマーケターをしている佐々木です。 最近は自販機でペットボトルを購入することにハマっています。 私は弊社の運営する資料請求サイト「ボクシル」のマッチング最適化を生業として生きているのですが、追うべきKPI・可視化したデータの共有にはスプレッドシートを好んで使っています。 SQLで取り出したデータであればRe:dashで共有するのがライトなのですが、 SQLでとってきたもの以外のデータを上手く組み合わせられない 様々なアレルギー反応を起こす人がいる(英語UIがダメな人、クエリ見ると卒倒しちゃう人etc...) 権限管理が大変 などダッシュボードとして利用していくにあたって、特に非エンジニアに浸透しづらいというのがあります。 そこでスプレッドシートをダッシュボードとして活用していく方法を紹介したいと思います。 概要 ツールごとの役割分担 使った技術 流れ 全体 1. Re:dashでクエリ作成 2. Re:dashのクエリ実行頻度設定 3. Re:dashでAPI取得&スプレッドシートで importdata 関数をかく 4. シートを開くor更新するたびにAPIを実行し、最新のデータを反映させるためのGASを作成 GASの実装方法 今回書いたGAS 補足 まとめ 概要 Re:dashのAPIとスプレッドシートのimportdata関数を利用することでシートに最新のデータを反映できます。 ツールごとの役割分担 ・データの抽出→Re:dash ・データの加工・ビジュアライズ→スプレッドシート 使った技術 データの抽出 SQL(Google Bigquery) クエリの定期実行 Re:dash API Re:dash APIの定期実行 Google App Script 流れ 全体 Re:dashでクエリ作成 Re:dashのクエリ実行頻度設定 Re:dashでAPI取得&スプレッドシートで importdata 関数をかく シートを開くor更新するたびにAPIを実行し、最新のデータを反映させるためのGASを作成 1. Re:dashでクエリ作成 2. Re:dashのクエリ実行頻度設定 3. Re:dashでAPI取得&スプレッドシートで importdata 関数をかく ↓こんな感じでRe:dashで出力したデータがスプレッドシートに表示されます。 4. シートを開くor更新するたびにAPIを実行し、最新のデータを反映させるためのGASを作成 GAS(Google App Script)とは、スプレッドシートやフォーム、カレンダーなどGoogleのサービスをカスタマイズするための言語でJavaScriptをベースとされています。G suiteを導入している企業であれば、業務改善にも役立ちます。 GASの実装方法 今回書いたGAS やりたいこと=常に最新のデータが見れるようにしたい 要件 シートを開くたびにRe:dashのAPIを実行 リロードしたらRe:dashのAPIを実行 var configs = [ { //ここでシートを指定 "sheetName": "シート1", //importdataを記述したセルを指定 "cell": "A2", //ここに先程importdataで使ったのと同じurlをいれる "url": "http://redash.xxx/api/queries/xxx/results.csv?api_key=~~~~~~~" }, /* 下のような形式で設定をカンマで区切って追加して保存すれば、反映されます(色んなところのカンマは忘れがちなので気をつけてください) , { "sheetName": "", "cell": "", "url": "" } */ ]; // ファイルが開かれた or ブラウザが更新されたときに実行される関数 function onOpen() { // 上で設定したconfigsのそれぞれ(forEach)のconfigを元にsetImportRedash関数を実行する configs.forEach(function(config){ setImportRedash(config.sheetName, config.cell, config.url); }); } // 「シート名、セル番号、redashのURL」 を受け取ってセル(redashから取ってくるデータ)を更新する関数 function setImportRedash(sheetName, cell, url) { var timestamp = Utilities.formatDate(new Date(), "JST", "yyyyMMddHHmmss") var formula = Utilities.formatString('=IMPORTDATA("%s&seed=%s")', url, timestamp) SpreadsheetApp .getActiveSpreadsheet() .getSheetByName(sheetName) .getRange(cell) .setValue(formula); } 補足 こんな感じで表示されているデータをもとにピボットテーブルを組んだり、 例えばこんな感じの担当営業リストとかを作って こんな感じで vlookup 関数を使ったりもできます。 まとめ いかがでしたか? スプレッドシートの importdata関数 はRe:dash以外でもAPIが用意されているサービスであれば応用がきくので、 「ツールが社内で定着しないよ!」と悩んでいる方は是非試していただければと思います。
アバター
エンジニアの笹原です。 笹 が好物のパンダからもじって パンくん と呼ばれています。 皆さんはGitのリモートリポジトリとして何を使ってますか?弊社ではGitHubを使っています! GitHubはそれ自体の使いやすさはもちろんですが、各種ツールとの連携のしやすさや自分でGitHub Appsを作ったりMarketplaceを使ったりすることでの拡張性の高さも魅力ですよね!! 先月、GitHubがPull Pandaを買収したことで、Pull Pandaが提供しているツールが無償利用できるようになりました!! pullpanda.com そこで、実際に導入したフローを紹介します! 概要 導入方法 GitHub・Slackとの連携 通知の設定 実際の通知 終わりに 概要 Pull Pandaが提供しているツールは大きく以下の3つに分けられます Pull Reminders PRの状態に応じて通知をしてくれる機能 チームに対してSlackのchannel宛に飛ぶ通知と、個人に対してSlackのDM宛に飛ぶ通知がある Pull Analytics PRがマージされるまでの期間などを可視化してくれる機能 Pull Assigner PRのレビュワーを自動的に割り振ってくれる機能 導入方法 実際にPull Reminderを導入してみましょう! マーケットプレイスからとPull Pandaのページからのどちらからでも入れられますが、今回はPull Pandaのページから入れてみたいと思います。 Pull Reminders: Pull request reminders for Slack & GitHub GitHub・Slackとの連携 Pull PandaのページにAdd To Slackボタンがあるのでそれを押して、まずはSlack連携をします。 Slack上で与える権限を確認してInstallボタンを押します。 次に個人アカウントのGitHub連携をします。 GitHub上で与える権限を確認してAuthorizeします。 Pull PandaのGitHub AppsをOrganizationもしくはアカウントのレポジトリに入れていきます。 連携するOrganization、アカウントを選択します。 どのレポジトリに入れるか選択します。 ここまでで、連携は一旦完了しました!!! 通知の設定 ここからは各種設定をしていきます。 チーム宛の通知と個人宛の通知をそれぞれ設定できます。 Team Remindersを押すと、チーム宛の通知をSlackのどのchannelに通知するか選択することになります。 以下のような項目を設定できます。 通知の日時 通知する条件 レビューの状態 リポジトリ PRの生存期間・変更されていない期間 タイトルやラベルでフィルタリング PRが開かれたり、マージされたりと言ったイベントのフック 個人宛には、My DM Settingを押して以下のような項目を設定できます。 イベントフックの通知 レビューをアサインされているPRについての通知 実際の通知 実際の通知をそれぞれ見てみましょう。 チーム宛の通知は以下のような情報が指定した時間に届きます。 - OpenになっているPRのリスト - どれくらい古いのか - 誰がアサインされているか 個人宛の通知は以下のように、指定したイベントが発生したタイミングでどういうイベントが発生したか通知してくれます。 終わりに Pull Remindersの導入方法を紹介しましたが、Pull Pandaが提供しているツールはどれも、Pull Requestベースで開発しているチームに有効なものだと感じました。 Pull Analyticsを用いて、Pull Requestの運用状況を可視化した上で、リリース頻度を上げたいとか、スキルを平準化したいと言ったチームの課題に応じて、Pull RemindersやPull Assinerの設定を変更したりすると良さそうですね!!
アバター
オフィスが変わり、自席から窓を眺めると東京タワーが見えるようになりました。 スマートキャンプの今川( @ug23_ )です。 2019年6月26日に五反田.rbにLT枠で参加してきました。 gotanda-rb.connpass.com 自分含め、4名の方が発表したのでそれぞれ紹介しようと思います。 @kutaike1504さん ぼくらのかんがえたさいきょうのfactory_bot @saiid_kkさん RSpecあなたならどう書く? @ug23_ 残す価値のあるテスト設計 @walkersumidaさん CircleCIで docker-compose最強? 飛び込みLT @nontak2 さん AWS Summit 2019行ってきた 最後に @kutaike1504 さん ぼくらのかんがえたさいきょうのfactory_bot speakerdeck.com RSpecに不可欠なfactory_botの改善を行った、という発表でした。 let地獄 そこからそれらを一発で作成できるようにする 一発でやらないと面倒だったのは認証周りだったのでそこをDIして解決 でも改善にはむちゃくちゃ時間がかかる… みんなどうしてるの…? という感じでした。 チームごとに方針を決めて守る、変えるときは一気に変える、など試行錯誤していくしかないのかなという印象でした。 @saiid_kk さん RSpecあなたならどう書く? speakerdeck.com 聴衆参加型のLTでした。RSpecでみんなどう書いてる?という二択に答えながら聞きました。参考までに、私の意見は以下の通りでした。 Request Specは: Controllerごと System Specは: どちらでもない Shared Examplesは: あまり使わない before/after(:all)は: 使ってもいいと思う NestedGroupは: まだ遭遇してない… テストデータの定義は: デフォルト値ぐらいはいれておきたい 時間は: 作る (後述) テストの説明は: 日本語 複雑な事前データは: beforeでもletでも場合によりけり itスコープ内は: 柔軟に 「時間作る?止める?」の議論については、毎回 Date.today などで生成したほうが思わぬバグに気付ける可能性もあるので毎回つくっておくのがよいのかなと思ってます。 私もまだそこまでRSpec書けてないのでRSpecらしいコード書けるように精進しようと思いました。 @ug23_ 残す価値のあるテスト設計 speakerdeck.com スマートキャンプのエンジニアとして初のパブリックなLTのようでした。ちなみに個人としても初めてでした。楽しかったー! テストとマインドマップ相性がいいと勝手に思っているので参考になったら嬉しいです。 @walkersumida さん CircleCIで docker-compose最強? speakerdeck.com あまり記事が上がっていないらしいですが、CircleCIで普通にdocker-composeが使えるようになった(なってた?)らしいです。 ローカル環境とテスト環境の差分でコケて苦しむ、というつらみから解消されるようでした。 そのままQiitaにも投稿されていました。 qiita.com 飛び込みLT @nontak2 さん AWS Summit 2019行ってきた 飛び込みでAWS Summitで聞いてきた話を話されていました。 LTの中ではRailsにおける負荷テストツールについて触れていました。たしかに、Rubyistが使う負荷テストツールってなんでしょうね。 私は以前の記事の通り、Scalaを扱っていたのでGatlingを使いがちです。 tech.smartcamp.co.jp tech.smartcamp.co.jp 最後に 久しぶりにコミュニティイベントに参加しましたが、いろんな人と話したり、新しい発見や刺激がたくさんあってよかったです。そして定期的にアウトプットするの大事だなと思います。 会場のZealsさん及びオーガナイザーの @terry_i_ さんありがとうございました! スマートキャンプではRSpec書きながら開発していきたいRailsエンジニアを募集しています。 ぜひ新しいオフィスに遊びにきてください! hrmos.co
アバター