スマートキャンプのPdM(プロダクトマネージャー)1年生の郷田です。 スマートキャンプにはエンジニアとして入社し、現在はSaaS事業のPdMをしています。 そこで今回は、エンジニアからPdMにジョブチェンジして気づいたことを2つ紹介したいと思います。 エンジニア以外の職種の悩みポイント エンジニアリングの面倒くささ 最後に エンジニア以外の職種の悩みポイント 気づいたことの1点目としては、エンジニア以外の職種の「悩みポイント」についてです。 日頃エンジニアとして働いている方であっても、デザイナー・マーケター・セールス・事業責任者・経営者など他の役割のメンバーに対して「誰が何のために何をしているか?」を理解する努めはされているかと思います。 しかし、エンジニアとして業務を遂行する上でプライドを持って守るべきものは長期的なシステムの成功になります。 そのため、エンジニア以外の職種の悩みポイントは当事者にならなければ理解しがたい問題であり、上記について本気で考える機会は少ないかと思います。 一方、PdMの業務スコープはプロダクトに関わる全領域です。 エンジニアリング以外のデザイン・マーケティング・セールス・事業責任・経営といった全領域を鑑みた上で、最善の一手を考え実施することが仕事になります。 そんな中でエンジニアリング以外の経験をしてきていないPdMが、各領域の専任者と話し施策を実施してもらうためには、彼らの 悩みポイントも認識しておく必要 があります。 エンジニアが認識しづらい悩みポイントの一例を挙げますと、 現場のフィールドセールス(営業)は、 商談数や売上の目標が達成できているか? 月の目標を達成できるペースなのか? できないのであればどのようなアクションを取るべきなのか? といった議題を毎週定例で行い、行動を積み重ねていく必要があります。 そのため、時には「サービスのメリット享受が薄いかもしれない顧客だが、この商談は受注していいか?」といったような悩みポイント(葛藤)が生まれることもあります。 これはちょうどエンジニアでいう「動くけどクソコードを今のリリースのためにマージしていいか?」といった悩みポイントに近いかなと思います。 こういった他職種の悩みポイントを知った上で施策の提案ができるか否かでスピード感が圧倒的に変わります。 エンジニアリングの面倒くささ 気づいたことの2点目としては、エンジニア業務の「面倒くささ」についてです。 エンジニアは複雑度の高いコードをアウトプットすることが仕事の一つです。 そのコードは一つのミスで不具合がおき、時には障害の原因となることもあります。 そのため、コードの抽象化や具体化・責任範囲の明確化や粒度の統一・自動テストやプロセスの改善などを取り入れて、短期長期含めて不具合が発生しないための取り組みを行うことが求められています。 一方、PdMは「何をつくるか」「なぜ作るか」といった情報を仮説や検証結果を元に施策としてアウトプットすることが仕事の一つです。 この施策は、事業に関わる全ての協力を元に実行することができます。 コードの実行とは違い、施策の実行にはコンパイラはないためエラーとなって実行できないことは無いです。 また、非常にクリティカルな問題以外は実行後に修正することができます。 したがってPdMにジョブチェンジすると、エンジニア業務の面倒くささに気づくことができます。 また、システム開発に尽力しているエンジニアに感謝する気持ちに気づくこともできます。 ※「面倒くささ」と表現しましたが、エンジニアの三大美徳の一つの「怠惰」の視点からエンジニアとしても正しい表現だと考えています。 最後に 以上が「エンジニアがPdMになって気づいたこと」になります。 PdMを経験することにより気づけることは他にもたくさんあります。 PdMの業務を通してエンジニアリングにも活かせる気づきを得ることができるため、エンジニアの方でPdMを経験できるタイミングがあればぜひチャレンジしてみてください!
スマートキャンプの入山です。 Kubernetes(k8s)を運用されている方々は、Podに受け渡す機密情報をどうやって管理していますか? k8sでの機密情報の管理といえばSecretリソースが一般的ですが、Secretリソースを管理する上では以下のような課題に悩む方が多いのではないでしょうか? SecretはBase64エンコードのみなので、内容が確認できれば簡単にデコードできてしまう SecretリソースのマニフェストにBase64エンコードのみの機密情報を含むため、GitHubなどにそのままコミットするのは危険 これらの対策として、 kubesec や Sealed Secrets などを利用して暗号化を行う方法が主流だと思いますが、今回は外部のKMSなどに保存した機密情報をk8sに直接受け渡すことが可能な Kubernetes External Secrets について、EKSとAWS Secrets Managerを例に紹介したいと思います! Kubernetes External Secretsとは 概要 メリット 導入 インストール アクセス権限設定 実際に試してみる 最後に Kubernetes External Secretsとは 概要 Kubernetes External Secretsは、ドメインレジストラ・レンタルサーバサービスを提供しているGoDaddy社が公開しているOSSです。 外部のKMSなどに保存した機密情報をSecretリソースとしてk8sクラスタに直接受け渡すことができるもので、現時点で以下との連携をサポートしています。 AWS Secrets Manager AWS System Manager Hashicorp Vault Azure Key Vault GCP Secret Manager 動作としては、 対象とする機密情報を指定したExternalSecretsリソースを作成しておくことで、コントローラがKMSに保存されている値をSecretリソースに反映してくれる というシンプルなものです。 メリット 冒頭に紹介したSecretを暗号化して管理する方法と比較して、以下のようなメリットがあると思います。 k8sで利用するSecretリソースのマニフェストに機密情報を保持しなくてよくなる 機密情報に関する管理(機密情報、アクセス権限など)を一元化できる 機密情報変更に伴う反映コストが減る 導入 公式のGitHubリポジトリに記載されている手順に従って、実際に導入していきます。 今回は、EKSとAWS Secrets Managerの環境で試してみます。 インストール インストールは、helmで全て行う方法とhelmとkubectlを使用して行う方法があります。 今回は、helmとkubectlを使用して行う方法で実施します。 1. helmをインストール マニフェストの生成にhelmが必要となるため、helmコマンドをインストールします。 2. リポジトリをclone Kubernetes External Secretsのリポジトリをローカルにcloneします。 $ git clone https://github.com/godaddy/kubernetes-external-secrets 3. マニフェストを生成 cloneしたディレクトリで以下コマンドを実行して、マニフェストを生成します。 ※公式の手順のコマンドにオプションを追加して、nameとregionを変更しています。 オプションの詳細は、 リポジトリ に記載されています。 $ helm template -f charts/kubernetes-external-secrets/values.yaml --output-dir ./output_dir ./charts/kubernetes-external-secrets/ --name test --set env.AWS_REGION='ap-northeast-1' コマンドを実行すると指定した output_dir 以下にマニフェストが生成されます。 4. 生成されたマニフェストをapply output_dir に生成されたマニフェストをapplyすればインストールは完了です。 kubectl apply -f ./output_dir/kubernetes-external-secrets/templates/ アクセス権限設定 Kubernetes External Secretsを使ってAWS Secrets Managerにアクセスするために権限設定が必要となります。 公式のサンプルを参考に以下のようなIAMポリシーを作成後、ロールにアタッチします。 { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "secretsmanager:GetResourcePolicy", "secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret", "secretsmanager:ListSecretVersionIds" ], "Resource": [ "arn:aws:secretsmanager:ap-northeast-1:111122223333:secret:aes256-7g8H9i" # AWS Secrets Managerからk8sに受け渡したいSecretのARN ] } ] } 実際に運用で利用する場合はkube2iamなどを利用して権限の付与先を最小限にすることが推奨されています。 実際に試してみる 1. AWS Secrets ManagerにSecretを保存 以下のコマンドやAWSコンソールを使って、AWS Secrets ManagerにSecretを保存します。 $ aws secretsmanager create-secret --region ap-northeast-1 --name test/credentials --secret-string '{"username":"admin","password":"1234"}' 2. ExternalSecretリソースを作成 k8sでSecretリソースを作成する代わりに、AWS Secret Managerから取得したいSecretの情報を指定したExternalSecretリソースを作成します。 以下ようなマニフェストを作成して、applyすれば完了です。 apiVersion: kubernetes-client.io/v1 kind: ExternalSecret metadata: name: test-credentials spec: backendType: secretsManager # optional: specify role to assume when retrieving the data roleArn: arn:aws:iam::123456789012:role/test-role # 作成したIAMポリシーを付与したロールのARNを指定 data: - key: test/credentials # AWS Secret Managerに保存したSecretのname name: username # 変数名を設定 property: username # AWS Secret Managerに保存したSecretのどのキーを取得するか指定 - key: test/credentials name: password property: password 3. k8sのSecretリソースを確認 ExternalSecretリソースで指定したSecretが、k8sのSecretリソースとして受け渡されているか確認します。 $ kubectl get secret test-credentials -o=yaml apiVersion: v1 data: username: YWRtaW4= password: MTIzNA== kind: Secret ︙ Secretリソースを取得した情報を参照し、指定したSecretがBase64でエンコードされた状態で表示されていれば成功です。 これで通常のSecretリソースと同様にPod内で利用することが可能となっており、AWS Secrets Manager側でSecretの値が変更された場合も自動でk8sのSecretリソースに反映されます。 最後に 今回は、KubernetesのSecretをKMSと連携して管理する方法を紹介しました! 機密情報を含んだSecretリソースのマニフェストをリポジトリにコミットせずに管理できることは、かなりのメリットだと思います。 また、当初はAWSのサポートだけでしたが、現時点でAzureやGCPもサポートしており、状況に合わせてKMSを選択できることも嬉しい点ですね! 権限などに注意して作り込めば、k8sのSecretを良い感じに管理できるようになるのではないでしょうか?参考になれば幸いです!
こんにちは!スマートキャンプでエンジニアをしている中川です。 いきなりですが、つい先日待望の Vue.js 3.0.0 beta がリリースされました! We just released Vue 3.0.0-beta.1! Here's an overview from @youyuxi on the status of 3.0 core and official tools & libraries: https://t.co/7TP5ZMtjK4 — Vue.js (@vuejs) April 16, 2020 ステータスは beta なのでいま2系からアップグレードすることに抵抗はありつつも、待望の新バージョンなので内容が気になる・試してみたい方も多いのではないでしょうか。(かくいう私自身がそうです) そこで今回の記事ではVue.jsの今後のロードマップを紹介して、何がいつリリースされるのか・どう移行するのか等をまとめた上で、気になったVue 3系の変更点をいくつかピックアップしていきます。 記事の後半には実際にVue 3系をサンプルプロジェクトで導入してみているので、ご興味がある方はご覧ください。 今後のスケジュール(ロードマップ)を見てみる まずはロードマップですが、こちらにGithub Projectsとして公開されています。 Roadmap · GitHub 列を時系列としてクオーター単位で区切られており、執筆時点(2020/04/29)では2020 Q1の最中に位置しています。 進行具合としては 3.0 Beta by end of Q1 とされていた3.0 Betaがすでにリリースされているので、概ねスケジュール通りかやや早いくらいで進行していると言えそうです。 また、RCリリースは2020 Q2の中ごろということで、だいたい7月ごろにリリースされるようなスケジュール感で認識していれば良さそうです。 他にも、左端のFAQの列には実際ユーザーから多く寄せられたであろう質問とその回答が記載されています。 回答の中から特に気になったポイントを以下に羅列しました。 既存のVue 2系ユーザーに対してはマイグレーションガイドやマイグレーションツールをCLIで提供(該当コードを自動でアップグレード・手動でアップグレードが必要なものもスキャン)する。 2系に関してはこの後(Vue 3のRCリリースとどちらが前後するかは不明)、2.7がリリースされる予定 互換性のある3系の機能が2系にも実装される 2.7は2系最後のマイナーリリースとなり、以後18ヶ月間LTSになる VuexはVue 3に対応するためのバージョン4をリリースする。 バージョン4は以前のバージョンと全く同じAPIを持ち、Vue 3に移行したユーザーがVuexもスムーズに移行出来るようにするためのもの すでにバージョン5としてVue 3で搭載される reactivity API などを活用したVuex自体の新しいデザインも行っているが、初期段階でありリリースは2020 Q3以降になる見込み 最後のVuexに関してはすでにbeta版が先日リリースされており、この記事の後半でも導入してみています。 And here's Vuex 4.0.0-beta.1! 🎉 Now we have TypeScript support as well. Please note that you must provide your own augment typings for `this.$store`. Please let us know if you find any issues 🙌 https://t.co/yQQMX7pZnC — Kia King Ishii (@KiaKing85) April 25, 2020 変更点を見てみる 次に、実際にVue 3系になることでどういった変更があったのかを見ていきます。 以下のリンクからRFC経由で3系に取り込まれたものの一覧が見れます。 Pull requests · vuejs/rfcs · GitHub 特に breaking change タグのついたPRは今後Vue 3系にアップデートする上で対応が必要なものも含まれる可能性があるものなので、ここからいくつかピックアップしてみます。 Scoped Style Changes Scoped Style Changes by yyx990803 · Pull Request #119 · vuejs/rfcs · GitHub 従来のVueでは、SFCのstyleタグに scoped を指定しているとき、基本的には該当のコンポーネントにのみCSSが適用されていますが、新たに ::v-deep , ::v-slotted , ::v-global を追加するPRになっています。 ::v-deep に関してはこれまで /deep/ や >>> といったシンタックスで同様のことが出来ていましたが、削除されたCSS自体のシンタックスと混同してユーザーが混乱するといった事情から3系からdeprecatedとなるようです。 話が逸れますが、個人的にはRFCのなかで触れられてる以下の一文が気になりました。 We are also aware that many users want to be able to use component props or state in the CSS of single-file components. We do have plans to support that but it will be in a separate RFC. データによって変動する可能性のある高さや幅を持つコンポーネントのスタイリングを見通し良く簡潔に実装することはこれまで難しかったので、ここが解決されるとかなり嬉しいですね...! Remove data object declaration Remove data object declaration by CyberAP · Pull Request #111 · vuejs/rfcs · GitHub 読んで字の如しですが、ルートコンポーネントの data プロパティの値にオブジェクトを渡すことが出来なくなります。 これまでルートコンポーネントの data プロパティの値には関数もしくはオブジェクトを渡すことが出来ましたが、2通りの宣言が出来てしまうことや、オブジェクトを渡したときのみすべてのインスタンス間で状態を共有出来ることが混乱を招くのが削除される意図のようです。 数年前から存在するUIのためのサンプルプロジェクトなどはオブジェクトを渡しているパターンがあったりするので、今後参考にする場合は気をつける必要がありそうです。 Remove filters Remove filters by yyx990803 · Pull Request #97 · vuejs/rfcs · GitHub これまでコンポーネントの template タグでは {{ msg | format }} のような形で値をフォーマットすることが出来ましたが、この構文が {{ format(msg) }} のように変わります。 変更の意図としては、 | というシンタックスがJavaScript自体の演算子と衝突することにより式の解析を複雑にしていることが挙げられています。 その他 気になったPRの紹介は以上ですが、他にもワクワクするような変更が多くあるので、一度上記のPR一覧から変更点を眺めてみるとよさそうです! また、Vue 3ではComposition APIといった大きな変更も予定されています。 Composition APIは以前ハンズオン記事を書いたのでよろしければ併せてご覧ください。 tech.smartcamp.co.jp 実際に試してみる 最後に、実際にVue 3のbeta版を手元で試してみます。 導入方法としては、Vue CLIのプラグインとしてVue 3のベータ版を試すためのものが公式から提供されているためそちらを使用していきます。 github.com まずはVue CLIでサンプルプロジェクトを作成します。 $ vue create try-out-vue-3 いくつかの質問に答えていきます。今回は以下のように選択しました。 Linterなどは好みですが、TypeScriptとVuexは選択しておくようにしましょう。 プロジェクトが作成されたことを確認したら上述したプラグインを入れます。 $ cd try-out-vue-3 $ vue add vue-next これだけでセットアップは完了です!この手軽さは素晴らしいですね。 念の為、バージョンを確認するために package.json を見てみます。 "vue": "^3.0.0-beta.1", "vue-router": "^4.0.0-alpha.5", "vuex": "^4.0.0-alpha.1" よさそうですね。 試しに $ yarn serve してみるとコケてしまうので、表示されたエラーに従っていくつかのファイルを修正していきます。 src/main.ts import { createApp } from "vue" ; import App from "./App.vue" ; import router from "./router" ; import store from "./store" ; const app = createApp ( App ); app.use ( router ); app.use ( store ); app.mount ( "#app" ); src/store/index.ts import { createStore } from 'vuex' export default createStore ( { state: {} , mutations: {} , actions: {} , modules: {} } ); src/router/index.ts import { RouteRecordRaw , createRouter , createWebHistory } from "vue-router" ; import Home from "../views/Home.vue" ; const routes: Array < RouteRecordRaw > = [ { path: "/" , name: "Home" , component: Home } , { path: "/about" , name: "About" , // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import( /* webpackChunkName: "about" */ "../views/About.vue" ) } ] ; const router = createRouter ( { history : createWebHistory ( process.env.BASE_URL ), routes } ); export default router ; 上記の変更を行った後、再度 $ yarn serve したところ無事立ち上がりました。 コンソール上のエラーも表示されていないのでよさそうですね。 以上で導入は完了です! まとめ 駆け足で紹介してきましたが、いかがだったでしょうか。 正式リリースまでは少し日がありますが、今から次バージョンに目を向けておき、スムーズな移行をしていきたいですね! 今回の記事は以上になります、それでは! www.wantedly.com
スマートキャンプのデザイナー/エンジニアのhaguriです。 弊社では3月からリモートワークに移行しています。 スマートキャンプでは開発チームが、「 BOXIL チーム」と「 Biscuet チーム」の2つあります。 以前の記事では、リモートワーク中の開発チームの様子や、行っているコミュニケーションの工夫などを紹介しました。 tech.smartcamp.co.jp 今回は、2ヶ月弱リモートワークをすることで見えてきた「Biscuetチーム」内の課題と解決に向けて試した方法について紹介します。 発生した課題「認識のズレ」 改善1:共通で呼べる名前をつける 改善2:必須確認事項をいつでも見れるようにする 改善3:アイテムごとにUIを作成して、UIを軸に話し合う 改善4:KPTを付箋のようにやる 「認識のズレ」をビジュアルコミュニケーションで改善 発生した課題「認識のズレ」 通常では、あるトピックについて話し合うときは同じスペースでホワイトボードに書いたり、モニターに映して指差しで確認したりしていました。 しかし、リモートワークになってからはSlackや Kibela を通じたテキストコミュニケーションが中心になります。 温度感が伝わらないことや、受け手によって認識も変わってくることで「認識のズレ」が生じてきました。 その課題を解決するために、デザインチームで導入しているコラボレーションツール『Figma』を使用して、ビジュアルコミュニケーションによる意思疎通の精度の向上を図ってみました。 改善1:共通で呼べる名前をつける Biscuetの開発チーム内では、いままで画面内の各領域について明確に名前が決まっていませんでした。 「左側の...」「真ん中のヒストリーのところの上の...」といった認識が難しい会話をすることが多くなりました。 そこで、以下の例のように画面内の各領域の名前を明確に決めました。 実際の画面:要素が多くて、何について話しているか分かりづらい状態 各エリアに名前をつけた状態 サービスをつくるうえでは、基本的なことです。 ただ、リモートワークで物理的な距離が離れているからこそ、共通の名前をつくることは大切です。 改善2:必須確認事項をいつでも見れるようにする リモートになって出来なくなったこととして、「張り紙コミュニケーション」があります。 もともとBiscuet開発チームでは、「プランニング時に確認すること」「リリース前に確認すること」といった必ず確認する項目を、ホワイトボードに書いたり、壁に張ったりして目視で確認しあっていました。 コミュニケーションをとるメインの場がZoomになったことで、共通の壁やホワイトボードがなくなり、張り紙を使用したコミュニケーションができなくなりました。 そこで、Kibelaのテンプレート機能とFigmaの埋め込み機能を使用して、リモートでもチーム内で確認しあえるようにしました。 改善3:アイテムごとにUIを作成して、UIを軸に話し合う Biscuetでは開発手法にスクラムを採用しており、実装する機能を毎週話し合っています。 tech.smartcamp.co.jp 完全リモートに移行したことで、最近ではZoomを使用するようになり、ホワイトボードや直接画面をみんなで見ることが出来なくなりました。 プロダクトの実際の画面を見ずに Kibela上で口頭による要件の話し合いをしたり 、結果として決まったことだけをkibelaに 簡略化して書いてしまう ようなことが起きてしまっていました。 それによって、完成したものにずれが生じたり、不具合が発生したりしてしまうことが増えてしまいました。 考えた解決策として、アイテムごとに毎回UIをFigmaで作成して、UIを軸に話し合うようにしました。 全員で同じUIを見て、仕様を考え、決まったことはFigmaの補足としてKibela上にテキストとして記述するようにしました。 可視化することで、誰がみても同じイメージを共有することができるようになりました。 改善4:KPTを付箋のようにやる スプリントの振り返りとしてKPTを実施しています。KPTもFigmaを使用しています。 オンライン上で付箋のようなコミュニケーションができるサービスはいくつか存在しています。 今回は、エンジニアもみんなFigmaを使用したビジュアルコミュニケーションができるように、練習のためにFigmaで実施しました。 この内容に関しては、スマートキャンプのデザインブログで紹介しているので、ご覧ください。 note.com 「認識のズレ」をビジュアルコミュニケーションで改善 物理的な距離が離れている状況では、 認識のズレが起こりやすい です。 そのために画像やイラスト、図形を使用して、見る人によって認識の差がうまれづらい方法による情報の伝え方を意識していくと良いです。 今後のリモートワークが続きそうですが、より効果的で効率的なアウトプットがチームとしてできるように考え、課題や上手くいったことはこのブログでも紹介していこうと思います。 スマートキャンプではデザインブログもnoteで運営しています。 各プロダクトに関する想いだったり、デザインの小話も書いているので、見ていただけるとうれしいです。 note.com ライター:葉栗 雄貴 / Haguri Yuki(Designer & Engineer)
こんにちは!フリーランスエンジニアとしてスマートキャンプに参画している芳岡です。 弊社のプロダクトであるBiscuet( https://biscuet.jp/ )の開発に初期から参画していますが、サービスが世の中に展開されていく過程、チームが大きくなっていく過程を間近で見れとても興味深く思っています。 今回は、そのBiscuetで使用しているVue.jsのパフォーマンス改善を行ったのですが、そこで気づいたいくつかのポイントを整理してお届けします。 Vue.jsのパフォーマンス 関数型コンポーネント propsは、オブジェクト全体か各プロパティごとか? プロパティごとに渡す方法 オブジェクトを渡す方法 注釈 最後に Vue.jsのパフォーマンス Vue.jsでは、状態変更によって、仮想DOMが繰り返し再計算( updateRender )されるため、それによりパフォーマンスが悪くなることがあります。 再計算に百msもかかってしまうと、もっさりした動作となりユーザにも印象がよくありません。 そこで、再計算の回数、つまりVue.jsのライフサイクルでいうところの update の回数を減らして改善を試みます。 ポイントは以下の2点となるのでそれぞれ説明していきます。 関数型コンポーネント props は、オブジェクト全体か各プロパティごとか? 関数型コンポーネント 関数型コンポーネントについての公式な解説は、こちらをご覧ください。 jp.vuejs.org 通常のコンポーネントと関数型コンポーネントを比較するため、千個のボタンコンポーネントを並べました。 このボタンを関数型コンポーネントにした時の表示時の処理速度を比較したいと思います。 ボタン1000個 結果はこちら 通常のコンポーネント 関数型コンポーネント クリックしたら描画されるようにしたので、クリックイベントの時間を見ています。 通常のコンポーネントが 153ms かかっているのが、関数型コンポーネントで 71ms になりました。 約半分 ですね。 ボタン一個あたりだと、 82μs の短縮です! まあ、μsを体感できる方はいないと思いますが...。 ひとつひとつでは小さな差ですが、ボタンだけでなくアイコンや、コンテナの機能を持つコンポーネントなど、出来るだけたくさんのコンポーネントを関数型コンポーネントとすれば、塵も積もれば山となりパフォーマンスアップに繋がっていきます。 最後に、それぞれのボタンコンポーネントのコードです。 ノーマルなコンポーネント < template > < button class = "btn" @click= "click" : style = "styles" > {{ label }} </ button > </ template > < script > export default { props: { label: String , color: String } , computed: { styles () { return { "background-color" : this .color } ; } } , methods: { click () { this .$emit ( "click" ) ; } } } ; </ script > < style scoped> .btn { width : 50px ; } </ style > 関数型コンポーネント < template functional> < button class = "btn" : style = "$options.styles(props)" v-on= "listeners" > {{ props.label }} </ button > </ template > < script > export default { props: { label: String , color: String } , styles ( props ) { return { "background-color" : props.color } ; } } ; </ script > < style scoped> .btn { width : 50px ; } </ style > 差分は以下です。 template タグに、 functional 属性を付ける。 props で渡された値は、 props.プロパティ名 で呼び出す。 computed 、 methods はなくなり、直接関数を定義する必要がある。また、定義した関数は $options.関数名 で呼び出す。 下位コンポーネントから上位のコンポーネントへイベントを上げるため、 v-on="listeners" を設定する。 ここでは、例として挙げたため、 props の数が2つですが、 props の数が多いほうが、処理時間の差は大きくなります。 propsは、オブジェクト全体か各プロパティごとか? 親から子コンポーネントに、 props を通して、値を渡すときどのようにしてますか? オブジェクトで渡してますか、それともオブジェクトのプロパティを個別に渡していますか? やり方によっては update の回数に大きく差がでる場合があります。 以下のコードではパフォーマンスの差を確認するために300個のボタンを並べてます。 プロパティごとに渡す方法 親コンポーネントのコード < template > < div > < div > < p > < button @click= "changeProperty" > プロパティ変更 </ button > | < button @click= "changeObjectRef" > 参照変更 </ button > </ p > < p > オブジェクト:{{ obj }} </ p > </ div > < normal-btn : label = "aObject.label" v- for = "i in list" :key= "`a-${i}`" /> < normal-btn : label = "bObject.label" v- for = "i in list" :key= "`b-${i}`" /> < normal-btn : label = "cObject.label" v- for = "i in list" :key= "`c-${i}`" /> </ div > </ template > < script > import NormalBtn from "@/components/NormalBtn" ; export default { components: { NormalBtn } , data () { return { list: [ ... Array (100) .keys () ] , obj: { a: { deep1: { deep2: 1 } } , b: 2 , c: 3 } } ; } , computed: { aObject () { return { label: this .obj.a.deep1.deep2.toString () } ; } , bObject () { return { label: this .obj.b.toString () } ; } , cObject () { return { label: this .obj.c.toString () } ; } } , methods: { changeProperty () { this .obj.a.deep1.deep2 = this .obj.a.deep1.deep2 + 1 ; } , changeObjectRef () { this .obj = Object .assign ( {} , this .obj ) ; } } } ; </ script > 子コンポーネント(NormalBtn)のコード < template > < button class = "btn" @click= "click" : style = "styles" > {{ label }} </ button > </ template > < script > export default { props: { label: String , color: String } , computed: { styles () { return { "background-color" : this .color } ; } } , methods: { click () { this .$emit ( "click" ) ; } } } ; </ script > < style scoped> .btn { width : 50px ; } </ style > 親側で、ひとつの大元のオブジェクト(変数名: object )から、 computed でaObject, bObject, cObjectという派生したオブジェクトを作成してます。 この派生したオブジェクトのプロパティ( String )を子コンポーネントに渡しています。 さて、ここで大元のオブジェクト(変数名: object )を変更したらどのようになるでしょうか。子コンポーネントは update されますか? 答えは、 props に渡された値が変更された時だけ、その子コンポーネントが update されます。逆に、 props に変更がない子コンポーネントは update されません。 変数 object の参照をまるっと入れ替えても、同じプロパティ値であれば update されません。(なお、プロパティ値が同じでも、参照が入れ替わった場合は、親コンポーネントの computed は再計算されるので注意してください) オブジェクトを渡す方法 次に親コンポーネントから子コンポーネントにオブジェクトを渡す場合です。 親コンポーネントのコード < template > < div > < div > < p > < button @click= "changeProperty" > プロパティ変更 </ button > | < button @click= "changeObjectRef" > 参照変更 </ button > </ p > < p > オブジェクト:{{ obj }} </ p > </ div > < object -prop-btn : object = "aObject" v- for = "i in list" :key= "`a-${i}`" /> < object -prop-btn : object = "bObject" v- for = "i in list" :key= "`b-${i}`" /> < object -prop-btn : object = "cObject" v- for = "i in list" :key= "`c-${i}`" /> </ div > </ template > < script > import ObjectPropBtn from "@/components/ObjectPropBtn" ; export default { components: { ObjectPropBtn } , data () { return { list: [ ... Array (100) .keys () ] , obj: { a: { deep1: { deep2: 1 } } , b: 2 , c: 3 } } ; } , computed: { aObject () { return { label: this .obj.a.deep1.deep2.toString () } ; } , bObject () { return { label: this .obj.b.toString () } ; } , cObject () { return { label: this .obj.c.toString () } ; } } , methods: { changeProperty () { this .obj.a.deep1.deep2 = this .obj.a.deep1.deep2 + 1 ; } , changeObjectRef () { this .obj = Object .assign ( {} , this .obj ) ; } } } ; </ script > 子コンポーネント( ObjectPropBtn.vue )のコード < template > < button class = "btn" @click= "click" : style = "styles" > {{ object.label }} </ button > </ template > < script > export default { props: { object : Object , color: String } , computed: { styles () { return { "background-color" : this .color } ; } } , methods: { click () { this .$emit ( "click" ) ; } } } ; </ script > < style scoped> .btn { width : 50px ; } </ style > 先に示した「プロパティごとに渡す方法」のコードとほぼ同じです。 違いは、子コンポーネントに渡す値をオブジェクトのプロパティでなく、オブジェクト全体を渡しているところ、子コンポーネントでは、受け取ったオプジェクトのプロパティを使用しているところです。 再度、同じ質問です。ここで大元のオブジェクト(変数名: object )を変更したら、どのようになるでしょうか。子コンポーネントは update されますか? 答えは、子コンポーネントで使用するオブジェクトのプロパティが変更されると、その子コンポーネントが update されます。 使用するプロパティの値が同じなら、子コンポーネントは update されません。 「プロパティごとに渡す方法」との違いは、変数 object の参照が変わった場合です。 内部のプロパティが全て同じであっても関連する子コンポーネントが全て update されます! この例でいえば、 300個のボタン全て(値が変更されていないものも含め) に update が走ります。 注釈 上で述べたように「オブジェクトを渡す方法」だと不要な update が行われる可能性があります。 ですが、言いたいことは「オブジェクトを渡すな」ということではなく、 実際の案件は複雑で、このような事例が紛れ込み易く見つけづらいということです。 Biscuetでも、オブジェクトを子コンポーネント、さらには孫コンポーネントに渡して操作したり、間に store を通してデータを変更したりしています。 具体的な修正の方法は様々だと思います( object の参照を変えないようなロジックにする、関数型コンポーネント等)。 ケースバイケースで、必要な対策を取れば大丈夫だと思いますが、その前に update 回数が多いところを見つけましょう。 調査はVue.jsのdevtoolsを使います。 ポイントとしては、以下の画像のように値を数箇所変えただけなのに updated が数十回〜走っているところは怪しいです。 最後に プロジェクトの初期から上記のような事項を気にしながら設計することは難しい場合もあると思います。 事後的にこういったパフォーマンスの懸念が出てきた場合でも、まずはコンポーネントの分解から取り掛かりましょう。 AtomicDesignを導入し、機能を複数持った大きなコンポーネントを小さく分解していくことが近道かと思います。 これだけで全て解決とは言えませんが、見通しが良くなることでなにか調子が悪いと感じたときも調査しやすくなるはずです。 以上、長文にお付き合いいただきありがとうございました!
こんにちは、BOXIL開発チームの徳田です。 ついに(?)緊急事態宣言が発令され、社会全体がバタバタしていますが皆さん元気にやっていますでしょうか。 スマートキャンプでは3月2日から新型コロナウイルスの感染防止対策として在宅勤務が行えるようになり、現在では原則出社禁止となっています。 これまでほとんどの業務時間を対面で過ごしていましたが、全員が在宅で仕事をするようになったので、今回はその様子をお伝えしようと思います! これまでの開発体制 BOXIL開発チームの様子 基地Zoom部屋 ペアプロ・モブプロ 週次振り返り (Retrospective) 週次成果発表 (Sprint Review) テキストコミュニケーション Biscuet開発チームの様子 サブZoom部屋 週次振り返り (Retrospective) おまけ: 全社的な動き これまでの開発体制 スマートキャンプは開発チームが2つあり、それぞれ BOXIL と Biscuet を開発しています。 どちらのチームもスクラムを導入しており、毎週金曜日にSprint Review, Retrospective, Sprint Planningを実施する開発プロセスを取っています。 開発時は個人作業とペアプロ・モブプロを臨機応変に使い分けており、必要があればモブプロ用の集会所に集まってわいわい開発をしていました。 在宅勤務になる前のモブプロの様子 BOXIL開発チームの様子 基地Zoom部屋 在宅勤務になり最初にやったことは、チームメンバが好きなタイミングで参加できるミーティングルーム 「基地Zoom部屋」 を作ることでした。 集中したいときは抜けて一人でコードを書いたり、複雑なロジック部分の設計をするときは基地に集まってディスカッションをする、といった形で活用しています。 Slack ChannelのTopic欄にURLを置いて、すぐ参加できるようにしています ペアプロ・モブプロ BOXILではモブプロとペアプロを使い分けており 、一人でタスクをこなすときもあれば、複数人で一緒に考えたり、コードを書いたりすることもあります。 複数人でコードを触るときは基地Zoomで集まって話しつつ、VSCode Liveshareを繋いで一つのプログラムを作っています。 (あまりドライバ・ナビゲータの運用をやらなくなってきたのでモブプロではなくなってきましたが...) github.com 週次振り返り (Retrospective) K -> P -> Tの順番で話す これまではホワイトボードと付箋を使って進行していたのですが、デザイナに協力してもらってFigmaをホワイトボード代わりに使ってみることに。 これが大成功で、在宅でも問題なくミーティングを行うことができています🎉 👍 Tryを考える前に、それぞれ話したい話題の付箋に「正」の文字を書いて、話すTopicを決めていましたが、より vote らしい 👍マークを用意してくれて代用できています。ありがとう! 週次成果発表 (Sprint Review) 概要はKibelaで事前に記述。これを画面共有しながら進めていきます Sprint ReviewもZoomを使ってやっています。 事前にKibelaで実施する内容を用意しておき、それをもとに進行して、リリースした機能については都度デモをしていく流れで、 都度チャットで来た質問に回答したり、デモ中でない開発メンバから補足説明をしたりと、臨機応変に動いています。 物理的にPCを共有する、というのはできなくなったのですが、画面共有を活用することで今のところは問題なく進められています。 リモートで気楽に参加できるからか参加人数が多い(うれしい) テキストコミュニケーション 今何の作業をやっているのか、進捗がどうか、相談したいことがないか、といったことが前よりわかりにくくなったから、Slackで「今何をしているか」がよく呟かれるようになりました。 めでたい感じのとき おかげで調子が悪いときのアラートや状況がつかめやすくなり、一緒に作業するかーという流れで基地Zoomに集まったりといった動きができるようになりました。 それ以外にもKibelaにドキュメントを書く文化が根付いてきて、在宅かどうかに関わらず今後に上手く残していけると良いなと思っています。 Biscuet開発チームの様子 サブZoom部屋 Biscuet開発チームでも上述したような基地Zoom部屋の取り組みを行っており、リモートでコミュニケーションが少なくなりがちな面を補えていると思っています。 一方で、「あるメンバーが実装するタスクに不明点があるのでガッツリ相談したい」であったり、「このタスクは誰かとモブで進めたい」のようなときに、そのまま長時間占有してしまう問題がありました。 タスクを話し合っているメンバーがいるなかで割り込むのはなかなか心理的な障壁が高いため、別のZoom部屋を用意しておき、そういった状況が発生した際はそちらの部屋に移動するような運用にしています。 Slackの開発チャンネルのTopicに設定して手軽に移動出来るようにしています 週次振り返り (Retrospective) BOXILチームでは上述したようにFigmaで振り返りを行っていましたが、Biscuet開発チームではAsanaを使ってKPTを行っています。 Asana上のKPTプロジェクト 具体的には画像のようにAsana上にプロジェクトを作成しており、KPTごとにセクションを分割、さらにKPTのなかにメンバーごとのタスクを作成してサブタスクとしてメンバーが思うそれぞれのKPTを書いていっています。 最初の準備がやや面倒ですが、一度やってしまえばプロジェクトの複製機能が使用出来るため以降はスムーズに準備出来るようになります。 以上がスマートキャンプ開発チームの在宅勤務の様子でした! 今のところ(まだ一ヶ月ですが)大きな問題は出ておらず、何とかやれているという感じです。 リモートは慣れないうちや、整備が整っていないうちはどうしても体調も崩れやすくなります。社会全体の不安感などもあるので気持ちも沈みやすくなるかと思います。 皆さんも無理せず、元気に在宅勤務をやっていきましょう! この記事が参考になれば幸いです。 おまけ: 全社的な動き 入社式、キックオフ、朝会、飲み会、達成会などがリモートで実施されました。 ピザパや新入社員の歓迎会もリモートでやるみたいです🍕🍺 Zoomのブレイクアウトルーム機能を活用して色々楽しんでいます。面白い機能なので是非使ってみてください 👋
スマートキャンプでエンジニアをしている瀧川です! 2月に育休を取得し、3月に復帰したと思ったらコロナでリモートワーク、そしてチーム異動となかなか落ち着かない今日このごろ。 みなさんいかがお過ごしでしょうか? 今回家にいる時間が多くなり、せっかくだから新しいことしたいよなーということで、以前から気になっていた Svelte を触ることにしました! Svelteの紹介記事では、「Vue.jsと構文が似ているため習熟が簡単」「Vue.jsの50倍早い」みたいなところにフォーカスされることが多いかなと思いますが、本記事では SvelteのTutorialをやるなかで、フレームワーク(ライブラリ)の機能として普段Vue.jsを利用している私がおもしろいなーと思ったもの をご紹介したいと思います。 Svelteとは 基本文法 特徴的な機能 propsやclassの省略記法 Await Block Reactive Statement (watch相当) Event fowarding (emit相当) Lifecycle Event Store Writable, Readable Derived (Getters相当) Custom (Actions相当) Transition パラメータ Custom Transition 特殊なタグ svelte:head, svelte:body, svelte:window svelte:component Module Context Debugging まとめ Svelte とは Svelteとは、ReactやVue.jsのようなフレームワークと同様にSPAに代表されるインタラクティブなUI/UXを簡単に構築するために、コンポーネント指向やリアクティブシステムなどを備えたツールです。 大きな違いは、ReactやVue.jsがフレームワークとしてブラウザで動作する際に機能するのに対し、 Svelteはコンパイラであり、ビルド時に理想的な素のJavaScriptに変換します 。 そのためフレームワークのオーバーヘッドがほぼなくなり、何十倍という高速化に成功しているとのことです。 後発であるため、 機能自体にも特徴があり 本記事ではそちらにフォーカスして紹介していきます。 ※ Svelteの公式サイトはコンテンツが多く、インタラクティブなチュートリアルやサンプルが整備されていてとてもわかり易いので、時間のある方はぜひ見てみてください! svelte.dev 基本文法 Vue.jsを使われてる方であれば、以下のサンプルである程度Svelteの文法や基礎機能は把握できるのではないでしょうか。 App.svelte < script > import SampleComponent from './SampleComponent.svelte' ; let count = 1 ; // data相当 $: doubled = count * 2 ; // computed相当 $: quadrupled = doubled * 2 ; function handleClick () { // methods相当 count += 1 ; } </ script > < button on:click= {handleClick} > < SampleComponent count= {count} /> </ button > < p > {count} * 2 = {doubled} </ p > {#if doubled > 0} // v-if相当 < p > {doubled} * 2 = {quadrupled} </ p > {/if} SampleComponent.svelte < style > // デフォルトでscopedになっている p { color : purple ; font-family : 'Comic Sans MS' , cursive ; font-size : 2em ; } </ style > < script > export let count = 0 ; // props相当 </ script > < p > Count: {count} </ p > 基本的には scriptタグ、 styleタグ、その他(template相当)といった構成 になっています。 (styleタグはデフォルトでscopedになっているようです) Vue.jsでいうところの data がscriptタグ内の let での変数定義 になっており、 methods は単純な関数定義(function) となっています。 他のコンポーネントを呼び出す際はインポートするだけで利用でき、 export let で定義された props 相当に値を受け渡す ことができます。 (propsのtypeやvalidatorはまだないようでした) 少し見慣れない記法でいうと、 computed は $: computed名 = 式 のように記述 します。 また v-if や v-for 相当の制御構文も {# if } や {#each cats as { id, name }, i} のような記法になっています。 その他にも Lifecycle Event や Slot といったコンポーネントの基本機能はサポートされています。 特徴的な機能 ここからVue.jsには存在しない機能や、使い勝手が向上している機能など紹介していきます! propsやclassの省略記法 以下のように変数(data)名とprop名やclass名が同一だった場合、省略記法が用意されています。 地味に便利ですね! < SampleComponent count= {count} class :big= {big} /> < SampleComponent {count} class :big /> Await Block Vue.jsに限らず非同期処理によるローディングなどは、実装が煩雑になるイメージがあります。 SvelteではPromiseの状態によるUIの変更を直にテンプレート内に記述することができます。 これにより、シンプルにローディングやエラー時の表示変更などが実装できるようになっています。 < script > let promise = getWaitFunction () ; async function getWaitFunction () { const res = await fetch ( `hoge` ) ; const text = await res.text () ; if ( res.ok ) { return text; } else { throw new Error ( text ) ; } } function handleClick () { promise = getRandomNumber () ; } </ script > < button on:click= {handleClick} > Wait Button </ button > {#await promise} < p > ...waiting </ p > {:then result} < p > Result is {result} </ p > {:catch error} < p style = "color: red" > {error.message} </ p > {/await} Reactive Statement (watch相当) これはおそらくVue.jsの watch に近い機能だと思います。 computed と似た記法で $: ブロック とすることで、 そのブロック内で使われている変数(data)が変更された際に、そのブロックが再評価される ようです。 使い勝手良さそうな反面、個人的には watch と比べて宣言的でないため若干怖いなとも思っています。 < script > let count = 0 ; // countの変更で発火 $: if ( count >= 10) { alert ( `count is dangerously high!` ) ; count = 9 ; } // countの変更で発火 $: { console.log ( count ) } function handleClick () { count += 1 ; } </ script > < button on:click= {handleClick} > Clicked {count} {count === 1 ? 'time' : 'times'} </ button > Event fowarding (emit相当) Svelteでは子コンポーネントから親コンポーネントへのイベント波及は、 createEventDispatcher を使います。 特徴的なのは、多段のコンポーネント呼び出しです。 Vue.jsでは末端コンポーネントで発生したイベントを最上位のコンポーネントで使いたい場合、間のコンポーネントでhandlingとemitを繰り返す必要があります。 Svelteでは以下のように 中継コンポーネントで on:イベント名 のように記述するだけで、親にイベントを受け流してくれるようになっています 。 またDOMイベントon:clickなども同様にできるようなので、Vue.jsのnativeのような役割もありそうです。 End.svelte < script > import { createEventDispatcher } from 'svelte' ; const dispatch = createEventDispatcher () ; function sayHello () { dispatch ( 'message' , { text: 'Hello!' } ) ; } </ script > Middle.svelte < script > import End from './End.svelte' ; </ script > <!-- 親コンポーネントにイベントを波及 --> < End on:message/> Lifecycle Event Lifecycle Eventは onMound 、 onDestroy 、 beforeUpdate 、 afterUpdate と特にVue.jsとも変わらないです。 しかし以下のような コンポーネント外でもLifecycle Eventを使える のは特徴的かなと思います。 これにより コンポーネント側の責務が減り、ライブラリ内で完結して終了処理まで実装することができます 。 util.js import { onDestroy } from 'svelte' ; export function onInterval(callback, milliseconds) { const interval = setInterval(callback, milliseconds); onDestroy(() => { clearInterval(interval); } ); } App.svelte < script > import { onInterval } from './utils.js' ; let seconds = 0 ; onInterval (() => seconds += 1 , 1000) ; // このコンポーネントが破棄されるとclearIntervalされる </ script > Store Vue.jsではコンポーネント間での状態管理はvuexがデファクトスタンダードだと思いますが、Svelteでは標準でStoreの実装が存在します。 Writable, Readable Store定義自体はとてもシンプルで、以下のようになります。 stores.js import { writable, readable } from 'svelte/store' ; export const count = writable(0); // subscribe, set, update export const immutableCount = readable(0, function start(set) { // 参照のみ // この中でのみ値を更新できる // e.g. 定期処理など } ); Storeの参照方法はSubscribeとAuto subscriptionがあります。 Subscribeは以下のようにStoreの値が変更されたことを検知する方法です。 こちらの場合、同時にcomputedのようなことや、Unsubscribe(検知されなくする)ができるのが特徴です。 < script > import { count } from './stores.js' ; let count_value; const unsubscribe = count.subscribe ( value => { count_value = value; } ) ; </ script > < p > {count_value} </ p > 一方のAuto subscriptionは単純にStoreの値を取得したい場合に使える省略記法となります。 < script > import { count } from './stores.js' ; </ script > <!-- $Storeの値名 --> < p > {$count} </ p > Derived (Getters相当) WritableかReadableの値を使って、別の値を生成する機能です。 stores.js import { derived, writable } from 'svelte/store' ; export const number = writable(0) export const double = derived( number, $number => $number * 2 ); Custom (Actions相当) Storeを更新する関数を定義することができます。 stores.js import { writable } from 'svelte/store' ; function createCount() { const { subscribe, set, update } = writable(0); return { subscribe, increment: () => update(n => n + 1), decrement: () => update(n => n - 1), reset: () => set(0) } ; } export const count = createCount(); Transition Vue.jsでもTransitionはサポートされていますが、 Svelteではすでに定義済みのTransitionが多く存在するためお手軽に実装することができます 。 最もシンプルな例は以下のようになります。 svelte/transition には現在fade、blur、slide、draw、scale、fly、crossfadeが定義されており、 タグにtransitionディレクティブを指定するだけ で表示・非表示切替時にTransitionをつけることができます。 またin、outというディレクティブを設定することで、表示・非表示それぞれでTransitionを設定することもできます。 < script > import { fade, scale } from 'svelte/transition' ; let visible = true ; </ script > < label > < input type = "checkbox" bind: checked = {visible} > visible </ label > {#if visible} < p transition:fade> Fades in and out </ p > < p in:fade out:scale> Fades in and Scale out </ p > {/if} パラメータ Svelteで定義されたTransitionにはパラメータが渡せるようになっており、それによってDurationなどをカスタマイズすることになります。 例えばflyであれば、delay、duration、easing、x、y、opacityが指定できるようです。 < script > import { fly } from 'svelte/transition' ; let visible = true ; </ script > < label > < input type = "checkbox" bind: checked = {visible} > visible </ label > {#if visible} <!-- 2秒かけてy軸に200px移動 --> < p transition:fly= "{{ y: 200, duration: 2000 }}" > Flies in and out </ p > {/if} Custom Transition Transitionを自由に定義する方法はCustom CSS transitionsやCustom JS transitionsの2つあります。 これに関してはVue.jsでもSvelteでも泥臭くはなってしまう印象ですが、Svelteでは svelte/easing にEasingの関数が定義してあったりとサポートが厚いかなと思います。 CSSTransition.svelte < script > import { elasticOut } from 'svelte/easing' ; let visible = true ; function spin ( node, { duration } ) { return { duration, css: t => { const eased = elasticOut ( t ) ; return ` transform: scale( ${eased} ) rotate( ${eased * 1080} deg); color: hsl( ${~~(t * 360)} , ${Math.min(100, 1000 - 1000 * t)} %, ${Math.min(50, 500 - 500 * t)} % );` } } ; } </ script > 特殊なタグ svelte:head, svelte:body, svelte:window Nuxt.jsでは head プロパティをコンポーネントに設定することでヘッダーに要素を設定することができますが、Svelteでは以下のように特殊タグを利用することで埋め込むことができます。 また bodyやwindowに対してイベント設定や値のbindも設定できる のはおもしろいですね。 < svelte :head> < link rel = "stylesheet" href = "hoge.css" > </ svelte :heaad> < svelte :body on:mouseenter= {handleMouseenter} on:mouseleave= {handleMouseleave} /> < svelte :window on:keydown= {handleKeydown}/ > < svelte :window bind:scrollY= {y}/ > svelte:component Vue.jsでは条件に応じて表示するコンポーネントを変える場合、テンプレート内で v-if を使っているかなと思います。 Svelteでは {#if } で切り替える方法の他に、以下のように記述することができます。 こうすることで、 コンポーネント切り替えのロジックをscriptに寄せられるため、より柔軟に条件など記述できる ようになります。 < script > import Yes from './Yes.svelte' ; import No from './No.svelte' ; let isChecked; $: selected = isChecked ? Yes : No; </ script > < input type = "checkbox" bind: checked = {isChecked}/ > < svelte :component this= {selected}/ > Module Context scriptとは別に <script context="module"> を定義することで、最初に一回だけ評価される、すべての同一コンポーネントで共通のデータやメソッドを定義することができます。 (シングルトンや静的クラスのようなイメージでしょうか?) あくまで限定的な用途を想定しており、moduleで宣言した変数はリアクティブではなく、scriptで変更しても再レンダリングはされないので注意が必要そうです。 (使いみちが難しいですね...) App.svelte < script > import Component1, { alertTotal } from './Component1.svelte' </ script > < Component1 /> < button on:click= {alertTotal} > alert </ button > Component1.svelte < script context= "module" > let totalCount = 0 ; export function alertTotal () { alert ( totalCount ) ; } </ script > < script > function handleClick () { totalCount += 1 ; } </ script > < button on:click= {handleClick} > countup </ button > <!-- 以下は 0 のまま変わらない... --> < p > {totalComponents} </ p > Debugging デバッグ用のブロックも組み込まれています。 {@debug 変数名} のように記述すると、指定した変数が変化した場合にconsoleに出力してくれるようです。 {@debug} とすると、debuggerが埋め込まれるみたいですね。 < script > let user = { firstname: 'Ada' , lastname: 'Lovelace' } ; </ script > < input bind: value = {user.firstname} > < input bind: value = {user.lastname} > {@debug user} {@debug} まとめ 今回Vue.jsユーザーである私が、Svelteの機能にフォーカスしておもしろさを紹介させてもらいました。 後発ということで Vue.jsやReactでの煩わしさを解消する機能だったり、Nuxtやvuexといったエコシステムでサポートされている機能が標準で組み込まれており、シンプルに利用できるツール だなと思いました。 まだエコシステムが未成熟だったりTypeScript未対応だったりが要因で国内での採用事例は少ないですが、このあたりの 整備が進むと爆発的に流行る可能性 はあるなと感じています。 弊社では今、フロントエンドをより早くより高い質(UI/UX)で実現できる方法を模索しています。 Svelteもその一つかもしれないと考えています。 これを読んでいただいた方で、もしフロントエンドの改修や技術推進に興味がありましたら、ぜひご連絡いただければと思います! ありがとうございました!
スマートキャンプの笹原です。 みなさんはWebサイトの、特にフロントのパフォーマンス改善を日頃から行っていますか? 常に意識しているという方もいれば、気が向いたときにたまに見てみるなんてこともあるんじゃないかと思います。 今回はそんなパフォーマンスに常に意識を配れるように、毎日Lighthouseを叩いてみたのでその構成を紹介したいと思います。 Lighthouseとは 要件 処理の流れと制約 実際の構成 1. 定期的にCloud Tasksに各ページごとのTaskをEnqueueする TaskをEnqueueされるCloud Tasksのキュー作成 TaskをEnqueueするFunctionの作成 2. 各ページにLighthouseを実行しBiqQueryに結果を格納する 終わりに Lighthouse とは まずはLighthouseについて簡単な説明です。 LighthouseとはWebサイトのパフォーマンスや品質を計測するツールで、コマンドラインツールもしくはChromeの拡張機能として提供されています。 WebサイトのURLを指定することで、Performance, Accessibility, Best Practices, SEOの5つの観点からそれぞれ100点満点として採点されたレポートを生成することができます。 最近では、 Lighthouse CI という、LighthouseをCI実行のタイミングでトリガーさせることが出来るツールも出てきています。 こちらについては、弊社の中川が試してみた記事があるので、こちらもご覧になってください。 tech.smartcamp.co.jp 要件 今回は以下の要件でLighthouseを定期実行しています。 本番環境を対象にして実行したい 対象となるページは本番環境のデータに変更に追随して変えたい 連動含め時系列的に並べて変化を捉えたいので、日次で実行した結果をBigQueryに保存したい こういった要件があったため、Lighthouse CIなんていう、いかにも定期的に実行するのに向いていそうなツールが登場している中、今回はLighthouse CIを用いませんでした。 もちろん、Lighthouse CIでも設定を変更することで上記の要件を叶えられる可能性もありましたが、基本的にはCI環境上でcommitを対象にして検証することが得意そうに思われたので、利用するのは見送りました。 処理の流れと制約 大まかな処理の流れは以下のようになります。 BigQueryのデータを元に対象となるページを抽出する 対象となるページごとに以下の処理を実行する Lighthouseの実行 BigQueryに実行結果を保存する 2-aについては実際に本番環境を叩くので、その頻度は稼働に問題ない状態にする必要があります。 とはいえ、1ページあたり10~30秒程度計測にかかるので、すべてのページを直列で行っているとページ数によっては実行時間がかかりすぎてしまいます。 なので、並列で実行可能なようにしながら、その並列数には上限を設けられる形での動作が求められます。 実際の構成 上記のような要件と制約を踏まえて、以下のような構成にしました。 1. 定期的にCloud Tasksに各ページごとのTaskをEnqueueする TaskをEnqueueされるCloud Tasksのキュー作成 まず、Cloud Tasksのキューを作成します。 $ gcloud tasks queues create lighthouse 次にキューの設定をしていきます。 本番環境を叩くことになるので、実行間隔や並列数には制限を設けたいです。 例えば、タスクの最大速度を1件/秒とし、最大並列数を5にする場合は以下のコマンドを叩きます。 $ gcloud tasks queues update-app-engine-queue lighthouse \ --max-dispatches-per-second=1 \ --max-concurrent-dispatches=5 以下が公式ドキュメントになるので、その他の設定をしたい場合はご覧になってください。 Creating Cloud Tasks queues | Cloud Tasks Documentation | Google Cloud TaskをEnqueueするFunctionの作成 定期実行のTriggerはCloud Pub/SubのCronを利用します。 こちらはFirebase FunctionsでTriggerをPus/SubにしたFunctionをdeployするだけで登録できます。 このTriggerで起動されたFunctionが実行するのは以下の2点です。 BigQueryからLighthouseを実行するべきページを取得する 各ページごとに、Cloud TasksにFirebase Functionsを叩く処理をEnqueueしていく EnqueueするのはHTTP Targetタスクにします。 HTTP Targetタスクはその名の通りHTTPリクエストを投げるタスクになっており、後ほど作る各ページにLighthouseを実行するFirebase FunctionをHTTPリクエストで実行します。 実際の流れはこんな感じになります。 const client = new CloudTasksClient(); const project = 'project-id' ; const queue = 'lighthouse' ; const parent = client.queuePath(project, tokyoRegion, queue); const httpMethod = 'POST' ; const headers = { 'Content-Type' : 'application/json' } ; const functionEndpoint = 'https://asia-northeast1-project-id.cloudfunctions.net/audit-url' ; export const enqueueLighthouse = functions .regions( 'asia-northeast1' ) .pubsub.schedule( '0 0 * * *' ) .timeZone( 'Asia/Tokyo' ) .onRun(async () => { const targetUrls = await fetchTargetUrls(); // BiqQueryからターゲットとなるURLを取得する if (targetUrls.length === 0) { return ; } await Promise.all(targetUrls.map((url) => { const payload = JSON.stringify( { url } ); const body = Buffer.from(payload).toString( 'base64' ); // EnqueueするTaskの内容を設定する // https://cloud.google.com/tasks/docs/creating-http-target-tasks const task: google.cloud.tasks.v2.ITask = { httpRequest: { httpMethod, functionEndpoint, headers, body } , } ; return client.createTask( { parent , task } ); } )); } ); あとは、この関数をdeployすれば、定期的にCloud Tasksにキューが積まれていきます。 2. 各ページにLighthouseを実行しBiqQueryに結果を格納する 次に、Cloud TasksからHTTPリクエストを受けてLighthouseを実行する処理を実装します。 lighthouseを実行するためのブラウザにはpuppeteerを用います。 ここは少し罠があり、lighthouse公式のドキュメントには Chrome Launcher を利用する実装方法が書かれているのですが、私が試した限りではFirebase FunctionsではChrome Launcherを使用してLighthouseを実行するとエラーが発生しています。 lighthouse/readme.md at master · GoogleChrome/lighthouse · GitHub 実際の流れはこんな感じになるかと思います。 // index.ts import * as functions from 'firebase-functions' ; import lighthouse from "lighthouse" ; import puppeteer from 'puppeteer' ; // lighthouse実行するのでtimeoutSecondsを伸ばしておく const runtimeOptions: functions.RuntimeOptions = { timeoutSeconds: 540, memory: '1GB' , } ; const puppeteerFlags: Array <string> = [ '--headless' , '--disable-dev-shm-usage' , '--disable-gpu' , '--no-zygote' , '--no-sandbox' , '--single-process' , '--hide-scrollbars' , ] ; const lighthouseFlags: LH.Flags = { output: 'json' , emulatedFormFactor: 'mobile' , // Performanceの点数に関係する項目だけに絞っています。 onlyCategories: [ 'performance' ] , onlyAudits: [ 'first-contentful-paint' , 'first-meaningful-paint' , 'speed-index' , 'interactive' , 'first-cpu-idle' , ] , } ; export const auditUrl = functions .regions( 'asia-northeast1' ) .runWith(runtimeOptions) .https.onRequest(async (req, resp) => { await runLighthouseAndPersistResult(req.body.url); resp.sendStatus(200); } ); async function runLighthouseAndPersistResult(url: string) { const result = await launchChromeAndRunLighthouse(url); // BiqQueryに結果を格納する処理 // データ形式などは https://github.com/sahava/multisite-lighthouse-gcp を参考 return insertLighthouseResult(result); } async function launchChromeAndRunLighthouse(url: string) { const browser = await puppeteer.launch( { args: puppeteerFlags } ); const results = await lighthouse(url, { ...lighthouseFlags, port: parseInt( new URL(browser.wsEndpoint()).port) } ); await browser.close(); return results; } 終わりに 今回はFirebase FunctionsからLighthouseを実行する構成例を簡単に紹介しました。 パフォーマンスを改善する上での第一歩は計測を始めることだと思うので、ぜひ皆さんもLighthouseを叩きまくってください。
スマートキャンプ、エンジニアの井上です。 弊社で挑戦の意味も込めて、BOXIL開発チームからBiscuet開発チームへの異動をしました。 今回はチーム異動で気づいたことをお伝えしていこうと思います。 1. スクラムによるチームへの引き継ぎコストの削減 2. 新しいチームへの不安 3.気持ちの切り替え 4. チーム異動のメリット メンバーが異動をできるという事例ができる 新しい技術に触れることでできることが増える 新しいビジネスに関わることでドメイン知識が増える 前のチームのノウハウを新チームへ共有できる まとめ 1. スクラムによるチームへの引き継ぎコストの削減 チームを移動するということで、自分がいなくても対応可能な状態にするために、引き継ぎのためのドキュメントを書いたり作業手順などを残すなどが必要かと思います。 弊社の場合は、スクラムを導入していた効果で属人性の高い作業などが少なく、誰でも同じ知識を持っている状態になっているため引き継ぎ作業が発生しませんでした。 そのため、チーム移動を聞いてから1週間ほどで問題なくチーム移動が行えました。 2. 新しいチームへの不安 チームを移動するということは、違うプロダクトを開発するというだけでなく、新しいメンバーと開発するということで、転職にも近いかたちになります。 その中でどのようなことをやっているのか、何をすればいいのかなどわからなくキャッチアップに時間がかかる場合があります。 隔週でチーム間で、どのようなタスクや取り組みをしているか共有しているため、チームでどんなことをしてるかなどはある程度理解した状態で話を聞くことができました。 その結果、オンボーディングやチームに関しての説明などは最小限でチームにジョインすることができました。 3.気持ちの切り替え 一番大変だったのはプロダクトが変わることに対しての気持ちの切り替えでした。 スクラムにより引き継ぎがなくなり、自分がいなくても大丈夫な状態でしたが、やりたいこと・やりきりたいことなどがある状態での異動だったので、辛くもありました。 しかし、自分でなくても達成できる状態になっているからこそ、異動する決断ができました。 4. チーム異動のメリット チーム異動の話を聞いたときにメリットについて考えました。 そして、実際に良かったと感じたところを紹介します。 メンバーが異動をできるという事例ができる 自分はBOXILチームの中でも長く1年半ほど開発していましたが、その自分が異動できることがわかれば、他の人も異動しやすくなるのでいい事例づくりになると思いました。 新しい技術に触れることでできることが増える Productが違えば使ってる技術や作るものも変わってくるので、新たに学習することが増え、エンジニアとしてさらに技術の幅が広がると感じています。 新しいビジネスに関わることでドメイン知識が増える 新しいビジネスに関わることで、今まで表面上しか理解していなかったことに対して深く知るいい機会になります。 また、実際にどう売るかや、現在の市場の状態などは本では得られない情報なのでとても勉強になります。 前のチームのノウハウを新チームへ共有できる 違うチームであれば同じ課題でも解決方法が違ったり、別の課題に注力してるので溜まるノウハウも変わってきます。 そして今回の異動で、BOXILチームの取り組んできて良かったことをBiscuetチームに還元することで、チーム間のノウハウの共有になるかと思います。 現在、Biscuetチームでテストを書くときにBOXILのテストコードを共有してテスト作成をすすめたり、振り返りの際にBOXILの失敗・成功事例などを紹介しています。 まとめ いかがでしたでしょうか? 今回はチームの異動して感じたことわかったことを紹介しました。 この内容がチーム異動の参考になれば幸いです。
お子さんのご誕生、おめでとう! スマートキャンプのプロダクトマネージャーの郷田です。 近頃、育休を取得されたエンジニアの方の記事をよく見かけるようになりました。 そんななか、弊社スマートキャンプでも直近でエンジニアが育休を取得する機会があったのですが、 本記事では逆の視点、つまり残されたメンバーの視点から、「育休でエンジニアリーダーが不在となった開発チームに、どのような変化があったのか?」をお届けします! 開発体制 スクラムでのプロダクト開発 チームの編成 エンジニアリーダーの業務 育休に入るまで 不在時の問題と対策案の共有 実際にエンジニアリーダー不在となって 困ったこと 困ることで起きたポジティブな変化 思ったより、困らなかったこと 育休期間を終えて 一人ひとりの感想 育休をとったエンジニアリーダーからのコメント まとめ その他 開発体制 はじめに、我々のチームではどのような体制で開発を行っているのかを紹介します。 スクラムでのプロダクト開発 我々のチームではスクラムのプロセスを取り入れたプロダクト開発を行っています。 『スクラムをどのように実現しているか?』については以前投稿した以下記事をご覧いただければと思います。 tech.smartcamp.co.jp チームの編成 エンジニアリーダーがいた頃のチーム編成をご紹介します。 今回はこのような体制の中でTさんが1ヶ月の育休を取ることとなりました。 担当者 所属チーム 役割 郷田さん POチーム プロダクトマネージメント、元エンジニア Tさん エンジニアチーム チームリーディング、テックリード、育休とった人 Hさん エンジニアチーム エンジニアリング、デザインもする人 Aさん エンジニアチーム エンジニアリング、インフラ強めの人 Cさん エンジニアチーム エンジニアリング、アプリ開発中心の人 ※ビジネスサイドのメンバーは省いています。 エンジニアリーダーの業務 育休前にエンジニアリーダーが担っていた業務や役割は以下になります。 エンジニアリング フルスタックの開発 サーバーサイドでは開発をリーディング 技術選定 アーキテクチャ設計や外部連携設計 リモート時短の業務者へのタスク割り振り スクラム 開発環境の改善に対する、アイデア出し・優先度付・工数の見積もり PdMの新機能アイディアに対する、実現可能性と工数の見積もり プランニングのファシリテーションと推進 生き字引き役 古い実装の経緯の把握 プロダクトの立ち上げ経緯のフェーズからエンジニアリングでの関わり有り 育休に入るまで 以下のタイムラインで育休に向けた準備を行いました。 育休取得の3ヶ月前 開発チームへの共有、相談 育休取得の1ヶ月前 MTGにて、起きうる問題の洗い出し 育休取得の1週間前 MTGにて、問題と対策を整理 不在時の問題と対策案の共有 POチームも含めて課題を話し合い、不在時にどのような問題が起きるか、それらにどのような対策が想定されるかをディスカッションし、チームの認識合わせを行った結果が以下となりました。 その1:業務委託のタスク割り振りに困る 対策案: スプリントプランニングに1Step追加し、チーム全体でタスク割り振りを実施 その2:技術的な意思決定に困る。アーキテクチャの設計や、コードの品質が下がるかもしれない 対策案: 外部アドバイザーに意見を求める 意思決定は3名全員でディスカッションして決めることとする その3:開発スピードが下がる 対策案: POチームにてスピード低下を前提とした事業計画の見直しを行う その4:さみしくなる 対策案: お子さんの成長記録を流すslackチャンネルを作って運用してもらう 実際にエンジニアリーダー不在となって 困ったこと 準備はしていたものの、いざ不在となると発覚する困りごとが沢山ありました。 1. エンジニアリーダーによる「意思決定」がなくなったこと 事前MTGでも技術的な意思決定に困る可能性がある件については検討していましたが、やはりエンジニアチームで行う意思決定の多くにエンジニアリーダーの意見が反映されいていたため、実際に不在となると「どうしよう?」と困るシーンが多かったようです。 2. 既存のコードでリーダーに依存していた部分が多かったこと エンジニアリーダーが不在となることで、エンジニアリーダーのみが把握していたコードがあることがわかり、それらに対する改修を即座に行えない状態となっていました。 3. ビジネスサイドからのざっくりとした開発要望の所感を聞く相談相手がいなくなったこと 「コレを実現してみたいけど、それってできるの?」といった相談をする相手がエンジニアリーダーとなっていたため、どこで誰に相談すればいいのかがわからない状態となっていました。 困ることで起きたポジティブな変化 実際に不在となるとエンジニアリーダーへ依存していた業務が沢山有ったことに再認識させられました。 それにより、開発メンバーは業務を進めるために自分が調べて「意思決定」をし、「コードを書く」必要がでたこと、またPOチームは開発チームに聞く前に「もう少し自分で調べる」時間を作り実施するようになりました。 エンジニアリーダー不在による穴は大きいものだったため、特に不在となった初期のころはスピードがかなり下がってしまいましたが、それにより一人ひとりの業務理解度があがり、1ヶ月が終わる頃にはメンバー全員のプロダクトや業務の解像度が上がり、不在の穴を充分に埋められるほどになっていました。 思ったより、困らなかったこと もっと困ると思っていたが、実際には困らなかったことも有りました。 スクラムによる恩恵 弊チームではスクラムの以下イベントのファシリテーションを毎回ランダムに決めています。 デイリースクラム リファインメント スプリントレビューでの開発デモ レトロスペクティブ スプリントプランニング これにより、各イベントへの理解度がスクラムマスターやエンジニアリーダーに偏らず、不在時も自然とスクラムを回すことができていました。 また、開発チームはメンバー全員の開発可能な合計時間(キャパシティ)と、過去の実績から実施可能ポイントの見積もりを行っています。 これにより、1名が不在となった場合に消化できるポイント(開発可能なタスク量の見積もり)ができていたため、タスクを詰め込みすぎる開発とならずにイテレーションを回すことができました。 育休期間を終えて 一人ひとりの感想 Hさん 既存機能がエンジニアリーダーに属人化している部分が多い認識はあったため、不在となることに不安があった。 属人化していた部分も開発を進めるために、メンバー全員でコードテストを書くことや複雑な機能のロジックのコードリーディングをして理解ができるようになったのは良かった。 開発プロセスはスクラムを導入して数ヶ月前から作り上げていっていたので、大きく困ることはなくいい感じに進めることができてよかった。 Cさん 育休に入るまでは不安感あった。新機能の設計・開発が、というよりも既存の複雑であったり属人的な機能で不具合が発生したら解決出来るのかな、みたいな漠然とした不安があった。 育休期間中は自分たちでやらざるを得ない環境になったことで、自分があまり触ってこなかった領域も触るきっかけになったしその結果アプリケーションの全体感がより立体的になった。 そのおかげで上述の漠然とした不安みたいなものが薄くなった。「読んでもわかんないかも」から「読めばいけるかも」になった。 Aさん 技術的な部分はもちろんだが、開発チームの統率や今までと違う体制になることによってどう意思決定していくかみたいな面もかなり不安があった。しかし、スクラムに取り組んでいてプロセスの型化ができていたり、今まで頼っていたけど足りない部分をみんなで補わないといけない!という危機感みたいなのがうまく噛み合って、育休前に想像していたよりもいい形でチームがワークしたと思う。 個人的には、テックリードが抜けた分、POや業務委託の方と認識齟齬が起きないようこまめに連携するようにしたり、今までよりもしっかり確認やレビューをするように意識した点もよかったのかなと思う。 人が抜けてメンバーが強制的に変わることで各メンバーの立ち位置が変わったり、チームで作業するときのスタイルが変わったりするのはとてもおもしろいし、刺激があってとてもいい変化だと思った。 郷田さん POチームから見ても、プロセス面も技術面もエンジニアリーダーに依存している部分が多いように感じていたため、困りごとは増えると考えていた。 誰かがなにかを担う形でエンジニアリーダーの業務を分散化する必要はあると考えていたため、各人のオーナーシップによって上手に巻き取ってもらうことができたのはとてもよかった。 特に、エンジニアリーダー不在による自分含めた一人ひとりの自責の意識が向上したことが一番の成果だと思う。 育休をとったエンジニアリーダーからのコメント Tさん スクラムで回していたり、各メンバーがオーナーシップとってくれる環境だったので、そこまで心配はしていなかった。 快く育休へ送り出してくれて、その間も滞りなく開発を進めてくれて感謝しかない! まとめ 以上が弊社の事例になります! いかがだったでしょうか? 育休を取得する側の不安以外にも、取得する人が所属しているチーム・組織の不安についても弊社の事例によって解消されうる部分があれば幸いです。 その他 当テックブログでは過去に、育休を取得したEMが「子育てで取り組んだことやエンジニアのノウハウをどう活かしたか?」を紹介した記事も書いております。 ご興味がございましたら、ぜひこちらも御覧ください! tech.smartcamp.co.jp
スマートキャンプでエンジニアリングマネージャーをしている米元です。 突然ですが、みなさんは転職活動をする際にどのようにして企業を選びますか? 企業のビジョン/ミッション・技術力・社員の人柄、などなど見るべきポイントはたくさんあると思います。 ただ数回の面接だけでは本当にその企業が自分にマッチしているのか分からない事もあるのではないでしょうか。 企業側も一緒に働くまでは候補者の方が自社で活躍できるのか、候補者と自分たちの期待値が合っているのかが分からないといった場合があると思います。 そこでスマートキャンプでは選考が進んだ候補者の方に対して、会食や体験入社などの面接以外の方法でお互いのマッチ度を測る取り組みを行っています。 今回はそれらの取り組みの中でも「体験入社」に最近参加された方にインタビューを行い、客観的な観点での感想を記事にしてみようと思います! 参考 身近なUXデザイン? 会社1日体験を作ってみた話|SMARTCAMP DEXIGN|note 「採用後の活躍」がゴール! 〜エンジニア採用フローを公開します〜 - SMARTCAMP Engineer Blog 想定読者 体験入社の制度について 今回体験入社された方ってどんな人? 体験入社インタビュー開始! 体験入社のスケジュール 体験入社を通して感じた事 1.スクラムの理解度が高いメンバーが揃っている 2.部署・職種を問わず仲が良い 3.良い意味での多様性がある その他、体験入社で気づいた事 体験入社を通して得られたもの・得られなかったもの 体験入社自体の改善点 体験入社全体を通しての感想 インタビューの最後に まとめ 想定読者 以下のような方々を想定しています 体験入社とはどのようなものか知りたい方 体験入社に参加すると何が得られるのか知りたい人 体験入社の制度について スマートキャンプの体験入社は以下のような内容となっています。 実際の業務を社員と一緒に行う 会議の場に同席してもらう 他部署メンバーとのランチや 全体朝会(Good&New) など会社のイベントに参加してもらう また、体験入社のゴールは以下のように定めています 候補者の方の会社選びの軸にマッチしているかどうかをお互いに判断できる お互いに不明点・懸念点が無くなり、働くイメージが持てる スマートキャンプの魅力を更に感じてもらう 今回体験入社された方ってどんな人? Web系企業でテックリードやマネジメントを経験されたミドルクラスのエンジニアです 体験入社インタビュー開始! それではインタビューを始めていきましょう! 体験入社のスケジュール - 体験入社お疲れ様でした!早速ですが体験された期間と内容を教えてください。 はい、期間は2日間です。2日目は午後からだったので正確には1.5日くらいですね。 初日は以下のようなスケジュールでした。 初日のスケジュール ## 午前中 - 朝会 - リファインメント - ランチ ## 午後 - 開発部署全体の会議 - スプリントレビュー - スプリントレトロスペクティブ(KPT) - スプリントプランニング - 体験入社1日目の振返り - 体験にも関わらず盛りだくさんな内容ですね! 面接の際にスクラムで開発を進めていることは聞いていたので、KPTなどスクラムのセレモニーを実施している日に参加したいと自分から希望しました。 KPT以外にもスプリントレビューやスプリントプランニングを同じ日に行っているので、ほぼ1日中セレモニーに参加していましたね。 実際は休憩の時間もあったので、その際にBOXILのソースを読む等していました。 - なるほど、それでは2日目はどんな内容だったのでしょうか? 2日目は午前の途中からの参加でした。 初日はBOXILチームのセレモニーでしたが、この日はBiscuetチームのセレモニーを中心に参加しました。 最後の方に少しですがモブプログラミングにも参加できました。 2日目のスケジュール ## 午前中 - スプリントレビュー - ランチ ## 午後 - スプリントレトロスペクティブ(KPT) - スプリントプランニング - BOXILの事業責任者と面談 - モブプロ - 2日間の振返り 体験入社を通して感じた事 - ありがとうございます!2つのプロダクトのセレモニーに参加されたのですね。約2日間で体験されて感じた事を教えて頂けますか。 はい、自分が特に良いなと思った点は3つです。 1.スクラムの理解度が高いメンバーが揃っている 1つ目として、一番驚いたのはスクラムの理解度が高いメンバーが揃っていることです。 KPTの際には改めてTryの意味・意義について確認する発言があったり、プランニングでもスパイクの目的や意義を意識してやることを決めていたりと、メンバー全員がスクラムの各要素の目的や意義を理解した発言や行動が多かったです。 スマートキャンプではスクラムマスターの役割を持つメンバーは不在なのですが、それでもちゃんとスクラムが出来ていました。 よく言われるスクラムマスターのゴールが「自分自身をクビにすること」なのですが、それに近い状態になっています。 今まで自分が見ていたチームと比べてレベルが高いと感じました。 2.部署・職種を問わず仲が良い 2つ目は部署や職種関係なく仲が良いと感じました。 初日は「厨房ですよランチ」と呼ばれているオフィス内で食材を持ち寄ってランチを食べる会に参加したのですが、いろんな部署の方がそれぞれの役割を超えてコミュニケーションをとられていました。 新卒の同期メンバーが持っているような空気感が中途も含めて全体であるのが良いですね! 2日目はBiscuetチームのランチに参加しましたが、1人が場を仕切ってもう1人が冗談を言って盛り上げ、他の1人がそれに突っ込むといった普段からの仲の良さを感じました。 仕事とプライベートの境界が良い意味で曖昧なのかなと思いました。 3.良い意味での多様性がある 3つ目は良い意味で多様性があることです。 初日はBOXILチーム、2日目はBiscuetチームに参加したのですが、それぞれチームの色が違っていました。 これは良い悪いではないのですが個人的には好きな状態です。 トップダウンでどのようなチームにするかを決められたのではなく、自己組織化した結果として多様性が生まれている事が良いと思いました。 今後新たにチームが出来た時も自然に実験が発生し、組織全体がよくなっていくのが想像できました。 その他、体験入社で気づいた事 - ありがとうございます!自分達が普段から行っていることを褒めてもらえると嬉しいですね!他に気になったことはありますか? そうですね、スクラムに関してはプランニングにかなり時間がかかるので、タイムキーパーを置いた方がよいかなと思いました。 また、KPTのTryについてですが、障害に起因するものについての話しに時間がかかっていたので、それに関しては別途ポストモーテムの時間をとって話した方がより集中出来て良さそうです。 全体に対しては、ランチの話と少し重なりますが、社員数が約70名という規模の割に仲の良さや一体感があると感じました。 普段の挨拶や、Slackでのコミュニケーション、スプリントレビューにビジネス職のメンバーも一緒に参加して議論しているところなどからそのように感じました。 また、初日の帰りのエレベーターで体験入社では関わっていない社員の方から話しかけられた事も良い印象が残っています。 体験入社を通して得られたもの・得られなかったもの - 今回の体験入社を通して、得られたもの・得られなかったものはありますか? はい、事業の説明やこれまでの経緯を聞く時間を多く取れたことで事業の狙いや考えがわかりました。 また、個人的に「こんな組織を作りたい」と思っていたものが実現されているのを目の当たりにして、実際に実現できるのだという事がわかりました。 具体的には以下のような組織です。 目線が事業・プロダクトに向いている 自分達のチームでよりよい物を作っていく意識がある プロダクトオーナーなどの役割はあるが、各自が他の役割に染み出して行動し、それによっていいものを作ろうとしている あとはポジティブな状態を目指せる事に共感して動いているのが強いなと思いました。 一定の目指すべき方向性がチームの中にあって、自分達が頑張ればその方向に向かっていけるという思いがあるように感じました。 逆に得られなかったものは技術や開発環境の知識です。 例えば技術的負債がどのような状態なのか、コードの質や開発のしやすさ(DX:Developer Experience)などは今回は分からなかったです。 ただ私の場合はスクラムのセレモニーへの参加を希望していたこともあり今回これらを知ることはMUSTではなかったので、あえて言うならという感じです。 求めるものが人よって違うので、それに合わせてメニューを作るのが良いのではないかと思います。 体験入社自体の改善点 - 体験入社自体の改善点は何かありますか? 短い期間で関わる人の名前を一気に覚えるのが大変なので、名札はあったほうがよいなと思いました。 また、先程の質問と重なりますが、この体験入社で得てほしいものと逆にフィードバックしてほしいものを事前に共有してもらえると本人もそのつもりで体験入社を迎えられてよいのではと思いました。 - 確かにそれはそのとおりですね!次回に活かします・・! 体験入社全体を通しての感想 - 最後に2日間の体験入社全体を通しての感想があれば教えて下さい。 いい人が多いなと感じました! あとはカルチャーマッチすると働きやすい会社なんだろうなと思いました。 現場のメンバーが面接に出てきたり、今回のような体験入社をしてくれたりと選考にかなり工数をかけている印象がありますが、選考の際にお互いのマッチ度を重視している姿勢がよく伝わりました。コストはかかるが良いやり方だと思います。 また、「Will」ベースの会社だという印象も持ちました。今現在ある課題に対して事業を作るというよりも、世の中がこの先どうなるからこのサービスが必要、という視点で事業を作っているような印象を持ちました。 - なるほど、第3者視点で見ると社内からでは気づかない点が見えて面白いですね! インタビューの最後に - ちなみにここまでかなりポジティブな感想を多く頂きましたが、それだけ褒めてくださるということは入社意思が固まったということで良いでしょうか? それはまだ考え中です!前向きに検討します!笑 - すいません、ちょっと早まりましたね!2日間本当にありがとうございました! こちらこそありがとうございました! まとめ 今回は実際に体験入社に参加していただいた方にインタビュー形式で聞いてみました。 内容自体よりも体験してどう感じたか、何を得た・得られなかったかを中心に書きました。 思った以上にポジティブな感想をもらえた一方で体験入社自体は改善点も見つかり、今後に活かす意味でも今回のインタビューを実施してよかったです! 体験入社についての私自身の考えですが、選考中の期間だけを考えると面接以外にこれだけの時間を使うのは会社・候補者の双方にとってそれなりに大変で、実際に労力やコストがかかります。 ただ入社後はそれ以上の期間、長いと数年間は一緒に働く事になるので、長期的に考えると1日や2日一緒に働くだけでミスマッチが解消されるのであれば十分コストに見合うのではないかと考えています。 最後に、弊社のことをもっと知りたい!という方は以下のブログや動画もご覧ください! ここまで読んで頂いてありがとうございました! boxil.jp note.com www.youtube.com
スマートキャンプ、エンジニアの入山です。 弊社で技術的挑戦の意味も込めて始めたKubernetes(k8s)も、小規模ながら運用を開始して1年以上が経ちました! 現在では、k8sでのインフラを採用したプロダクトが無事に本番リリースを迎え、ユーザーが本番稼働を行うまでになっており、躓きながらも少しずつ運用知見が溜まってきています。 今回は、k8sを実際に運用してわかった3つの知見を紹介したいと思います! PodのNode配置が偏る 解決策 ローリングアップデート時にダウンタイムが発生する 解決策 Pod削除時にコンテナによってプロセスが終了するタイミングが異なる 解決策 最後に PodのNode配置が偏る k8sではPodを新規作成する場合に、kube-schedulerが各ノードのリソース使用状況等から判断した最適なNodeへスケジューリング(配置)を行います。 しかし、このスケジューリング機能はPodの新規作成時にしか実施されないため、クラスタで障害が起こった際はもちろんのこと、Pod数や負荷状況などの要因によって新規スケジューリング時に偏りが発生した場合、Podがうまく各ノードに分散されずに偏ったままとなってしまいます。 弊社の運用時には、ノードの障害が起こっていないにもかかわらず、デプロイを繰り返しているうちに気付いたらPodがあるノードに偏っており、そのノードの負荷が高くなるだけでなく、冗長性・信頼性が低下してしまっていたことがありました。 このような状況に陥った場合は、k8s側では自動再スケジューリングが行われないため、何らかの手段を使って再スケジューリングを行う必要があります。 解決策 Deschedulerを利用することで、任意のタイミングでPodの再スケジューリングを行うことができます。 Deschedulerは動作として、設定したポリシーに該当するPodをNodeから削除させることで、kube-schedulerがPodを再スケジューリングする契機を作ります。現時点で5つのポリシーがあり、用途に合わせて柔軟にPodを再スケジューリングさせることができます。 尚、DeschedulerはJobで動作させる必要があるため、実際に運用する場合はCronJobで実行するなどの工夫が必要です。 GitHub - kubernetes-sigs/descheduler: Descheduler for Kubernetes Deschedulerについては@ponde_mさんの資料がとてもわかりやすく、参考にさせていただきました! speakerdeck.com ローリングアップデート時にダウンタイムが発生する k8sはDeployment定義のDockerイメージのバージョンを変更してapplyすることで、自動でPodのローリングアップデートを行ってくれます。 このローリングアップデートは、新バージョンのPodが起動したことを契機に、旧バージョンのPodの削除が開始される仕組みになっています。 しかし、この「新バージョンのPodが起動した」状態は、Pod内のすべてのコンテナが起動したことだけを検知したものであり、各コンテナのプロセスがサービス開始できる状態になったことを保証するものではないため、コンテナ起動からサービス開始できる状態になるまでに時間を要する場合などでは切替時にダウンタイムが発生する可能性があります。 解決策 readinessProbeを利用したヘルスチェックの仕組みを入れることで、サービス開始できない状態のPodを検知し、トラフィックを送らないように制御することができます。これによって、ローリングアップデート時のダウンタイムも防ぐことができます。 readinessProbeは、コンテナに対して任意のヘルスチェックを設定することでサービス開始ができる状態か確認する機能で、ヘルスチェックに失敗したPodはServiceのエンドポイントから外される仕組みになっています。また、一度エンドポイントから外されたPodについてもヘルスチェックに成功した場合は、再度Serviceのエンドポイントへ登録されます。 ヘルスチェックの方法は、httpGet、exec、tcpSocketの3つから選ぶことができるため、コンテナに合わせて柔軟に設定ができます。 同じようなヘルスチェック機能としてlivenessProbeもあり、こちらはヘルスチェックに失敗した際にPodを破棄・新規作成する機能を備えています。 Configure Liveness, Readiness and Startup Probes | Kubernetes readinessProbeについては以下の記事が参考になります! cstoku.dev Pod削除時にコンテナによってプロセスが終了するタイミングが異なる k8sでは、Podの削除が開始されると各コンテナに対してTERMシグナル(正常終了要求)を送信し、TERMシグナルを受け取った各コンテナでプロセスの終了処理が開始されます。 この終了処理には、猶予期間(デフォルト30秒)が設定されており、猶予期間内にプロセスが正常終了されないコンテナについてはKILLシグナル(強制終了要求)が送信され、Podごと強制的に削除されます。また、TERMシグナルの送信と同時にPodをServiceから削除する処理も実行されます。 ここで問題になるのが、各コンテナのプロセスが終了するまでの時間に差が発生する可能性があることです。 Pod内のコンテナ同士で連携処理を行う構成においては、この時間差によって連携処理がエラーになる可能性があり、最悪の場合は強制終了される猶予であるの30秒の間ずっとエラーになる可能性もあります。また、Serviceからの削除が完了するまでは新規トラフィックの制御も行われないため、このような状況に陥った場合はエラー状態のままトラフィックを受け続けることになります。 弊社においてもこの事象が実際に過去発生していました。 弊社の例では、Pod内にRailsアプリコンテナとauth認証コンテナが存在しており、コンテナ間で認証処理を行っていたのですが、即時終了するauth認証コンテナに対して、Railsアプリコンテナが正常終了されず強制終了まで生き続けるという現象が起きていました。これにより、auth認証コンテナの終了後からRailsコンテナが強制終了されるまでの30秒間は、Railsからauthコンテナの認証ができないために処理がエラーになっていました。 解決策 preStopフックを利用してコンテナが終了する直前の動作を指定することで、各コンテナの終了動作やタイミングを操作することができます。 preStopフックは、コンテナごとに終了時のTERMシグナルが送信される前に任意のコマンド実行ができる機能で、プロセス終了のための任意コマンドの投入だけでなく、sleepなどのコマンドを実行することでTERMシグナルの投入タイミングを調整することもできます。尚、preStopフックが設定されている場合は、preStopフックが完了したタイミングでTERMシグナルが送信されます。 preStopフックの設定もヘルスチェック同様にhttpGet、exec、tcpSocketの3つから選ぶことができます。ただし、execを利用する際は同期処理である必要があり、非同期処理のコマンドを実行した場合は、即時にpreStopフックが完了したと判断されてしまうため、非同期処理を行う場合は終了処理に必要な時間を目安にsleepさせる必要があります。 尚、Pod終了時の詳しい挙動は、以下公式ドキュメントに記載されています。 Pod | Kubernetes Podの終了動作やpreStopフックについては、以下の記事が参考になります! qiita.com 最後に 今回はk8sを実際に運用してみてわかった知見を紹介しました! 今回紹介したようなPodの配置や終了などのk8s側で自動的に制御されている部分の動作について、導入・設計時からしっかり把握しておくのはなかなか難しいと思います。 今回の対策で挙げた例以外にも同様に問題を解消する方法はあると思いますが、一例として参考になれば嬉しいです!
スマートキャンプで Biscuet を作っているエンジニアの中川です。 本記事は2月5日に弊社で開催したTDDワークショップについて紹介します! TDD: テスト駆動開発のこと。テスト駆動開発とは、テストファーストとして初めにテストコードを書き、その後テストをパスするコードを実装し、さらにその後コードをリファクタリングして良くする、というサイクルを回していく開発手法のこと。 今回のワークショップはマネーフォワードと共同開催し、合計20名のエンジニアが参加しました! また、講師としてテスト駆動開発の第一人者である和田卓人( @t_wada )さんにお越しいただきました。 本日はスマートキャンプ株式会社様および株式会社マネーフォワード様にお招きいただき、1日コースのTDDワークショップを開催させていただきました。午後の演習とコードレビューでは鋭い質問がたくさん飛び出し、議論が盛り上がりました。ご参加くださいました皆様、誠にありがとうございました! — Takuto Wada (@t_wada) 2020年2月5日 当日の流れ 当日は丸一日かけてワークショップを行いました。 午前 前半は、t_wadaさんによる講演+ライブコーディングがありました。 講演自体はTDDをまだやったことがない初心者でも分かる内容になっており、「TDDとは?」というところから丁寧に解説していただきました。 その後は、t_wadaさんによるライブコーディングとして、FizzBuzzを題材に以下のTDDにおけるサイクルを回しながら実際に開発していく様子を見せて頂きました。 午後 後半はt_wadaさんに考えて頂いたお題に対して、参加者がペアプロで取り組みました。 事前のアンケートによると参加者の3/4がテストを書いた経験があったため、お題の難易度設定は難しめ(初お披露目!)にしたとのことでした。 当日用意していただいたお題はこちらから見れます。(当日ご本人に許可いただきました!) Revenue Recognition · GitHub 作業中は、各チームt_wadaさんにアドバイスを貰いつつ取り組み、中間と最後にモブレビューを参加者全員で行いました。 レビューでは、TDD的に気になるポイントや自分のチームとの違いについて参加者が気軽に発言していて、活発な議論が行われました! 終わりに 今回のワークショップの事後アンケートの結果はこのようになり、参加者の満足度が非常に高いものになりました! 先日のTDDワークショップのアンケート結果を拝見し、参加した皆様の満足度の高さに強い手応えを感じた。 「パブリックイメージと違って質問もしやすく、とてもわかりやすい講習でした。ありがとうございました!」という熱いコメントもいただき、大変嬉しいと同時に、それな……という気持ちに🦁 — Takuto Wada (@t_wada) 2020年2月7日 僕個人としても実践的にTDDを学べることでいままでTDDについて誤解していた部分が明確になり学びを得ることができました! 弊社ならびにマネーフォワードグループでは今後もこういった取り組みを通してエンジニアの技術向上に取り組んでいきます!
こんにちは、 BOXIL の開発をしている徳田( @haze_it_ac )です。 今日はBOXILの開発チーム、特にエンジニアが今どういうことを考えてどんな開発をしているのか、そしてこれからどうなっていこうとしているか をご紹介します。 スマートキャンプという名前を聞いたことがある人、興味がある人に読んでもらえると嬉しいです。 合わせて読みたい BOXIL開発チームの今 開発体制 開発プロセス・スタイル 今の課題 やりたいことに対してのリソース不足 技術負債 BOXIL開発チームのこれから 採用 改善活動: 技術 改善活動(プロセス おわりに: 宣伝 BOXIL開発チームでお待ちしています エンジニアイベントやっています 合わせて読みたい tech.smartcamp.co.jp 昨年末までの「BOXIL開発チームのこれまで」を、現Product Managerの笹原が書いているので一緒に読んでもらえると嬉しいです🙏 BOXIL開発チームの今 今の開発チームを、徳田の目線で振り返ってみます。 開発体制 現在、「BOXIL開発チーム」は3つの役割を持つチームが定義されています。(兼務もいます) 1. Product Manager スクラムにおけるPOの役割です。 CS, Sales等とのコミュニケーションや仕様(=Product Backlog)に関する責任を持ちます。 現在、Product Managerとして一名が担っています。 2. Designer Team https://boxil.jp , https://boxil.jp/mag のUIや、BOXILにかかわるLPやイベントで使用するチラシ等のデザインを行うチームです。 デザイン、見た目の責任を持ちます。 現在、一名+業務委託メンバが担っています。 3. Developer Team デベロッパーの集まり、所謂エンジニアです。 Product Manager、Designerが作った仕様・デザインを実装する責任を持ちます。スクラムで言うところのPBLの消化です。 現在、正社員二名と業務委託メンバに加えてProduct Managerが兼任で担っています。 補足: 現時点ではスクラムマスターの役割を持っているメンバはいません。 昨年からお手伝いいただいている アジャイルコーチ には、今は主にPO側の改善活動に注力してもらっています。 (スクラムマスターは任命するものではなく自然発生的に生えてくるもので、生えていないうちはチーム全体で補うため大丈夫、という認識です。) 開発プロセス・スタイル スクラム 開発プロセスのベースはスクラムです。 毎週金曜日に Sprint Review, 振り返り, Planning を実施。それ以外の月〜木に作業を行っています。 モブプロ・ペアプロ・個人作業 3~4ヶ月ほどモブプロを積極的に取り入れていましたが、少しずつモブでやること・やらないほうが早くできることの認識がメンバ間で合ってきたこともあり、最近は少しずつ個人やペアでの開発が多くなっています。 今はDeveloper Teamの中で、正社員二名チーム・Product Manager+業務委託メンバチーム の2つに分かれて、担当する開発範囲を分けて開発しています。 ペアでやるか、個人作業+レビューでやるかも、そのチーム間で好きに決めてやっています。 チーム間の連携は随時必要に応じてドキュメントを書いて共有しています。今週からは金曜日に時間を取ってやるようになりました。 参考: 実践して分かったモブプログラミングのメリット・デメリット - SMARTCAMP Engineer Blog 振り返り tech.smartcamp.co.jp めちゃくちゃ振り返っています。 朝会(Daily Scrum)、毎週の振り返り、KPT等は安定してずっと出続けており、一ヶ月も経つとチームの形やプロセスがかなり変わっています。 お気持ちを書くSlack Channelも爆誕して、日々心も言葉にして、後で振り返っています 今の課題 やりたいことに対してのリソース不足 昨年末にプロダクトマネージャが爆誕し、アジャイルコーチ・デザイナと共にPOのサイクルが回ってきたことで、開発チーム全体のボトルネックがDeveloper Teamに寄ってきました。 (最近は PdM, Designer, コーチで Opportunity Canvas や Lean Canvas を作成していて、Backlogの質もどんどん上がってきています👏) 開発速度を上げていくための施策はいくつか走っていますが、やりたいと思っていることの全てをDeveloper Teamだけでこなすことはできておらず、(元)開発リーダでもあるProduct Managerに一部機能開発を手伝ってもらっている状況です。 技術負債 複数サービスが密結合している ことや、Viewにかなりのロジックが残っていることから、開発やテストに大きな影響が出ています。 課題となる箇所にかかわる機能改修を行う際はリファクタリングや不要なコードの削除をしており、少しずつ改善はされていますが、まだまだやれることは多いです。 BOXIL開発チームのこれから 採用 まずは、Product Managerが開発にも入っている状態を脱するのがDeveloper Teamとしての第一の目標。 そのために、今のメンバで開発をすすめるためにできることはやると同時に、採用もやっていくことになります。 現時点でメンバも全員採用の面接に入ったり話をしたりしていますが、会社そのものを知ってもらったり、興味を持ってもらうための活動を開発とは別軸でやっていく必要があります。 (具体的には このエンジニアブログ もそうですし、 カンファレンスへのスポンサー 、 自社開催のエンジニアイベント 等。やれることはやっていますが、今後も継続してやっていくぞ!という意味です) 改善活動: 技術 今でも開発の合間のリファクタリングは積極的に実施していますが、もっと直せる部分は多くあります。 ある程度モノリスでの改善ができたら、システム・組織の分割を行い、人が増え、チームが大きくなっても開発を早く進められるような形にアプリケーションも変えていく必要があります。 Ruby on Railsのレイヤ以外でも、クリティカルなインフラ周りの改善などももっとやっていきたい...と思っています。 改善活動(プロセス リファクタリングの障壁の一つに、複雑な割に仕様がソースコードに以外にないことがあげられます。 tech.smartcamp.co.jp そのためオンボーディングプロセスにおいて、現状の仕様を共有していく手段がモブプロ・ペアプロで直接伝えるぐらいしか今は無く、(最終的にはどうであれそうなるのですが)関連する機能のソースコードを全部読まないと先に進めない状況になっています。 また、人によって仕様の理解度に差があり、考慮漏れが発生したりすることもあります。 それらを解決するため、 構造化されたテスト や、重要な仕様のドキュメントを整備していこうとしています。 おわりに: 宣伝 BOXIL開発チーム、特にDeveloper Team目線からのお話を割と長々と書かせていただきました。イメージは湧きましたか? 残りは宣伝です。が、ここでブラウザバックせずに、読んでくれると嬉しいです😌 BOXIL開発チームでお待ちしています 解決しないといけない課題はある程度見えていますが、とりあえず人が足りないこともあってやれる範囲はめちゃくちゃ広いチームです。 また課題に対していくつか書かれている解決策は、今の状態で最善だと思うやり方です。 「もっとこうしたほうが良い」とか、「ここは得意だからやらせろ」とかは喜んで聞き、適切であれば即座に実行したり、だめそうなら一緒に考えていける組織です。 興味を持った、少し話を聞いてみたいと思った方はぜひ気軽にお話しましょう!!!!! hrmos.co エンジニアイベントやっています smartcamp.connpass.com 2/21に、スマートキャンプで開催するエンジニア向けのイベントを行います。 採用文脈でイベントのこと書いちゃったけど 管理画面とか、フォームとかを仕事でこねこねしている人はぜひ気軽に来てください🙏🙏🙏🙏🙏🙏🙏🙏
スマートキャンプ20卒エンジニア(現インターン生)の高砂です! 私は先日、応用情報技術者試験に合格致しました! 応用情報技術者試験の受験を検討している方やそれについて知りたい方の参考になればと思い、なぜそれを受験したのか、どのような学習を行ったかをまとめていこうと思います。 受験目的 IT知識の習得 やったこと 学習計画を丁寧に立てた 午前試験は2冊の本を読み込んだ 午後試験は選択領域のみ勉強した 結果 知識だけではなく自信も身に付いた 受験目的 IT知識の習得 「応用情報技術者試験(以下、AP)」とは「情報処理技術者としての知識・技能が一定以上である事を認定する国家試験」である「情報処理技術者試験」の一種です。 「情報処理技術者試験」は10種類以上の試験区分に分かれていますが、APはIT全般に対して応用的な知識・技能をもつ人が対象という位置付けです。 情報処理技術者試験区分 引用元: IPA 独立行政法人 情報処理推進機構:情報処理技術者試験:試験の概要 私がこれを受験した目的は「エンジニアとして働く上でのコミュニケーションに必要なIT知識の習得」です。 私は専門が情報系ではなく知識に乏しい為、インターンをする中で先輩エンジニア達との会話についていけない、もしくは上手く伝えられない事が多々ありました。 先輩エンジニア達に相談した結果、APに合格できるくらいの知識があればそれが解決できるという結論になりました。 なので学習の分かりやすい目標として、AP合格を目指しました! やったこと 学習計画を丁寧に立てた APの試験範囲はかなり広く、特に未経験エンジニアにとってはとてつもなく膨大に感じられます。試験範囲は大きく分けると3ジャンルあり、それぞれ一例としては、 テクノロジ系 アルゴリズム PCの仕組み DB/NW/セキュリティ 開発管理技術 マネジメント系 プロジェクトマネジメント システム監査 ストラテジ系 システム戦略 経営戦略 法務 のような領域が試験範囲です。しかも系列の試験であるITパスポート試験や基本情報技術者試験(以下、FE)と比べると、APはより深い理解が求められるので生半可な学習では合格できません。後述する参考書が800ページを超える事からも、その試験範囲の膨大さが伝わるかと思います。 学習は試験日の約4ヶ月前から始め、最初は参考書をのんびりと読んでいました。 しかしそれでは学習進捗の定量的な測定が出来ずモチベーションも続かない事から、2ヶ月前からはこのようにキッチリ学習計画を立てて進めるようにしました(数字は過去問の目標正解率)。 学習計画(抜粋) 午前試験は2冊の本を読み込んだ 午前試験の勉強についてはまずFEの参考書、次にAPの参考書を使って勉強しました。尚、これらは弊社の「書籍購入無料制度」にて用意して頂きました。 gihyo.jp gihyo.jp なぜ系列試験の方の参考書を用いたのかというと、それはFEもAPと範囲は一緒で、かつ深さは浅いからです。 APは何年か経験のあるエンジニアを主な対象とした試験なので、APの参考書も同様に説明が一部省略されていると感じました。 なので未経験エンジニアとしてはまずFEの参考書で広く浅く学習し、次にAPの参考書で広く深く学習する事にしました。 加えて毎週末に過去問を解き、その正解率で学習進捗の測定を定量的に行いました。 大きい分野ごと学習進捗(抜粋) 大きい分野ごとの正解率で学習計画に対する達成度合いを確認しつつ、小さい分野ごとの正解率でどの分野が自分は苦手なのかを把握する事で、そこを重点的に学習するなど学習計画を修正しつつまんべんなく知識を付けていきました。 小さい分野ごとの学習進捗(抜粋) 午後試験は選択領域のみ勉強した 午後試験は解く問題を選べる為、私は仕事に繋がる5ジャンル(情報セキュリティ、データベース、情報システム開発、プログラミング、プロジェクトマネジメント)を先輩エンジニア達と共に決め、その領域のみ集中的に勉強しました。 午後試験は記述式の設問もある為、午前試験よりも更に深い理解が必要になります。 なので選んだ領域についてはただ学習するだけではなく、見覚えの無い単語がなくなる位、とにかく分からない言葉や仕組みがあれば徹底的に調べるようにしました。 また、これも午前試験と同様に定量的な学習進捗の測定で苦手分野は重点的に学習しました。 結果 知識だけではなく自信も身に付いた これらの学習によって結果的には合格でき、目的であったIT知識の習得も出来ました! ただ正直なところ、学習中はずっと自信がなく、受験後も合格通知が来るまでは合格したとも思えていませんでした…。 しかし「情報処理技術者の国家試験に合格した」という事実が自分に勇気を与えてくれ、先輩エンジニア達とのコミュニケーションも自信を持って行えるようになりました。 APの合格を目指すには多大な努力が必要ですが、それによって得られる「知識」と「自信」は努力が報われるだけの価値が十分にあると感じました! なのでもし受験を迷われていましたら、是非一歩踏み出して欲しいと思っています。この記事がその参考になれば幸いです。
こんにちは。スマートキャンプで https://boxil.jp/ を作っている徳田( @haze_it_ac )こと、とってぃです。 この前 朝会 で、同僚とタコパをして楽しかった話をしたら大学生と言われました。 ご存知の方もいらっしゃるかと思いますが、スマートキャンプは2019年11月にマネーフォワードグループにジョインしました。 boxil.jp グループ間のエンジニア交流の一環として、また、スマートキャンプの収益の主軸でもあるBOXILのことをマネーフォワードの人たちにも知ってもらおう!ということで、BOXILのソースコードや実際の画面を眺めながら、課題を話したり議論をする会を開催しました! BOXILの画面を実際に見ながら説明をする様子 当日はスマートキャンプ、マネーフォワード合わせて20名を超える人数に集まっていただきました。 最初に私が会の趣旨とBOXIL開発チームが感じている現状の課題感やBOXILそのものの概要を説明し、全員でGemfileや、DBのテーブルとカラムを見たり、 途中から4グループに分かれてモブプロの形式でソースコードや画面を見てわいわいしました。 なぜ入っているのかよくわからないGemfileが見つかったり(!)、特定のメンバしか知らない歴史を発掘したり、大変そうなロジックを眺めたりと、とても盛り上がりました。 マネーフォワードとのエンジニア交流は今後も引き続きやっていく予定です!わいわい Meetupの宣伝 smartcamp.connpass.com 2/21(金) にBtoB SaaS エンジニアMeetupの第3回を実施します! 登壇、通常参加どちらもまだまだ空いているので、気軽にご参加ください 🙌
こんにちは。スマートキャンプの中川です! 普段はBiscuet開発チームでエンジニアをしています。 先日1月22日にテックブログの運営にまつわるパネルディスカッション形式でトークするイベント『Tech Blog Night 〜継続的に社外へアウトプットできるチームを作る〜』が開催されました。 lapras.connpass.com LAPRAS両角さん、クックパッド勝間さん、そして弊社スマートキャンプから笹原が登壇し、増席しても参加抽選枠オーバーの人気イベントとなりました。 本記事はそのイベントレポートとして、各トピックごとに各人が話されていた内容を簡単にまとめたものになります! ブログ立ち上げの経緯について(ブログを始めた理由と狙っていた効果は?) テックブログの運用方法(頻度、担当者、記事内容の決め方、社内の調整、メンバーのモチベーション維持など) テックブログにより得られた効果について 過去にあった苦労、失敗について 会場質問 運用担当が頑張っていっぱい書かなきゃいけない問題にはどうしたらいい? KPIはどうしている? ブログを書くことでの評価はどうしている? まとめ ブログ立ち上げの経緯について(ブログを始めた理由と狙っていた効果は?) 勝間さん: テックブログ自体は2008年から立ち上がっていた 勝間さんが入社する前 2008年時点だと社員50名、エンジニア4名の時代 主婦は知っているけどエンジニアにはよくわからない、知名度がないサービスだった 目的としては エンジニアの採用 自分たちのプレゼンスを上げて採用につなげる狙い 勝間さん自身もブログ経由で入社した 採用イベントやります!の告知エントリを見て 当時目新しかったRailsを使ってリニューアルしていてすごいな、と興味があった 笹原: 認知獲得が目的 事業領域がtoBのSaaS、マーケティング、メディアなのでエンジニアが全然スマートキャンプを知らないことが課題だった いかにして認知を獲得していくか? エンジニアブログという手段もあるよね、とはいえなかなか出来ないよねという話は前々からしていた えいやで内部の数人で始めた ドメインを取得してはてなブログのProプランを購入してスタートした 個人的な思いもあった エンジニアとしてブログ書いてみたい、発信してみたいという気持ち 社内にドキュメント書く文化を根付かせたい 知見をブログに投稿する流れが出来ればドキュメント代わりに「ブログのこの記事見て」、という使い方も出来るんじゃないかという仮説があった テックブログの運用方法(頻度、担当者、記事内容の決め方、社内の調整、メンバーのモチベーション維持など) 勝間さん: 2008年スタートだが、何回か執筆が止まる期があった 実は『ブログ盛り上げていくぞ!』号令が今までに4,5回出ている 2009~2011年あたりは人事・広報が主体となって号令をかけてエンジニアが渋々やる、みたいな感じだった 言われたからやる、が定常化していてなかなか根付かなかった そこで、CTOが主導となってエンジニアへのプレゼンス上げるために書こうね!と 当番表 を作った 半期のはじめに当番表のCSVが吐き出されるおみくじプログラムがある 技術側のトップが統制したことがよかった 業務として書きましょう、というスタンスだったのもよかった 評価にも含まれる 盛り上がってきたので最近はエンジニア以外にもサービスディレクターなども投稿している とにかく 書くことが大事だという文化 がある 書いたものに対するチェックとかはない 2週間に1回エンジニア全員が集まるMTGがあってそのなかでテックブログ紹介コーナーがある 書いていれば見てもらえるし書いてなければその場でバレる 笹原: 頻度は週1固定で出している 向こう1ヶ月分は誰がなにを書くか大まかに決めている 一緒に考える・寄り添う姿勢を心がけている とはいえ書けないときはある その場合は中心メンバーが頑張って書いていた チーム全体で書き続けることで文化として定着する 最初は週1で書くのもしんどかったが、12月にはアドベントカレンダーを敢行し書ききれるようにまでなった 最初はインセンティブを用意していた 記事を出しても鳴かず飛ばずだったときにマネージャーにお願いして、 1記事で100ブクマ突破したら寿司100貫奢ってもらう 約束を取り付けた わかりやすいので目標に向かって頑張るようになった ブランディングなどは最初期は何も考えずやってた 時流に乗ったやつは伸びそうだよね、という意識はあった はてブが伸びそうベースで考えていた 最近はエンジニアが普段の業務で何をしているか発信できる記事を出すことも心がけている テックブログにより得られた効果について 勝間さん: 圧倒的に採用(に効果があった) 「クックパッドに興味もったきっかけ」を聞いたときの返答がほぼテックブログになった ここ3年くらい 実際にこうして現象として起こっているからこそ続けていかなきゃね、という雰囲気になっている テックブログが盛り上がってきたことで、あらかじめ仕込んでおいたネタをリリースする流れがでてきた 社内ブログもあるが、そちらは情報を小出しにすることが多い その小出しになった情報がまとまってテックブログの記事として投下される 社内のメンバーはその記事を読んで全容を知る、みたいなことがままある (質問) 1エンジニアが記事を書く頻度は? 年1回くらい 書く順番は自由に交換OK 笹原: 明確なブログ経由での採用はまだない 今まで全く認知がなかったところから、「テックブログやってますよね!」みたいな認知が得られるようにはなってきた エンジニアにドキュメントを書く力がついてきた ブログ以外でもドキュメントを残すようになった ブログに開発プロセスを残すことで、採用面談などの時にその記事を見てもらうことが出来るようになった 実際に公開されている記事を見てもらうことはブランディングの面でも効果があると感じる 過去にあった苦労、失敗について 勝間さん: 良くも悪くもネームバリューがあるブログになってきた 書く敷居がどんどん上がってきている ちゃんと書かないとやばいと思うと書くのが憂鬱になったりする 自然発生した流れとして、 Github Enterpriseでプルリクを作って記事本文をレビューしてもらう 習慣がある メンバー間でレビューする レビューを通さないと不安になるようになってきた 笹原: 最初の立ち上げ期は量的にしんどかった これからはいかにブランディングに貢献していくかを考えないといけない 今までは継続を考えてればよかった これからは記事内容を精査することが必要になってくる 会場質問 パネルディスカッションの内容は以上となります。 以下は参加者の質問を一部抜粋してお送りします! 運用担当が頑張っていっぱい書かなきゃいけない問題にはどうしたらいい? 勝間さん: 当番制度が出来る前は書いてもらうのが難しかった その上で ブログは仕事のひとつ。書かないのは仕事してないと同じことだぞ、とプレッシャーをかける 笹原: 運営が複数人いることはよかった 3人で30記事/年くらい書いたが、1人だったら無理だった 周りをせっつきつつ、自分たちもやると続けられる とにかく投稿に穴を開けないのが大事 開発合宿などがあるときは記事を先に仕込んでおく KPIはどうしている? 勝間さん: 特に決めていなくて、PVやはてブの数も全然みてない 1年の振り返りとしてはてブが多かった記事を執筆した人にアワードを授与する取り組みはやっている 業務としてKPIを追ったりはしない 笹原: KPIはあるが特に追ってはいない はてブ数がKPIになっていて、はてブが多い = バズった とみなせば認知獲得の指標になる 会社のブランディング目線だとKPIも違ってくる オーガニックからの流入も少し見ていた 社内にメディア運用チームがいる どういうタイトルだったらSEOがつよい?みたいなのは社内のメンバーが教えてくれる 取りたいキーワードはタイトルの左に寄せる などテクニックがある ブログを書くことでの評価はどうしている? 勝間さん: 評価内容に社内外でのアウトプットという項目がある テックブログはその手段のひとつ ちゃんとした記事はアウトプットとして評価するし、逆の場合もある ブログ以外の評価対象としてはOSS貢献やイベントの登壇がある 笹原: 制度としてはあまり考えられていない 職位によるイメージ ジュニアであれば「記事を書くこと」となるしシニアであればもっと高い目標になる 通常の評価にプラスとして評価することはあるけど、メイン要素として評価することは現時点ではない まとめ テックブログの運用に関する非常に実践的な内容が聞けて最高でした。 また、その後の懇親会でお話した方のなかにはこれからテックブログを始めようと思っている方も多くいらっしゃっていて、業界としてテックブログを始める機運が高まっているんだなと感じました! 弊社が実際1年間テックブログを運営してみてどうだったか、をまとめた以下の記事も併せてチェックしてみてください! tech.smartcamp.co.jp
スマートキャンプエンジニアの今川( @ug23_ )です。 先週、Regional Scrum Gathering Tokyo 2020にフル参加してきました! 2020.scrumgatheringtokyo.org 本記事では聞いたセッションを中心に考えたことや、 火曜日からやったこと をまとめました。 わたしとRSGT 全スライド 聞いたセッション Day1 keynote: The Ten Bulls of the Scrum Patterns アジャイルコーチ活用術 みなさんのプロダクトバックログアイテムはOutcomeを生み出していますか? 見積りしないスクラム モブプログラミング x 行動分析学 x 教育 特殊部隊SETチームの日常 - 技術と実験を融合した実践アジャイル術 - A Scrum Bookの歩き方 Day2 Keynote: Lost in Translation: The Manager’s Role in Agile チームの再定義 -進化論とアジャイル- Team-Based TEAM - 会社を越えるチーム - Day3 Open Space Technology NEXT→ACTION 全体を通して 火曜日からやったこと まとめ わたしとRSGT 今回の話の前に、私がなぜRSGTが好きなのかを書きます。 RSGT自体は2015年に初参加しています。実はセッションの一部で話すという経験をしていました。 2015.scrumgatheringtokyo.org 大学院のカリキュラムで学生チームで1年間スクラムを実践したところで、話しにきて!というお誘いを受けて教員のみなさんと一緒に登壇させて頂いたのでした。 見たら有料の日があったり、OSTに 実践者向け って書いてあって怖くて初日しかでてなかった、と懐かしい気持ちになりました。当時学生だった私にはこういうコミュニティが強烈に印象にのこりました。 ランチ出るのすごい! XPとかスクラムとかアジャイルとか絡み合ってるんだなー スクラムにはスクラムマスターが必要って聞いたのにスクラムマスターは要らないとか言ってるし 色んな人が居る!なんかメイド服着てる人いるし …というところが強かった思い出。 2016のチケットの高さにビビり、学生でお金なくてやめてしまい、その後はスクラムから離れていたので参加しなくなっていたのですが、2019で久々に参加しました。 2015とはぜんぜん違うな、と思いつつも参加しただけで気持ちが本当にブチ上がって 年越し の感覚を味わいました。OSTで喋ったり、てんちょ(ヤッホーブルーイング井出さん)の話を聞いてチームで仕事しよう!という気持ちになれました。 そんなわけで2020も当然参加だ!と11月の時点でチケットを確保していたのでした。 ちなみにRSGT2020期間中にRSGT2021のSuper Early Birdチケットが発売されましたが買えませんでしたw 全スライド スライドが公開されているものをまとめたエントリをスクラムマスダーさんが公開されていたのでリンクしておきます。 scrummasudar.hatenablog.com 聞いたセッション Day1 keynote: The Ten Bulls of the Scrum Patterns confengine.com 牛?何の話だろう?と思いながら聞いていましたが、十牛図とScrum Patternsの話でした。 www.tees.ne.jp パターンは自己を見つけるための助けになるもの はとても腑に落ちました。私は学生時代4年間裏千家茶道をやっていたのですが、守破離を感じながら稽古をしていました。パターンをなぞって こういうの好き・こういうの楽しいよね というのがわかる感覚が思い起こされました。 一方で、スクラムにおいては自分はどの段階にいるんだろう、と。牛を見つけた?捕まえた?「どの段階にいるか」が大事ではないとはいえ、現在地を把握したいなという気持ちになりました。 余談ですが、同時通訳聞きながらメモ取ってるとやっぱり疲れました。英語で聞きたい気持ちがでてきた。 アジャイルコーチ活用術 slide.meguro.ryuzee.com 冒頭の シャッター音に配慮しようという規範を守りましょう のアナウンスに密かに感銘を受けていました。仕事する上で 規範を守る という意識がしばらくなかったなと感じた瞬間でした。 コーチング とは、というところから選び方まで詳しく解説されていました。確かに、人にコーチングしてもらうならこうだよな、と思う内容でしたが、ほっとくと便利屋さんのように使ってしまいがちなので選ばなければならない時が来たときに見返そうと思った内容でした。 社内ではサイボウズの天野さんにコーチングしていただいていますが、関わり方は間違っていなそうで安心しました。 tech.smartcamp.co.jp みなさんのプロダクトバックログアイテムはOutcomeを生み出していますか? speakerdeck.com ダイヤ という概念が紹介されていました。どんぐらい価値があるの?というのが、金額で測れなかったり、あとで議論したときに忘れがちなので導入したほうがいいときもありそうだと思いました。 Guild Worksさんはいろんな現場を支援されていてすごいな、という感想を持ちました。 見積りしないスクラム speakerdeck.com 見積もりの辛い部分を回避できて、それが有効に回っているのがわかりました。そして前回のRSGTの話から実践してそれを発表している構造自体が素晴らしい点です。 Scrumの5つの価値基準からこの施策の有効性を説明していたのがとてもよかったです! 見積もりをある種のフィードバックシステムかのように考えるのいいなあと思ったりしました。 モブプログラミング x 行動分析学 x 教育 モブプログラミング x 行動分析学 x 教育 from Takuo Doi www.slideshare.net いろんな手段を試してより好子が多く出現するしくみを考えようとする、という内容。 人によってはひとりでのびのびさせて上げるほうがよりよく回るというのが面白いですね。土肥さんは以前から行動分析学の話をされているようなのでこれまでの発表を見返してみようかなと思いました。 特殊部隊SETチームの日常 - 技術と実験を融合した実践アジャイル術 - speakerdeck.com HIROさんが元気に発表しているのをみて安心しました。 一緒に痛い目にあうことで真に必要な支援がわかる というのは横断的なスペシャリストチームに共通する考え方だと思います。SETI的なチームやSREチームのような職能ベースのチームも増えてきていますが、 作ってやったから作れ ではなく、真に必要な支援を必要なだけ、必要としている組織に与えていくのがいいあり方なんだろうなと思いました。 A Scrum Bookの歩き方 ほぼほぼKeynoteの補足のような、Copeとのインタラクティブな会話や質疑が飛び交うセッションでした。 騎郎さんは、A Scrum Bookは 鈍器 レベルだけども、10年かかってスクラムパターンをまとめてきたのでぜひ手にとってほしいとおっしゃっていました。拾い読みしても有用とのこと。英語が…。 Day2 Keynote: Lost in Translation: The Manager’s Role in Agile Lost in Translationは 相互理解の難しさ を描いた映画とのことでした。 組織を変えるにはまずリーダー陣が変わらないといけない、そのためにはまず下位から変わらなければならない。リーダー陣によい気付きを与えられるように、リーダー陣が各メンバーによりよい振る舞いをできるように、やがて組織全体を変革できるように、まずは自分の行動を変えたり、良いものを紹介することから始まるんだなという衝撃を受けました。 いきいきとした仕事 ができるといいな。 アジャイルな組織をつくるためにアジャイルを使おう は良い言葉でした。アジャイルで変化を一気にやることをしないことを覚えたのに、組織改革でそれをやらないの?と言われている感じでしたね。 今週CAL1研修を受けた方はより理解できたのかも。いいなー! チームの再定義 -進化論とアジャイル- 基盤チーム、分割されていたとは。 別プロジェクトにバラバラになってしまったところはBGMもあいまって本当に悲しい気持ちになってしまいました。最終的には 人間としての超個体のありかた をまた模索しはじめたのでやはり基盤チームだなと思いました。 なによりきょんさんの発表のいいところは、考えた仮説をenPiTで学生にやらせてみて効果を実感していて 開発経験のない学生でもできたんだから! といってくれるところだと思います。愛と勇気。 Team-Based TEAM - 会社を越えるチーム - speakerdeck.com いまのプロダクト以外のものを開発しろ、と言われた時、同じチームとして振る舞えるだろうか? と考えるきっかけになりました。プロジェクトチームでなく、プロダクトチームでもなく、チームのためのチームというあり方。 なんか他の発表でも岡田メソッドが引用されていました。他の分野の知識をスクラムとか開発プロセスに持ってくるの大好きなのでどんどん話されてほしい。 Day3 Open Space Technology 半分以上 占いによる人生相談室 をしていました。楽しかった。 スキをみていろんなディスカッションを渡り歩きました。 NEXT→ACTION コミュニティについてみんなで紹介するタイミングで、tddyyχの紹介をしました。 tddyyx.github.io たしかに、2015からするとしっかり活動しているコミュニティは増えましたね。コミュニティとチームと自分、みんなでよりよいやり方を考えていこう、という考え方は目からウロコでした。感動しました。 みんなひとりじゃない、だから事例を共有しあって、それを実践してまた共有して、RSGTのようなコミュニティができるんだなと最高の気分になって帰りました。 火曜日から何する というワードがぐるぐるしてきて、なにをしようか考えていました。 全体を通して いろんなチームでいろんなチャレンジ・実験が行われていて、それを聞いて深く感銘を受けていたと思います。 特にSahotaさん→きょんさん→およべさんの流れは完璧で、Day2はそのままホワイエでゆったりしていました。 自分はチームに何ができるんだろう チームをより良くするための第一歩とはなんだろう そもそもなぜ一緒にいられるんだろう という気持ちになりながら三連休を過ごすことになりました。 火曜日からやったこと チームとしては、 もっとOutcomeを増やせるようにしたい 今まではスキルトランスファーやチームワークを意識して、すべての実装をモブプログラミングでやっていた モブプログラミングが有効だと感じられないタイミングもあり、ある程度ひとりひとりで作業する時間も必要そうだ、と考えが起きている これからより人を増やしてキャパシティ自体を上げていきたい そのためにもどんな人が必要かを定めたい という議論の真っ最中でした。そこで、これらを提案してみました。 MTGによって時間がズレたり、リモートによって場所がズレたりしても意識的にモブを取り入れつつ開発できるようなしくみにしたいね モブプログラミングの有効性について、一旦やめてみることで実験してみよう 人をいれて余裕がなくなるかもしれないけど、技術的な研鑽ができるチームでありたいね 人が入れ替わってもうちのチームらしい部分は残っている気がするけどなんだろうね その後も、採用や開発体制など、チームでどうあるべきか?という議論がたくさんできました。タフクエスチョンを投げたかもな、と思いましたが結果的にチームがより次のステップへ進むための議論のきっかけになったかもしれません。 今のチームはまだまだ歴史が浅いので、いかようにも変容できるけど、それでもうまくいったことを再現できる組織でありたいね、という話ができました。 まとめ RSGT最高でした。実行委員会のみなさまおつかれさまでした。年一でこうして変わりなくイベントがあると これを実践してRSGTで話したい! という願望を持ってやれる気がします。最高のイベントでした。来年もまたギャザギャザしましょう。 スマートキャンプでは、スクラムを実践して改善を繰り返しながらワイワイ開発したいメンバーを募集しています。 hrmos.co https://hrmos.co/pages/smartcamp/jobs/000000093 hrmos.co
明けましておめでとうございます。 スマートキャンプの笹原です。 2020年になったのにまだ引きずってんのかよって思われるかもですが、今回は 2019年のアドベントカレンダー に参加してみてわかったことを振り返っていきたいと思います!!! なぜAdvent Calendarに参加したか 参加のための事前準備 実際の参加状況 数字で振り返るAdvent Calendar ページビュー はてブ Google Discoverからの流入 Google検索からの流入 Qiita内でのメトリクス 心で振り返るAdvent Calendar アンケート 最後に なぜAdvent Calendarに参加したか 結論から言うと、『Advent Calendarに参加してみたかった』が理由になります。 先日公開した記事 にもある通り、このエンジニアブログを始めてから1年が経ちます。 実は、そのエンジニアブログを始めんとする1年前にもAdvent Calendarに参加してみようという話が上がってました。 一番最初にAdvent Calendarがあれば、一気にコンテンツ量が増えて始めて1ヶ月である程度充実したブログになると考えたからです。 とはいえ、以下のような要因から踏み切れずに、年明けからのスタートになりました。 ブログという形でのアウトプット経験の豊富なメンバーがいなかったこと どれくらいの工数がかかるかわからなかったこと どれくらいのリターン(認知度)が得られるかわからなかったこと つまり、Advent Calendarには2018年のときに挑戦しようとしてできなかった因縁があったのです。 そんな苦い思い出(?)から1年が経つうちに、毎週欠かさずにブログを更新し続けたことで自信がついてきました。 そこでですね、今年は違うぞと、10人でも回せんだぞ、というところを魅せるべくAdvent Calendarに参加することにしました。 参加のための事前準備 事前にしておくことは以下の2つです。 Advent Calendarを作る Advent Calendarを埋める Advent Calendarを作る上でよく使われているのは以下の2つのサービスでしょうか。 Qiita Adventar 今回は初めてでもあり、違いもよくわからなかったので技術系に強そう、ということでQiitaにしました。 重要なのは、その次のAdvent Calendarを埋める作業ですね。 埋めるにあたって以下のようなポリシーを定めた上で早い物順で取っていきました。 平日は必須で更新する 休日は出したいお題があれば任意で更新する このようなポリシーにしたのは、エンジニアの数が10人程度のため全日程埋めようと思うと、3記事書かなければならない人がでて来るからです。 実際の参加状況 結果としては、平日は全て埋めたうえで、25日間のうち20日間記事を出しました!! デザイナーにも デザインブログ で協力してもらっているので、このエンジニアブログで出したのは18記事になります。 スマートキャンプ アドベントカレンダー 数字で振り返るAdvent Calendar ページビュー 12月は通常の月の2倍程度のページビューとなりました。 通常の月だと週に1本出しているので、記事の本数に比例するほどには閲覧はされなかったことになります。 ページビューの推移(2019年5月〜2019年12月) この理由としては12月中はAdvent Calendarがあることでホットエントリーなどキュレーションの競争率が激しかったからではと推察してます。 その中でも伸びた記事はあり、いずれも内容・タイトルともに興味をそそられるものだったなと思います。 私はAWS EC2のt2インスタンスを誤解していた - CPUクレジットとベースラインパフォーマンス、そしてT2 Unlimited - SMARTCAMP Engineer Blog 実践して分かったモブプログラミングのメリット・デメリット - SMARTCAMP Engineer Blog はてブ 数字で振り返るAdvent Calendar第2弾ははてブ数です。 最低 最高 平均 2 67 23.4 平均はてブ数が23.4ということで全体平均の40.7 *1 からは少なからず減っていたことになります。 Google Discoverからの流入 続いては、はてブが低迷したなか支えた流入源の一つであるGoogle Discoverからの流入です。 巷でGoogle砲とか呼ばれているやつです。 Search Consoleから閲覧できるDiscoverのパフォーマンス ここからの流入はあまりはてブに影響しなかったりもするので見えづらかったりはするんですが、Search Consoleに登録しておくとSearch Console上で解析できるようになります。 Google検索からの流入 最後もSearch Consoleから取れる情報なのですが、Google検索からの流入です。 記事を増やすことに対して、そこまで変化が急に現れてくるものでもないのですが、前月比で1.6倍位の流入になりました。 Google検索からの流入 1年間で記事を増やしてきたことによって、何かしら記事を投稿したらそれを早い段階でGoogle検索に載せてもらえるようになってきたのかもしれません。 Qiita内でのメトリクス Advent Calendarを載っけていたのはQiitaなので、そちらの状況がどうだったかも書いておきます。 記事自体はこちらのブログに書いているのでいいね数が伸びなかったのは良いとして、購読者も9人に留まりました。 購読していただいた9人の方ありがとうございました!!! Qiita内でのメトリクス 購読者数ランキング上位を見ると納得感もあるのですが、これらの企業に追いつけ追い越せの精神でまだまだブランディングしていかなきゃなと思いました! 購読者数ランキング 心で振り返るAdvent Calendar アンケート Advent Calendarを終えて、参加したみんなに簡単にアンケートを取ってみました。 アンケート① やってみてどうだったか アンケート② 今年もやりたいか 数字で振り返るのほうでも分かる通り、普段ほどはPV等が伸びないのでコスパが悪いと感じている人もいました。 そういったことや、普段の5倍のペースで記事を作らないといけないというところで、全体的にツラさも感じていたようです。 ただ、少人数でやりきったことに達成感を感じていたり、何かしらの学びを得ている人もいました。 最後に 2019年のAdvent Calendarに参加したことをここまで振り返ってきました。 ざっくりまとめると、Advent Calendarに参加してみて以下のようなことがわかりました。 記事の本数が多くなることで全体的なPVは上がるため、認知度は上がる可能性あり 記事あたりのPV数やはてブ数などのメトリクスは普段ほどは上がらない 少人数でもAdvent Calendarに挑戦してやりきることで達成感はあるが、ツラいことはツラい 来年やるかどうかはまだわからないですが、Advent Calendarの頃にはまた何かしらの変化が訪れてるんだろうなと思いワクワクします。 というわけで、本年も宜しくおねがいします! *1 : https://tech.smartcamp.co.jp/entry/tech-blog-retrospective-first-year#%E3%81%AF%E3%81%A6%E3%83%96%E6%95%B0
スマートキャンプエンジニアの瀧川です。 本記事は スマートキャンプ Advent Calendar 2019 - Qiita の25日目の記事です。 このスマートキャンプ エンジニアブログを開設して今日でちょうど1年が経ちました 🎉 1年前のクリスマスに私がオーナーとしてはじめたことですが、長続きしないんじゃないか...採用につながるなんてあるんだろうか...そんな不安を抱きながらのスタートでした。 それが 結果として1年間毎週記事公開、Techブログスコアランキング4位 *1 、イベント登壇オファー *2 などなど大きな成果 を得ることができました。 10人そこそこのメンバーで、これだけの成果を挙げられたはとても貴重な体験で、様々な知見も得られたので、節目となる本記事で出せるものは全て出していこうと思います! なぜエンジニアブログをはじめたか 採用のためのブランディング エンジニア組織や個人の成長 自分の成長 結果としてなにが得られたか PV数 はてブ数 ブランディング ドキュメント力 どうやって数値を伸ばしたのか 記事と流入元の関係を分析 はてブやホットエントリーの仕組みを分析 SEOについて学ぶ どうやって毎週公開を維持したか 寄り添う インセンティブや成果の共有で成功体験の共有 運営側が気合で書く Tips タイトルはバズ狙いよりわかりやすく アイキャッチはあまり数値に影響しない Twitterアカウントとの併用は大変 ブログのデザインはレスポンシブにするほうが良い 最後に なぜエンジニアブログをはじめたか 採用のためのブランディング 1つ目は採用を目的としたブランディング です。 弊社はB2B企業であり、エンジニアの方々が弊社のプロダクト触る機会はとても少なく、 どれくらいな規模のどんなプロダクトを作っている企業なのか といった認知に課題がありました。 具体的には、私たち働くエンジニアとしてはビジネス的にもおもしろく、技術的にもこだわりがあり、やりがいもあるのに、面接などの限られた時間での説明では伝えきれないなと肌で感じていました。 定常的にアウトプットをすることで、説明をする前にある程度の弊社エンジニアに関する情報を持っている状態にしたり、または説明に使う資料として活用できるんじゃないかという発想がきっかけでした。 エンジニア組織や個人の成長 2つ目はエンジニア組織や個人の成長 です。 エンジニアとして技術スキルを向上させたり、新しい技術領域に踏み込んだりすることはとても重要かなと思っているのですが、定常的な業務の中で実現していくのはなかなか難しいと感じていました。 (技術導入の調査工数や共有コストが、プロダクトのフェーズに合わないことはありますよね...) そういったときにブログを書く時間として調査をして公開して共有、良さそうであればプロダクトにも反映といったサイクルが回せればいいなと思いました。 また、誰がどんな技術に興味があるのか、なにをやりたいのかをそこまで知らないなと感じており、メンバーのことを知る機会にもなるかなという思いもありました。 他にも、エンジニアとしてやったことを、正しくわかりやすく文章にまとめる(ドキュメント化)技術は重要であり、それは実際書いて人に見てもらう経験が成長への近道だと思っていて、「ブログにも出せるから」というのがよい口実になってドキュメント文化が形成できればとも思っていました。 自分の成長 3つ目は個人的にエンジニアブログやってみたかったから です笑 2つ目に書いたとおり、アウトプットすることでエンジニアとして成長すると考えてはいたのですが、私個人がやったことを文章にまとめたり、アウトプットするのがとても苦手だったんですよね... なので、採用のため、組織のためというプレッシャーとモチベーションを自分に与えることで、その壁を打ち壊そう!という思いがありました。 結果としてなにが得られたか PV数 PVは基本的にGoogle Analyticsとの連携し取得したデータを見ていました。 以下が開設してから本日までの日別PV数になります。 ※ Google Analyticsより 現時点(2019/12/25)で 累計114,257PV でした。 1月2月数百PVでしたが、4月に記事がバズったりするなかでノウハウが安定し、現在週一の記事公開で9000PVで安定したかなというところです。(月平均9527.58PV, 月最大32,156PV) グラフを見ていただくと、PV数は記事公開日のスパイク(1〜2日でほぼ落ち着く)と定常的なアクセス(現在200PV程度)で構成されているようです。 はてブ数 総はてブ数は現時点(2019/12/25)で2,686 でした。 記事数は66ですので、記事平均40.7となります。 はてブ数トップ3が以下となります。 平成から令和に変わるタイミングで出した企画記事が1位、2位3位はクライアントサイド(Vue.js)記事でした。 tech.smartcamp.co.jp tech.smartcamp.co.jp tech.smartcamp.co.jp ブランディング 大きくブランディングとして成果がではじめたのは、以下の記事で取り上げていただいたあたりかなと思います。 note.com あまり他社ブログなどをベンチマークしていなかったので、エンジニア全員4位という結果に驚きました。 数値として成果がでたということで、モチベーションも上がりましたし、こちらの記事をみて弊社を知ったという方も採用選考の中でいらっしゃいました。 また、イベントの登壇オファーを頂いたりと更にアウトプットの場につながり、当初想定した以上に反響のある取り組みになったなと感じています。 lapras.connpass.com そもそもエンジニアブログを継続する自体が、エンジニアに裁量と熱量がある証明になると考えていたので、そこも達成することができました。 ドキュメント力 当初の目的の1つ、ドキュメント文化の形成もある程度進んだかなと思っています。 例えば、技術的なところだと、AWSのアカウント管理をTerraformでやっているエンジニアが記事に起こして誰でもPullRequest送れるようにしたり *3 、Atomic Designでクライアント設計しているチームが記事を書いて他のチームが参考にしたり *4 といったコミュニケーションをブログを通して起こすことができました。 また面接時の会社紹介などでも、スクラムに取り組んでいること *5 やオンボーディング大事にしていること *6 を引用しながら伝えたりもできるようになってきました。 文章を書く力や意識についても明らかに向上しており、ブログ開始直後はネタ出し、アウトライン作成、文章作成、校正すべてで手伝う必要があったりとコストがかかった覚えがありますが、なんと Qiita AdventCalendar ではなにもせずとも平日全て埋めることができ感動しました(圧倒的感謝!) どうやって数値を伸ばしたのか 記事と流入元の関係を分析 流入元(掲載媒体)によってPV数やはてブ数は大きく変わってきます。 どんな記事がどこから流入しやすいかを分析するのは大事だと感じています。 以下が全体での流入元のサマリとなります。 (direct)は置いておくとして、ホットエントリー、Smartnews、Google検索、Twitter、Chrome(Android)のおすすめ、Google News、その他の順番になっています。 ※ Google Analyticsより訪問者の参照元 これだけ見るとホットエントリーとSmartnews、Google検索の流入が同程度と思われるかもしれませんが、掲載された記事数が異なります。 Smartnewsに大々的に掲載されたのは、以下の4記事でした。(それぞれ単体で3000~7000PV) 新卒Webエンジニアだった頃の自分に教えたいちょっとしたタスクからでも経験値を積んでいく考え方 - SMARTCAMP Engineer Blog 【ありがとう平成】年代別にIT技術まとめてみた - SMARTCAMP Engineer Blog 『エンジニアが自称PMになるまで』をテーマに登壇してきた内容【10分まとめ】 - SMARTCAMP Engineer Blog 無償になったPull Remindersを導入してみた! - SMARTCAMP Engineer Blog なんとなくですが、時流に乗った記事(4月に新入社員ネタ、平成令和ネタ)、話題になってからすぐ試してみた記事(PullReminder記事)はクリックされやすいのかなとは思います。 その他だと、Chrome(Android)のおすすめ記事は割合としては少ないですが、以下に代表される技術を丁寧に解説した記事が載りやすいかなと感じています。 私はAWS EC2のt2インスタンスを誤解していた - CPUクレジットとベースラインパフォーマンス、そしてT2 Unlimited - SMARTCAMP Engineer Blog こういった仮説をもとに記事を書いて、公開して、どうだったかのサイクルを回しながら運営しています(これが結構楽しい) はてブやホットエントリーの仕組みを分析 はてブの伸びと、掲載媒体(ホットエントリーITカテゴリーやホットエントリー総合、SmartnewsやGoogle News)の関係を把握したいと思い、Redashで記事公開からのはてブ推移を出せるクエリを作成しました。 例としては以下になります。 このデータとGoogle Analyticsのデータをあわせて分析し、ある程度の記事公開プロセスを安定させていきました。 (以下はあくまでこういった傾向があるというはなしです) 20時から24時、ホットエントリーに乗っていると、はてブが伸びやすい 6時から9時の間、ホットエントリーに乗っていると、はてブが伸びやすい 記事公開から12時間くらい経過するとホットエントリーから急速に落ちる はてブ数が100を超えるとホットエントリー総合に載って流入が加速する 24時時点で30はてブ程度だと最終的に60はてブくらいで着地する etc... ※ 実際に上記Redash分析用のPythonコードも貼っておきます import requests from datetime import datetime result = {} add_result_column(result, 'url' , '' , 'string' ) add_result_column(result, 'time' , '' , 'integer' ) add_result_column(result, 'count' , '' , 'integer' ) add_result_column(result, 'acc' , '' , 'integer' ) hb_entry = 'http://b.hatena.ne.jp/entry/json/' urls = [ '{{URL1}}' , '{{URL2}}' ] for url in urls: response = requests.get(hb_entry, params={ 'url' : url}).json() # for bm in response['bookmarks']: # add_result_row(result, {'user': bm['user'], 'time': bm['timestamp'], 'comment': bm['comment']}) def round_by_minutes (dt, minutes= 10 ): return dt.replace(minute = int ( round (dt.minute / minutes) * 10 )) dts = [round_by_minutes(datetime.strptime(bm[ 'timestamp' ], '%Y/%m/%d %H:%M' )) for bm in response[ 'bookmarks' ]] first_dt = min (dts) dts = [(dt - first_dt).seconds / 60 for dt in dts] acc = 0 for dt in sorted ( set (dts)): count = dts.count(dt) acc = acc + count add_result_row(result, { 'url' : url, 'time' : dt, 'count' : count, 'acc' : acc}) SEOについて学ぶ 記事流入元の分析やはてブ推移の分析は公開時のバズ(スパイク)を大きくしようという施策ですが、 長期的な技術のブランディングなど考えるとSEOも意識しておく必要 があるかなと考えています。 弊社では幸運なことに、自社メディアも運用しておりSEOに詳しいメンバーも在籍しているため、基礎からテクニックまで手軽に学ぶことができました。 実践できてないものも多いですが、以下に取り組みを紹介しておきます。 タイトルにキーワードを重要なものから左にいれる キーワードの表記ゆれをなくす 目次をいれる(目次で全体が把握できるようにする) 最低文字数1500以上、狙いたいキーワードで検索して一番上に出てくる記事より多いのが理想 URLをカスタムURLにする はてなブログだと/entry/2019/12/25/184533のようになるが、階層が浅く意味のある英単語のほうがよい /entry/engineer-onboardingのようにハイフン区切りの英単語にする Google Search Consoleなどツールを見て改善(リライト)をする 以下を見るとコンテンツ(記事)が増えたこともあり順調に伸びているなと感じています。 伸びしろがたくさんあると思うので、注力していきたいところです。 (現在 aws client vpn とか aws ソリューションアーキテクト といったキーワードが強いようです。インフラ企業ですね) ※ Search Consoleより どうやって毎週公開を維持したか 寄り添う まずは献身的に依頼しているメンバーに手を貸す必要があると考えました。 記事を出すまでのプロセスとしては、 ネタのアイディア出し アウトラインを書く 記事を書く 校正する アイキャッチ作る 公開する のようになります。 やってみると、3. 記事を書くだけでも慣れないとすごく大変なんですよね。 なので、基本的に 3. 記事を書く以外はすべて相談または丸投げして構わないというスタンス にしていました。 あと意識していたのが以下になります 3週間前には執筆依頼する 記事の内容については本人の書きやすいものにする 常にチーム関係なく情報収集し、普段の業務でかけそうなネタ、技術挑戦の提案ができるように心がける 書いてくれたことに感謝して自分でもちゃんと読む インセンティブや成果の共有で成功体験の共有 これが一番大きい理由かもしれません。 3月末にまったく記事が見られず、はてブも1しかつかない、とてもモチベーションが下がっていました。 なんとか打開したいと思い、マネージャーと交渉して、 1記事で100はてブ超えたら、寿司100貫メンバーに振る舞う という約束してもらいました。 そしてなんとそれから三週間後にVue.jsの記事が200はてブを超えてしまいました。 記事が伸びたのは偶然でしたが、メンバー全員で「もしかして寿司いくのか!?」という思いを共有できて 一丸となるきっかけになった のかなと思っています。(CMOの林さんその節はありがとうございました) インセンティブとしてはこの一回だけでしたが(あまりにも早く達成してしまったのでスポンサーが恐れてしまった)、その後も記事がバズったり、noteで紹介頂いたり、幸運にもすべてのイベントを楽しみながら全員でこなせたなと感じています。 運営側が気合で書く 寄り添って、本人のやる気もあるけど、タスク状況的に厳しい...そんなときは仕方ないので運営メンバーで書くようにしていました。 毎週記事公開はブランディングとしても重要ですが、書いてくれるメンバーのよい責任感にもつながっていると感じていたので、そこは死守しようとがんばりました。 ただ、気合で書くのも難しいので、早めに依頼している人のタスク状況や進捗などキャッチして、もしものときは誰がなにを書くかを話合うようにしていました。 Tips タイトルはバズ狙いよりわかりやすく かなり迷いどころなのですが、 バズを狙ったタイトル(煽り文句を入れたり、シャレを混ぜたり)は難しいのでおすすめしません! 記事を書くコストが高いので、冒険するよりも堅実に、端的に内容がわかるものがよいと思います。 アイキャッチはあまり数値に影響しない アイキャッチははじめてから紆余曲折あって、技術ロゴだけ期、著者の顔出し期、デザイナの本気期、いらすとや期とありましたが、 結果的にあまりPVやはてブ数には影響しない と感じています。 (アイキャッチでバズるとかはありえなそう) あまりにも意味のわからない、内輪ネタとかを避けていれば何でもいいかなと最近は思っています。 1つだけ意識していることは、表示する媒体(サイトや端末)によって端が見切れていたりするので、中央に要素を寄せるほうがいいかなと思います。 Twitterアカウントとの併用は大変 運営するなかで、Twitterアカウントを作って記事公開をアナウンスすると、流入が増えるんじゃないかという仮説でやってみました。 しかし、これは特に効果はありませんでした。 おそらく公開のアナウンスだけでなく、フォロワーを増やす施策やバズ狙いツイートなど別のノウハウが必要そうだなと感じました。 ブログのデザインはレスポンシブにするほうが良い はてなブログのカスタムテーマだと、レスポンシブに対応していないものも多くあります。 本ブログ訪問者のデバイス内訳は以下のようになっており、 モバイルが60%以上占めている ので対応しておくほうがよいでしょう。 ※ Google Analyticsより訪問者のデバイス内訳 最後に 1年間のエンジニアブログ運営のまとめを本記事でさせてもらいました。 ざっくりまとめると、真剣にエンジニアブログと向き合って、データを見たり、著者に寄り添ったりすることで以下の目的を果たすことができたということになります! 採用のブランディング ◎ エンジニア組織の成長 ◎ 個人の成長 ◎ 0からはじめて、数値的にも質的にも実感できるほどの成果を挙げる経験はなかなかできないので、とても楽しい1年でした(Google Analyticsとか見るたびにワクワクしていた) 来年はSEOを強化して定常的にPVを獲得したり、特定の技術の記事を厚くしてよりブランディングするとか次のステップに進められればいいなーと思います! 以上で今年の最後の記事は終わりとなります! 1年間ありがとうございました! *1 : https://note.com/chanmoro/n/n4473f2f14a12 *2 : https://lapras.connpass.com/event/155775/ *3 : https://tech.smartcamp.co.jp/entry/2019/01/22/153532 *4 : https://tech.smartcamp.co.jp/entry/2019/08/29/115331 *5 : https://tech.smartcamp.co.jp/entry/first-scurm-summary *6 : https://tech.smartcamp.co.jp/entry/engineer-onboarding