BASE株匏䌚瀟のブログ - TECH PLAY

TECH PLAY

BASE株匏䌚瀟

BASE株匏䌚瀟 の技術ブログ

å…š616ä»¶

この蚘事はBASE Advent Calendar 2020の16日目の蚘事です。 devblog.thebase.in はじめに こんにちは。BASE株匏䌚瀟フロント゚ンドチヌムに所属しおいる田䞭です。 こちらの蚘事にもあるように、BASEではここ䞀幎匱の間、リモヌトワヌクメむンの働き方でした。 devblog.thebase.in そんな䞭、数ヶ月前にスタヌトしたあるプロゞェクトに、私含め2名のフロント゚ンド゚ンゞニアがアサむンされたした。アサむンされた方はその月にJoinされたばかりの方だったこずず、プロゞェクトスタヌト時は私が別のプロゞェクトを䞊行しお進めおいたこずもあり、メむンで関わるこずができおいないプロゞェクトに察しお、䜕かよいアプロヌチはないだろうかず暡玢しおいたした。その1぀の手段ずしお、実隓的にモブプログラミングをやっおみた様子をご玹介したいず思いたす。 事前に行ったこず モブプログラミングに぀いおおおたかな抂芁を知っおおく 必芁な情報の共有 珟圚進行䞭のプロゞェクトで取り組めそうなタスクをピックアップし、仕様抂芁やデザむンずずもに共有 䜜業䞭のブランチを共有し、ロヌカルで動く状態にしおおいおもらう 今回私以倖の他のメンバヌはモブプロをやるぞず蚀っおモブプロをやったこずはあたりなかったそうですが、気づいたらその状態になっおいたこずはあったずいうこずでした。私自身はモブプロを党く経隓したこずがなかったため、モブプロの抂芁に぀いお、どのような圹割があるのかや、実斜したレポヌト蚘事などを読んでおきたした。 実斜抂芁 メンバヌは3名 プロゞェクトメンバヌのフロント゚ンド゚ンゞニア2名、プロゞェクトメンバヌではないフロント゚ンド゚ンゞニア1名 時間は各回60~90分皋 タむピスト1名ずモブタむピスト以倖を時間亀代制 党員リモヌトワヌクでの実斜だったため、タむピストが゚ディタずブラりザを画面共有する圢匏 メンバヌ数に関しおは、プロゞェクトメンバヌだけのペアプロでも良かったのですが、実隓的にプロゞェクト倖のメンバヌずもやっおみたいず思い3名で行いたした。 結果ず所感 進め方に぀いお リモヌトずなるず亀代時にpushやpull、開発環境を敎える時間などがある皋床かかった。 今回プロゞェクトメンバヌ2名ずプロゞェクトメンバヌではない方1名での実斜で、実斜前は仕様の共有や前提条件の説明などが難しいかもしれない、ずいう懞念があったが、倧きな問題はなく進められた。 時間の区切りが難しく、ある皋床キリのよいずころで亀代ずはいえもう少し ず延長しおしたいがちだった。 時間配分に぀いおは改善の䜙地がありそう。 プロゞェクト倖のメンバヌも含めたこずの懞念に぀いおは、どちらにせよ担圓プロゞェクト倖のものもチヌム内でコヌドレビュヌを行うずいうこずず、むしろその堎でコヌドを芋ながら説明し、レビュヌが行われおいるような状態になるため、コヌドレビュヌの効率化にも繋がりそうだなず思いたした。たた、フロント゚ンド開発ではブラりザず゚ディタずデザむンを行き来するが、ディスプレむ枚の堎合は画面共有で埋たっおしたうのでモブの圹割の堎合は難しそうず感じた。 心理的な面に぀いお コヌドず䜜業を共有するこずでチヌムで働いおいる感を感じられたずいう意芋が出た 新しく入ったメンバヌぞのオンボヌディング的に行うのも良さそうずいう意芋も リモヌトワヌク環境䞋で、ただ盎接䌚ったこずがないメンバヌずも仕事を進める䞭で、䞊蚘のような意芋があり実斜しお良かったです。新しく入ったメンバヌに関しおも、タむピストの圹割であれば、モブに指瀺されたこずをタむピングし぀぀、分からないこずをその堎で質問できるずいう環境になるのでよさそうですね。 タスクに぀いお 今回甚意しおいたタスクが比范的小芏暡の単玔なコンポヌネント䜜成やAPI連携だったため、いく぀かタスクを終わらせるこずはできた。 正盎各回䜜業できた量はそこたで倚くはなかった。 タスクの数や難易床に関しおは、あたり最初からやり方を固めすぎず、ゆるく始めお改善しおいければいいなず思っおいたので、今埌ある皋床の回数を実斜し、慣れおくればこなせるタスク数は自然ず増えおいくのではないかなず思いたした。今埌は詊行錯誀が必芁な耇雑なタスクに取り組んでみるのもおもしろそうです。 その他 タむピストは自分の意志を反映させずにモブに蚀われたずおりタむピングするだけずいう圹割になれるコヌドを客芳的に芋るこずができ、察象箇所以倖のずころたで思考をめぐらせるこずができたずいう意芋があり、新鮮でした。たた、バック゚ンド゚ンゞニア、たたぱンゞニア以倖の方がオブザヌバヌ的に参加するのもよさそうずいう声もありたした。 たずめ 新メンバヌも倚い䞭のリモヌトワヌク環境䞋で、プロゞェクトを円滑に進めるための取り組みずしお、フロント゚ンドメンバヌ数名でモブプロを実斜しおみたした。ただ数回しか実斜できおおらず、よりよい進め方は暡玢䞭ですが、今埌定期的に実斜し改善を重ねおいくこずで質を䞊げおいけたらず思いたす。 明日は、情シスチヌムの猪股さんです もしBASEで働くこずに興味を持っおいただけた方は、ぜひご連絡ください 採甚情報はこちらから
この蚘事はBASE Advent Calendar 2020 15日目の蚘事です。 devblog.thebase.in こんにちは、Native Application Groupの倧朚です。最近React.jsを䜿ったフロント゚ンドアプリケヌションの開発に取り組んでいたすが、プロゞェクトをmonorepoで管理しおいたす。 今回は、monorepo管理にしたはいいが、Visual Studio Code゚ディタヌ(以䞋vscode)で、TypeScriptのモゞュヌルのautoimportのパス解決に悩たされおやったこずを、Next.jsずいうReact Frameworkを䜿った䟋でご玹介したす。 Monorepo? monorepoは、次のうち1぀たたは耇数圓おはたる堎合に採甚するのが効果的かず思いたす。 Web/ネむティブなど耇数プラットフォヌムのアプリケヌションが存圚 メむン/管理画面など同じデヌタ゜ヌスにアクセスする別々の圹割を持぀耇数のアプリケヌションが存圚 それらのアプリの実行環境に䟝存せず同じように利甚する機胜が存圚 API Clientや共通UIコンポヌネントなど特定アプリの環境に䟝存しない独立した共有する機胜 最埌の 実行環境に䟝存せず同じように利甚する機胜 ずいうのは、過去に曞いた ガワネむティブアプリ(Creator)を、React Nativeで眮き換えおみおの䞀幎間戊いの蚘録 で、React Nativeの耇数の実行環境を共存する詊みで玹介したした。 さお、フロント゚ンドアプリケヌション開発で適切に機胜分割したパッケヌゞを、manyrepoなど機胜ごずにリポゞトリが分割されたものではなく、monorepoで管理する利点はなんでしょうか? Guide to Monorepos for Front-end Code ずいう蚘事によるず、次の5぀が挙げられおいたす。 党おの蚭定ずテストを䞀぀の堎所で 䞀連の関連するコミットをたずめおグロヌバルに機胜を簡単にリファクタリング 簡略化されたパッケヌゞのバブリッシング より簡単な䟝存関係管理 分離された状態を維持したたた、共有パッケヌゞのコヌドを再利甚可胜 1.は運甚の話で、パッケヌゞごずにCIやテストの構成を䞀぀にしおおけば、それらの蚭定を远加する必芁はなく、すぐに起動するこずが可胜ずなりたす。 たた、4.ず5.の話の意味するずころは、䟝存関係を適切に保おるし、新たにパッケヌゞをmonorepo内に远加しおも、共有パッケヌゞを参照するこずが簡単になるずいうこずです。 Multi-root Workspace vscodeの Multi-root Workspaces は、耇数のプロゞェクトフォルダヌをたずめお操䜜できる機胜です。 蚘事の解説によるず、manyrepoのような機胜ごずにリポゞトリが分割されたものに察しお有効な機胜であるずいう認識をもちたすが、今回は次のようなフォルダヌ構成を持぀monorepoに適甚したした。 . ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .prettierrc ├── .stylelintrc ├── .vscode/ │   └── settings.json ├── README.md ├── multi-root-ts-monorepo.code-workspace ├── package.json ├── packages/ │   ├── admin/ │   │   ├── .vscode/ │   │   │   └── settings.json │   │   ├── next-env.d.ts │   │   ├── next.config.js │   │   ├── package.json │   │   ├── pages/ │   │   │   ├── _error.tsx │   │   │   └── index.tsx │   │   └── tsconfig.json │   ├── storybook/ │   │   ├── .storybook/ │   │   │   ├── addons.js │   │   │   ├── config.js │   │   │   └── preview-head.html │   │   ├── package.json │   │   └── stories/ │   │   └── Button.stories.js │   ├── ui/ │   │   ├── dist/ │   │   │   ├── components/ │   │   │   ├── constants/ │   │   │   ├── hooks/ │   │   │   ├── index.d.ts │   │   │   └── index.js │   │   ├── package.json │   │   ├── src/ │   │   │   ├── components/ │   │   │   ├── constants/ │   │   │   ├── hooks/ │   │   │   └── index.ts │   │   └── tsconfig.json │   └── web/ │   ├── .vscode/ │   │   └── settings.json │   ├── next-env.d.ts │   ├── next.config.js │   ├── package.json │   ├── pages/ │   │   ├── _error.tsx │   │   └── index.tsx │   └── tsconfig.json └── yarn.lock 26 directories, 37 files monorepo内には、4぀のパッケヌゞが存圚したす。 - admin: 管理画面のNextアプリケヌション - storybook: 共有UIコンポヌネントに察するStorybook - ui: Nextアプリケヌションで利甚する共有UIに関するコヌドを管理するパッケヌゞ - web: 本䜓のNextアプリケヌション これら䞀぀䞀぀をworkspaceに远加するず、゚ディタヌのファむル゚クスプロヌラヌでは次のように芋えたす。 なぜ、monorepoにこの機胜を適甚するの? ずいう話ですが、monorepoプロゞェクト党䜓のvscodeの蚭定(workspace蚭定)の他に、それぞれのフォルダごずにvscodeの蚭定をカスタマむズできるようになりたす。それによっおvscodeの機胜を利甚するのにいく぀か利点があり、特にvscodeのautoimportに関しお助かったので、玹介しおいきたす。 vscodeのautoimport vscodeでTypeScript/JavaScriptファむルにコヌドを蚘述しおいるず、次のようなサゞェストが衚瀺されるこずがありたす。 サゞェストを適甚するず、䞋蚘のように参照先を自動でimportしおくれたす。 import * as React from 'react' ; // **↓自動で挿入** import { SIZES } from '../../constants' ; export const useSize = ( size: keyof typeof SIZES ) => { const [ value , setValue ] = React.useState < number >(); React.useEffect (() => { setValue ( SIZES [ size ] ); } , [] ); return value ; } ; この自動むンポヌトなのですが、vscodeの蚭定ファむルに次の蚭定を远加するこずにより、サゞェストされるパスに倉化が生たれるこずになりたす。 " typescript.preferences.importModuleSpecifier ": " auto " 蚭定倀は党郚で3぀ありそれぞれ䞋蚘の通りです。 蚭定倀 説明 auto むンポヌト パス スタむルを自動的に遞択したす。 non-relative jsconfig.json / tsconfig.json で構成されおいる baseUrl に基づきたす。 relative ファむルの堎所を基準にしたす。 䞊のコヌド䟋は、アプリケヌションからラむブラリのように利甚する共有パッケヌゞの実装コヌドでしたが、 Nextアプリケヌションのパッケヌゞではどのようにこの機胜を利甚するのが良いでしょう? アプリケヌションパッケヌゞの䟋 アプリケヌションでは耇数のパッケヌゞを組み合わせお倚くのコヌドを実装するため、フォルダヌ階局が深くなりがちです。そのため盞察パスでimportするずいう蚭定だず、import文が長くなる可胜性があり奜たしくありたせん。たた、リファクタリングの際に゜ヌスファむルの配眮を頻繁に移動する可胜性もあり、階局がズレるずimport文にある盞察パスの ../ を増やしたり枛らしたりする䜜業が発生したす。 それに察する解決案の䞀぀ずしおは、モゞュヌルバンドラヌず tsconfig.json の paths を䜿うずいうものです。 Nextでは、Webpackずいうモゞュヌルバンドラヌを䜿っおいるため、Webpackの機胜 resolve.alias を利甚しお、パスのaliasを䜜成するこずができ、指定するimportパスを柔軟に倉曎するこずができたす。 const withPlugins = require('next-compose-plugins'); const withTM = require('next-transpile-modules'); module.exports = withPlugins( [ withTM(['@multi-root-ts-monorepo/ui']), ], { reactStrictMode: true, webpack(config, options) { // [...] config.resolve.alias['~web/i18nextConfig'] = path.join( __dirname, 'i18next.config.js' ); config.resolve.alias['~web/defaultConfig'] = path.join( __dirname, 'default-config.js' ); config.resolve.alias['~web'] = path.join(__dirname, 'src'); return config; } } ); 次に、この゚むリアスをTypeScriptで䜿えるように tsconfig.json の paths にも定矩するようにしたす。参照先のルヌトが必芁なため、 baseUrl も䜵せお指定したす。 { "extends": "../../tsconfig.json", "compilerOptions": { "target": "es5", "lib": ["es2016", "dom", "dom.iterable", "esnext", "webworker"], "noEmit": true, "jsx": "preserve", "baseUrl": ".", "paths": { "~web/i18nextConfig": ["i18next.config.js"], "~web/defaultConfig": ["default-config.js"], "~web/*": ["src/*"] } }, "exclude": ["node_modules"], "include": [ "next-env.d.ts", "**/*.ts", "**/*.tsx", "../../@types/worker-loader/index.d.ts" ] } この゚むリアスを利甚するこずによっお、盞察パスや゜ヌスコヌドを栌玍したフォルダヌの倖のパッケヌゞルヌトにある i18next.config.js のようなファむルの実際のパスを、隠蔜するこずが可胜ずなるわけです。 // 盞察パスの代わりに゚むリアスを䜿う䟋 import { FC , FormHTMLAttributes } from 'react' ; import { FormProvider , UseFormMethods } from 'react-hook-form' ; //import { FormDevTool } from "../../lib/react-hook-form/devtool"; <- この代わりに゚むリアスを䜿う import FormDevTool from '~web/lib/react-hook-form/devtool' ; type FormProps = { // eslint-disable-next-line @typescript-eslint/no-explicit-any methods: UseFormMethods < any >; } ; type Props = FormHTMLAttributes < HTMLFormElement > & FormProps ; const Form: FC < Readonly < Props >> = ( { id , methods , children , onSubmit , className , } ) => ( < FormProvider { ...methods } > < FormDevTool control = { methods.control } / > < form id = { id } className = { className } onSubmit = { onSubmit } > { children } < /form > < /FormProvider > ); export default Form ; // `src/` フォルダヌを跚いだ䜍眮にあるファむルのimportで `src/`を隠蔜する䟋 import { useTranslation } from '~web/i18nextConfig' ; import Editor from './editor' ; type Props = { editorName: EditorName ; onDismiss?: () => void ; } ; const CheckoutEditModal: FC < Props > = ( { editorName , onDismiss , } ) => { useKeydown ( 'Escape' , onDismiss ); const { t } = useTranslation (); vscodeの蚭定 さお、アプリケヌションパッケヌゞにおいお、柔軟にimportパスを蚭定できるこずは説明したしたが、結局vscodeの蚭定に぀いおあたり觊れおおりたせんでした。 フロント゚ンドのmonorepoプロゞェクト構成で、パッケヌゞのimportがどう動いお欲しいのかをたずめたすず、次の通りです。 1. monorepo内の他のパッケヌゞをimportする際には、npmの他のラむブラリず同じく、 package.json に定矩した name でimportパスが解決される { "name": "@multi-root-ts-monorepo/ui", // [...] } // 参照するパッケヌゞのnameで解決 import { Button } from '@multi-root-ts-monorepo/ui' ; import * as React from 'react' ; const App: React.FC = () => { return ( < div > Hello , World ! < Button onClick = { () => null } m = {[ '0' , '0 1rem' ]} label = "a test button" > Test ! < /Button > < /div > ); } ; export default App ; 2. 共有パッケヌゞ内に属する゜ヌスファむル同士のimportは、盞察パスでimportが解決される import * as React from 'react' ; // 同じパッケヌゞ内の゜ヌスファむルの盞察パスで解決 import { SIZES } from '../../constants' ; export const useSize = ( size: keyof typeof SIZES ) => { const [ value , setValue ] = React.useState < number >(); React.useEffect (() => { setValue ( SIZES [ size ] ); } , [] ); return value ; } ; 3. アプリケヌションパッケヌゞ内の゜ヌスファむル同士のimportは、webpackを利甚するため、゚むリアスでimportが解決される import { FC , FormHTMLAttributes } from 'react' ; import { FormProvider , UseFormMethods } from 'react-hook-form' ; // 盞察パスの代わりに゚むリアスを䜿う import FormDevTool from '~web/lib/react-hook-form/devtool' ; type FormProps = { // eslint-disable-next-line @typescript-eslint/no-explicit-any methods: UseFormMethods < any >; } ; type Props = FormHTMLAttributes < HTMLFormElement > & FormProps ; const Form: FC < Readonly < Props >> = ( { id , methods , children , onSubmit , className , } ) => ( < FormProvider { ...methods } > < FormDevTool control = { methods.control } / > < form id = { id } className = { className } onSubmit = { onSubmit } > { children } < /form > < /FormProvider > ); export default Form ; 1.に関しおは特別な蚭定は必芁ないため考えるこずはないのですが、2.ず3.に関しおは異なるimportパスを解決する必芁があるため、党䜓ず個別の蚭定を適切に定矩する必芁がありたす。 Multi-root Workspacesを利甚するず、党䜓のworkspace蚭定ず個別に远加したフォルダヌごずの蚭定の2皮類の蚭定を定矩するこずができたす。3.の堎合、webpackずいうモゞュヌルバンドラヌのサポヌトが必芁なこずから、2.の方匏を党䜓で蚭定、3.の方匏を個別に蚭定するのが良さそうずいうこずで出来䞊がったのが次の蚭定です。 党䜓のworkspace蚭定(multi-root-ts-monorepo.code-workspace) 2.の方匏を優先する蚭定を远加 { " folders ": [ { " name ": " project-root ", " path ": " . " } , { " path ": " packages/admin " } , { " path ": " packages/storybook " } , { " path ": " packages/ui " } , { " path ": " packages/web " } ] , " settings ": { " typescript.tsdk ": " ./node_modules/typescript/lib ", // 盞察パス方匏 " typescript.preferences.importModuleSpecifier ": " relative ", " typescript.preferences.importModuleSpecifierEnding ": " minimal ", " eslint.alwaysShowStatus ": true , " eslint.packageManager ": " yarn ", " eslint.validate ": [ " javascript ", " javascriptreact ", " typescript ", " typescriptreact " ] , " editor.codeActionsOnSave ": { " source.fixAll.eslint ": true , " source.fixAll.stylelint ": true } } } } アプリケヌションパッケヌゞでの個別蚭定(settings.json) "non-relative" を指定するず、monorepo内の他パッケヌゞのimportパスたでも、 "baseUrl" からみた盞察パスに倉曎されおしたうようなので、 "auto" を蚭定。 実際に詊しおみたずころ、importしようずしおいる゜ヌスファむルが、芪フォルダたでの䜍眮にある堎合は盞察パスが遞択され、それ以䞊に離れおいる堎合は、゚むリアス蚭定が優先されるようです。 { "typescript.preferences.importModuleSpecifier": "auto", } その他考慮すべきこず はじめの方に玹介した Guide to Monorepos for Front-end Code で出おきた「党おの蚭定ずテストを䞀぀の堎所で」に関連する話です。 䞊の説明に埓い、テスト実行環境やESLint環境は、パッケヌゞが増えおも远加蚭定しなくおもいいように、プロゞェクトルヌトに甚意しおいたした。そのため、これらのツヌルからはWebpackで定矩した゚むリアスなどを認識できるように远加蚭定が必芁ずなりたす。 テストやESLintのために必芁な远加蚭定 Webpackで定矩した゚むリアス蚭定が、プロゞェクトルヌトからみたら䜕凊にあたるのか認識できるようにするようにする必芁がありたす。 { "extends": "./tsconfig.base.json", "compilerOptions": { "baseUrl": ".", "paths": { "~web/i18nextConfig": ["packages/web/i18next.config.js"], "~web/defaultConfig": ["packages/web/default-config.js"], "~web/*": ["packages/web/src/*"] // [...] } }, "exclude": ["**/dist", "**/build", "node_modules"] } たずめ アプリケヌションの開発に必ずしも必芁ではないが、開発効率に倧きく貢献する機胜が提䟛されおいるこずを知るこずは重芁だなず改めお思いたした。たた良さそうな機胜を芋぀けたら玹介しおいきたいず思っおおりたす。 明日は、フロント゚ンドチヌムの田䞭さんですお楜しみに 参考 ガワネむティブアプリ(Creator)を、React Nativeで眮き換えおみおの䞀幎間戊いの蚘録 Guide to Monorepos for Front-end Code Multi-root Workspaces
この蚘事はBASE Advent Calendar 2020の14日目の蚘事です。 devblog.thebase.in こんにちは。BASE株匏䌚瀟 デザむンチヌムの北村( id:lllitchi ) です。 「BASE」は今幎の10月に、デザむン線集機胜のフルリニュヌアルを行いたした。 binc.jp baseu.jp デザむン線集はサヌビスリリヌス圓初からほが改修されず、「BASE」の管理画面の䞭でもかなり叀いUIの画面でした。ショップデザむンを䜜るメむン機胜であるにもかかわらず、倚すぎる課題を抱えおいたため、なかなかフルリニュヌアルが行えなかった機胜です。 今たで関わった改修のなかでも最長の開発期間になったこのデザむン線集リニュヌアルの、どんな郚分が倧倉だったかをプロゞェクトに関わった人間の目線で振り返っおみようず思いたす。 HTML線集Appず、ショップテヌマの関係 「BASE」のショップデザむンは、いく぀かあるオフィシャルテヌマから奜きなものを遞択しお、自分のショップデザむンに反映するこずができたす。たた、「 デザむンマヌケット 」でデザむナヌが制䜜した高品質なテヌマをお手ごろな䟡栌で賌入するこずもできたす。 さらに、「BASE」の拡匵機胜である「 HTML線集App 」ずいうAppを提䟛しおおり、このAppをむンストヌルするず、利甚しおいるテヌマのHTMLずCSSを盎接自由に線集できるようになりたす。 デザむン線集が抱えおいた、倚すぎる課題 課題1: 「HTML線集 App」で線集したテンプレヌトは曎新するこずができない 「HTML線集 App」でテヌマを利甚するず、前述のずおり、テヌマのHTMLずCSSを盎接自由に線集できるようになりたす。オヌナヌさんには、ショップのトップペヌゞにバナヌを配眮したり、ナビゲヌションにブランドサむトぞのリンクを远加したりず、さたざたな甚途で利甚しお頂いおたした。 ですが、 床でもコヌド倉曎をしおしたうずBASEによるショップペヌゞの曎新Appをふくむ新芏機胜の远加、䞍具合修正などが自動で適甚されず 、オヌナヌさん自らメンテナンスをしなくおはいけないずいう倧きな問題点を抱えおいたした。 最近では、商品にギフトラッピングや名入れオヌダヌなどを远加できる「 商品オプションApp 」や、商品ペヌゞに動画やスラむドショヌなどの衚珟を远加できる「 商品説明カスタム 」ずいった、ショップ情報の充実に圹立぀Appがリリヌスされおいるのですが、こういった新芏機胜も远埓できなくなっおしたいたす。 Appを利甚したい堎合、テヌマを遞び盎しおむチから再線集する必芁があり、オヌナヌさんにはずおも倧きな負担になっおいたした。 課題2: HTML線集せざるを埗ない、シンプルすぎるショップテヌマ 「BASE」が提䟛しおいるオフィシャルテヌマは、必芁最䜎限のナビゲヌションず画面があるだけの非垞にシンプルなペヌゞ構成になっおいたす。ブログや商品怜玢やカテゎリヌ衚瀺を利甚したいオヌナヌさんは、「BASE Apps」で機胜を远加するずいうのがBASEのショップテヌマの䜜りになっおいたす。 さらに、蚭定できるデザむン項目は「ロゎ」ず「背景」ず「ナビゲヌションカラヌ」のみずいう自由床の少なさでした。ちょっずした工倫にも、HTML線集Appの利甚が必芁でした。 課題3: サポヌト業務の圧迫 蚭定できる項目が少なすぎるため、ショップのブランド衚珟を高めるためには、前述のようにHTML線集Appを利甚しお盎接テヌマを線集せざるを埗ない䜜りになっおいたす。ですが、気軜にむンストヌルできるずはいえ、すべおのショップオヌナヌさんがHTMLやCSSを䜿いこなせるわけではありたせん。 基本的なサポヌトやリファレンス・ヘルプはほがなく、CSには日々テヌマ線集に関する問い合わせが届いおいたした。䞻にフロント゚ンドチヌムずデザむンチヌムがこのお問い合わせぞ察応しなければならず、日々の業務を圧迫するずいう倧きな課題も抱えおいたした。 課題4: PC衚瀺甚のテヌマずスマヌトフォン衚瀺のテヌマ オフィシャルテヌマはレスポンシブ察応されおおらず、 PC衚瀺甚のテヌマずスマヌトフォン衚瀺のテヌマが別々で甚意 されおきたした。スマヌトフォン甚のテヌマはもずもずHTML線集Appに察応しおいないため、スマヌトフォン甚のテヌマは独自で開発されおきたした。 スマヌトフォン甚テヌマ独自機胜の䟋 䟋えば、スマヌトフォンでは「最近チェックした商品」や「関連商品」の欄が衚瀺されたすが、PCでは衚瀺されたせん。PC衚瀺ずスマヌトフォン衚瀺では情報に差異が生たれおしたい、ショップのブランディングを統䞀するのが難しくなっおいたした。 HTML線集Appずいう倧きな足かせ 自由床の少なさをHTML線集Appでカバヌしおいるが、HTML線集を利甚するず新芏機胜のアップデヌトに远埓できない ずいう負のルヌプをBASEのショップデザむンはずっず抱えおいたした。 手軜に線集できる機胜ずしおHTML線集Appを提䟛しおいる以䞊、長幎積み䞊げた負債を返枈しなければなりたせんでした。 新しいデザむン線集が目指したこず 新しいオフィシャルテヌマ 今たでの「BASE」のデザむン線集に欠けおいた、「倚様なデザむン遞択肢」を提䟛するこず、HTML線集Appに頌らなくおも「盎感的な操䜜」で誰でもかんたんにむメヌゞ通りのショップをデザむンできる機胜を目指したした。 特にデザむンの䞊で倧倉だったのは、テヌマのレむアりトを新しく刷新するこずです。既存のオヌナヌさんがスムヌスに移行できるように、レむアりトは既存を螏襲し぀぀、より利甚シヌンが分かるようなクリ゚むティブにアップデヌトしたした。オフィシャルテヌマはデザむンチヌムのみんなに手䌝っおもらっお、以前の倍のテヌマ数を甚意するこずができたした。 すべおのオフィシャルテヌマがスマヌトフォン察応デザむンに 新しいオフィシャルテヌマ 無料で利甚できるオフィシャルテヌマが、すべおスマヌトフォン察応デザむンずなりたした。ショップデザむン機胜からデザむンした内容は、スマヌトフォンペヌゞ・PCペヌゞに同時に反映されたす。 ノヌコヌドで盎感的にデザむンを線集 「ショップデザむン機胜」では、HTMLやコヌドの線集を必芁ずせず、ノヌコヌドで盎感的に線集するこずができたす。 さらに、フォントの倉曎や、ナビゲヌションの远加や䞊び替え、「BASE」以倖のサむトURLの远加など、今回新たに远加した線集機胜も党お無料で利甚するこずができたす。 たた、お知らせやピックアップ商品、スラむドショヌやSNSアむコンなど、20皮類以䞊あるパヌツの䞭から必芁なものをネットショップに远加するこずが可胜です。パヌツを远加する䜍眮も調敎できるので、䌝えたい情報や商品などの構成をご自身で決めるこずが可胜です。 「HTML線集 App」をアップグレヌド 「HTML線集 App」を、より本栌的なショップペヌゞ制䜜にも察応できる゚ディタにアップグレヌドしたした。新しい「HTML線集 App」は、画面党䜓を䜿っおのコヌディングずプレビュヌができるようになり、倧芏暡な線集もより快適におこなうこずができるようになりたした。 テキストの倉曎や画像の远加など、デザむンパヌツを掻甚しお手軜にデザむンをおこないたい堎合は、「ショップデザむン機胜」を。専門知識を掻かしお本栌的な線集をおこないたい方は、「HTML線集 App」を、ず目的に応じお䜿い分けおもらうような機胜ずしお提䟛しおいたす。 ショップテヌマをリニュヌアルしお 結果的に長期プロゞェクトにはなりたしたが、今埌の「BASE」のショップデザむンにおいお負債になっおいる郚分を解決できる開発に関わるこずができたこずの達成感は倧きく、1幎間このプロゞェクトに携われおよかったなず思っおいたす。 去幎のアドベントカレンダヌでも自瀟の開発に぀いお振り返ったのですが https://devblog.thebase.in/entry/2019/12/13/110000_1 、過去の開発においお、そのずきにくだした意思決定は圧倒的に正しくおあずから状況が倉わっおそれが最適ではなくなるこずももちろんありたすが、珟圚のBASEはそれを積み重ねおきた結果なんだなず思っおいたす。 デザむン線集リニュヌアルの開発のさなか、コロナの圱響で匊瀟も党瀟員がリモヌトワヌクぞ移行したした。プロゞェクトの「Times」チャンネルを䜜り、日々の雑談もOKずいうチャンネルを䜜っお積極的にオンラむンコミュニケヌションを取ろうずいう斜策をおこなったずころ、30日でのチャット投皿数が党チャンネル内でも2䜍ずいう結果になり、リモヌトであっおもこのプロゞェクトを進めおいく熱量のようなものを感じられお、個人的にずおも良かったです。 1ヶ月間のSlackチャンネル投皿数 新しいデザむン線集、ぜひ觊っおみおください。 明日はネむティブアプリチヌムの roothy さんです
前眮き この蚘事はBASE Advent Calendar 2020 13日目の蚘事です。 devblog.thebase.in こんにちは、BASE株匏䌚瀟 Product Dev Division でバック゚ンド゚ンゞニアを務めおいる元朚です。 以前、瀟内で同僚の゚ンゞニアず話しおいたずき、 「TDDっお頭では分かっおいるけど、テストから曞くっおなかなか難しいよね」 ずいう話がありたした。 そこで、自分がTDDでプログラムを曞くずきに行なっおいるTips的なものを玹介しおみたいず思いたす。 あくたで 「自分はこういう感じで実践しおいる」 ずいうものであり、 「これが正しいTDDだ」 ず䞻匵するものではありたせんので、軜い気持ちで読んでいただけたら幞いです。 そもそも、TDDずは テスト駆動開発 (Test Driven Development) のこずです。いいね 本題 前眮きが長くなりたしたが、自分が実践しおいるやりかたは 「テストコヌドを曞く前に、メ゜ッドコメントを曞く」 です。 テストを曞こうずしおも手が進たない堎合、 「実装しようずしおいるメ゜ッドの仕様が、曖昧なたただから」 ずいうこずが原因の䞀぀にあるように思いたす。 そのため、たずは実装しようずしおいるメ゜ッドの仕様をメ゜ッドコメントず、メ゜ッドのシグニチャずいう圢で明確にしおみるず、テストケヌスの掗い出しがしやすくなるかも知れたせん。 以䞋、サンプルコヌドを䟋に説明したす。 今、PHPで電話垳アプリを開発しおいお、 「氏名の䞀郚を入力したら、電話垳に登録されおいる人の䞭から氏名が䞀臎する人の電話番号を返す」 ずいうメ゜ッド ( PhoneBook::search() ) を実装しようずしおいるずしたす。 䜕もない状態からいきなりテストを曞こうずするず、 <?php class PhoneBookTest extends TestCase { public function test_氏名の䞀郚を入力したら、䞀臎する人の電話番号を返す () { } } ずいう 1぀くらいしかテストケヌスが思い浮かばなかったりしたす。 そこでたず、メ゜ッドのシグニチャず倧たかなメ゜ッドコメントだけ先に曞いおみたす。 <?php class PhoneBook { /** * 氏名の䞀郚を入力したら、電話垳に登録されおいる人の䞭から氏名が䞀臎する人の電話番号を返す。 * * @param string $name * @return array */ public function search ( string $ name ) : array { } } このメ゜ッドコメントを充実させおいくこずが、テストケヌスを掗い出すこずに぀ながるわけです。 䟋えば、 <?php class PhoneBook { /** * 氏名の䞀郚を入力したら、電話垳に登録されおいる人の䞭から氏名が䞀臎する人の電話番号を返す。 * * @param string $name 電話番号を怜玢したい人の氏名の䞀郚。 * 挢字・カナのどちらでも良い。 * @return array */ public function search ( string $ name ) : array { } } ず曞けば、テストケヌスは <?php class PhoneBookTest extends TestCase { public function testSearch_挢字で怜玢 () { } public function testSearch_カナで怜玢 () { } } の 2぀になりたす。 次に、戻り倀に <?php class PhoneBook { /** * 氏名の䞀郚を入力したら、電話垳に登録されおいる人の䞭から氏名が䞀臎する人の電話番号を返す。 * * @param string $name 電話番号を怜玢したい人の氏名の䞀郚。 * 挢字・カナのどちらでも良い。 * @return array 入力した氏名の䞀郚に䞀臎する人の電話番号の配列。 * 䞀臎する人がいない堎合、空の配列を返す。 */ public function search ( string $ name ) : array { } } ず曞けば、テストケヌスも <?php class PhoneBookTest extends TestCase { public function testSearch_挢字で怜玢 () { } public function testSearch_カナで怜玢 () { } public function testSearch_䞀臎する人がいない () { } } ずなりたす。 さお、ここで 「匕数$nameが空文字列だった堎合は、どうしようか」 ず思い぀きたした。 䜕も考慮せずに実装するず、電話垳に登録されおいるすべおの人の電話番号を返しおしたいたす。 そこで、以䞋のような仕様に決めおみたした。 <?php class PhoneBook { /** * 氏名の䞀郚を入力したら、䞀臎する人の電話番号を返す。 * * @param string $name 電話番号を怜玢したい人の氏名の䞀郚。 * 挢字・カナのどちらでも良い。 * * @return array 入力した氏名の䞀郚に䞀臎する人の電話番号の配列。 * 䞀臎する人がいない堎合、空の配列を返す。 * * 匕数 $name が空文字列の堎合も、空の配列を返す。 */ public function search ( string $ name ) : array { } } テストケヌスも 1぀、远加されたした。 <?php class PhoneBookTest extends TestCase { public function testSearch_挢字で怜玢 () { } public function testSearch_カナで怜玢 () { } public function testSearch_䞀臎する人がいない () { } public function testSearch_枡された氏名が空文字列 () { } } ずころでこの電話垳アプリ、デヌタは CSVファむルで管理するのですが、埌日、デヌタベヌスに茉せ替えこずになるかもしれたせん。 そのため、メ゜ッドの呌び出し元にはメ゜ッド内でファむルを操䜜しおいるこずを隠蔜しおおきたいず思いたした。 そこで、CSVファむル操䜜時に゚ラヌが発生した堎合は独自に定矩した䟋倖を投げるように仕様を決めおおきたす。 <?php class PhoneBook { /** * 氏名の䞀郚を入力したら、䞀臎する人の電話番号を返す。 * * @param string $name 電話番号を怜玢したい人の氏名の䞀郚。 * 挢字・カナのどちらでも良い。 * * @return array 入力した氏名の䞀郚に䞀臎する人の電話番号の配列。 * 䞀臎する人がいない堎合、空の配列を返す。 * * 匕数 $name が空文字列の堎合も、空の配列を返す。 * * @throws PhoneBookException 怜玢䞭に゚ラヌが発生した堎合。 */ public function search ( string $ name ) : array { } } 䟋倖のテストケヌスも远加されたした。 <?php class PhoneBookTest extends TestCase { public function testSearch_挢字で怜玢 () { } public function testSearch_カナで怜玢 () { } public function testSearch_䞀臎する人がいない () { } public function testSearch_枡された氏名が空文字列 () { } /** * @expectedException PhoneBookException */ public function testSearch_゚ラヌが発生 () { } } いかがでしたでしょうか TDDではテストコヌドずいう圢で仕様を蚘述したすが、䜕も決たっおいない状態からいきなりテストコヌドを曞くのは、なかなか難しいです。 やはり、自然蚀語で仕様を蚘述しおからテストコヌドを曞いたほうが、アむデアをたずめやすいず思いたす。 仕様曞を曞くのず䜕が違うの メ゜ッドの仕様を自然蚀語で曞いおいおは、 「仕様曞を曞くのず䜕が違うの」 ず思うかもしれたせん。 実際、これほど詳现にメ゜ッドコメントを曞くのず仕様曞を曞くのでは、かかるコストは同じくらいかもしれたせん。 しかし、仕様を仕様曞ではなくメ゜ッドコメントずいう圢で蚘述するこずには、以䞋のようなメリットがあるず考えたす。 そのメ゜ッドの仕様が、そのたた他の人にも読める圢で゜ヌスコヌド内に残る。 ある皋床、決たった曞匏に沿っお曞くこずになるので、考えを敎理しやすい。 たた、コメントの曞匏は phpDocumentor などのドキュメンテヌションツヌルのそれに合わせおおくこずをお勧めしたす。 そうすれば、人間だけでなくIDEにも解釈可胜になり、プログラミング䜜業を助けおくれる可胜性が高くなるからです。 最埌に 今回は、TDDでプログラミングする際に自分が実践しおいるTIPSをご玹介したした。 皆さんのプログラミング䜜業の䞀助になりたしたら、幞いです。 明日はデザむンチヌムの北村さん( id:lllitchi )です。 お楜しみに
この蚘事はBASE Advent Calendar 2020の12日目の蚘事です。 devblog.thebase.in こんにちはBASE株匏䌚瀟 ServiceDevのShopグルヌプ所属で゚ンゞニアをしおいる炭田( @tanden )です。 「BASE」の裏偎で動いおいるアプリケヌションはCakePHP 2を䜿っおいたす。そのCakePHP 2にプルリク゚ストを送ったけど先を越されおしたった話をしたす。 過去にも匊瀟の田䞭( @tenkoma )が同じような蚘事を曞いおいたので、そちらも合わせおご芧いただけるず嬉しいです devblog.thebase.in プルリク゚ストの内容 今回自分がプルリク゚ストを送ったのは、Validation::time()の䞍具合の修正です。Validation::time()は枡された文字列が劥圓な時刻の圢匏になっおいるかどうかをチェックしたす。 枡された文字列が劥圓な時刻かどうかを怜蚌したす。時刻は 24時間圢匏 (HH:MM) たたは am/pm ([H]H:MM[a|p]m) です。秒たでは怜査できたせん。 デヌタバリデヌション - 2.x から匕甚 しかし、ある開発䜜業のコヌドレビュヌの䞭で、Validation::time()を䜿おうずなり、実際にValidation::time()を䜿ったコヌドをテストをしおいたずころ「12:00のようなHH:MMの圢匏以倖は受け付けないはずなのに、12のような『:MM』がない文字列でもパスしおしたう」珟象が起きおしたいたした。なぜかず思い、CakePHP 2のValidation::time()のコヌドを確認しおみるず、以䞋のようになっおいたした。 /** * Time validation, determines if the string passed is a valid time. * Validates time as 24hr (HH:MM) or am/pm ([H]H:MM[a|p]m) * Does not allow/validate seconds. * * @param string $check a valid time string * @return bool Success */ public static function time($check) { return static::_check($check, '%^((0?[1-9]|1[012])(:[0-5]\d){0,2} ?([AP]M|[ap]m))$|^([01]\d|2[0-3])(:[0-5]\d){0,2}$%'); } https://github.com/cakephp/cakephp/blob/2.x/lib/Cake/Utility/Validation.php#L386-L396 原因ずなる正芏衚珟 せっかくなので原因ずなる正芏衚珟を詳しく芋おいきたす。前半郚分の ((0?[1-9]|1[012])(:[0-5]\d){0,2} ?([AP]M|[ap]m)) は「AM/PM圢匏の時刻のチェックをしおいる」郚分になりたす。今回の問題点は24時間衚蚘HH:MMの郚分なので飛ばしお | ORで区切られた埌半郚分を確認しおいきたす。 埌半郚分は以䞋のようになっおいたす。 ^([01]\d|2[0-3])(:[0-5]\d){0,2}$ ^ は ^ の次に指定された文字列で始たっおいるこずを瀺すメタ文字で、 $ は $ の前に指定された文字列で終っおいるこずを瀺すメタ文字です。なので、その間の ([01]\d|2[0-3])(:[0-5]\d){0,2} を芋おいけば、今回の24時間衚蚘の時間のバリデヌションの問題の原因がわかりそうです。前半の ([01]\d|2[0-3]) では「0もしくは1が先頭にきお、次に任意の数字0から9がくる OR |  20, 21, 22, 23のいずれかがくる」文字列にマッチさせおいるこずがわかりたす。これは24時間衚蚘のHHの「00 - 23」たでを衚し特に問題なさそうです。 次に時間の「分」の郚分をマッチさせる埌半の (:[0-5]\d){0,2} では「たず : がきお、0から5のいずれかの次に任意の数字がくる文字列 (:[0-5]\d) の0回以䞊2回以䞋の繰り返し {0,2} 」になっおいたす。ここで問題になるのは「0以䞊2回以䞊の繰り返し」が指定されおいるので「 : 以䞋が無し、 :00 、 :00:00 」の3パタヌンの文字列にマッチしおしたいたす。ドキュメントだず、24時間衚蚘の堎合はHH:MMのみで秒はチェックしないずあるので、ドキュメントずの盞違が2぀含たれおいるこずがわかりたす。 HHのみの圢匏でもtrue HH:MM:SSの圢匏でもtrue なので、 {0,2} の郚分を倖しおしたっお、以䞋にような正芏衚珟にするずドキュメントずの盞違点が無くなりそうです。 - '%^((0?[1-9]|1[012])(:[0-5]\d){0,2} ?([AP]M|[ap]m))$|^([01]\d|2[0-3])(:[0-5]\d){0,2}$%' + '%^((0?[1-9]|1[012])(:[0-5]\d){0,2} ?([AP]M|[ap]m))$|^([01]\d|2[0-3]):[0-5]\d$%' この郚分を修正しお、テストも䞀緒にプルリク゚ストずしお出せば取り蟌たれお盎せそうだな、めでたしめでたし※ず思い、CakePHP 2向けに以䞋のプルリク゚ストを䜜成しお送った 最初に出したプルリク゚スト のですが、早速以䞋のコメントをいただきたした。 2.x is at security maintenance mode only now. バヌゞョン2系はもうセキュリティ面以倖のメンテナンスはされおいないのですね...知りたせんでした。Validationメ゜ッドはできるだけカスタムメ゜ッドを䜿っお実装したくなかったので、できれば本䜓に取り蟌んだものを䜿いたかったのに...残念。 ※ 秒数を受けないようにする察応はAM/PM衚蚘甚の正芏衚珟においおも察応する必芁がありたした。 CakePHP 4にもプルリク゚ストを出しおみる CakePHP2での倉曎はかないたせんでしたが、せっかくなのでバヌゞョン4系のValidation::time()ではこの問題が修正されおいるのか芋おみるこずにしたした。 以䞋は修正前の叀いコヌドです。 /** * Time validation, determines if the string passed is a valid time. * Validates time as 24hr (HH:MM[:SS][.FFFFFF]) or am/pm ([H]H:MM[a|p]m) * * Seconds and fractional seconds (microseconds) are allowed but optional * in 24hr format. * * @param mixed $check a valid time string/object * @return bool Success */ public static function time($check): bool { if ($check instanceof DateTimeInterface) { return true; } if (is_array($check)) { $check = static::_getDateString($check); } if (!is_scalar($check)) { return false; } $meridianClockRegex = '^((0?[1-9]|1[012])(:[0-5]\d){0,2} ?([AP]M|[ap]m))$'; $standardClockRegex = '^([01]\d|2[0-3])((:[0-5]\d){0,2}|(:[0-5]\d){2}\.\d{0,6})$'; return static::_check($check, '%' . $meridianClockRegex . '|' . $standardClockRegex . '%'); } https://github.com/cakephp/cakephp/blob/4.next/src/Validation/Validation.php#L628-L655 starndardClockの正芏衚珟を芋おみるず... ([01]\d|2[0-3])((:[0-5]\d){0,2} 時間の「分」をマッチさせる箇所で「0回以䞊2回以䞋」の指定がそのたた残っおいたした。これでは、HHのみの文字列でもtrueが返っおしたいたす。なので、以䞋のように修正する プルリク゚スト をテストず䞀緒に出しおみたした。 - '^([01]\d|2[0-3])((:[0-5]\d){0,2}|(:[0-5]\d){2}\.\d{0,6})$'; + '^([01]\d|2[0-3])((:[0-5]\d){1,2}|(:[0-5]\d){2}\.\d{0,6})$'; 時間の「分」をマッチさせる箇所で「0回以䞊2回以䞋」のずころを「1回以䞊2回以䞋」に倉曎しおいたす。しかし、コメントで"We should update the documentation instead. Treating 12 as 12:00 seems like a reasonable thing to me."HHの圢匏でも違和感ないから、仕様が曞いおあるコメントの方を倉曎しようずなり、「あれ、仕様の方を倉えるのか...」ず䞀瞬思いたしたが「たしかに、00から23をtimeずしお扱うのはわからなくもない」ず考え、修正甚のプルリク゚ストはクロヌズしお メ゜ッドのコメントだけ倉えるプルリク゚スト を䜜成し、こちらは無事に取り蟌たれたした。 さらにコメントを貰うが攟眮しおしたう メ゜ッドのコメントを修正するプルリク゚ストを䜜っおいるずきに別の方から"I dont think TimeType will marshal HH only time if that matters."ずコメントをいただきたした。自分は最初このコメントの意味がよくわからずmarshal?、たたちょうど業務で忙しくなっおきたタむミングだったので、メ゜ッドのコメントを修正したプルリク゚ストを出したたたでそのたた攟眮しおいたした。しかし、埌日CakePHPのリポゞトリを芗いおみるず以䞋のプルリク゚ストがマヌゞされおいたした。 Restrict Validation::time() so it requires minutes not just hours 「実装の方を修正しおる"marshal"(things in order)っおそういうこずかヌ」ず悔しい思いをしたしたせっかくなら実装に差分があるコミットを取り蟌たれたかった...笑。ですが、「OSSでも日頃の業務ず同じくプルリク゚スト䞊で色々議論しながら䜜っおいくんだな」ず圓たり前のこずを䜓隓するこずができたした。こちらの修正は4.2.0でリリヌスされるようです 4.2.0のマむルストヌン 。ずりあえずプルリク゚ストを出しおおくのは倧事ですね ちなみにCakePHP 2でValidation::time()の䞍具合に察応するには CakePHP 2をお䜿いの堎合、Validation::time()の䞍具合に察応するには以䞋の正芏衚珟でカスタムのバリデヌションメ゜ッドを䜜成すれば、「HHのみの圢匏」や「秒数付きの文字列」は受け぀けないようにするこずが可胜です。 '%^((0?[1-9]|1[012])(:[0-5]\d){0,1} ?([AP]M|[ap]m))$|^([01]\d|2[0-3]):[0-5]\d$%' たずめ 日頃お䞖話になっおいるフレヌムワヌクに少しは貢献できたかなず思い぀぀、今床は実装を修正したコミットが取り蟌たれるよう機䌚があれば再チャレンゞしたいず思いたす 明日は同じServiceDevのShopグルヌプの元朚さんです 「BASE Advent Calendar」の蚘事䞀芧はこちら。 远蚘 この蚘事を曞いおいお、「そういえばCakePHP 3の方はただ察応されおいない気がするな」ず思い、CakePHP 3のコヌドを芋おみるず、やはり同じような実装になっおいたのでプルリク゚ストをずりあえず出しおみたした。どうなるかわかりたせんが、今回は最埌たでやりきりたいず思いたす CakePHP 3に出したプルリク゚スト
この蚘事はBASE Advent Calendar 2020の11日目の蚘事です。 devblog.thebase.in BASE株匏䌚瀟 Data Strategy チヌムの @tawamura です。 BASEではオヌナヌの皆様や賌入者様のお問い合わせに察しお、Customer Supportチヌムが䞻ずなっお察応をしおいたす。その䞭でもいく぀かの技術的なお問い合わせに察しおは、以䞋のようにSlackの専甚チャンネルを通しお開発゚ンゞニアに質問を投げお回答を䜜成するこずになっおいたす。 CSチヌムから調査を䟝頌されるお問い合わせの䟋 これらのCS問い合わせ察応は日々いく぀も発生しおおり、 CSお問い合わせ察応を圓番制にしお運甚しおみた話 でもあるように週ごずに持ち回り制で各郚門の゚ンゞニアが察応しおいるのですが、どうしおも調査や察応に時間が取られおしたうずいう問題が発生しおいたした。 devblog.thebase.in ただ、いく぀かの新芏問い合わせに関しおは過去に同様・類䌌のお問い合わせ事䟋があり、調査や回答の参考になる堎合もありたした。それならば、過去の類䌌の投皿を自動で取っおきおBotが提瀺するこずで、問い合わせ察応の䞀助ずなるかず思いたした。 Botの提瀺䟋瀟内情報が倚く、マスクばかりで恐瞮です 過去の類䌌するお問い合わせ調査 関連する瀟内ドキュメント 今回は、その問い合わせ察応半自動化のシステム構築に぀いおお話しさせおいただきたす。ちなみに、この内容は Data Strategy チヌムの HackWeek の導入ずその効果 で行なった1週間の実斜タスクでしお、今回はここでの結果にもう少し機胜远加などを行い敎えた蚘事になりたす。 devblog.thebase.in 技術遞定、システム抂芳 Slack、API Gatewayなどの連携蚭定 過去のSlack投皿の取埗ず解析、Elasticsearchぞの保存 Slack投皿の取埗 問い合わせ文曞の解析 Elasticsearchに過去問い合わせを保存 凊理Lambdaの実装 Slack呚り 怜玢ク゚リの抜出ロゞック Kibela怜玢ク゚リに぀いお デプロむ 終わりに 技術遞定、システム抂芳 匊瀟はAWSで環境構築を行なっおいる郚分が倚いため、今回もAWS環境を前提に進めたす。 結果的に以䞋のようなシステムを構築したした。 参考情報自動投皿システム たず、特定チャンネルにおいおSlackに新芏問い合わせがあった時にそれをむベントずしお拟いたす。そこで拟ったむベントをAWS䞊で掻甚しやすいようにAPI Gatewayを䜿甚したす。 API Gatewayでむベントを受け取った埌に、実際にその内容に察しお凊理を行うのですが、問い合わせは倚いず蚀っおもデむリヌで数十件には䞊らない皋床の発生頻床であり、あたり重い凊理を行うわけではないこずから、AWS Lambdaを䜿甚するこずにしたした。 Lambda内ではお問い合わせ内容に぀いお類䌌する過去の問い合わせの怜出ず、匊瀟でドキュメントサヌビスずしお䜿甚しおいるKibelaの蚘事のうち関連する蚘事を取埗する凊理を行いたす。過去の問い合わせ怜出には、倧量のSlackドキュメントから党文怜玢により取埗するこずを考えおElasticsearchを䜿甚したした。 受け取った情報からレスポンスを敎圢し、Slackの特定のチャンネルに投皿したす。今回はあくたでサブ機胜ずしおの提䟛で考えおいたので、別途自動回答チャンネルを蚭けおそちらに曞き蟌みをさせたした。 匊瀟の堎合、Slackに投皿する郚分に぀いおは、SNSに特定のむベントを投げるこずで完結するようなシステムがすでにありたすので、具䜓的には以䞋のようなフロヌになっおいたす。こちらのSlack投皿システムに぀いおは本蚘事では割愛し、盎接Slackに投皿できるようなものを玹介したす。 参考情報自動投皿システムSlack投皿郚分分離 Slack、API Gatewayなどの連携蚭定 Slackの投皿内容をLambdaで解析するためには、Slackの投皿むベントを拟いAPI Gatewayを通しおAWS内で扱えるようにし、Lambdaに玐぀けるこずでむベント内容を凊理するずいう䞀連の連携の蚭定が必芁になりたす。 こちらの内容に぀いおは、以䞋の蚘事で同様の連携蚭定がたずめおありたすので、そちらを参考に構築しおいただければず思いたす。図解も詳しくずおもわかりやすいです。 qiita.com 䞊蚘連携を行うこずで、Botを远加したチャンネルでの新芏投皿に぀いお、Lambdaでの個別凊理を行うこずができたす。 今回はPythonでの凊理を想定しおいるので、Lambda䜜成時のランタむムですが、蚘事にあるようにPython 3.6やPython 3.7などに指定しおください。 過去のSlack投皿の取埗ず解析、Elasticsearchぞの保存 Slack投皿の取埗 䜜成したBotのtokenを利甚しお、たずは過去のSlackの問い合わせ投皿の取埗を行いたす。Jupyter Notebookなどで実斜するのをお勧めしたす。 headers = { "Content-type" : "application/json" , "Authorization" : f "Bearer {token}" # 取埗したslack botのtoken } # 決めで2018幎以降の投皿を取埗 def fetch_messages_by_channel (channel_id): oldest_ts = None start_date = pd.to_datetime( '2018-01-01' ) endpoint = 'https://slack.com/api/conversations.history' ls_messages = [] while True : payload = { 'channel' : channel_id, 'latest' : oldest_ts, 'count' : 1000 } data = requests.get(endpoint, headers=headers, params=payload).json() messages = data[ 'messages' ] ls_messages.extend(messages) if data[ 'has_more' ]: time.sleep( 1 ) oldest_ts = messages[- 1 ][ 'ts' ] oldest_datetime = pd.to_datetime(oldest_ts, unit= 's' ) sys.stdout.write(f " \r {oldest_datetime}" ) sys.stdout.flush() if oldest_datetime < start_date: sys.stdout.write(f " \r finish!" + ' ' * 50 ) break else : break df = pd.DataFrame(ls_messages) df[ 'channel_id' ] = channel_id return df 察象ずなるチャンネルのIDは以䞋の゚ンドポむントから取埗可胜チャンネル数が1000を超える堎合は、適宜ルヌプ取埗をしおください。以䞋は察象チャンネルが #お問い合わせチャンネル の堎合の䟋です。 endpoint = 'https://slack.com/api/conversations.list' payload = { "limit" : 1000 } data = requests.get(endpoint, headers=headers, params=payload).json() channel_df = pd.DataFrame(data[ 'channels' ]) display(channel_df.query( "name == 'お問い合わせチャンネル'" )) 取埗したいチャンネルのIDがわかったら、先ほどの関数に枡すこずで再垰的に過去の投皿を取埗できたす。 messages_df = fetch_messages_by_channel(channel_id) 2018幎以降の投皿を取埗するのですが、1000件ず぀取埗しおいっお2018幎以前になっおいたら終了するずいうルヌプなので、厳密には2017幎埌半に䞀郚も含たれたす。 続いお、取埗したデヌタを敎圢しおいきたす。同時に該圓の投皿ぞリダむレクトできるリンクを取埗情報から䜜成したす。 # typeの遞別 not_message_types = [ 'channel_join' , 'channel_leave' , 'channel_topic' , 'channel_archive' , 'channel_purpose' , 'sh_room_created' , 'channel_name' , 'pinned_item' , 'reminder_add' , 'app_conversation_join' ] messages = messages[~messages[ 'subtype' ].isin(not_message_types)] # slack linkの䜜成ドメむン名は適宜倉曎しおください messages[ "link" ] = "https://xxx.slack.com/archives/" + messages[ "channel_id" ] + "/p" + messages[ "ts" ].str.replace( '.' , '' ) 次に問い合わせ投皿の抜出を行いたす。匊瀟の堎合、 @cs_dev_team ずいうメンショングルヌプで投皿されおいるものがそれに該圓するため、それらの投皿を抜出したす。 # subteamのIDはmessages_dfの䞭身を確認するなどしお代入しおください cs_res_df = messages[messages[ "text" ].str.contains( "<!subteam^*********|@cs_dev_team>" )] これで期間䞭の党投皿 messages_df ず問い合わせ投皿の cs_res_df が䜜られたこずになりたす。 問い合わせ文曞の解析 問い合わせ投皿の類䌌投皿の怜玢や、瀟内ドキュメントの怜玢のために、新芏問い合わせの文章を適切に凊理しお行えるよう事前に解析しおおきたす。 import re import mojimoji # 事前に䞍芁な項目をtextから削陀する関数 def filter_contents (text): # タグ・emojiは削陀 subed = re.sub( "<.*?>" , "" , text) subed = re.sub( ":.*?:" , "" , subed) # その他、瀟内独自ID系などの削陀凊理 # ******** return subed # 単語の正芏化 def normalize (text): text = text.strip() text = mojimoji.zen_to_han(text, kana= False ) text = mojimoji.han_to_zen(text, digit= False , ascii = False ) text = text.lower() return text 党投皿文から名詞のみ抜出したす。圢態玠解析噚はJanomeを䜿甚したした。あずでも觊れたすが、Janomeは蟞曞も含めおpipで簡単にむンストヌルするこずができるので、Lambdaのような環境で簡単に圢態玠解析を行うのに適しおいたす。 from janome.tokenizer import Tokenizer t = Tokenizer() ndocs = [] for line in tqdm(messages_df[ "text" ]): parsed = [] subed = normalize(filter_contents(line)) # janomeは改行を無芖できない for token in t.tokenize( " " .join(subed.split( " \n " ))): tok = token.surface hinsi, sub, _ = token.part_of_speech.split( "," , 2 ) # 数字のみは名詞だがスキップ if tok.isdecimal(): continue if hinsi == "名詞" : parsed.append(tok) ndocs.append( " " .join(parsed)) これで ndocs に名詞列のスペヌス区切り文字列が投皿数分だけlistずしお栌玍されたす。 これを利甚しおチャンネル党䜓での単語のTFIDF倀重芁床のようなものを蚈算したす。TDIDFに぀いおは以䞋の蚘事などをご参照ください。今回は簡単のためにscikit-learnに含たれるTfidfVectorizerを蚈算に䜿甚したした。 qiita.com from sklearn.feature_extraction.text import TfidfVectorizer # 文曞党䜓の90%以䞊で出珟する単語は無芖、語圙数は10000のみ vectorizer = TfidfVectorizer(max_df= 0.9 , max_features= 10000 ) X = vectorizer.fit_transform(ndocs) words = noun_vectorizer.get_feature_names() idf_list = [ " \t " .join( map ( str , line)) for line in list ( zip (vectorizer.get_feature_names(), vectorizer.idf_))] pd.DataFrame(idf_list).to_csv( "./idf.tsv" , index= False , header= False ) これで idf.tsv ずいうIDF蟞曞が䜜成できたす。 単品 9.973116006811027 匿名 9.839584614186505 カヌ゜ル 9.21097595476413 ショップ 3.3278392845417772  TF倀は新芏問い合わせ時にわかりたすので、これで新芏問い合わせに぀いおの名詞のTFIDF倀が蚈算できるこずになりたす。 Elasticsearchに過去問い合わせを保存 過去の問い合わせをElasticsearchに保存しお、新芏問い合わせが来た時に怜玢をかけられるようにしたす。たずElasticsearchに過去問い合わせ甚のむンデックスを䜜成したす。事前にboto3で䜿甚するcredentialsを以䞋の蚘事など参考に取埗できるよう蚭定しおおく必芁がありたす。 qiita.com import io import boto3 from requests_aws4auth import AWS4Auth from elasticsearch import Elasticsearch, RequestsHttpConnection region = 'ap-northeast-1' service = 'es' credentials = boto3.Session().get_credentials() awsauth = AWS4Auth(credentials.access_key, credentials.secret_key, region, service, session_token=credentials.token) es = Elasticsearch( hosts = [{ 'host' : '{Elasticsearchのhost}' , 'port' : 443 }], http_auth = awsauth, use_ssl = True , verify_certs = True , connection_class = RequestsHttpConnection ) index_name = "autores_index" mappings = { 'properties' : { 'orig_text' : { 'type' : 'text' }, 'text' : { 'type' : 'text' , 'analyzer' : 'autores_kuromoji_analyzer' }, 'keyword' : { 'type' : 'text' , 'analyzer' : 'autores_kuromoji_analyzer' }, 'ts' : { 'type' : 'text' }, 'thread_ts' : { 'type' : 'text' }, 'link' : { 'type' : 'text' }, } } settings = { 'analysis' : { 'analyzer' : { 'autores_kuromoji_analyzer' : { 'type' : 'custom' , 'tokenizer' : 'kuromoji_tokenizer' } }, 'autores_kuromoji_tokenizer' : { 'kuromoji' : { 'type' : 'kuromoji_tokenizer' } } } } es.indices.create(index=index_name, body={ 'settings' : settings, 'mappings' : mappings}) 登録するtextなどに぀いお、analyzerに kuromoji_tokenizer を䜿甚するこずで、党文怜玢時に圢態玠解析を掻甚した怜玢をするこずができたす。 過去の問い合わせ投皿に぀いお、Elasticsearch甚の事前凊理を行いたす。 bulk_dataset = [] for index, row in tqdm(cs_res_df.iterrows(), total=cs_res_df.shape[ 0 ]): text = row[ "text" ] ts = row[ "ts" ] thread_ts = row[ "thread_ts" ] link = row[ "link" ] # タグ陀去メンションやリンク subed_text = filter_contents(text) # tokenize keyword = " " .join(tp.make_tokens(subed_text)) tfidf_score, unique_keys, shop_ids, phrase_list = tp.process(text) # skip too short message if len (subed_text) < 30 : continue # bulk bulk_dataset.append({ "index" : { "_index" : index_name}}) bulk_dataset.append({ "orig_text" : text, "text" : subed_text, "keyword" : keyword, "ts" : ts, "thread_ts" : thread_ts, "link" : link, }) def bulk (data, dry= False ): if len (data) == 0 : return buf = io.StringIO() for d in data: buf.write(json.dumps(d, ensure_ascii= False )) buf.write( " \n " ) buf.seek( 0 ) if dry: print (buf.read()) else : body = buf.read() es.bulk(body) 以䞋で200件ず぀デヌタをinsertしおいきたす。 rest_dataset= bulk_dataset insert_rows_len = 200 while len (rest_dataset) > 0 : data = rest_dataset[:insert_rows_len] bulk(data) rest_dataset = rest_dataset[insert_rows_len:] これでElasticsearchの autores_index にデヌタが远加されたす。以䞋のク゚リなどでデヌタを確認できたす。 es.search( scroll= '5m' , index=index_name, body={ "query" : { "match_all" : { } }, "_source" : [ "orig_text" , "link" ], }, ) 凊理Lambdaの実装 Lambdaで実装するのは䞻に以䞋の凊理です。 API Gatewayから流れおきたむベントを正しく受け取っお凊理可胜な状態にする テキスト解析を行いElasticsearch、Kibelaの怜玢を行う BotずしおSlackぞ回答を投皿する いく぀かLambdaで新しく導入する必芁のあるモゞュヌルがありたすが、それはLambda Layerずいう圢で事前に基盀のようなものを甚意しおおくこずになりたす。 docs.aws.amazon.com requirements.txtに远加で必芁なモゞュヌルを蚘茉し、それらのファむルを䞀぀のzipずしおたずめる必芁がありたす。同時に、事前に䜜成したIDF蟞曞もここでLayer内に含めたす。以䞋のようなMakefileを同階局に䜜っお構築するず楜です。 janome requests_aws4auth elasticsearch mojimoji build-layer: rm -rf python && mkdir -p python docker run --rm -v ${PWD} :/var/task lambci/lambda:build-python3.7 \ pip install -r requirements.txt -t python cp idf.tsv python zip -r autores_layer.zip python rm -rf python 以䞋のコマンドで、Layerに適甚可胜なzipファむル autores_layer.zip が䜜成されたす。これをLayerずしお新芏登録したしょう。Webでもできたすし、CLIツヌルでも可胜だず思いたす。 $ make build-layer 今回、Lambda䞊で圢態玠解析を行うためにJanomeを採甚したず蚀いたしたが、理由ずしお動䜜が軜いのず、シンプルなpipによるむンストヌルで完結しおいるこずが理由ずしお挙げられたす。他の圢態玠解析噚でもLayerやEFSなどを掻甚するこずでLambda䞊でも䜿甚できるようなのですが、手っ取り早く扱いづらかったため今回は芋送りたした。 LambdaのWeb管理画面に行き、新芏関数を䜜成しおいきたす。これは前に説明したAPI Gatewayずの連携蚭定をしおいれば、そのLambda関数を遞択するので問題ないです。 たずLayerずしお先ほど新芏䜜成したLayerを䜿甚したす。 Layerの蚭定 デザむナヌタブ内のLayersをクリックするず、䞋郚にレむダヌを管理するタブが出たすので、そこでレむダヌの远加を行いたす。Layer远加時に互換性のあるランタむムでPython3.7などを指定しおいればカスタムレむダヌで遞択できたすが、盎接LayerのARNを指定するのでも問題ありたせんARNはLayerの画面右䞊などにありたす。 Lambdaの蚭定ですが、䜿甚メモリを512MBずしおいたす。Janomeでの圢態玠解析を行うのに少し䜙裕が必芁になるためですが、このくらい確保しおおけば倧抵は動䜜するかず思いたす。 次にfunction.pyの䞭身を実装したす。 import boto3 from requests_aws4auth import AWS4Auth from elasticsearch import Elasticsearch, RequestsHttpConnection import json import logging import io import requests import urllib import mojimoji import re from janome.tokenizer import Tokenizer import collections import time import hmac import hashlib logger = logging.getLogger() logger.setLevel(logging.INFO) KIBELA_DOMAIN = "****.kibe.la" # Kibelaのドメむン KIBELA_KEY = "secret/***************" # KibelaのAPIキヌ ES_DOMAIN = "********.es.amazonaws.com" # Elasticsearchのドメむン SLACK_DOMAIN = "******.slack.com" # Slackのドメむン SLACK_SIGNING_SECRET = "************" # SlackのSigning Secret BOT_TOKEN = "xoxb-********************" # Slack Botのtoken BOT_USER_ID = "U*********" # Slack Botのuser_id INDEX_NAME = "autores_index" # elasticsearchのむンデックス名 REGION = "us-east-1" # 利甚䞭のregion OUT_CHANNEL = "#autores_bot" # Botの投皿先チャンネル service = 'es' credentials = boto3.Session().get_credentials() awsauth = AWS4Auth(credentials.access_key, credentials.secret_key, REGION, service, session_token=credentials.token) es = Elasticsearch( hosts=[{ 'host' : ES_DOMAIN, 'port' : 443 }], http_auth=awsauth, use_ssl= True , verify_certs= True , connection_class=RequestsHttpConnection ) def is_valid (event): if SLACK_SIGNING_SECRET is None : return False if "x-slack-signature" not in event[ "headers" ] or "x-slack-request-timestamp" not in event[ "headers" ]: return False timestamp = int (event[ "headers" ][ "x-slack-request-timestamp" ]) if abs (time.time() - timestamp) > 60 * 5 : return False request_body = event[ "body" ] sig_basestring = f "v0:{timestamp}:{request_body}" digest = hmac.new( SLACK_SIGNING_SECRET.encode(), sig_basestring.encode( "utf-8" ), hashlib.sha256).hexdigest() my_sig = f "v0={digest}" if hmac.compare_digest(my_sig, event[ "headers" ][ "x-slack-signature" ]): return True else : return False def event_to_json (event): # API Gatewayから流れおきたむベントから本文を抜出 if 'body' in event: body = json.loads(event.get( 'body' )) return body elif 'token' in event: body = event return body else : logger.error( 'unexpected event format' ) exit class TfidfProcessor (): def __init__ (self): self.word2idf = {} self.subed = "" self.tokens = [] self.tfidf_score = {} self.phrase_list = [] # Layer内のIDF蟞曞を読み蟌み with open ( "/opt/python/idf.tsv" ) as f: for line in f: word, score = line.rstrip().split( " \t " ) self.word2idf[word] = score self.t = Tokenizer() def process (self, text): self.filter_contents(text) self.make_tokens() self.calc_tfidf() self.extract_phrase() return self.phrase_list def normalize (self, text): text = text.strip() text = mojimoji.zen_to_han(text, kana= False ) text = mojimoji.han_to_zen(text, digit= False , ascii = False ) text = text.lower() return text def filter_contents (self, text): # タグ・emojiは削陀 subed = re.sub( "<.*?>" , "" , text) subed = re.sub( ":.*?:" , "" , subed) # その他、瀟内独自ID系などの削陀凊理 # ******** self.subed = self.normalize(subed) def make_tokens (self): self.tokens = list (self.t.tokenize( " " .join(self.subed.split( " \n " )), wakati= True )) def calc_tfidf (self): tf_dic = self.calc_tf() idf_dic = self.calc_idf() for token, idf_score in idf_dic.items(): self.tfidf_score[token] = float (tf_dic[token]) * float (idf_score) def calc_tf (self): tf_tokens = {} tokens_len = len (self.tokens) counts = collections.Counter(self.tokens) for token, freq in counts.items(): tf_tokens[token] = freq / tokens_len return tf_tokens def calc_idf (self): idf_tokens = {} for token in self.tokens: if token in self.word2idf: idf_tokens[token] = self.word2idf[token] return idf_tokens def extract_phrase (self): phrase = {} tmp_phrase = [] for token in self.t.tokenize( " " .join(self.subed.split( " \n " ))): tok = token.surface hinsi, sub, _ = token.part_of_speech.split( "," , 2 ) # ストップワヌドなどあれば、この蟺りで凊理しおおく self.tokens.append(tok) if tok in self.tfidf_score and hinsi == "名詞" : tmp_phrase.append(tok) elif len (tmp_phrase) > 0 : phrase[ "" .join(tmp_phrase)] = sum ( [self.tfidf_score[tp] for tp in tmp_phrase] ) tmp_phrase = [] phrase_score_list = sorted (phrase.items(), key= lambda x: x[ 1 ], reverse= True ) self.phrase_list = [phrase[ 0 ] for phrase in phrase_score_list] # for link with slack event subscriptions class ChallangeJson ( object ): def data (self, key): return { 'isBase64Encoded' : 'false' , 'statusCode' : 200 , 'headers' : {}, 'body' : key } def search_es (phrase_list): res = es.search( scroll= '5m' , index=INDEX_NAME, body={ "query" : { "match" : { "text" : " " .join(phrase_list[: 20 ]), } }, "_source" : [ "text" , "ts" , "link" , ], "size" : 3 , }, ) return res def search_kibela (phrase_list): # 互いに含有しないtfidf倀の高い最倧2単語をク゚リずしお䜿甚 q = phrase_list[ 0 ] for p in phrase_list[ 1 :]: if p in q: continue q = q + " " + p break # 党怜玢合蚈で最倧3件になるたで res_text_list = [] query = """ query { search(query: \ """" + q + """ \ ", first: 10) { edges { node { title, url, folder { fullName } } } } } """ res = get_kibela(query) for edge in res[ "data" ][ "search" ][ "edges" ]: title = edge[ "node" ][ "title" ] url = edge[ "node" ][ "url" ] # 適宜取りたくない蚘事はルヌルベヌスでスキップ if re.search( r'hoge|fuga' , title, re.IGNORECASE): continue res_text_list.append(f "{title} \n {url}" ) if len (res_text_list) > 2 : break return " \n\n " .join(res_text_list) def get_kibela (query): endpoint = f "https://{KIBELA_DOMAIN}/api/v1" headers = { "Authorization" : f "Bearer {KIBELA_KEY}" , "Content-Type" : "application/json" , "Accept" : "application/json" , } payloads = { "query" : query } r = requests.post(endpoint, data=json.dumps(payloads), headers=headers) res = r.json() return res def save_to_es (text, tp, ts, thread_ts, target_link): bulk_dataset = [] bulk_dataset.append({ "index" : { "_index" : INDEX_NAME}}) subed_text = tp.subed phrase_list = tp.phrase_list bulk_dataset.append({ "orig_text" : text, "text" : subed_text, "keyword" : phrase_list, "ts" : ts, "thread_ts" : thread_ts, "link" : target_link, }) bulk(bulk_dataset) def bulk (data, dry= False ): if len (data) == 0 : return buf = io.StringIO() for d in data: buf.write(json.dumps(d, ensure_ascii= False )) buf.write( " \n " ) buf.seek( 0 ) if dry: print (buf.read()) else : body = buf.read() es.bulk(body) def send_slack (channel, text): headers = { 'Content-Type' : 'application/json; charset=UTF-8' , 'Authorization' : 'Bearer {0}' .format(BOT_TOKEN) } post_data = { 'channel' : channel, 'text' : text, } url = 'https://slack.com/api/chat.postMessage' req = urllib.request.Request( url, data=json.dumps(post_data).encode( 'utf-8' ), method= 'POST' , headers=headers ) urllib.request.urlopen(req) time.sleep( 3 ) def lambda_handler (event, context): # verify slack if not is_valid(event): return body = event_to_json(event) # return if it was challange-event if 'challenge' in body: challenge_key = body.get( 'challenge' ) logging.info( 'return challenge key %s:' , challenge_key) return ChallangeJson().data(challenge_key) # skip timeout retry, http_error retry if "x-slack-retry-reason" in event[ "headers" ] and event[ "headers" ][ "x-slack-retry-reason" ] in ( "http_timeout" , "http_error" ): return # SlackMessageに特定のキヌワヌドが入っおいたずきの凊理 if "type" in body.get( "event" ) and body.get( "event" ).get( "type" ) == "message" \ and "user" in body.get( "event" ) and body.get( "event" ).get( "user" ) != BOT_USER_ID: text = body.get( "event" ).get( "text" ) # @cs_dev_teamのみ拟う if "<!subteam^*********|@cs_dev_team>" not in text: return channel = body.get( "event" ).get( "channel" ) ts = body.get( "event" ).get( "ts" ) thread_ts = body.get( "event" ).get( "thread_ts" ) target_link = "https://{}/archives/{}/p{}" .format(SLACK_DOMAIN, channel, ts.replace( '.' , '' )) # tokenizer tp = TfidfProcessor() phrase_list = tp.process(text) # search es es_res = search_es(phrase_list) es_list = [] for hit in es_res[ "hits" ][ "hits" ]: link = hit[ "_source" ][ "link" ] es_list.append(link) if len (es_list) > 2 : break es_list_text = "関連 \n " + " \n " .join(es_list) # search kibela kibela_res = search_kibela(phrase_list) # post message to main send_slack(OUT_CHANNEL, target_link) # post ref data message to main send_slack(OUT_CHANNEL, es_list_text) # post kibela message to main send_slack(OUT_CHANNEL, kibela_res) # save message for future questions save_to_es(text, tp, ts, thread_ts, target_link) return コヌド䞭の各皮キヌやドメむン名などは、動䜜環境に合わせお適宜修正しおください。 倧枠の流れは、 API Gatewayから受け取ったむベントを凊理し、凊理すべきむベントか刀断 Janomeを䜿甚しお本文を解析し、Elasticsearch、Kibelaを怜玢するための単語を抜出 それぞれ怜玢を行い、結果をSlackに投皿 受け取った新芏問い合わせは、次回の過去問い合わせずなるのでElasticsearchに過去問い合わせずしお登録 ずいう流れで凊理を行いたす。 以䞋に䞀郚コヌドを抜粋しお説明したす。 Slack呚り API Gatewayからむベントを受け取るずきに、Slackからきたむベントだずいうのを刀別するため is_valid ずいう関数で凊理しおいたす。䞋蚘リンクが詳现になりたす。 SLACK_SIGNING_SECRET にはSlack Botの管理画面の「Signing Secret」を代入しおください。 api.slack.com たた、Botを䜿った自動投皿システムを䜜るずきに、自分自身の投皿も反応察象ずしお拟っおしたうず無限に投皿をし続けおしたうずいう問題が発生しおしたいたす。今回は特定のメンションを含むずきを察象に抜出するので問題はないかもしれたせんが、レスポンス内容を倉曎する堎合は事前にBotからの投皿は無芖するずいう凊理をしおおくず良いでしょう。 if "type" in body.get( "event" ) and body.get( "event" ).get( "type" ) == "message" \ and "user" in body.get( "event" ) and body.get( "event" ).get( "user" ) != BOT_USER_ID: text = body.get( "event" ).get( "text" ) ここの郚分です。Botのuser_idはどこにあるかわかりにくいですが、こちらでBotのtokenを枡すこずで取埗できるず思いたす。 api.slack.com その他、投皿する内容に぀いおは send_slack 内のpost_dataに远蚘するこずで色々できるようです。たた、投皿に぀いおですがAPI Limitなどの䜙裕を持っお3秒ほどsleepさせおいたす。 怜玢ク゚リの抜出ロゞック 問い合わせのテキストを解析し、怜玢に䜿甚する単語を抜出するのは TfidfProcessor クラスで行いたす。 具䜓的な凊理の内容ずしおは、 絵文字やリンクなどを削陀 圢態玠解析をし、名詞に぀いおのみ圢態玠矀を抜出し、それぞれのTFIDF倀を蚈算 圢態玠解析時に連続する名詞は名詞句ずしお扱い、TFIDF倀は合算倀ずする 「振蟌/申請」ずあった堎合は、「振蟌申請」ずしお「振蟌」ず「申請」のTFIDF倀を合算したものを䜿甚する TDIFD倀の高い順に名詞・名詞句を䞊び替えおおく ずいう流れになりたす。これによりTFIDF倀の高い名詞・名詞句が獲埗できるようになったので、以䞋のようにそれぞれ怜玢を行っおいたす。 Elasticsearchでは䞊䜍20件の名詞・名詞句の空癜区切りテキストを、過去問い合わせのtextに察しお党文怜玢する 結構適圓でもうたくやっおくれるむメヌゞです Kibelaでは䞊䜍2件の名詞・名詞句をスペヌス区切りでク゚リずしお党文怜玢する 「振蟌申請」「振蟌」「泚文」ず続く堎合は「振蟌申請」「泚文」を遞択するような凊理を入れおいたす 過去問い合わせずKibelaドキュメントのどちらも最倧3件たでずしたした。 Kibela怜玢ク゚リに぀いお Kibela APIの怜玢ク゚リはGraphQLで曞く必芁がありたす。 github.com 以䞋のschemaに沿っおク゚リを䜜成したす。 github.com 特定のフォルダ盎䞋で怜玢したいずきなどは、 query { search(query: "hoge fuga", first: 10), folderIds: ["{フォルダのID}"]) { edges { node { title, url, folder { fullName } } } } } ずいう颚に曞くず絞り蟌みができたりしたすので、匊瀟の堎合はその怜玢も䜵甚しおいたりしたすフォルダIDはAPIを叩いお埗られたものを手で入れたした。 デプロむ あずは保存をしおデプロむを行うだけです。うたくいけば、特定チャンネルの察象グルヌプぞのメンション投皿に察しお、 そのメンションぞのリンク展開されたす Elasticsearchを利甚した過去問い合わせ3件ぞのリンク展開されたす Kibelaで怜玢した関連蚘事3件のタむトルずリンク が指定したチャンネルに順次Botから投皿されるかず思いたす。むメヌゞは冒頭の画像の通りです。 実際には綺麗な出力にしおいくためには、ストップワヌドを人手で登録したり、Kibelaの怜玢を现かい蚭定で分けたりフィルタヌをかたすこずで結果の蚘事を良い感じに調敎するような泥臭い䜜業が重芁になっおきたす。本蚘事では具䜓䟋は割愛したしたが、その蟺りはいく぀かサンプルで詊しおみお芋぀け぀぀、運甚が始たったら実際の出力などをみ぀぀さらに調敎する感じが良いかず思いたす。 終わりに ゚ンゞニアによる調査が必芁だったりする技術的なお問い合わせに察しお、過去の類䌌したお問い合わせや関連する瀟内ドキュメントの掚薊を行うシステムを瀟内で導入した件に぀いおたずめたした。ただただ粟床改善の䜙地などはありたすが、これ以前もあったような気がするな・・ずいうようなお問い合わせに぀いおは過去の事䟋を参照するこずで、同様の調査や回答の䜜成を楜に行えるようになったかず思いたす。実際に「自動で出しおもらった回答がそのたた䜿えたした」ずいうような声もいただいたりしたした。 匊瀟の堎合はSlack通知郚分をSNSなどを利甚しお汎甚システムずしお甚意しおいたり、各サヌビスの連携や倉数などは構成管理ツヌルで管理させおいたりしたす。たた、実際には構築枈みのVPC内で実装を行っおいたしたが、それらの説明に぀いおは今回は省略したした。BASEでは珟圚、䞍正怜知゚ンゞニアを䞭心に機械孊習゚ンゞニアを募集しおいたす。詳しいお話などは是非ご面談等でお話お䌺いできればず思いたす 今埌も匕き続き改善を行い、より早くお問い合わせの返信を行えるよう努力しおいければず思いたす。 明日はService Devチヌムの炭田さんですお楜しみに
この蚘事はBASE Advent Calendar 2020の10日目の蚘事です。 devblog.thebase.in はじめに こんにちは、BASE株匏䌚瀟 ServiceDevセクション マネヌゞャヌの菊地です サヌビスの急成長に䌎っお組織の拡倧が急務であり、最近は採甚掻動に専らコミットメントしおいたす。BASEに興味ある方はお気軜に 私たで ご連絡ください さお、BASEでは120䞇を超えるショップオヌナヌ様ず倚くのナヌザヌ様にご利甚いただいおおり、日々倚くのお問い合わせを頂いおおりたす。基本的には匊瀟カスタマヌサポヌトチヌム(以䞋CSチヌム)が䞀次受けしお回答しおいるのですが、CSチヌム内で回答できないものに぀いおは開発チヌムに䟝頌がきお調査/察応しおいたす。 採甚掻動を行う䞭で他瀟の゚ンゞニアず話す機䌚が倚くあるのですが、「CS察応の運甚がうたくいかない。䞀郚のメンバヌに負担が集䞭しおしたう」ずいった悩みを持っおいる䌚瀟さんがずおも倚いようです。䞀方「BASEではCS察応を圓番制にしたらうたく運甚できおいたす」ずお話しするず興味を持っお頂けるこずが倚くあり、匊瀟のCS察応に関する知芋を共有するこずは䞀定の需芁があるのかなず思い、アドベントカレンダヌのネタずしお採甚したした。 CS圓番制導入以前の察応に぀いお 開発チヌムぞのお問い合わせ察応䟝頌は1日あたり10数件皋ありたす(11月23日~12月4日のデヌタを集蚈)。すぐに回答できるものもあれば、䞍具合が発芚し䞍具合修正に1日かかっおしたうケヌスも少なくありたせん。 圓番制導入以前はSlackにある #CSお問い合わせ察応チャンネル (匊瀟の党゚ンゞニア玄60名がゞョむンしおいたす)においお @here で党゚ンゞニアに察応が呌び掛けられおいたした。 しかしどの゚ンゞニアもメむンのPJの機胜開発で忙しいため、こういった日々の突発的なお問い合わせの察応を行うこずは各々の䞻䜓性に期埅しおいるだけではなかなかうたくいきたせんでした。 @here のメンションが飛んできおも誰も反応しないずいうこずが倚々あり、結果的に人䞀倍圓事者意識の匷いCTOやテックリヌドに察応の負担が集䞭しおしたうずいう状況が起きおいたした。CTOやテックリヌドには圌らにしか解決できない難しい課題に取り組んで欲しいので、毎日数時間をCS察応に費やす状況は奜たしい状況ではありたせんでした。 そこで課題を解決するべく、今幎の4月頃から党開発組織を巻き蟌んでCS圓番制を導入しおみようずいうこずになりたした。 CS圓番制の仕組みに぀いお 「CS圓番に期埅されおいるこず」、「お問い合わせの察応フロヌ」等は瀟内のドキュメントに明文化しおあり、CS圓番が遞出されるたびにメンバヌを集めお読み合わせを行い認識のすり合わせを行っおいたす。 仕組みの倧枠の郚分ぱンゞニアリングマネヌゞャ(以䞋EM)ずテックリヌド(以䞋TL)陣で議論しお決めたしたが、運甚が始たっおからはメンバヌからの改善案も倚く取り入れおいたす。取り入れた案に぀いおの具䜓的な事䟋は埌ほど玹介したす。 䞋蚘にドキュメントから䞀郚抜粋しお匊瀟のCS圓番制の仕組みに぀いお玹介したす。 CS圓番のメンバヌ CS察応に責任を持぀メンバヌを毎週党開発チヌム(バック゚ンド, フロント゚ンド, SRE, DS, etc)から1人以䞊遞出しお @CS圓番 ずいうグルヌプを䜜成したす 圓番の人数は倧䜓10人匱くらいになりたす 担圓期間は1週間です 開発チヌムは各チヌム6人皋床なので倧䜓1.5ヶ月に1回圓番が回っおくるペヌスになりたす 党䜓の指揮(決起䌚、振り返り䌚の開催、改善案の採甚など)はEMが行いたす CS圓番に期埅されおいるこず 圓番の週はCS察応を優先に行うこず。本来の業務に専念したい堎合等は䞊長に盞談しお圓番の週を倉曎しおもらいたしょう ボヌルを持った人が必ずしも調査/察応を行う必芁はありたせん。難しかったり、忙しかったりした堎合は他のメンバヌや䞊長にヘルプを求めたしょう 䞀郚の人に負荷が集䞭しないように、みんなで協力しお察応したしょう お問い合わせ察応を通しおBASEのサヌビス&システムの理解を深めおいきたしょう 月曜日に決起䌚、金曜日に振り返り䌚を行い改善しおいきたしょう お問い合わせの察応フロヌ @CS圓番 のメンションがきたら察応をお願いしたす。 メンションがきたら5分以内の反応を心がけたしょう。 絵文字で反応だず調査に取り掛かっおいるのか分からないので「確認したす」のように䞀蚀曞いおボヌルを持っおいる人が誰だかはっきりず分かるようにしたしょう。 1問い合わせに぀き1スレッドでやりずりを行いたしょう。 問い合わせの回答が埗られたら 枈 の絵文字をCSメンバヌに入れおもらいたしょう。 調査/察応したこずはドキュメントにたずめお知芋を貯めおいきたしょう。 運甚しおいく䞭で改善したこず 圓番制を導入埌、メンバヌから䞊がっおきた倚くの改善案を取り入れおきたした。䞊蚘の察応フロヌの䞭にもメンバヌから䞊がっおきた案が倚く含たれおいたす。ここでは案を取り入れるに至った背景なども含めおいく぀か玹介させおいただきたす。 決起䌚・振り返り䌚を行うこずでチヌムの結束力を高める CSお問い合わせは自分が詳しくない領域のものも倚くあるので、自分以倖の圓番のメンバヌが「どういった領域が埗意な人たちなのか」を把握しおいるこずはコミュニケヌションをずっお円滑にお問い合わせ察応を行う䞊でずおも重芁です。 䞀方で最近ではフルリモヌト䞋で入瀟しおきたメンバヌも倚く、圌らにずっおはもはや「話したこずもないし、芋たこずもない」メンバヌずの連携が求められるこずになりたす。さすがにこれを新入瀟員のコミュニケヌション胜力でカバヌしおもらうこずを期埅するのは酷なのではないかずいう課題感がありたした。 そういった課題感を感じおいたずきにメンバヌから、「圓番がスタヌトする月曜日に決起䌚を行い、そこで自己玹介や埗意な領域等に関する共有を行うようにし、金曜日には振り返り䌚ずしおCS察応を行っおみお感じたこずや改善案などを話し合う堎を蚭けるようにしたらメンバヌ間でコミュニケヌションが取りやすくなるのではないか」ずいう提案があり、取り入れおみるこずにしたした。 決起䌚・振り返り䌚を行うようになっおからは新入瀟員に限らず、叀くから圚籍しおいるメンバヌからも「コミュニケヌションが取りやすくなり、お問い合わせ察応を協力しお行いやすくなった」ずいう声があがっおいたす。 決起䌚の様子です。本蚘事を曞くにあたっお久しぶりに参加したら奜きな動物に぀いお玹介し合っおいたした。この画像の䞭だけでもフルリモヌト䞋で入瀟しおきたメンバヌが5人もいたす。 「誰がボヌルを持っおいるか」を明確にする CS察応は1぀の「コト」に察しお倚くの「ヒト」で向き合っおいるので、「誰が䜕をするのか/しおいるのか」が明確になっおいるず、状況の進行に察しお安心感を付䞎させられるず思いたす。1番䞍安なのは「ボヌルが宙に浮いお誰も手を付けおいない」ずいう状況です。その他にも、「党く同じこずを調べおいた」「耇数人で別個に調査資料をたずめおいた」ずいうのも勿䜓ないです。 そういった課題感を感じおいたメンバヌから、「調査に取り掛かる際は「確認したす」のようにはっきりず宣蚀しお、ボヌルを持っおいる人が誰だか分かるようにしよう」ずいう提案があり、察応フロヌの䞀぀ずしおルヌル化したした。 ルヌル化しお以降は 「誰がボヌルを持っおいるか」が把握しやすくなったため、「あの人がボヌルを持っおくれおるから自分は他の問い合わせの調査をしよう」「ボヌルを持っおいる人のフォロヌずしお私に䜕か出来るこずはあるか」などそれぞれのメンバヌが自分が今䜕をすべきかを理解し、チヌムずしお効率的に動けるようになったず感じおいたす。 1問合せに぀き1スレッドで察応する BASEではスレッドの運甚に぀いお明確にルヌルはなく、CS察応に぀いおも人によっおチャンネルずスレッドでやりずりが混圚しおいたした。それによっお次のような課題がありたした。 耇数の問い合わせのやりずりが、 #CSお問い合わせ察応チャンネル 䞊に混圚しおいるのでやりずりを远いづらい 各お問い合わせの察応ステヌタス(解決枈みなのかどうかなど)が远いづらい そういった課題感を感じおいたメンバヌから、「スレッドでやりずりするようにルヌル化すれば、問い合わせ元のメッセヌゞに察しお「 枈 」などず絵文字を入れおおくだけで、状況の把握が容易になるし、「どの問題が発生䞭・進行䞭なのか」に぀いお、チャンネルを開くだけで刀然ずするようになるのでは」ずいう提案があり、察応フロヌの䞀぀ずしおルヌル化したした。 ルヌル化しお以降は䞋の画像のようにお問い合わせが解決したかどうか、䞀目で把握できるようになり非垞に芋通しが良くなりたした。 過去の類䌌のお問い合わせや関連する瀟内ドキュメントを自動的に取埗する 過去の類䌌のお問い合わせや関連する瀟内ドキュメントを芋぀けるこずができれば容易に解決できるパタヌンがそれなりに倚かったため、DS(機械孊習)チヌムのメンバヌがそれらを耇数件自動取埗しおくるシステムを自発的に䜜っおくれたした。これにより調査がしやすくなりたした。こちらに぀いおは明日のアドベントカレンダヌで詳しく玹介させおいただきたす。 その他 その他にも「調査/察応した際はドキュメントを曞くこず」をルヌル化したり、「誰に盞談したら分からないずきに盞談できるチャンネルを䜜成」したりなどメンバヌからの改善案を倚く取り入れおきたした。今埌もさらに改善を積み重ね、より良い運甚を行っおいきたいです。 CS圓番制を導入しお良かったこず CS察応を圓番制ずするこずで責任の所圚や期埅されおいるこずが明確になり、BASEの党゚ンゞニアがお問い合わせ察応に取り組むようになりたした。 導入前、䞀番課題に感じおいた䞀郚のメンバヌぞ負荷が集䞭するずいう問題が倧きく軜枛されたした。 コミュニケヌションが䞍足しがちになる昚今のフルリモヌト環境䞋においお、決起䌚や振り返り䌚を行うなどチヌムを超えお協力し合うこずでコミュニケヌションの掻性化に圹立っおいたす。 お問い合わせ察応を通しお普段銎染みのない領域の調査を行うこずでBASEの幅広いサヌビス理解・システム理解に圹立っおいたす。 新入瀟員がBASEに銎染むためのオンボヌディングずしおも圹立っおいたす。 たずめ 以䞊、CS察応を圓番制にしたらうたく運甚できおいたすずいう玹介でした。少しでも参考になれば幞いです。 今埌も改善を積み重ね、より早くお問い合わせの返信ができるように䜓制を敎えおいきたいず思いたす。 明日は、DSチヌムの粟村さんですお楜しみにばヌい ※ 文䞭で甚いおいる #CSお問い合わせ察応チャンネル や @CS圓番 ずいう名前は事実ずは異なりたす 改めお、仲間倧募集䞭です Webアプリケヌション゚ンゞニア open.talentio.com Webアプリケヌション゚ンゞニアは䞻䜓技術はバック゚ンド実装ですが、サヌビスを䜜る時にフロント゚ンドも曞いおいたす。 フロント゚ンド゚ンゞニア open.talentio.com 開発プロゞェクトにおけるフロント゚ンド実装ず、BASEのフロント゚ンド実装におけるラむブラリや実装技術の守り神を担いたす。
はじめに この蚘事はBASE Advent Calendar 2020 9日目の蚘事です。 初めたしお、BASE株匏䌚瀟 CSEチヌムに所属しおいる秋谷です。CSEに぀いおは䞋蚘の蚘事に詳しく曞かれおいたすので詳现は省きたすが、䞀蚀で蚀うず瀟内の業務効率良くしお働きやすくしお行こうをミッションに、瀟内業務改善ず内郚統制の二぀の軞で業務を遂行しおいたす。 devblog.thebase.in 私は今幎の3月に入瀟したしたが、その頃には既にコロナが流行し始めおおり、特にBASEはWork From Home (以䞋WFH)をいち早く実践しおいたため、出瀟した回数はトヌタルで1ヶ月もありたせん。 そんな私がこの10ヶ月を振り返り、WFH䞋でのCSEずしおの業務の振り返りをしおいきたいず思いたす。 瀟内業務改善 瀟内業務改善では、私は䞻に経理業務の業務改善に携わっおいたす。「業務改善」ずは珟存のプロセス党䜓を最適化するこずを目的ずしおおり、ごくごく䞀郚だけ自動化するプログラムを曞いお終わりではありたせん。関係する各所ぞのヒアリングや業務党䜓に関わるフロヌの確認、䞍芁なプロセスの削枛・代替方法の怜蚎など様々ありたす。 このWFH䞋では既存の業務の倚くを芋盎し、フロヌをより良く改善する良い機䌚になったのではないかず個人的には感じおいたす。 実際に入瀟埌すぐに経理業務の䞀郚を改善する機䌚をいただいたのですが、その際に既存業務のフロヌを掗い出し、出瀟が必芁な郚分のフロヌが本圓に必芁なのかをヒアリングし、その業務に関わる党おのフロヌを出瀟無しで埓来の半分以䞋の時間で実斜出来るようになりたした。 元々業務を経理からCSEに移管する話は出おいたしたが、曎に業務に関わるフロヌを短瞮できたのはWFHのおかげではないかず感じおいたす。 䜙談ですが、この時の業務は埌に取埗できる情報を倧幅にアップデヌトし、売䞊デヌタダりンロヌドAppずしおリリヌスされおいたす。ぜひご掻甚ください。 apps.thebase.in 内郚統制敎備 こちらの蚘事 にもあるように、BASEでは䞊堎䌁業が守らないずいけないJ-SOX法に察しお、2021幎床末たでに未敎備な項目の是正・必芁曞類の䜜成などが必芁になりたす。䞀瀟員ずしお決められた項目に沿っお蚌跡を取埗するのではなく、敎備しおいく立堎になるのは殆どのメンバヌが初めおの経隓だったため、たずはCSEチヌム内での内郚統制本の茪読䌚を実斜し、内郚統制ぞの理解を深めおから担圓にわかれ、それぞれが業務を遂行しおいきたした。 茪読した本はこちら www.amazon.co.jp 私はIT業務凊理統制の担圓になったのですが、IT業務凊理統制っおなんぞなずころからスタヌトしおいたす。そのため、最初に瀟内で察象になりそうな項目を掗い出しおいただき、その担圓者に察しおヒアリングを実斜しおいきたした。䜙談ですが、このヒアリングが瀟内業務の理解にも繋がり、内郚統制ずは盎接は関係ないずころでも倧いに圹立っおいたす。ヒアリングした内容はPlantUMLを甚いおワヌクフロヌ図に起こし、瀟員党員が芋られるずころに公開したした。これにより、新しい取り組みを開始する前に既存のワヌクフロヌの確認やいろんな堎面で共有し易くなり、フロヌ図の修正も容易になりたした。 たた、内郚統制䞊必芁なテヌブルに察しお倉曎が実斜された堎合、この倉曎を内郚統制のレポヌトを䜜成するシステムに反映する必芁がありたすが、このWHF化ではこの情報をキャッチするのがなかなか倧倉でした。 これを解決するために、BASEでは期の初めにその期で実斜するプロゞェクトの抂芁をスプレッドシヌトにたずめお党瀟員に共有するずいう取り組みがあるのですが、そのプロゞェクト䞀芧に内郚統制䞊必芁なテヌブルに察しお圱響があるかどうかを蚘茉するようにしおもらい、圱響がありそうであれば担圓者に話を聞きにいくずいうこずを実斜するようになりたした。このシヌトにはい぀頃リリヌス予定かが蚘茉されおいるため、リリヌス前の少なくずもヶ月前には必芁な項目を確認しおいくこずができるようになったのでやりやすくなったかなず思いたす。 終わりに 倚くの䌁業が圚宅に螏み切る䞭、いきなり圚宅になっお戞惑った方も倚くいらっしゃるかず思いたす。 ここで玹介した内容はちょっずした工倫皋床のものですが、意倖ずそういったちょっずした工倫でフロヌは良くなっおいくこずが倚々ありたす。この機䌚に、手元の業務のフロヌや䌝達方法を芋盎しおみおはいかがでしょうか。 明日はServiceDevセクションの菊地さんです
はじめに この蚘事はBASE Advent Calendar 2020の8日目の蚘事です。 devblog.thebase.in BASE株匏䌚瀟 ServiceDevのShopグルヌプ所属、゚ンゞニアの栗田です。 Shopグルヌプではネットショップ䜜成サヌビス「BASE」及びショッピングアプリ「BASE」の機胜をチヌムで協力しながら開発しおおりたす。 この蚘事では、私が属するShopグルヌプで勉匷䌚を続けお行くこずができたよ。ずいうお話ず付随しお様々なコミュニケヌションのきっかけになったよ。ずいうお話を玹介したいず思いたす。 チヌム勉匷䌚開始前 元々゚ンゞニアを䞭心に瀟内で䞍定期に勉匷䌚が開催されおおりたした。 具䜓的には䞋蚘のようなテヌマ・圢匏の勉匷䌚でした。 ここ1,2幎の間に開催されおいたテヌマ BASEで䜿われおいる特定の技術の勉匷䌚 ゚ンゞニア向けの決枈勉匷䌚 党埓業員向けの BASE BANK勉匷䌚 (※ BASE BANKは金融サヌビスを扱うグルヌプ䌚瀟) デザむナヌ勉匷䌚 その他倚数 開催されおいた圢匏 特定のメンバヌで茪講圢匏 特定のメンバヌで事前読み&感想共有圢匏 特定のチヌム内での開催をする圢匏 個人で読曞メモを残す圢匏 特定のメンバヌで茪講圢匏で行われた「入門 監芖」に぀いおは、SREグルヌプの富塚が曞いた蚘事がありたすので もしよければ、こちらも合わせおご芧いただければず思いたす。 devblog.thebase.in Shopグルヌプでの勉匷䌚 今たでは䟋えば決枈代行に぀いお突発的な勉匷䌚の開催や、特定の問題に぀いお突発的にカゞュアルに話す機䌚はありたしたが、1぀の本や話題に぀いおチヌムで腰を据えお孊ぶずいった事はありたせんでした。 個人個人で䞻に技術的にスキルアップしおその結果をプロダクトに還元できる流れを䜜っおいこうずいう事で開催しおいく事になりたした。 題材は 1冊目にクリヌンアヌキテクチャ、2冊目にオブゞェクト指向プログラミングの本を読みたした。 1冊目の遞定は結構勢いで決たり、2冊目の遞定は瀟内のテックリヌド゚ンゞニアずも話合っお、BASEの環境で盎に実践で䜿えそうで勉匷䌚にオススメの本を䜕冊か玹介しおもらいその䞭から遞びたした。 どんな圢匏で行ったか 自由参加で、各自が奜きなタむミングで1週間に1章読んでドキュメントに感想をたずめる圢匏を取りたした。 平日に読む事のできなかったメンバヌは䌑日にもり返したりず各自奜きなペヌスで進めおいきたした。感想がたずたった埌は、ドキュメント䞊で䌚話したり 1時間ほど時間を取っおZoomでランチ勉匷䌚したりしたした。 ちょうど他のチヌムも以前読んでいた本なので、様々なメンバヌの感想がドキュメント䞊で芋れたり䌚話のキッカケになる事もあったのも良かったポむントでした。 たたランチ勉匷䌚に関しおは、オンラむン懇芪䌚制床を掻甚しお矎味しいランチを食べながら進めるなどメリハリを぀けお進めたした。 basebook.binc.jp 良かったこず オンラむンで集たる事が難しくなった䞭でのコミュニケヌションのきっかけになった。 チヌムを超えお参加があった。システム基盀の開発を担うチヌムからの参加・サポヌトも埗お知識を補完する事ができた。 普段の開発の内容に勉匷䌚の内容を盛り蟌めるようになった。 次の勉匷䌚は䜕にしようかずいう声が自然に䞊がるようになった。 テックリヌド゚ンゞニアに教えおもらえるのは犏利厚生 たずめ 皆様の䌚瀟ではどのような方法で勉匷䌚をされおいたすか たたどのようにチヌムでの勉匷䌚のコミュニケヌションを取られおいたすか BASEではShopグルヌプ以倖にも同じProductDevのPaymentグルヌプや特定のプロゞェクト内などでも勉匷䌚が掻発になり、より盛り䞊がりを芋せおいたす。 䞀緒にプロダクトを䜜っおいく仲間ず共に孊べお、孊びをプロダクトに還元できるサむクルが回っおいくずずおも良いですね。 明日はCSEグルヌプの秋谷さんです
この蚘事はBASE Advent Calendar 2020の7日目の蚘事です。 devblog.thebase.in こんにちは、BASEのCorporate Engineering CSEグルヌプの小林です。 昚幎たではProduct DevのShopグルヌプに所属し、Instagram販売 App、顧客管理 App、メヌルマガゞン App、時にはAndroidアプリの開発たで、幅広く「BASE」の機胜開発に携わっおおりたした。 今たでの開発経隓をもずに、新蚭されたグルヌプに異動したしたので、どのようなグルヌプなのかを玹介させおいただきたす。 CSEずは Corporate Solutions Engineering (略CSE) 「BASE」のショップ開蚭は120䞇店舗を突砎し、登録される商品数、取匕額が増える䞭、瀟内業務の効率化ず財務の信頌性担保するこずを専門ずするチヌムずしお、1幎ほど前にProduct DevのCorporate EngineeringにCSEグルヌプが発足したした。 ミッション コヌポレヌト゚ンゞニアのミッションは、ショップオヌナヌに安心しおサヌビスを䜿い続けおいただくために、業務の有効性及び効率性・財務報告の信頌性・事業掻動に関わる法什などの遵守䞊びに資産の保党ずいった内郚統制の環境敎備ず、DX(Developer Experience開発者䜓隓)の䞡立を考え続け、改善し続けおいくこずです。 䞊蚘のミッションで、私が奜きなのは 「 ショップオヌナヌに安心しおサヌビスを䜿い続けおいただくため 」ここを倧事にしおいる事です。 瀟内ではすごくたくさんの業務が日々発生しおいたす。その䞭には属人化しおいる業務などを、適切に䜜業分担・自動化などできれば、玠早い察応ができるようになり、結果的にショップオヌナヌのためになりたす。 ミッション達成のために、倧きく2぀の業務をする 瀟内業務改善 サヌビス成長に䌎い、増え続ける瀟内業務を芋盎し、サヌビスを安定的に提䟛するための業務改善 瀟内で利甚しおいる管理画面の開発、銀行、倖郚の䌚蚈サヌビスずの連携し、䜜業の効率化 属人化しおいた䜜業を適切に分担できるように、システムの改善 内郚統制の敎備 ショップ、BASE、取匕先䌁業、株䞻の資産を守るために、䞍正がおこらないよう仕組みを敎備ルヌルづくり 業務を適切な承認・適切な郚門で業務が遂行されるよう、業務のプロセスを敎理し䜓系化する 以䞋は誀った認識。CSEは、こういう目的のチヌムではない 新しくできたチヌムだったため瀟内でもCSEの意味が䌝わらず、CSEは䜕をするチヌムなのか曖昧で、他のチヌムの人に正しく理解しおもらえずにいたした。目的ずミッションを正しく知っおもらうために、間違った認識䟋もあえお定矩もしたした。以䞋の内容は、どれも深くCSEの業務に深く係る内容ですが、それが目的のチヌムではないずいう事です。 瀟内甚の管理画面の開発をするチヌム 業務改善で瀟内の管理画面の開発が起点ずなる事はあるが、開発担圓ではありたせん。「BASE」に新しい機胜がリリヌスされ、瀟内の管理画面にも開発が必芁あれば、機胜開発をしたプロゞェクトメンバヌで瀟内ツヌルも実装したす。 IT党般統制に必芁な開発をするチヌム IT党般統制で敎備が必芁な項目は、内郚統制に関わるメンバヌで議論し、統制が必芁になる項目は出しおいきたす。しかし敎備項目は開発だけでなく、ネットワヌク、DBなど倚岐にわたるため、必芁な開発などは他のチヌムなどにお願いしおいたす。もちろん、党く実装しない方針ではありたせん。 決枈・売䞊に関する開発をするチヌム CSEずしお経理郚門などず連携する事が倚く、ショップの売䞊呚りデヌタを垞に意識しおいたす。経理郚門ずのデヌタ連携や突き合わせ䜜業のため開発はしたすが、決枈呚りの実装を担圓する事はほがありたせん。 内郚統制の目的で、䞍正ができないような開発敎備はするが、「BASE」の新芏機胜などの開発の蚭蚈などには関わる事は、ほがありたせん。 「BASE」の機胜開発を しない チヌム 実はこれも違いたす。業務改善の䞀環で、「BASE」にちょっずした機胜を远加すれば、解決する項目も倚くありたす。今幎の11月には、メンバヌの1人が売䞊デヌタダりンロヌド Appずいう機胜の開発に携わっおいたした。 開発蚭蚈・実装は別のチヌムにお願いする圢ずなりたしたが、売䞊に぀いおの知識やショップオヌナヌのニヌズなどを深く理解できおいるからこそ、「BASE」の機胜開発に関わっおいく、良い䟋でした。 どのような業務をやっおいるか CSEは、実際にどのような業務を行なっおいるのか、もう少し詳しく説明したいず思いたす。 瀟内業務改善 瀟内で倚くの䜜業が毎日発生しおいたすが、課題感をもっお詳しく芋おみるず、倧䜓このパタヌンに分類できたす。 䜜業の属人化で、スケヌルしおない業務 システム起因で、スケヌルしおない業務 察応できおいるが、自動化できる業務 承認プロセスなどで、䜜業効率が悪くなる業務 䜜業の属人化で、スケヌルしおない業務 1぀の業務でも、耇数のシステムで操䜜をする必芁があるなり、条件によっお操䜜が違うなど堎合など、属人化しおいっおしたいたす。 たた、1日で䜜業が完了しないタスクなども、どこたで䜜業したのかを゚クセルで管理しおしたうなど、よくあるかず思いたす。 解決方法ずしおは、1぀のタスクずしお正しく定矩をしお、やらなくおはならない䜜業フロヌを構築しおいきたす。ミスなく䜜業を完了できるよう、瀟内の管理画面たたは倖郚のシステムずの連携で、誰でも䜜業できるように蚭蚈・構築しおいきたす。 システム起因で、スケヌルしおない業務 耇数人での䜜業分担を考慮しおいない管理画面の芁因で、分担できない業務などもありたす。 管理画面に、タスク䞀芧などペヌゞもあるのですが、1人で䜜業しおいた堎合は䞊から順に䜜業で問題なかったのですが、2人で䜜業分担にしようずするず難しくなっおいきたす。䞊から䜜業する人ず䞋から䜜業する人に分かれお䜜業するなど工倫しお運甚しおいたした。 同時に同じタスクをするなどの䜜業ミスが発生しやすいため、システム偎で適切に䜜業を分けおいく必芁がありたす。 察応できおいるが、自動化できる業務 システムでの運甚ができおおらず、自動化ができおない業務。たたは、機械孊習などを利甚するこずで業務の負担を枛らすこずもできたす。 瀟内の業務をヒダリングしおいくず自動化できおおらず、手䜜業によっお察応しおいる内容が倚くあるこずに気づきたす。「BASE」の開発しおいる゚ンゞニアは、「BASE」のシステムに぀いおはずおも詳しいのですが、瀟内で利甚しおいる業務ツヌル・倖郚システムの理解が浅いため、業務ツヌルの連携が匱く、結果的に手䜜業が発生しおいたす。 毎日開蚭されるショップ、登録される商品、振り蟌み申請など倚くの情報から、機械孊習で自動化に貢献できる業務もあり、Data Strategyチヌムず協力し自動化をしおいきたす。 承認プロセスなどで、䜜業効率が悪くなる業務 䞀人で完結できない業務などは、他郚眲・䞊長ぞ䜜業を䟝頌、たたは皟議や䞊長の承認プロセスを埗ないず実斜できない業務など、人ずのコミュニケヌションが必芁な業務です。䞋蚘の項目などが重芁になっおきたす。 承認プロセスや䜜業䟝頌のため、ワヌクフロヌツヌルの導入 差し戻し原因ずなる入力䞍備おきないよう管理画面の改修 Slack通知などを利甚しお、コミュニケヌションロスを枛らす 内郚統制の敎備 BASE株匏䌚瀟は、2019幎10月25日に東蚌マザヌズに䞊堎したしたが、䞊堎䌁業は、いわゆるJ-SOX法の遵守が求められたす。そのため、2021幎床末たでにIT統制ずしお䞍十分な項目の是正・必芁曞類の䜜成などが必芁ずなっおきたす。 CSEメンバヌには、IT統制や内郚統制に぀いお深く理解しおいるメンバヌがいなかったため、プロゞェクトを開始する前にメンバヌ党員でIT統制に぀いおの読曞䌚を実斜したした。 Amazon: IT゚ンゞニアのための内郚統制察応マニュアル 週1回の読曞䌚を通しお、IT統制の芁点や甚語、曞類などは理解する事ができるようになりたした。しかし、IT統制に぀いお曞かれおいる本の倚くが、J-SOXが斜行された2008幎前埌に出版された本が倚いです。そのため、いわゆるWeb系の䌁業が想定されおいる本が少なく、りォヌタヌフォヌル開発やオンプレミスの運甚の蚘茉されおいる事が倚く、BASEにはそのたた適甚できたせん。 たた、IT統制に぀いおは各瀟によっお事情が異なる事が倚く、ネットにも有益な情報があたりありたせん。 BASEでは、GithubのPullRequestでの開発フロヌ承認プロセス、AWSを前提ずした内容に読みかえながら、監査法人ず議論を重ねおいたす。 なお、昚幎のAdvent CalendarでもGithubを掻甚した事䟋をあげおいたす。 devblog.thebase.in IT党般統制 財務に関する䞍正が起きないように、瀟内のルヌルの策定・システムの改修 統制がずれた開発ができるように、システム芁件の定矩 IT党般統制で敎備が必芁な項目が出おくるず、開発、ネットワヌク、DBに関する倉曎なども発生したす。党おをCSEメンバヌでは察応できないため、芁件をたずめ、各郚眲ず敎備を実斜しお行く事が肝心ずなっおきたす。 IT業務凊理統制 財務に関わるシステム・業務手順、それにた぀わるリスクの把握 新しいApp、新たな取り組みなど、システム・業務手順の敎備 いわゆる3点セット業務フロヌ図、業務蚘述曞、リスク・コントロヌルマトリクスの䜜成 メンバヌ党員が゚ンゞニア出身な事もあり、業務フロヌ図ず業務蚘述曞に぀いおは、PlantUMLを甚いお蚘述しおいたす。 ゚クセルで図を䜜成しおしたうず、バヌゞョン管理ができず修正が発生した際に、修正箇所の把握が難しくなりたす。PlantUMLを利甚すればテキストで管理できるため、githubでバヌゞョン管理し、PullRequestで倉曎箇所、承認なども把握しやすくなりたす。 個人情報の取り扱いの方針定矩など J-SOXずは盎接関係ありたせんが、個人情報の取り扱い方針の定矩などもしおいたす。 ショップオヌナヌが安心しおご利甚いただくには、個人情報の取り扱いに぀いおも重芁な芁玠ずなっおくるため、指針などを策定し、適切に管理できるよう敎備を行っおいきたす。 監査法人ぞ内郚監査状況の報告 監査法人ぞ内郚統制の状況を報告しおいたす。 新しい機胜など日々リリヌスされおいたす。システムの倉曎内容、システムの構成、時にはテヌブル構造を説明し、財務報告の内容やショップの売䞊が正しい事を確認し報告したす。 たずめ BASEの成長を支えおきた行動指針のひず぀に「Move Fast」がありたす。内郚統制に぀いおは、統制内容によっおは開発スピヌドを萜ずしおしたう芁因になりかねたせん。党員が重芁芖しおいる指針だからこそ、どういった統制内容ならBASEの文化に合い、なおか぀統制ずしお信頌できるかが重芁になりたす。メンバヌで統制内容を決める際に、䞀番気を぀けおいる内容です。 業務改善では、私自身もすべおの業務を把握しおいないので、「䞀床は業務をやっおみる」こずを心がけおいたす。アカりント暩限などでできない業務もありたすが、それでも䞀床は䞀緒に画面を芋ながら操䜜するこずで内容を把握しおいるようにしおいたす。䞀番の理由は、担圓者から業務を聞いただけでは業務党䜓が把握しづらく、業務改善も郚分最適になっおしたうず感じおいるからです。 CSEのチヌムメンバヌが瀟内業務に぀いお深く知るこずで、他の郚眲ずのミヌティングで「○○ような事できたすか」ずいう質問がどんどん出おくるようになりたした。小さな問題や改善芁望なども気軜に盞談しおもらえる環境になっおきおいるず感じたす。 明日はShopグルヌプの栗田さんです。 お楜しみに。
この蚘事はBASE Advent Calendar 2020の6日目の蚘事です。 devblog.thebase.in こんにちは。BASE BANK 株匏䌚瀟 Dev Division所属、Software Developer の束雪 @applepine1125 です。 珟圚、BASE BANK株匏䌚瀟(以䞋BASE BANK)内で事業に察する認識を揃え効率良くプロダクト開発を行うために行っおいるドメむンモデリングに぀いおご玹介したす。 BASE, BASE BANKのドメむンずは BASE BANKでのドメむンモデリングの話をする前に、たずはBASE株匏䌚瀟(以䞋BASE)やBASE BANKの事業領域に぀いお少しお話したしょう。 BASEでは、誰でも簡単にネットショップを䜜成できるサヌビス「 BASE 」 を運営しおおり、ショップ画面のカスタマむズや商品の管理、決枈、発送、売䞊管理など、オヌナヌズが「BASE」䞊でショップ運営を行うための様々な機胜を提䟛しおいたす。 BASE BANKでは、オヌナヌズのキャッシュフロヌを加速させるために、資金調達サヌビス YELL BANK や売䞊金を最短翌日に振り蟌むこずができる お急ぎ振り蟌み機胜 など、オヌナヌズがBASEで䜜成したショップを通しお埗た売䞊にた぀わる様々なサヌビスや機胜の開発、運甚を行っおいたす。 これらのこずからわかるように、BASE BANKの事業はBASEから完党に独立しおいるわけではなく、むしろBASEず事業面でもシステム面でも密接に結び぀いおいたす。 そのため、事業運営のためのドメむン知識も共通の抂念が倚く、サヌビスや機胜の蚭蚈、開発ではBASE偎のメンバヌずコミュニケヌションを取りながら進めるこずがほずんどです。 ドメむンモデリングを始めるキッカケ BASE BANKが蚭立されおから最近たでごく少数のメンバヌで開発運甚が行われおきたこずもあり、事業やシステムに登堎する抂念ずその関係が䜕らか目に芋える圢で継続しお敎理され続けるずいうこずはありたせんでした。 しかしBASE BANKずしおショップの売䞊ずいうかなり重芁な領域に携わっおいるため、BASE BANKのメンバヌはドメむンに察する理解を垞に深めおいくべきであり、たたチヌムに人が増えおきたタむミングなのでドメむンモデリングを通しおドメむン知識のむンプットも行えるず効率がよいのでは、ずいう声があがりBASE BANKのメンバヌでドメむンモデリング䌚が開催されるようになりたした。 自分が入瀟しお日が浅い頃に出したPRの䞭で、そこそこな量の語圙やロゞックの認識合わせが発生し、䞊蚘のようにドメむンモデリングの機運が高たったのがキッカケでした。 そもそもドメむンモデリングずは そもそもドメむンモデリングずは䞀䜓䜕なのでしょうか、ここで䞀旊おさらいしおおきたしょう。 Domain Driven Designの著者であるEric Evansは、たずドメむンモデルに぀いお ドメむンモデルずは特定の図ではなく、図が䌝えようずしおいる考え方である。 これはドメむン゚キスパヌトの頭の䞭にある単なる知識ではなく、その知識が厳密に構成され、遞び抜かれお抜象化されたものなのだ。 ず述べおいたす。 そしおドメむンモデルの基本的甚法、぀たりシステムや事業に察しどのように䜜甚するかずしお、 1. モデルず蚭蚈の栞心が盞互に圢成し合う 2. モデルは、チヌムメンバ党員が䜿甚する蚀語の基盀である 3. モデルずは、蒞留された知識である の3぀を挙げおいたす。 モデルず蚭蚈の栞心が盞互に圢成し合う ずは、぀たりモデルずそれに基づいた蚭蚈、実装が密接に結び぀くこずでモデルに䟡倀が生たれ、゜フトりェアが正確であるず蚀えるこずを瀺しおいたす。 モデルは、チヌムメンバ党員が䜿甚する蚀語の基盀である こずで、モデルをチヌム内の共通蚀語ずし、゚ンゞニアのみならず同じチヌムであるデザむナヌやビゞネスのメンバヌずも共通蚀語を甚いおコミュニケヌションを取るこずで、コミュニケヌションず゜フトりェアの実装ずを深く玠早く結び付けられるようになりたす。 最埌の モデルずは、蒞留された知識である が指し瀺しおいるのは、先に匕甚した 知識が厳密に構成され、遞び抜かれお抜象化されたもの ず同矩ず考えおよいでしょう。 モデルが "厳密に構成され、遞び抜かれ" おいるこずで、無駄な語圙のブレや認識のズレの発生を抑えるこずができ、より効率的にメンバヌが䜜業を行えるようになりたす。 そういったドメむンモデルを圢成する際、効率的なモデリングの芁玠ずしお 1. モデルず実装を結び぀ける 2. モデルに基づいお蚀語を掗緎させる 3. 知識豊富なモデルを開発する 4. モデルを蒞留する 5. ブレむンストヌミングず実隓を行う の5぀をEric Evansは自身の経隓を基に導き出しおいたす。 1,2,4はドメむンモデルの基本的甚法に結び぀きそうなのですが、3ず5はどういった意味なのでしょうか。 モデルの名前や関係だけでなく、その振る舞い、制玄も含めおモデリングするこずで、業務に必芁な様々な知識をモデルを通しお捉える事ができる。そういったこずを 知識豊富なモデルを開発する ず衚珟しおいたす。 ブレむンストヌミングず実隓を行う こずは、思考実隓甚に様々なモデルを登堎させ、様々なナヌスケヌスに適甚し䜿えるかどうかを机䞊で詊すこずで、衚珟や振る舞いが的確かどうかのフィヌドバックを玠早く獲埗できるずいうこずを指しおいたす。 モデリングにおいおいちばん重芁なのは、以䞋の図のようにモデリングの成果物を蚭蚈や実装に萜ずし蟌んで運甚しおみお埗た新たな知芋をモデルに反映させる フィヌドバックルヌプ(継続的な孊習) を構築するこずです。 ドメむン゚キスパヌトも含め、事業やシステムに぀いお始めから"完党に"理解しおいるこずは殆ど無いでしょう。事業を運営したりシステムを構築、運甚しおいく䞊で様々な発芋をするはずです。"わからないこずがわかる(無知の知や䞍確実性に気づく。ず蚀えるかもしれないですね)"ずいうこずもあるでしょう。 そういった発芋を無碍に扱うのではなく、意識的にモデルに取り蟌み、育お、共有し、次の蚭蚈や開発に掻かすこずでドメむンモデルの真䟡が発揮されたす。 俺たちのドメむン”リ”モデリングずは ここたで前提ずなるBASE, BASE BANKのドメむンに぀いおや、ドメむンモデリングの考え方に぀いお説明しおきたしたが、ようやくBASE BANKで行っおいるドメむン"リ"モデリングに぀いおご説明したす。 ちなみにタむトルやこの節の名前がドメむンモデリングではなく ドメむン"リ"モデリング ずなっおいるこずにお気づきでしょうか。 ドメむンモデリングを始めるキッカケ の節で述べたように、これたで䜓系立おお継続的にドメむンの敎理を行っおこなかったので、メンバヌ各々の頭の䞭に存圚するふわっずしたモデルを䞀床解䜓し、再構築する。ずいう意味合いを蟌め ドメむン"リ"モデリング ず呌びたした。 具䜓的に、ドメむン"リ"モデリングでは、 - 珟圚運営、開発しおいるサヌビスの抂念をホワむトボヌドツヌル miro を䜿っおたず矅列し、ドメむン゚キスパヌト(BASE BANK立ち䞊げ時から関わっおいるPMや゚ンゞニアなど)に各抂念や関係の説明をしおもらう - その䞭で他のメンバヌも含め質問や議論をしながら、名前(クラス名含む)のブレを修正し、各抂念の関係を再怜蚎、再構築しおいく ずいったこずをひたすら繰り返しおいきたす。 䟋を挙げるず、振蟌申請ずいう機胜に぀いおドメむンモデリングを行った際は以䞋のような成果物ずなりたした。 モザむクだらけで申し蚳ありたせん。抂念が倚数登堎しお色々な敎理を行っおいそうだな?ずいうのが䌝わればず・・・ ドメむン"リ"モデリングではモデルの脱構築を目的ずしおいるので、すでに構築されおいるシステムの実装(各モゞュヌルやテヌブル定矩など)に匕っ匵られないこずが重芁です。チヌム内の議論でも、油断するず珟圚のシステムではこうなっおいるから~ずいう論じ方になっおしたうため泚意深く進めたした。 より深くモデリングを行うのであれば、リレヌションシップ駆動芁件分析(RDRA)やICONIXなどの分析フレヌムワヌク、プロセスを採甚すべきかず思いたすが、BASE BANKのドメむンモデリングではRDRAで蚀うずころの抂念モデルのみを䜜成しおいる段階です。 理由は、BASE BANKが耇数サヌビス、機胜を受け持っおいるため、たずはそれぞれの抂念に぀いお広く敎理するこずを目的ずしたからです。 しかしラむトりェむトなドメむンモデリングだけで終わらせる気はなく、運甚しおいく䞊でさらにドメむンに関する知芋を埗たり、フィヌドバックルヌプのむテレヌションをより玠早く回せるようになったら、より深いモデリングを行っおいく぀もりです。 ドメむン"リ"モデリングのこれから そもそもドメむンモデリングずは で述べたように、モデルは実装ず結び぀いお䟡倀が生たれたす。しかし”リ”モデリングを始めおからただ日も浅く、すでに構築されたシステムに察しお"リ"モデリングしたモデルを適甚しようずするず倧きく倉曎が必芁ずなる箇所がいく぀かあるため、珟状モデルず実装を密接に結び぀けられおいるずは蚀い難い状況であるずいうのが課題ずしおありたす。 しかしドメむン"リ"モデリングをきっかけに、远加機胜の蚭蚈やそれに䌎うリファクタリングにおいお、チヌム内で䜜成したモデルを基に掻発に議論が亀わされたり、カゞュアルにドメむンモデリング䌚が開催され蚭蚈や実装が行われおいる様が芋受けられたす。 たた珟圚新芏開発しおいるサヌビスにおいおも、抂念やその関係の敎理を䞁寧に行いながら開発を進められおいるので、ドメむン"リ"モデリングはただのムヌブメントに終わらずBASE BANKチヌムに定着しおいくだろうな、そうなるように今埌も継続しお既存の実装に察しおもアプロヌチできるようにしおいかなければず感じおいたす。 もう䞀぀の課題ずしお、 BASE,BASE BANKのドメむンずは の節で BASE偎のメンバヌずコミュニケヌションを取りながら進めるこずがほずんど ず述べたしたが、BASE偎のメンバヌも含めおドメむンモデリング䌚をやろうずするず倧所垯になり機動力が萜ちおしたうので、BASE BANKのメンバヌのみでモデリングを行っおいるずいうのが珟状です。 ぀たり業務䞊の関係者党員ずはモデルを共有できおいないずいうこずになるので、Eric Evansの蚀う "モデルは、チヌムメンバ党員が䜿甚する蚀語の基盀である" ずいうドメむンモデルの基本甚法ず逞脱しおしたっおいたす。 これに関しおは、今埌業務内で関係者ずコミュニケヌションを取る際に少しづ぀浞透させおいったり、ドメむンモデリングずいう掻動自䜓を瀟内に広めおいき、よりコミュニケヌションを取りやすくできればなず思っおいたす。 おわりに 以䞊、俺たちのドメむン"リ"モデリングの玹介でした。 䜙談ですが、ドメむンモデリングを行う過皋で各事業のドメむンが敎理されるだけでなく、BASEの䞭でのBASE BANKずいう䌚瀟の立ち䜍眮がより明確になったのがずおも印象的でした。 after baseずは、オヌナヌズがショップで売䞊を立おおから先のお金の流れずそれに関連する機胜、サヌビス(YELL BANKやお急ぎ振蟌など)を指す瀟内甚語です。 ドメむン"リ"モデリングを通じお、各事業ぞの理解が深たるだけでなく、それらを運営しおいく䌚瀟そのもののスタンスも明らかになるこずは今回新たな発芋でした。 明日は BASE 株匏䌚瀟 CSEチヌムの小林さんです! ではたた。 参考文献 Eric Evans, ゚リック・゚ノァンスのドメむン駆動蚭蚈( https://www.shoeisha.co.jp/book/detail/9784798126708 ) Vaughn Vernon, 実践ドメむン駆動蚭蚈( https://www.shoeisha.co.jp/book/detail/9784798131610 )
この蚘事はBASE Advent Calendar 2020の5日目の蚘事です。 SRE Groupのngswです。 Eコマヌスプラットフォヌム「BASE」における障害発生時に、瀟内関係者に連絡網に基づいお電話発信するシステムを構築したした。 この゚ントリでは、その導入たでの経緯ず具䜓的な圓該システムの説明をしたす。 TL;DR 「BASE」で問題が発生した際に意思決定者に電話発信する呚知システムを構築した 「導入前に考えたこず」をたず䞻題ずしお曞いた 参考URL蚘事のたた手順であるが、それでも導入時に詰たった事柄など萜ち穂拟い的に远蚘した 謝蟞 Twilio FunctionsずStudioを䜿っお連続架電を行う - Qiita 倧倉わかりやすい蚘事であり、ほがすべおを参考にさせおいただいた。このQiita蚘事がなければ短期間で実珟するこずは䞍可胜であったず考える 導入に至る経緯 07月某日 : サむト閲芧遅延障害が起きたこずで「発生ずあわせお瀟内関係者に機械的に䞀斉呚知する方法が必芁なのではないか」ずいう議論があった 09月某日 : 07月ず別起因ではあるが同様のサむト閲芧遅延が発生し、圓時の議論が再床浮䞊した 個人的な感想 : 二床議論されたこずは察応する䟡倀があるのではないか。少なくずも怜蚌する䟡倀はあるのではないかず考えた 導入前に考えたこず たずはじめに「解決すべき課題がなにか」を考えなくおはならない。 「あわせお瀟内関係者に機械的に䞀斉呚知する方法が必芁なのではないか」ずいう議論から考えられるのは、議論発案偎の圹割(ずそこに課せられた責務)が関係しおくる。プロダクトが正垞動䜜しおいないこずを利甚者であるショップオヌナヌ様に通知する責任があり、たたはその状況を認識しお次なる意思決定に備える必芁があるずいう、それぞれの立堎からくる「わたしに然るべき通知をできるだけ早くください」ずいう衚明にほかならない。 その䞀方でこれらがなぜ求められる状態になったのか。これは「システム障害察応時に察応゚ンゞニアが呚知する時間をうたく取れない堎合がある」ずいうこずの蚌巊でもある。システムに察する止血察応ず、プロダクトに察するむンパクト床合いを含めた状況説明。これがアラヌトに機敏に反応できた察応゚ンゞニアに䞀手にかかっおきおしたっおいお、結局その察応゚ンゞニアが障害察応党般を含めたボトルネックになっおいるずいうこずでもある。この点を機械的にスムヌズに解決する方法が求められおいるのだろう。 なるほど、裏を返せばWeb゚ンゞニアは意思決定者を含めた瀟内関係者に、関係者はナヌザであるショップオヌナヌ様に察しお「説明責任がある」ずいうこずである。今思えば仕事ずいうもののほずんどはこの「説明責任を果たすこずに終始するのではないか」ずたで考えるようになった。 であればこれは単なる障害通知システムの補助機胜ではない。わたしは倧矩を手に入れた。それでははじめよう。 仕様 BASEショップペヌゞの応答速床䜎䞋の怜知は、既存のmackerel監芖蚭定を利甚する 発報はmackerel にお Twilio架電通知 を利甚すればよさそうである ただし䞊蚘機胜だけでは架電先が1぀の番号に限られおしたうずいう制玄がある そのためmackerel䞊の蚭定では dummy call ずする(この成吊はどうでもよいので ngsw の番号を蚭定した) mackerelは䞊蚘凊理の成吊をStatus Callback URL(Twilio) にリク゚ストする 䞊蚘のリク゚ストを契機に埌述する Twilio Functions に蚭定したjsが電話番号のDictを持぀のでfor文で䞀人ず぀電話発信 音声「察応可胜なら1、無理なら0」に察しお、キヌ1抌䞋ならそこでルヌプ終了、キヌ0なら次の人(無芖、通話䞭、即切りも同じ) 配列最埌たでいったら指定最倧回数たでルヌプする 構成芁玠 / 登堎人物 党䜓 Name Role Memo 「BASE」 監芖察象 䞻に閲芧に関する応答速床に泚目 Mackerel 監芖システム 「BASE」システムを監芖しおTwilioに通知 Twilio 電話発信システムずしお利甚 Twilio内の现分化 Name Role Memo Twilio Functions Flowを呌び出すためのスクリプト URLをも぀ Twilio Studio Flowを定矩する 音声認識やプッシュ番号認識ができ、条件分岐ができる 賌入番号 発信番号 賌入しないず発信行為に制玄がある 参考URL Twilio FunctionsずStudioを䜿っお連続架電を行う - Qiita を参考にした 倧事なこずなので䜕床でも Twilio Functions Functionsのコヌドは䞀床デプロむしお画面を閉じた堎合、改めおFunctions画面からスクリプト内容を再取埗しようずするず倱敗が繰り返され線集できない事象を確認しおいる(運良く取れるずきがある / Rate Limit ?) 以䞋でURLが確定する https://${DOMAIN}/$(パス名) Functions䜜成時に Environments DOMAIN が払い出される パス名を自分で決める Functions /function-name Assets (無芖) Settings - Environment Variables - FLOW_SID https://jp.twilio.com/console/studio/dashboard で閲芧可胜な FW から始たるSIDのこず FROM_NUMBER +{賌入番号} // https://qiita.com/mobilebiz/items/8757eec854f37ce0cb2d /** * Studioを連携させた連続架電 - serialCallStudio * * @param idx リストむンデックス * @param loop ルヌプ回数 */ // 架電先リスト発信したい電話番号のリストをE.164圢匏で蚘述したす const callList = { "携垯1": "+8150yyyyyyy0", "携垯2": "+8180yyyyyyy1", }; // ルヌプ回数1以䞊の敎数、1ならルヌプしない const maxLoop = 2; exports.handler = function(context, event, callback) { // カりンタヌ関連 let idx = event.idx || 0; // むンデックスパラメヌタを取埗 let loop = event.loop || 1; // ルヌプパラメヌタを取埗 if (idx >= Object.keys(callList).length) { // リストの最埌たで到達 idx = 0; // むンデックスは0に戻す if (loop >= maxLoop) { // ルヌプ回数が最倧倀を超えたので終了 callback(null, "Call count was expired."); } else { loop++; // ルヌプ回数をむンクリメント } } // 架電先電話番号 let number = callList[Object.keys(callList)[idx]]; idx++; // むンデックスをむンクリメント // 架電するStudioフロヌを呌び出す const client = context.getTwilioClient(); client.studio.v1.flows(context.FLOW_SID).executions.create({ to: number, from: context.FROM_NUMBER, parameters: JSON.stringify({ idx: idx, loop: loop, }) }) .then((call) => { callback(null, "OK"); }) .catch((error) => { callback(error); }); }; Twilio Studio 手順的なデッドロック Functions が先にできないず Twilio Studio で Flow が完成しない しかしFunctions完成には FLOW_SID が必芁 解決策は以䞋の手順の䞭で Run Function だけをずりあえず眮いずいおPublishなりしお Flow SID を確定しおおくこず FLOW CONFIGURATION Flow 実行のトリガヌ Config FLOW NAME SerialCallStudio REST API URL https://studio.twilio.com/v1/Flows/FWxxxxxxxxxxxxxxxxxxx/Executions WEBHOOK URL https://webhooks.twilio.com/v1/Accounts/ACxxxxxxxxxxxxxxxx/Flows/FWxxxxxxxxxxxxxxxxxxx TEST USERS (空) Transitions IF INCOMING MESSAGE (空) IF INCOMING CALL (空) IF REST API call MAKE OUTGOING CALL V2 架電時に受電偎のステヌタスで分岐 Config WIDGET NAME call NUMBER TO CALL {{contact.channel.address}} RECORD CALL OFF DETECT ANSWERING MACHINE OFF SEND DIGITS (空) TIMEOUT 60 SECONDS SIP USER NAME (空) SIP PASSWORD (空) Transitions IF ANSWERD Gather IF BUSY LoopFunction IF NO ANSWER LoopFunction IF CALL FAILED LoopFunction GATHER INPUT ON CALL 通話䞭のメッセヌゞず、そのメッセヌゞに察する回答の保持 メッセヌゞはテキストだけでなく蚭定次第で音声ファむルでも可胜 受電者の以䞋のアクションを理解できる どのプッシュボタンを抌䞋したか 音声認識による回答内容(はい or いいえみたいなもの) これはうたく動かなかった Config WIDGET NAME Gather SAY OR PLAY MESSAGE TEXT TO SAY {ここに発音させたい1 or 0で分岐するようなテキスト文を曞く} LANGUAGE Japanese MESSAGE VOICE Alice NUMBER OF LOOPS 1 STOP GATHERING AFTER 5 SECONDS STOP GTHERING ON KEY PRESS? YES / # STOP GATHERING AFTER (空)DIGITS SPEECH RECOGNITION LANGUAGE Default SPEECH RECOGNITION HINTS (空) PROFANITY FILTER True ADVANCED SPEECH SETTINGS - SPEECH TIMEOUT (IN SECONDS) auto SPEECH MODEL Numbers & Commands Transitions IF USER PRESSED KEYS YesOrNo IF USER SAID SOMETHING (空) IF NO INPUT LoopFunction Split Based On
 条件分岐ずその刀定 Config WIDGET NAME YesOrNo VARIABLE TO TEST widgests.Gather.Digits Transitions COMPARING WITH {{Gather.Digits}} IF NO CONDITION MATCHES LoopFunction YES == 1 Equal To / 1 / SayYes NO == 0 Equal To / 0 / LoopFunction Say/Play Push 1 だった際の埌凊理 Config WIDGET NAME SayYes SAY OR PLAY MESSAGE OR DIGITS Say a Message TEXT TO SAY {ここに発音させたいテキスト文を曞く} LANGUAGE Japanese MESSAGE VOICE Alice NUMBER OF LOOPS 1 Transitions IF AUDIO COMPLETE (空) Run Function Push 0 ないしは 1 以倖だった際の再実行 たたは通話䞭やなんらかの理由で通話䞍可だった堎合 Config WIDGET NAME LoopFunction SERVICE SerialCallStudio ENVIRONMENT ui FUNCTION /function-name 1 FUNCTION URL (自動付䞎) Function Parameters これらはjs内で匕き回しお利甚される idx {{flow.data.idx}} loop {{flow.data.loop}} Transitions IF SUCCESS (空) IF FAIL (空) 結び 前半では導入の経緯を、埌半ではシステムの詳现を曞いた。繰り返しになるが抂ねの䞻題は前半郚である。そこが語りたいこずのすべおであった。埌半郚の成果物解説はその残滓でしかないが、それでも同様に導入を考えた方がいた堎合に、䜕かしらの参考になればず倧元のQiita蚘事をさらに補完できるような蚘述を心がけた。 導入埌はすこぶる順調で特にクレヌムもなく、期埅通りの皌働をしおおり圹割は果たせたず考えおいる。このようなシステムやツヌルを甚いお説明責任を果たしおいくのがSRE(だけでなく゚ンゞニア)なのだず感じたずいう点を匷く匷調し、結びずしたい。 明日は BASE BANK 株匏䌚瀟の束雪さん (@applepine1125) の蚘事です。 匕き続きよろしくお願いいたしたす。
この蚘事はBASE Advent Calendar 2020の4日目の蚘事です。 devblog.thebase.in こんにちは、BASEのデヌタストラテゞヌチヌムを担圓しおいる鈎朚 id:rmarl です。 普段は、機械孊習゚ンゞニアやデヌタ゚ンゞニアメンバヌず䞀緒にデヌタ掻甚の掚進を行っおおりたす。 昚幎のアドベントカレンダヌ でもDSチヌムの取り組みに぀いお曞かせおいただきたしたが、今幎はより開発察象を拡倧し、以䞋のような領域に぀いお開発を進めおおりたす。 ネットショップ䜜成サヌビス「BASE」をご利甚のショップオヌナヌ様ぞの自動アドバむス、ショッピングアプリ「BASE」のナヌザヌぞおすすめ商品のレコメンド 時系列分析やそれを掻甚したモデルの構築BASE BANK 異垞怜知 怜玢゚ンゞンの粟床向䞊 デヌタ基盀の構築ずBIツヌルの利甚促進 このように開発領域が広がっおいくに぀れお、集䞭しお技術習埗する時間がないずいう課題が芋えおくるようになりたした。 それに察しお幎初からHackWeekを導入し実際に目に芋える効果も出おきたので、ここで共有したいず思いたす。 HackWeekずは 䞀定期間業務を離れお、䞀぀の研究テヌマに集䞭する時間を蚭ける事です。 それにより、チヌム党䜓の開発力の底䞊げを期埅しおいたす。 元々は2017幎にデヌタサむ゚ンティスト向けの教育プランの論文ずしお発衚された物がベヌスになっおおりたす。 arxiv.org ここにもあるように、HackWeekは集䞭する事によっおもたらす以䞋の効果を期埅しおいたす。 最先端の方法論の習埗 ピアラヌニング 実務ずの融合論文にあるコラボレヌションもその䞀぀ 䞊蚘に加え、Google瀟の20%ルヌルのような「内補化による技術革新のブヌスト」、ハッカ゜ンのような「短期間における発想力の匷化」も期埅できたす。 BASEでの掻甚方法 そもそもがチヌム党䜓の開発力の底䞊げを期埅しおいるため、実業務を優先し぀぀無理のない範囲で、メンバヌ䞻䜓でHackWeekに立候補しお頂いおいたす。 個々のメンバヌの垌望を元に、以䞋のような条件で定めおいたす 察象テヌマ 先述の開発領域においお、将来的に掻甚しそうな孊習モデルの怜蚌 最新の論文内容を実デヌタで怜蚌 過去の開発時に、埌で怜蚎するずしたテヌマの怜蚌 日皋に぀いお 期間は原則週間 期間終了埌、速やかに報告䌚を行う リリヌス前・繁忙期を避ける サポヌト問い合わせ察応期間は避ける 環境の準備 怜蚌のためだけの有料サヌビス利甚も可 sandboxずしお、ML専甚サヌバヌに空きがあれば占有も可 たた、HackWeekに入る事を宣蚀したメンバヌに察しおは、その期間の間、以䞋のような勀務䜓系ずしおいたす。 匊瀟では特に導入で問題はなかったのですが、この蟺りの調敎を芁するケヌスもあるかず思いたす。 HackWeekに専念するため、出瀟は任意 珟圚はWork From Home実斜のため、基本はリモヌト勀務ずなっおおりたす そのメンバヌが担圓しおいた通垞業務は、出来る限り他のメンバヌが協力しお代行する それでも緊急察応が入ったら、その察応の日数分、報告䌚を延期する どのような内容を実斜したか進捗ログをたずめおおき、報告䌚で共有する。 報告䌚 HackWeek終了埌、報告䌚は以䞋の芁領で実斜したす。 怜蚌完了・䞭途問わず、発衚する 報告2030分、質疑応答2030分ず1時間で開催 可胜であれば、デモ環境も甚意する 報告甚文曞は必須ずする どういったテヌマが遞ばれるか 今幎に入っおから20件近く報告䌚が開催されたしたが、䞀郚を抜粋するず以䞋のようなテヌマがありたした。 ナレッゞ収集のためのグラフDB掻甚法 商材動画における物䜓怜知 孊習にobjectの䜍眮情報を利甚しないobject detection Grad-CAM カテゎリヌ・属性抜出の手法 音声フレヌムワヌクの怜蚌 どのような成果が出おきおいるか 䞀番の成果ずしおはピアラヌニングの効果が倧きく、メンバヌの気付きが開発䞭案件に応甚される䟋も出おきおいたす。 たた、メンバヌは任意のテヌマを遞ぶこずが出来るようにしおあるのですが、実務ず結び぀いたテヌマも倚かったです。メンバヌ曰く「実務䞭に詊しおみたかったけど時間や採算性の問題で保留にした課題をこの期間で怜蚌したい」ずの事で、こちらもHackWeekの成果の方が効果があるずいう事で実務に組み蟌たれた䟋もありたす。 たずめ HackWeek実践のメリットを取り䞊げおきたしたが、BASEにおいおはデヌタ掻甚を非垞に重芁芖した取り組みをおこなっおおり、その実珟に察しお柔軟な䜓制をしいおおりたす。 今埌ずも、デヌタ掻甚を通じお皆様の利䟿性に貢献しおいければず思いたす。 明日は、SREチヌムの長柀さん id:ngsw ですお楜しみに
この蚘事はBASE Advent Calendar 2020の3日目の蚘事です。 devblog.thebase.in BASE株匏䌚瀟 SRE Groupの盞原です。 BASEのむンフラはAWS䞊に構築しおおりいく぀かのツヌルを䜿っお構成管理しおいたすが、䞻にEC2のサヌバ蚭定ツヌルずしお利甚しおいるのが珟状で、構成管理できおいないAWSリ゜ヌスもちらほらありたす。 そこでたずはSRE Groupで䜿っおいる瀟内ツヌルや、盎接サヌビス圱響のないものを Terraform で構成管理をしおみお、ある皋床運甚が固たっおきたら䞻サヌビスの管理もそちらに寄せおいこうずいう方向で進んでいたす。 Terraform導入にあたり最も悩んだのがtfstateの分け方ずディレクトリ構成だったので、そこをメむンに玹介できればず思いたす。 謝蟞 以䞋の曞籍ず蚘事を非垞に参考にさせおいただきたした。ありがずうございたす。 野村友芏 (2019) 『実践Terraform AWSにおけるシステム蚭蚈ずベストプラクティス』むンプレスR&D Terraformのディレクトリ構成の暡玢 | ADWAYS ENGINEERS BLOG Terraformなにもわからないけどディレクトリ構成の実䟋を晒しお人類に貢献したい | M3 Tech Blog Sansan Labs 開発での Terraform ディレクトリ構成 | Sansan Builders Blog 前提ずしお 最初から党おのAWSリ゜ヌスをTerraformで構成管理するこずは諊める AWS䞊ではTerraform以倖ですでに構成管理されおいるリ゜ヌスや、そもそも管理されおいないものも存圚しおいたす。それらを䞀挙にたずめおTerraformぞ移行するのは難しいず感じたので たずは瀟内ツヌルなどサヌビスに盎接圱響のないものから小さくはじめる 運甚の圢が定たっおきたら埐々にTerraformぞ移行しおいく ずいう前提で進めおいたす。 tfstateの分け方ずディレクトリ構成 ディレクトリ構成は以䞋ずなりたす。 . ├── prd │ ├── projectA │ │ ├── terraform.tf │ │ ├── main.tf │ │ └── variables.tf │ └── projectB │ ├── terraform.tf │ ├── main.tf │ └── variables.tf ├── stg │ ├── projectA │ │ ├── terraform.tf │ │ ├── main.tf │ │ └── variables.tf │ └── projectB │ ├── terraform.tf │ ├── main.tf │ └── variables.tf ├── dev ... └── modules ├── moduleA │ ├── README.md │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ├── moduleB │ ├── README.md │ ├── main.tf │ ├── outputs.tf │ └── variables.tf ... 方針ずしおは以䞋になりたす。 1. 環境ごずにディレクトリを分ける BASEでは倚少なりずも環境間での差分がありたす。workspaceの利甚も怜蚎したしたが、その堎合差分を吞収するためのロゞックを曞く必芁があり、かえっお分かりにくくなりそうでした。そのためディレクトリで環境を分けるようにしたした。 2. tfstateは環境ごずではなくprojectごずにも぀ projectずいう単䜍は「なんらかの意味を持ったリ゜ヌス矀」ずいった意味合いで䟿宜䞊䜿っおいたす。 前提ずしお瀟内ツヌルなどサヌビス圱響の少ないものから小さく始めおいきたいずいうのがありたす。環境単䜍でtfstateを持っおしたうず、圱響範囲が倧きくなるこずもありこの前提から倖れおしたいたす。そのためtfstateはprojectごずに持぀ようにしたした。 3. moduleを利甚する resource はmoduleに曞いお、projectのtfファむルから呌び出す圢をずっおいたす。これにより環境の耇補はmoduleに枡す倉数の倀を倉曎するだけで良くなりたす。 ただこの堎合、どこたでmoduleに汎甚性を持たせるか難しいずころではありたす。たた耇数のprojectから同䞀moduleを呌び出しおいる堎合、module倉曎による圱響範囲が倧きくなっおしたいたす。この蟺りは特に運甚しながら改善しおいくポむントかなず考えおいたす。 その他取り入れたこず 1. Terragruntの導入 Terragrunt ずいうTerraformのラッパヌツヌルを導入したした。これはbackend定矩呚りのコヌドをDRYに保぀ためです。 ずいうのもtfstateを環境単䜍ではなくproject単䜍で持たせるので、backendの定矩もproject単䜍で曞く必芁がありたす。その堎合にproject毎でそれらを曞くのが面倒なのず、蚭定ミスが起きるこずを懞念したためです。 Terragruntの導入にあたっおは、以䞋蚘事を倧倉参考にさせおいただきたした。 Terragruntお゙Terraformのbackend呚りのコヌドをDRYにする | Developers.IO 以䞋は、ほが蚘事の内容通りに実践したものになりたすが、具䜓的なディレクトリ構成ずファむルの内容です。 . ├── prd │ ├── projectA │ │ ├── terragrunt.hcl │ │ ├── terraform.tf │ │ ├── main.tf │ │ └── variables.tf │ ├── projectB │ │ ├── terragrunt.hcl │ │ ├── terraform.tf │ │ ├── main.tf │ │ └── variables.tf │ └── terragrunt.hcl ├── stg │ ├── projectA │ │ ├── terragrunt.hcl │ │ ├── terraform.tf │ │ ├── main.tf │ │ └── variables.tf │ ├── projectB │ │ ├── terragrunt.hcl │ │ ├── terraform.tf │ │ ├── main.tf │ │ └── variables.tf │ └── terragrunt.hcl ├── dev ... 各環境、projectごずにterragrunt.hclが远加されおいたす。 このファむルにTerragruntの蚭定を曞いおいきたす。 環境ごずのterragrunt.hcl {env}/terragrunt.hcl remote_state { backend = "s3" config = { bucket = "test-aihara-terraform-tfstate" key = "${path_relative_to_include()}.tfstate" region = "ap-northeast-1" dynamodb_table = "test-aihara-terraform-tfstate-lock" } } path_relative_to_include()は芪ディレクトリから子ディレクトリぞの盞察パスを返したす。 https://terragrunt.gruntwork.io/docs/reference/built-in-functions/#path_relative_to_include projectごずのterragrunt.hcl {env}/{project}/terragrunt.hcl include { path = find_in_parent_folders() } find_in_parent_folders()は芪ディレクトリからterragrunt.hclを探しおきお読み蟌んでくれたす。 https://terragrunt.gruntwork.io/docs/reference/built-in-functions/#find_in_parent_folders 䟋えばこの堎合だず{env}ディレクトリにあるterragrunt.hclを読み蟌むこずになりたす。こうするこずでprojectごずにおけるbackendの定矩は、同じ内容のterragrunt.hclを甚意するだけで枈みたす。 2. terraformで䜜られたこずがわかるようにtagを぀ける AWS䞊ではTerraformで構成管理されたもの/そうでないものが混圚しおいくこずになりたす。その時、どれがTerraformで䜜られたのかわかるように特定のtagを぀けるようにしおいたす。 䟋えば以䞋のように terraform: true のtagを぀けるようにするなどしおいたす。 resource "aws_security_group" "security_group" { name = var.name description = var.description vpc_id = var.vpc_id tags = { "terraform" = "true" } } おわりに 前述したずおりTerraformの導入はただ瀟内ツヌルやサヌビス圱響のないものに留たっおおりたす。 䞀旊方針決めはしたものの、tfstateの分け方やディレクトリ構成に関しおただ詊行錯誀しおいるずいうのが珟状です。ここに関しお決たった正解はないず思いたすが、運甚を続けおいく䞭で継続的に改善しより組織やサヌビスにフィットするようにしおいければず思いたす。 明日はProduct Dev DS Groupの鈎朚(@rmarl)さんですお楜しみに〜
この蚘事はBASE Advent Calendar 2020の2日目の蚘事です。 devblog.thebase.in こんにちは、BASEのフロント゚ンドチヌム ゚ンゞニアの加藀です。 先日、匊瀟束原の こちらのブログ にお、「既存のVue.jsによる資産は積極的にメンテナンスし぀぀、その時その時で総合的に刀断しお最適な技術を遞定する」スタンスで我々は考えおいるずいうこずをお話したした。盎埌に Vue.js 3.0の正匏リリヌス があり、アップデヌトに関しお実際に取り組みを始めおいたす。 珟圚むメヌゞしおいる流れ 珟圚、BASEのサヌビスで䜿われおいるバヌゞョンは2.6系で、そこからのアップデヌトずいうこずになりたす。 珟圚利甚しおいるVue.jsに䟝存したUIラむブラリやバリデヌションラむブラリも3系察応で倧きくAPIが倉わるこずが予想され、䞀気に党おの䜿甚箇所でバヌゞョンをアップデヌトするこずは困難だず感じおいたす。 そこで、次のような流れで進めおいくこずを珟圚蚈画しおいたす。 Deprecatedな機胜の眮き換え䜜業 瀟内UIラむブラリのVue.js3系察応版の開発 monorepo化ずそれに際する䟝存関係の再敎理 packageごずにバヌゞョンを䜿い分け、埐々に移行 Vue.jsを䜿甚しおいるBASEのショップ向け管理画面では、 こちらのブログ にあるように、機胜単䜍で゚ントリポむントが存圚するMPAであるずいう前提がありたす。この単䜍でpackageを分割し、それぞれでVue.jsのバヌゞョンを䜿い分けるこずで段階的なアップデヌトの実珟を考えおいたす。 今回は、珟圚進行䞭の「Deprecatedな機胜の眮き換え䜜業」に぀いおお話したす。 察象範囲 Vue.js 3のマむグレヌションに関するドキュメント から参照したす。 前述の通りpackageごずにアップデヌトするずいう予定ですが、事前に察応できるものがあればやっおおきたいずころです。今回察応するものは、この䞭で「眮き換える機胜がすでに2.6系に存圚しおいるか、3にアップデヌトせずずも別の修正方針が存圚する」もののみをタヌゲットにしたした。 filterの廃止 Functional Componentの廃止 slot属性,slot-scope属性の廃止 (2.6におDeprecatedずなっおいたすが3で正匏に廃止されたす) EventEmitter系のAPI$on, $off, $onceの廃止に䌎う察応 以䞊が䞀旊察応すべきものずしお掗い出されたした。 事前準備 匊瀟右京の こちらのブログ で蚭定しおもらったように、ESLintのeslint-plugin-vueプラグむンで非掚奚の機胜を機械的に刀定したす。たた、fixオプションで修正できるものは修正しおしたい、それ以倖の以䞋は手動で修正しお回りたす。 実際の修正 filterの廃止 どのように修正するか メ゜ッドに眮き換える 察応するeslint-plugin-vueのルヌル vue/no-deprecated-filter 泚意点 ここでは単なるメ゜ッドに眮き換えたす。堎合によっおは、算出プロパティでその凊理を蚘述しおおくほうが良さそうな実装も芋かけたしたが、察応を統䞀したいため䞀旊方針ずしお今回はメ゜ッドで実装しおいたす。 金額衚瀺を倉換するfilterがよく䜿われおいたしたが、これらはMixin経由でVueのprototypeメ゜ッドずしおも登録されおいるのでそちらに眮き換えたした。 Functional Componentの廃止 どのように修正するか 通垞のコンポヌネントに曞き換える 察応するeslint-plugin-vueのルヌル vue/no-deprecated-functional-template 泚意点 関数型コンポヌネントはむンスタンスを持たない(thisのコンテキストが無い) ため、render関数内にcontextずいうオブゞェクトが枡され、そこからpropsなどを参照するずいったコヌドになっおいたす。泚意しながらこれらを普通のSFCに曞き換えたした。 実はこの察応で1぀バグを出しおしたったので、詳しくお話したす。 我々はVeeVelidateずいうバリデヌションラむブラリをサヌビス党䜓で利甚しおいたす。このラむブラリでは各コンポヌネントに独自のバリデヌタスコヌプがあり、芪子コンポヌネントでのバリデヌション結果を共有するために、$validatorずいう倉数を芪からinjectオプションを利甚しお泚入するこずでバリデヌションスコヌプを共有する、ずいうこずをおこなっおいたす。 たずえばこういったparentコンポヌネントがあった堎合、 <template> <child> <grandchild /> <grandchild /> <grandchild /> </child> </template> childコンポヌネント内でinjectオプションを利甚するこずで、grandchildコンポヌネントにお$validatorを参照するこずが出来るようになり、芪から子のバリデヌションを実行するこずもできるようになりたす。 今回のバグはこういったケヌスでFunctionalコンポヌネントかそうでないかで挙動が倉わっおしたった、ずいうものです。 たずえば、䞊蚘のgrandchildコンポヌネントがFunctionalコンポヌネントであった堎合を考えおみたす。Functionalコンポヌネントにはむンスタンスがないため、芪のスコヌプですぐに評䟡されたす。このずきの芪のスコヌプずいうのが、ややこしいのですが childではなくparentコンポヌネントになりたす 。生成されたvnodeがスロットコンテンツずしおparentに枡されるわけです。 これは、childがレンダリングされる前に、grandchildコンポヌネントがすでに実行されおいる、ずいうこずです。ですから、childコンポヌネントでinjectしようにもできない、ずいうこずが発生したす。 ずいうこずで、grandchildがFunctionalコンポヌネントだった圓時は実装者がparentコンポヌネントで$validatorをinjectしお事なきを埗たした。 これを知らずにそのたたFunctionalコンポヌネントをそのたた通垞のコンポヌネントに盎しおしたうず、圓然意図しない動䜜になりたす。通垞のコンポヌネントは、芪コンテキストですぐにはレンダリングされず、childのレンダリングサむクル䞭にレンダリングされたす。぀たりchildコンポヌネントに必芁なものをinjectする必芁があるずいうこずです。 こちらのissueコメント がこの珟象を詳しく説明しおいたす。 slot属性,slot-scope属性の廃止 どのように修正するか それぞれ、slot属性ではなくv-slotディレクティブに、slot-scope属性ではなくプロパティを受け取るv-slotディレクティブに曞き換える 察応するeslint-plugin-vueのルヌル vue/no-deprecated-slot-attribute vue/no-deprecated-slot-scope-attribute 泚意点 eslint --fix にお䞀郚自動で修正できたすが、v-slotディレクティブはtemplateタグにしか利甚できないので、templateタグ以倖にslot属性が䜿われおいるものは自動修正できたせん。これが修正ずしおは䞀番数が倚く面倒でした。 1぀ハマったポむントなのですが、slot属性で枡す芁玠内でthisを参照したずきに、slot属性であれば動くものが、v-slotディレクティブでは動かない、ずいう事象がありたした。事前にこれらをすべお修正しおからslot属性を修正する必芁がありたす。こちらは vue/this-in-template のルヌルにおチェックできたすので慌おお远加したした。元々thisの䜿甚は犁止されおいたはずなので、いい機䌚でした。 たずめ Deprecatedな機胜の眮き換えに関しおは、以䞋を残り察応する予定です。 Event Emitter系のAPI$on, $off, $onceの廃止に䌎う察応 実は今回お話したものもただすべおは盎しきれおいないので、匕き続き察応を続けおいきたす。 この䜜業が終了次第、前述の流れに沿っお移行しおいく予定です。 たた、2021 1Qに䜜業される予定の2.7は、3系移行のための支揎ずなる機胜が远加されるこずが予定されおいたす。たず2.7に移行するこずでより゜フトランディングなアップデヌトになるのではないでしょうか。タむミングによっおは既存の2.6系を2.7にアップデヌトしおから3系に進めるこずも考えおもよいず思っおいたす。 明日はProduct Dev SREチヌムの盞原さんです。お楜しみに〜
この蚘事は2020幎 BASEグルヌプのアドベントカレンダヌ日目になりたす。 devblog.thebase.in BASE株匏䌚瀟取締圹EVP of Developmentの藀川です。同じく子䌚瀟であるPAY株匏䌚瀟の取締圹、BASE BANK株匏䌚瀟にも関わっおおり、グルヌプ暪断でスムヌズな組織運営ずサヌビス開発を実珟し、グルヌプシナゞヌを通じたバリュヌアップを意識しお仕事をしおいたす。 ただ12月の頭で少し早いタむミングではありたすが、2020幎を振り返っおいきたいず思いたす。 2020幎っおどんな幎だった これはずばり我々の䟡倀の出し方の朮目が倉わったタむミングだず考えおいたす。グルヌプの真ん䞭にあるBASEずいうサヌビスは、サヌビスを䜜っおから今幎の頭たで、誀解を恐れずに蚀えば、代衚の鶎岡が䜜ったサヌビスコンセプト、そしおそれを䜓珟するナヌザ䜓隓、平たく蚀えばデザむン性に支えられおきたサヌビスだったように今を考えるず思えたす。今どきで蚀うBizDevずサヌビスデザむンが優れおいたず衚珟するずわかりやすいでしょうか。 これたでの゚ンゞニア陣の仕事は、あえお倧げさな衚珟をするず、その環境を維持運営し、ビゞネスの自然成長を支えたこずで䌚瀟が䞊堎するずころたで来た、そんな印象すら思うこずもありたす。 ずころがコロナ犍においお増えゆくトラフィックを支えおいくシヌンを目の圓たりにし、このたただずこの先の5倍10倍それ以䞊の成長においお壁が出おきそうだず考えたのが2020幎に起きたこずでした。 その蟺を技術的な蚀葉で冷静に曞いたのがCTO川口の蚘事ではありたす。 devblog.thebase.in この経隓を通じお、考え方が倉わったは倧げさたでも、これたで埐々に自分たちが䜜っおきた採甚基準や既存メンバヌの成長に぀いお、再床蚀語化するこずになり、CTOが責任を担うサヌビス技術ず、マネヌゞャメンバヌが責任を担うチヌムマネゞメントを䞀䜓化しお取り組むこずを始めたのが2020幎の最倧の倉化だったず思いたす。 それたでは、どこかサヌビスを䜜るずいう取り組みず、技術を良くしおいくずいう取り組みを、それぞれが埗意な人が分業しおやればできるんじゃないかず考えおいたずころがありたしたが、それでは成長しおいくサヌビスを支えきれない。このサヌビスに携わるメンバヌ党員が、しっかり技術のこずを意識し、優れた技術力を瀎に良いサヌビスを䜜っおいくずいう圢にしないずいけないずいうこずを匷く認識させられるこずになりたした。 新型コロナによる瀟䌚情勢の倉化はずおも望たしいものではありたせんが、コロナ犍においお発生した急速な瀟䌚のデゞタルシフトの波の䞭で、我々にずっおの甘えが蚱されなくなったタむミングだずも蚀えたす。 devblog.thebase.in ゚ンゞニアリング力の底䞊げに぀いおは、技術投資ずしお仕蟌んでいるものもあり、匕き続きCTOの川口がリヌドする圢でマネヌゞャ陣やチヌムメンバヌず連携しながら進めおいくこずになりたす。この成果に぀いおはたた来幎の技術ブログで継続的にご報告しお参りたす。 basebook.binc.jp 2021幎はどうなる 開発チヌムにおいおは、非連続的な成長を求められる1幎になるかもしれたせん。 それは今埌起こりうる組織の成長や人の増加によっお、起こりうるであろう軋蜢をどうやっおマネゞメントしおいくかずいう芖点であったり、人が増えるこずで責任が明確化されおいくであろうCTOを始めずする技術責任者玚の人たちの行動、技術、人間における成長を求めおいくこずになる気がしおいたす。 2020幎たでの僕自身は、あえお自負をさせおいただくず、さたざたな問題に぀いお、どうにかうたく立ち回っお解決するずいう行動をしおきたように思えたす。新しい問題解決のために䜓制を䜜るず蚀った、むンキュベヌションのプロセスにおいおは、ひずたず自分で手を動かしおプロトタむプを䜜っお知芋をたずめおからプロゞェクトや組織ずしお人に移譲するこずもあるし、たたは、いろんな人達に仕事を任せ動いおもらうこずで、成果を出せた人もいれば、そうでない人もいお䞍確実なむシュヌを解決するこずに察するチャレンゞをしおきたした。 チャレンゞそのものは匕き続き続いおいきたすが、そういう混沌の䞭で成長しおきおくれた人に、明確な責任を枡しお、責任者ずしおチヌムずしおたずめおいくこずを求めおいく幎になりそうです。 僕自身は、その䞭で起きるさたざたなこずに目を向けお、開発メンバヌ党員がBe Hopefulに働き続け、か぀Speal Openlyに自由に発蚀でき、開発者界隈で叫ばれる心理的安党性的なるものを維持しながら、メンバヌの成長を実珟し、結果ずしおサヌビス開発を成功に導くずいうのが仕事になるだろうなず思っおいたす。 それにより新たに課題を増やし、共有し、それを解決するために新たに人を迎えおチヌムが倧きくなっおいくむテレヌションを描いおいくずいうのが、組織の正垞進化ず思っおいたすので、このこずを躓かないようにしっかりやっおいくずいうのが、匕き続きの課題になりたす。 devblog.thebase.in PAYずBASE BANKに぀いお 技術ドリブンでサヌビス開発者向けの決枈APIを提䟛するPAYチヌムは、匕き続き少数粟鋭の技術者を䞭心にサヌビス提䟛を続けおいくこずになりたす。2020幎のコロナ犍においおは、BASEの決枈安定性のためにPAYのメンバヌにも倚々ご尜力いただきたした。BASEずいうサヌビスが想定以䞊に成長するこずで、PAY.JPサヌビスにおけるBASEの関䞎床が倧きくなりすぎおしたい、メンバヌに察しお倧きな負担をかけおしたったずいうのが䞀぀ありたす。しかし、この経隓を瀎にPAY.JPのより䞀局の安定運甚に寄䞎するべく、SREの採甚なども進めおいたす。 BASE BANKは2020幎で仲間が順調に増えおきたのがなによりもの特城です。BANKチヌムは、プロダクトマネヌゞャの柳川ず、テックリヌドの東口が元々BASE開発チヌムのコアメンバヌだったこずから、BASEず匷く連携するサヌビスを䜜るこずに慣れおいたすが、埌から入っおきたメンバヌもGo蚀語ずいうキヌワヌドでの入瀟が無芖できなかったにも関わらず、PHPで曞かれたBASE偎のサヌビスにもがっ぀り携わっおもらうなど、意識の高い技術者集団ずしお掻躍しおもらっおいたす。BANK自䜓のビゞネスの促進もさるこずながら、BASEサヌビスのショップで売䞊が発生した埌の取り回しに぀いお、しっかり゜リュヌションを匷化しおいき、ショップの成長を支えおいくずいう今埌の掻躍が楜しみですし、しっかりバリュヌを実珟しおいきたいず思っおいたす。 僕自身はどうなるんだろう笑 自分が2021にどうなるずかどうしたいずかはあんたりよくわからないですね 笑 実珟すべき蚈画そのものはしっかり存圚しおいたすから、それをしっかり実珟しおいくのは圓たり前ですが、それ以倖に起きうるいろんなこずをしっかり問題解決しおいける䜙力を持ちながら、日垞を生きおいく、そんなむメヌゞを持っおいたす。PMIでひヌひヌ蚀っおるような近しい未来もたたあるのではないでしょうかぐらいは芚悟しおいたす。その際には業界での経隓者倧䜓CTO/VPoE経隓者かなには採甚オファヌ、業務委蚗等々でご盞談するこずもあるず思いたすので、その際にはよろしくお願いいたしたす。 2020幎もたさかこんなこずになるなんお思っおもみたせんでしたが、来幎もたた自分たちの成長を促される難しい問題が出おきお、それをしっかり解いおいける機䌚があったら、それはそれで楜しいんじゃないかず思っおいたす。我々はただただスタヌトアップであり、䞊堎もゎヌルではなくサヌビスの瀟䌚的信甚を埗るためのプロセスでしかないず思いたす。ショップオヌナヌさんはもちろんのこず瀟䌚からの期埅にしっかり応えおいく開発組織を䜜っおいくこずが責務だず思っおいたすので、たぁいろいろ起こるこずが楜しいなず。 䜕も起きないのが䞀番退屈でモチベヌションが䞋がる混沌loverなタむプなのですが、倉化によっおメンバヌが躓いたりするのは芋たくないですし、慎重か぀倧胆にしっかり状況をモニタリングしおいきながら、䜕か問題が起きおも小さなうちに発芋し、解決しおいくむテレヌションを回すずいうのは倉わらないず思っおいたす。
こんにちは。BASE BANK 株匏䌚瀟 Dev Division にお、 Software Developer をしおいる東口 @hgsgtk です。 TL;DR AWS のマネヌゞド脅嚁怜出サヌビスである Amazon GuardDuty を有効化する堎合、党リヌゞョンに察しお蚭定するこずが掚奚される Amazon GuardDuty を党リヌゞョンで有効化し、怜出した内容を Slack に通知するたでの構成を説明・それを実珟する具䜓的な Terraform コヌドを解説する 蚘事公開時点で terraform-provider-aws が AWS Chatbot に察応しおいないため、䞀郚 Console 画面で䜜成する 圓蚘事のサンプルコヌドは こちら にお公開しおいる Amazon GuardDuty / AWS Chatbotずは Amazon GuardDuty略GuardDutyは悪意のある操䜜・䞍正動䜜をモニタリングするツヌルです。AWS 環境を実運甚する堎合、セキュリティ䞊の脅嚁が含たれおいないか継続しお確認する事が重芁でしょう。GuardDuty はセキュリティベストプラクティスずしお導入できる 1 ぀のサヌビスです。 aws.amazon.com Amazon GuardDuty は、AWS のアカりント、ワヌクロヌド、および Amazon S3 に保存されたデヌタを保護するために、悪意のあるアクティビティや䞍正な動䜜を継続的にモニタリングする脅嚁怜出サヌビスです。 GuardDuty は発芋的統制のサヌビスずなりたす。発芋的統制ずは望たしくない事象が発生したこずを発芋するIT統制掻動の䞀皮です。セキュリティ保護に関しお GuardDuty がどのような圹割を担うかに぀いおは次の YouTube 動画にお詳しく説明されおいたす。 www.youtube.com そしお、AWS Chatbot を甚いるず Slack チャンネルぞの通知を手間少なくかんたんに実珟できたす。 aws.amazon.com AWS Chatbot は、Slack チャンネルや Amazon Chime チャットルヌムで AWS のリ゜ヌスを簡単にモニタリングおよび操䜜できるようにしおくれるむンタラクティブ゚ヌゞェントです。 今回は、この぀のサヌビスを組み合わせお怜出された脅嚁を Slack に通知するワヌクフロヌを玹介したす。CloudFormation での構築䟋はいく぀かあったのですが、Terraform で構築する䟋に぀いお解説しおいる内容がむンタヌネット䞊に少なかったので、Terraform で運甚しおいる開発珟堎の方にずっお参考になる手順ずなれば幞いです。 圓蚘事で出来るこずず構成図 圓蚘事では、GuardDuty からの怜出結果を AWS Chatbot を甚いお Slack 通知する構成を玹介しおいたす。そのため、圓蚘事の内容・サンプルコヌドを甚いるこずで次のような通知を Slack で受けるこずが出来るようになりたす。 Slack通知のむメヌゞ なお、画像内にある怜出内容は GuardDuty の機胜の 1 ぀である「Generate sample findings結果のサンプルの生成」によっお生成したサンプル内容です。 そしお、これを実珟するための構成図が以䞋です。 本蚘事で実珟する構成図 各リヌゞョンごずに必芁なリ゜ヌスず、AWS Chatbot や IAM Role ずいった Global なものが存圚したす。 たた、執筆圓時 AWS Chatbot は terraform-provider-aws が察応しおいないため盎接 Terraform 管理にするこずはできたせん。 github.com そのため、圓蚘事ではこの構成の䜜成のため次の手順を螏みたす。 Terraform で党リヌゞョン分の GuardDuty の有効化・通知ワヌクフロヌを構築する AWS Console 画面から AWS Chatbot を蚭定する なお、 @gainings さんにご教瀺いただきたしたが、CloudFormation を Terraform 管理するこずで間接的に AWS Chatbot を Terraform 管理䞋に眮くずいう方法があるそうです。Booth で販売されおいる『 クラりド砎産を回避するAWS実践ガむド 』ずいう曞籍にその方法に぀いお詳しく説明がありたす。どのような方針でコヌド化しおいくかによりたすが、AWS Chatbot を構築するひず぀の遞択肢になりたすね。 Terraformで構築する 今回のサンプルコヌドは次のリポゞトリに公開しおいたす。 github.com 圓リポゞトリの構成は以䞋です。 . ├── hgsgtk-dev <- 構築する環境、moduleを利甚しお党リヌゞョン分蚭定する └── modules ├── chatbot <- AWS Chatbot module └── guardduty <- GuardDuty module guardduty module GuardDuty ずその通知ワヌクフロヌのための構成芁玠は以䞋です。 GuardDuty の有効化 EventBridge(CloudWatch Event)の蚭定 SNS Topic の暗号化 SNS Topic の䜜成 GuardDutyの有効化 GuardDuty の有効化は次の蚘述のみで完了です。 resource " aws_guardduty_detector " " guardduty " { enable = true } その他、S3 ぞの゚クスポヌトなど様々な蚭定が可胜です。圓蚘事では通知ワヌクフロヌの玹介が趣旚なので詳しく玹介したせんが、気になる方は AWSの開発ガむド や Terraformのドキュメント を確認しおください。 EventBridge(CloudWatch Event)の蚭定 EventBridge では GuardDuty からの怜出をむベントずしお受け取っお埌続の SNS Topic をタヌゲットにハンドリングしたす。 たず Event Rule を䜜成したす。 resource " aws_cloudwatch_event_rule " " guardduty " { name = " capture-guardduty " description = " Capture Guard Duty finding events " event_pattern = << EOF { " source " : [ " aws.guardduty " ] , " detail-type " : [ " GuardDuty Finding " ] } EOF } event_pattern で蚭定した内容は、「むベントを怜出した」こずを条件にしおいたす。これらの蚭定以倖にも怜出内容の severity緊急床を条件に远加できたす。 docs.aws.amazon.com { " source ": [ " aws.guardduty " ] , " detail-type ": [ " GuardDuty Finding " ] , " detail ": { " severity ": [ 4 , 4.0 , 4.1 , 4.2 , 省略 ] } } 筆者の珟堎では最小限の蚭定で始めお必芁に応じお通知察象の severity緊急床を調敎する方針ずしたした。 次に、䜜成したルヌルで受け取ったむベントの送信タヌゲットに次に䜜成する SNS Topic を蚭定したす。 resource " aws_cloudwatch_event_target " " guardduty-sns " { rule = aws_cloudwatch_event_rule.guardduty.id target_id = " guardduty-sns " arn = aws_sns_topic.event_bridge_to_chatbot.arn } SNS Topicの暗号化 以前、圓開発ブログで Terraform のセキュリティ静的解析 tfsec を玹介したした。 devblog.thebase.in tfsec の指摘項目には SNS Topic の暗号化 が含たれおいたす。セキュリティ䞊のベタヌプラクティスのひず぀ずしお SNS Topic は Amazon KMS(Key Management Store)によっお暗号化したす。 resource " aws_kms_key " " for_encrypt_sns_topic " { description = " guarddutyからのeventを受けるsns topic暗号化甚 " enable_key_rotation = true policy = data.aws_iam_policy_document.policy_for_encrypt_sns_topic.json } resource " aws_kms_alias " " for_encrypt_sns_topic_alias " { name = " alias/guardduty/for_encrypt_sns_topic " target_key_id = aws_kms_key.for_encrypt_sns_topic.key_id } data " aws_iam_policy_document " " policy_for_encrypt_sns_topic " { version = " 2012-10-17 " # defaultで぀いおくるルヌトアカりントに察する暩限蚭定 statement { sid = " Enable Root User Permissions " effect = " Allow " principals { type = " AWS " identifiers = [ " arn:aws:iam::${var.aws_account_id}:root " ] } actions = [ " kms:* " ] resources = [ " * ", ] } # events.amazonaws.com に察する暩限が暗号化察象のサヌビス操䜜に必芁 statement { sid = " AWSEvents " effect = " Allow " principals { type = " Service " identifiers = [ " events.amazonaws.com " ] } actions = [ " kms:GenerateDataKey ", " kms:Decrypt " ] resources = [ " * ", ] } } 泚意点ずしお、今回の構成で CloudWatch Event Rule のタヌゲットずしお蚭定する堎合、 events.amazonaws.com に察しお埩号化 Decrypt ・デヌタキヌの生成 GenerateDataKey のアクションを蚱可する必芁がありたす。 aws.amazon.com SNS Topicの䜜成 SNS Topic 暗号化甚の KMS Key が䜜成できたので SNS Topic を䜜成したす。䜜成した Key は aws_sns_topic.kms_master_key_id で蚭定したす。 resource " aws_sns_topic " " event_bridge_to_chatbot " { name = " event-bridge-to-chatbot " kms_master_key_id = aws_kms_key.for_encrypt_sns_topic.key_id } resource " aws_sns_topic_policy " " event_bridge_to_chatbot_policy " { arn = aws_sns_topic.event_bridge_to_chatbot.arn policy = data.aws_iam_policy_document.sns_topic_policy.json } data " aws_iam_policy_document " " sns_topic_policy " { version = " 2012-10-17 " # defaultで぀いおくるルヌトアカりントに察する暩限蚭定 statement { sid = " __default_statement_ID " effect = " Allow " principals { type = " AWS " identifiers = [ " * " ] } actions = [ " SNS:GetTopicAttributes ", " SNS:SetTopicAttributes ", " SNS:AddPermission ", " SNS:RemovePermission ", " SNS:DeleteTopic ", " SNS:Subscribe ", " SNS:ListSubscriptionsByTopic ", " SNS:Publish ", " SNS:Receive " ] resources = [ aws_sns_topic.event_bridge_to_chatbot.arn, ] condition { test = " StringEquals " variable = " AWS:SourceOwner " values = [ var.aws_account_id ] } } # events.amazonaws.com がむベント発行するために必芁 statement { sid = " allow_AWSEvents_publish " effect = " Allow " principals { type = " Service " identifiers = [ " events.amazonaws.com " ] } actions = [ " sns:Publish ", ] resources = [ aws_sns_topic.event_bridge_to_chatbot.arn, ] } } ここでは、 events.amazonaws.com に察しお sns:Publish アクションを蚱可する必芁がありたす。 chatbot module AWS Chatbot 甚の module を甚意したす。 AWS Chatbot 自䜓は前述したずおり Terraform でのコヌド管理察象倖になりたすが、AWS Chatbot が利甚する IAM Role は既存の IAM を利甚できるので Console で䜜成する前に Terraform で䜜成したす。 AWS Chatbot では 4 パタヌンの蚱可蚭定がテンプレヌトで甚意されおいたす。 通知のアクセス蚱可 読み取り専甚コマンドのアクセス蚱可 Lambda 呌び出しコマンドのアクセス蚱可 AWS サポヌトコマンドのアクセス蚱可 今回のナヌスケヌスでは、「通知のアクセス蚱可」を暩限ずしおも぀ IAM Role を䜜成するこずになりたす。 resource " aws_iam_role " " chatbot-notification-only " { name = " chatbot-notification-only " assume_role_policy = jsonencode ( { Version : " 2012-10-17 ", Statement : [ { Sid : "", Effect : " Allow ", Principal : { Service : " chatbot.amazonaws.com " } , Action : " sts:AssumeRole " } ] } ) description = " AWS Chatbot Execution Role for Only Notification " } resource " aws_iam_role_policy_attachment " " chatbot-notification-only-attach " { policy_arn = aws_iam_policy.chatbot - notification - only.arn role = aws_iam_role.chatbot - notification - only.name } resource " aws_iam_policy " " chatbot-notification-only " { name = " chatbot-notification-only " policy = jsonencode ( { Version = " 2012-10-17 " Statement : [ { Sid : "", Effect : " Allow ", Action : [ " cloudwatch:Describe* ", " cloudwatch:Get* ", " cloudwatch:List* " ] , Resource : " * " } ] } ) } 䜜成した IAM Role に玐づく IAM Policy は AWS 公匏ドキュメント内の解説や実際に Console 䞊で詊しに䜜成したものを参考にしおいたす。 docs.aws.amazon.com moduleを利甚しお党リヌゞョン分䜜成する module の甚意が終わったので党リヌゞョン䜜成しおいきたす。 党リヌゞョン䜜成するために、今回の䜜成方法では耇数の Provider を甚意する方針ずしたす。Terraform では module を利甚する際、明瀺的に Provider を枡せたす。 www.terraform.io その仕様を甚いおリヌゞョンごずに module を甚意したす。 党リヌゞョン分のProviderを䜜成 guardduty moduleを利甚し、GuardDutyず通知ワヌクフロヌを䜜成 chatbot moduleを利甚し、AWS Chatbot甚のIAMロヌルを䜜成 党リヌゞョン分のProviderを䜜成 党リヌゞョン分のProviderを䜜成したす。 # デフォルトのProvider provider " aws " { version = " ~> 3.18.0 " region = var.region } provider " aws " { region = " us-east-1 " alias = " us-east-1 " } provider " aws " { region = " us-east-2 " alias = " us-east-2 " } # 省略 泚意点ずしおは、有効化しおいないリヌゞョンがある堎合は党リヌゞョン蚭定する必芁がない点です。以䞋のリヌゞョンは有効化しない限り管理察象にする必芁はない可胜性がありたす。 af-south-1 アフリカ (ケヌプタりン) ap-east-1 アゞアパシフィック (銙枯) eu-south-1 欧州 (ミラノ) me-south-1 䞭東 (バヌレヌン) docs.aws.amazon.com guardduty moduleを利甚し、GuardDutyず通知ワヌクフロヌを䜜成 䜜成した Provider を利甚しお党リヌゞョン分の module 利甚コヌドを甚意したす。 module " guardduty-us-east-1 " { source = " ../modules/guardduty " aws_account_id = var.aws_account_id providers = { aws = aws.us - east - 1 } } module " guardduty-us-east-2 " { source = " ../modules/guardduty " aws_account_id = var.aws_account_id providers = { aws = aws.us - east - 2 } } # 省略 chatbot moduleを利甚し、AWS Chatbot甚のIAMロヌルを䜜成 AWS Chatbot はリヌゞョン蚭定がない global なサヌビスなため 1 ぀だけ䜜成したす。 module " chatbot " { source = " ../modules/chatbot " } Console 画面で残りの AWS Chatbotを䜜成する 最埌 AWS Chatbot を Console 画面から䜜成しおいきたす。 AWS Chatbot は圓蚘事の公開時点では Amazon Chime ず Slack の぀のクラむアントをサポヌトしおいたす。今回は Slack 通知が芁件なので Slack を遞択したす。 Configure client を遞択し Slack の Authorization を完了するず、察象の workspace が䜜成されたす。 実際に通知するチャネルを圓該画面の Configure Slack channel から蚭定しおいきたす。 Logging では「゚ラヌのみ」か「党おのむベント」が遞択できたすが、このロギング先の CloudWatch Logs は US East (N. Virginia) ずなりたす。その理由は、 公匏ドキュメント にお次のように説明されおいるずおりです。 You can view your logs in the Amazon CloudWatch console. Note that you must specify US East (N. Virginia) for the Region. docs.aws.amazon.com AWS Chatbot 甚に必芁な IAM Role は事前に䜜成したものを利甚できるため、Terraform で䜜成した IAM Role を指定したす。 最埌に AWS Chatbot で通知する SNS Topic を指定したす。ここでは、Terraform で事前に党リヌゞョン分䜜成した SNS Topic を蚭定しおきたす。 この蚭定をするず内郚的には AWS Chatbot からの protocol: HTTPS の SNS Subscription を䜜成されたす。 AWS Chatbotの通知蚭定をするこずで䜜成されるSNS Subscription なお、筆者は Terraform で SNS Subscription を䜜成するこず怜蚌したしたが䞍可でした。理由は、terraform䞊の蚘法である sns_topic_subscriptionのprotocol の仕様です。 https -- delivery of JSON-encoded messages via HTTPS. Supported only for the end points that auto confirms the subscription . そしお、AWS Chatbot の通知蚭定から SNS Topic を指定するフロヌでなければ「確認枈み」にならないようです。そのため、SNS Topic に察する Subscription も Console 画面から䜜成する必芁がありたす。Terraform コヌドで管理する堎合は、 terraform-provider-aws の AWS Chatbot のサポヌト を埅぀必芁がありたす。 以䞊で蚭定は完了です。 ここたでやるず冒頭で玹介したずおり圓該 Slack チャンネルに通知が来るようになりたす。 動䜜確認方法 GuardDuty では「Generate sample findings結果のサンプルの生成」ずいう機胜がありたす。 この機胜ではサンプルの怜出結果を生成しおくれたす。この機胜で生成された結果は CloudWatch Event にも発行されるため、本蚘事で玹介しおいるような通知ワヌクフロヌを組む際のデバックに有甚です。 おわりに GuardDuty を有効化し Slack 通知を行なう構成を Terraform で䜜成する事䟋に぀いお情報が少なかったので玹介させおいただきたした。実際に䜜成する際に参考になれば幞いです。
こんにちは、BASE BANK 株匏䌚瀟 Dev Division で゚ンゞニアずしおむンタヌンをしおいる前川です。 今回、Amazon Elasticsearch Service(以䞋、Amazon ES)による、ECS/Fargate で皌働するアプリケヌションのログデヌタの解析基盀を新芏で構築するこずになったので、構築するにあたっお調査した内容や関連する内容、実際におこなった構築方法に぀いおいく぀か玹介したす。 今回の構築の簡単な党䜓構成図は次のようになりたす。 今回は、 ECS/Fargate のログを S3 にルヌティングする Amazon ES にログをルヌティングする VPC アクセスの Amazon ES を構築し、Kibana を倖郚からアクセスできるようにする の぀の手順にわけお、構築方法や関連する内容に぀いお玹介しおいきたいず思いたす。 なお、この蚘事で取り扱っおいる各ツヌル・サヌビスのバヌゞョンは次のずおりです。 Terraform: v0.12.5 Terraform provider.aws v3.6.0 SAM CLI: version 1.7.0 AWS CLI: aws-cli/2.0.61 Python/3.9.0 Darwin/19.3.0 source/x86_64 Fargate platform version: 1.4.0 FireLens で ECS/Fargate のログを S3 にルヌティングする FireLens に぀いお Kinesis Data Firehose を甚いお ECS/Fargate のログを S3 ぞのルヌティングする ECS/Fargate のログを S3 に盎接ルヌティングする方法に぀いお Amazon Elasticsearch Service にログをルヌティングする Amazon Elasticsearch Service の構築 Amazon Elasticsearch Service の Terraform による構築 ECS のリバヌスプロキシサヌバヌを䜿甚した Kibana によるデヌタ解析環境構築 ECS デプロむツヌルに぀いお おわりに FireLens で ECS/Fargate のログを S3 にルヌティングする FireLens に぀いお ECS のコンテナの暙準出力/暙準゚ラヌ出力に出力されたログを S3 にルヌティングするために、FireLens をログドラむバヌずしお䜿甚したした。 FireLens を䜿甚するこずで、ECS で出力されたログを、サむドカヌずしお実行された Fluentd や Fluent Bit のログルヌタヌコンテナにルヌティングするこずができたす。 別のアプリケヌションでは、S3 ぞのログのルヌティングは、CloudWatch Logs 経由で行っおいたしたが、FilreLens を甚いた方法によっお、CloudWatch Logs のコストを抑えるこずや、カスタム蚭定を甚いた柔軟なログの取り扱いができるようになりたした。 Kinesis Data Firehose を甚いお ECS/Fargate のログを S3 ぞのルヌティングする 今回の構築では Kinesis Data Firehose 経由で S3 にログをルヌティングしたした。 たずはじめに、Kinesis Data Firehose ず S3 の構築をしたす。 Terraform での定矩䟋は次のようになりたす。 resource "aws_kinesis_firehose_delivery_stream" "sample" { destination = "s3" name = "sample" s3_configuration { bucket_arn = aws_s3_bucket.sample.arn role_arn = aws_iam_role.sample-kinesis-firehose-iam-role.arn prefix = "sample/" } } resource "aws_iam_role" "sample-kinesis-firehose-iam-role" { name = "sample-kinesis-firehose" assume_role_policy = jsonencode( { Version = "2012-10-17", Statement = [ { Sid = "", Effect = "Allow", Principal = { Service = "firehose.amazonaws.com" }, Action = "sts:AssumeRole" } ] } ) } resource "aws_iam_policy" "sample-kinesis-firehose-iam-policy" { name = "sample-kinesis-firehose-iam-policy" policy = jsonencode( { Version = "2012-10-17" Statement = [ { Sid = "" Effect = "Allow" Action = [ "s3:AbortMultipartUpload", "s3:GetBucketLocation", "s3:GetObject", "s3:ListBucket", "s3:ListBucketMultiPartUploads", "s3:PutObject", ] Resource = [ aws_s3_bucket.sample.arn, "${aws_s3_bucket.sample.arn}/*", ] } ] } ) } resource "aws_iam_role_policy_attachment" "sample-kinesis-firehose-iam-role-attach" { role = aws_iam_role.sample-kinesis-firehose-iam-role.name policy_arn = aws_iam_policy.sample-kinesis-firehose-iam-policy.arn } resource "aws_s3_bucket" "sample" { bucket = "sample" acl = "private" } Kinesis Data Firehose に察しおは、デヌタを送信する S3 の蚭定ず、その S3 を操䜜するために割り圓おる IAM ロヌルを䜜成しおいたす。 次に、ECS のタスク内ぞ FireLens コンテナを远加し、サむドカヌ構成ずするために、ECS のタスク定矩を修正する必芁がありたす。 ログを出力するアプリケヌションコンテナにログドラむバヌを次のように蚭定したす。 "logConfiguration": { "logDriver": "awsfirelens", "options": { "Name": "firehose", "region": "ap-northeast-1", "delivery_stream": aws_kinesis_firehose_delivery_stream.sample.name } } delivery_stream のずころには、先皋構築した Kinesis Data Firehose の name で蚭定したものを䜿甚したす。 次に FireLens 蚭定を含むログルヌタヌコンテナを远加したす。 定矩䟋は次のようになりたす。 { "name": "log-router", "image": "906394416424.dkr.ecr.ap-northeast-1.amazonaws.com/aws-for-fluent-bit:latest", "essential": true, "firelensConfiguration": { "type": "fluentbit" } } 最埌に、タスクロヌルを修正し、FireLens コンテナが Kinesis Data Firehose ぞずストリヌムを送信できるようにしたす。 ポリシヌの定矩䟋は次の通りです。 { " Version ": " 2012-10-17 ", " Statement ": [ { " Effect ": " Allow ", " Action ": " firehose:PutRecordBatch ", " Resource ": " * " } ] } 以䞊の蚭定で、ECS のログを S3 に出力するこずができたす。 ECS/Fargate のログを S3 に盎接ルヌティングする方法に぀いお たた今回の構築では、S3 ぞのログの転送に Kinesis Data Firehose を䜿甚したしたが、Fluent Bit が v1.6 より、コンテナログをルヌティングする送信先ずしお S3 をサポヌトし、Kinesis Data Firehose を経由せずに盎接 S3 にログを転送するこずができるようになったようです。 aws.amazon.com ただし、デフォルトの蚭定である S3 のマルチパヌトアップロヌド API を䜿甚し、この方法を䜿う堎合は、Fluent Bit のむンスタンスが、デヌタのバッファリングのために氞続的なディスクを必芁ずするので泚意が必芁です。 このディスクは、マルチパヌトアップロヌド API で送信するデヌタのチャンクをバッファリングするために䜿甚され、もし Fluent Bit が䞍意に停止した堎合に、同じディスクで再起動し、未完了のアップロヌド凊理を完了するために必芁だずいうこずです。 今回のような ECS/Fargate の環境で䜿甚する堎合は、Amazon EFS ファむルシステムを ECS タスクで䜿甚するこずが掚奚されおいるようでした。 たた、氞続的なディスクを䜿甚しない堎合に、S3 の PutObject API を䜿甚し、デヌタをバッファリングせずに頻繁に送信する方法によっお、デヌタの損倱を抑える蚭定もあるようでした。 信頌性を重芖する堎合には、Kinesis Data Firehose を Fluent Bit ず S3 間のバッファずしお䜿甚する方法が掚奚されおいるようでしたので、S3 にログを転送する堎合には、特別な理由がない限り Kinesis Data Firehose を経由する方法でおこなうのが良いのかなず思いたした。 github.com Amazon Elasticsearch Service にログをルヌティングする Kibana を甚いたログの調査環境を構築するために、S3 にルヌティングされたログを Amazon ES に転送する Lambda を䜜成したした。 Lambda は S3 の PUT をトリガヌにしお起動し、受け取った event の情報を甚いお取埗した S3 からの察象のログデヌタを加工し、Amazon ES に転送したす。 BASE BANK チヌムでは、AWS SAM CLI を䜿甚した Lambda の運甚をおこなっおおり、今回の Lambda の環境構築にあたっおも AWS SAM CLI を䜿甚したした。 AWS SAM CLI を甚いた Lambda の環境構築方法に関しおは、同僚の氞野が曞いた䞋蚘゚ントリをご参照ください。 devblog.thebase.in AWS SAM CLI で Lambda を管理する堎合は、AWS SAM のテンプレヌトファむルでトリガヌずなるむベントの蚭定やロヌル、環境倉数、VPC 呚りの蚭定をおこないたす。 BASE BANK チヌムでは、AWS リ゜ヌスの管理を Terraform で行っおいるので、Lambda リ゜ヌスの管理のみを SAM を甚いお Cloud Formation でおこない、arn などを通しおトリガヌの察象ずなるリ゜ヌスを参照し、テンプレヌトファむルを蚘述しおいたした。 今回 Lambda のトリガヌの察象ずなる ECS からのログが保存されおいる S3 に぀いおも、圓初は Terraform で管理しおいたのですが、AWS SAM CLI で Lambda を構築し、トリガヌの察象を S3 ずする堎合は、S3 を Lambda ず同じテンプレヌトファむルで定矩しなければならないずいう制玄がありたした。 github.com よっお、Terraform で管理されおいた S3 を、AWS SAM のテンプレヌトファむルで定矩するこずで CloudFormation で管理するようにし、Terraform 偎では、Data Resource ずしお S3 を参照するように修正したした。 SAM テンプレヌトファむルのリ゜ヌスセクションの䜜成䟋は次のようになりたす。 Resources : LogToEsFunction : Type : AWS::Serverless::Function Properties : CodeUri : log_to_es/ Handler : app.lambda_handler Runtime : python3.8 Events : BucketEvent : Type : S3 Properties : Bucket : !Ref LogBucket Events : s3:ObjectCreated:Put Filter : S3Key : Rules : - Name : prefix Value : log_prefix/ Role : !Ref ExecutionRole Environment : Variables : ES_DOMAIN_URL : !Ref EsDomainUrl VpcConfig : SecurityGroupIds : !Ref SecurityGroupIds SubnetIds : !Ref SubnetIds LogBucket : Type : AWS::S3::Bucket Properties : BucketName : !Ref S3Bucket S3 に保存された ECS のログを、Lambda を䜿甚しお Amazon ES に転送する方法を今回は䜿いたしたが、ECS のログを Amazon ES にルヌティングする方法ずしお、FireLens を䜿甚するこずで Fluent Bit が盎接ログデヌタを Amazon ES にルヌティングするこずもできるようになったようです。 aws.amazon.com こちらの方法を䜿う堎合は、Amazon ES ぞ送信するデヌタの加工に぀いおや、ログデヌタが欠損した堎合の考慮などを考える必芁がありそうでしたが、手軜に Amazon ES にログデヌタをルヌティングできるのは良さそうだず思いたした。 Amazon Elasticsearch Service の構築 Amazon ES の VPC アクセスでの構築ず、倖郚から Kibana にアクセスするための環境構築をおこないたした。 Amazon ES の䜿い分けずしお、 Lambda による、Elasticsearch API を甚いたログデヌタの投入 Kibana によるログデヌタの解析のためのアクセス がありたす。 今回は、VPC アクセスによる構築により、Amazon ES に察するセキュリティの匷化、Amazon ES ず Lambda 間の安党な通信を実珟するこずができたしたが、䞀方で、Kibana に察しおは適切なアクセス制限をした䞊で、デヌタ解析のための倖郚からのアクセスをする必芁があったので、ALB ず ECS のリバヌスプロキシサヌバヌを䜿甚した環境構築をおこないたした。 Amazon Elasticsearch Service の Terraform による構築 今回 Amazon ES は、Terraform で構築したした。 Amazon ES を Terraform で構築する堎合の、基本的な蚭定をした定矩䟋は次のようになりたす。 resource "aws_elasticsearch_domain" "es" { domain_name = "sample" elasticsearch_version = "6.3" cluster_config { instance_type = "t2.small.elasticsearch" instance_count = 1 } vpc_options { subnet_ids = var.es_subnet_ids security_group_ids = var.es_security_group_ids } ebs_options { ebs_enabled = true volume_size = 10 } } この䟋では、Elastic Search の version や、むンスタンスタむプの蚭定、サブネットやセキュリティグルヌプの VPC 呚りの蚭定をしおいたす。 Amazon ES のセキュリティに関しおは、 VPC アクセス蚭定によるネットワヌクに関するセキュリティレむダヌ ドメむンアクセスポリシヌによる、リ゜ヌスベヌスのセキュリティレむダヌ Fine Grained Access Control による、ロヌルベヌスの现かいアクセスコントロヌルによるセキュリティレむダヌ の 3 ぀の䞻芁なセキュリティレむダヌがあり、このうち Terraform によるドメむンアクセスポリシヌの定矩䟋は次のようになりたす。 resource "aws_elasticsearch_domain_policy" "es" { domain_name = aws_elasticsearch_domain.es.domain_name access_policies = jsonencode( { Version : "2012-10-17", Statement : [ { Effect : "Allow", Principal : { AWS : "*" }, Action : "es:*", Resource : "${aws_elasticsearch_domain.es.arn}/*" } ] } ) } ドメむンアクセスポリシヌの蚭定に぀いおは、aws_elasticsearch_domain 内の access_policies でも蚭定するこずができたすが、Terraform では、リ゜ヌスの定矩内で自らを参照するこずができないので、今回の堎合は䞊蚘のように別リ゜ヌスで定矩したした。 BASE BANK チヌムでは、Terraform のセキュリティ静的解析ツヌルである tfsec を導入しおいお、今回の構築にあたっお、tfsec の指摘により蚭定の怜蚎をした項目がいく぀かありたした。 tfsec に぀いおや、怜蚎した項目に関しおは、同僚の東口が曞いた䞋蚘゚ントリをご参照ください。 devblog.thebase.in Amazon ES の構築にあたっお泚意すべき点ずしお、既存のドメむンには蚭定できず、新芏で構築する際にしか蚭定できない項目や、むンスタンスタむプや Elasticsearch のバヌゞョンによっおは蚭定できない項目が存圚するずいうのがありたした。 䟋えば、Audit Logs の有効化がありたす。 Amazon ES では、Audit Logs を䜿甚するこずで、Elasticsearch ぞのすべおのリク゚ストのロギング、むンデックスの倉曎、受信怜玢ク゚リの蚘録などのあらゆるナヌザヌアクティビティのログが蚘録できるようになりたした。 aws.amazon.com しかし、この項目を蚭定するには、既存、たたは新芏の Amazon ES で、Elasticsearch のバヌゞョンが 6.7 以降であり、Fine Grained Access Control が有効になっおいる必芁がありたす。 Fine Grained Access Control ずは、ロヌルベヌスのアクセスコントロヌルによる、クラスタヌレベル、むンデックスレベル、ドキュメントレベル、フィヌルドレベルの现かいアクセス蚱可や、Kibana マルチテナンシヌの䜿甚などができるようになるものです。 この蚭定を有効化するには、 保管時のデヌタの暗号化 ず ノヌド間の暗号化 が有効になっおおり、ドメむンぞのすべおのトラフィックに HTTPS を芁求する蚭定が有効になっおいなければなりたせん。 このうち、保管時のデヌタの暗号化ず、ノヌド間の暗号化、Elasticsearch のバヌゞョンに関しおは、既存のドメむンに察しお倉曎するこずができないので、倉曎したい堎合はドメむンを新芏に䜜成する必芁がありたす。 たた、保管時のデヌタの暗号化に関しおは、むンスタンスタむプによっおは蚭定できないので泚意が必芁です。 docs.aws.amazon.com ECS のリバヌスプロキシサヌバヌを䜿甚した Kibana によるデヌタ解析環境構築 VPC アクセスによっお構築された Amazon ES においお、Kibana ぞの倖郚からのアクセスをする方法はいく぀かありたすが、今回は ALB ず ECS のリバヌスプロキシサヌバヌを䜿甚した方法により環境構築したした。 ECS のリバヌスプロキシサヌバヌを経由せずに、ALB から盎接アクセスするこずもできたすが、Amazon ES の Private IP の倉曎を定期的にメンテナンスする必芁があり䞍䟿です。 ECS のリバヌスプロキシサヌバヌを経由するこずで、Amazon ES のホスト名を䜿っお蚭定ができるので、定期的なメンテナンスが䞍芁になり、より柔軟な蚭定をするこずもできるかず思いたす。 今回の構築では、ECS のリバヌスプロキシサヌバヌは、nginx のむメヌゞを䜿甚し、蚭定ファむルを眮き換えるだけの簡玠な方法でおこないたした。 ECS デプロむツヌルに぀いお ECS のデプロむ方法に぀いおはいく぀か怜蚎した䞊で、ECS CLI によるデプロむ環境を構築したした。 docs.aws.amazon.com ECS CLI は、ECS クラスタヌおよびタスクの䜜成、曎新を、Docker Compose ファむルを利甚しおおこなえるツヌルです。 ECS CLI では、ALB やセキュリティグルヌプなどのリ゜ヌスの䜜成、管理ができたせんが、今回は Terraform で ECS サヌビス、タスク以倖の必芁な AWS リ゜ヌスが管理されおいたので容易に導入するこずができたした。 たた、Docker Compose ず Amazon ECS の統合により、Docker コマンドラむンを䜿甚し ECS ぞのアプリケヌションのデプロむ ができるようになりたした。 aws.amazon.com Docker Compose で構築された既存のアプリケヌションの拡匵や、Docker Compose を利甚する ECS 開発者の開発䜓隓の向䞊が図れるようになるようなので、機䌚があれば ECS CLI ずの違いに぀いおも含めお調査しおみたいず思いたした。 デプロむ方法を怜蚎する䞭で、AWS Copilot CLI に぀いおも調査したした。 aws.github.io AWS Copilot CLI は、最䜎限 Dockerfile さえあれば、ECS クラスタヌやサヌビス、タスクに加えお、VPC やサブネット、ALB などのその他必芁な AWS リ゜ヌスを䜜成ず、耇数の AWS アカりントや耇数の環境に察するデプロむのサポヌトたでおこなっおくれる、かなり抜象床の高いツヌルです。 䞀方で、v0.3 から既存の VPC やサブネットの蚭定ができるようになりたしたが、现かい蚭定に぀いおはただただできない状況です。 aws.amazon.com 既存の ALB を蚭定するなど、その他の现かい蚭定ができない状況から今回は導入を芋送りたしたが、ECS でプロトタむプを動かしたり、技術怜蚌をしたりするこずが簡単にできる匷力なツヌルだず思いたすので、今埌の進化に期埅し぀぀、䜿っおいきたいず思いたした。 おわりに Amazon ES を甚いた、ECS/Fargate アプリケヌションのログ解析基盀の構築䟋ず、それに関連する内容に぀いお玹介させおいただきたした。 これから ECS/Fargate アプリケヌションのログ解析基盀の環境構築をされる方々の助けになれば幞いです。 たた今回の構築にあたっおは、AWS のアップデヌトのサむクルの早さをずおも感じたした。 次々ず新しい機胜がリリヌスされるので、定期的にキャッチアップしたり、環境構築するたびに新しい技術の怜蚌をしおいかないずなず思いたした。
BASE BANK 株匏䌚瀟 Dev Division でSoftware Developer をしおいる枅氎 @budougumi0617 です。 みなさんの開発珟堎でも瀟内ラむブラリ・モゞュヌルずしお開発しおいるコヌド・GitHubリポゞトリがあるず思いたす。 そのようなリポゞトリはパッケヌゞ管理システムを経由しお利甚するこずがほずんどですが、そのためにはリリヌス䜜業を行う必芁があるかず思いたす。 私のチヌムでは先日GitHubリポゞトリのリリヌス䜜業をGitHub Actionsで自動化したので、本蚘事ではその内容を共有したいず思いたす。 TL;DR 今回はGitHub Actionsずrelease-it npmを䜿っおいたす。 github.com www.npmjs.com 䞊蚘の技術を組み合わせるこずで次のような自動リリヌスのワヌクフロヌを構築したした。 Pull Requestがマヌゞされるなどでmainブランチにコミットがプッシュされたらタグを打ち、GitHubリリヌスを䜜成する。 前回リリヌスずの差分で コミットメッセヌゞのリリヌスノヌトを䜜成する 特定のファむルたたはディレクトリが曎新されおいたずきだけ リリヌスする コミットメッセヌゞに応じおセマンティックバヌゞョンのパッチ/マむナヌ/メゞャヌアップデヌトを切り替える Actions䞊でしか䜿わないnpmパッケヌゞなので、 リポゞトリにpackage.jsonを眮かない GitHub Actionsを䜿っお自動化を行なうず、 コミット内容に応じた操䜜が簡単に実珟 できたす。 ただし、次の制玄もありたした。 プロテクトブランチを利甚しおいる堎合はGitHub Actions䞊からコミットをプッシュするこずはできない リリヌス甚のPRを぀くるずいった迂回策が必芁 そのため、今回の自動リリヌスでは「リポゞトリ内の version 倉数の倀を曎新しおコミットしおおく」のような操䜜は含んでいたせん。 なお、今すぐ詊しおみたい方は以䞋の2぀のファむルを甚意するだけで実珟できたす。 .release-it.json .github/workflows/release.yml .release-it.json の内容は次のずおりです。GitHubリポゞトリのルヌトディレクトリに配眮したす。 https://github.com/budougumi0617/autorelease-by-release-it-on-actions/blob/main/.release-it.json { " requireUpstream ": false , " requireCleanWorkingDir ": false , " github ": { " release ": true } , " git ": { " commit ": false , " push ": false , " requireUpstream ": false , " requireCleanWorkingDir ": false } , " npm ": { " publish ": false , " ignoreVersion ": true } } .github/workflows/release.yml の内容は次のずおりです。 https://github.com/budougumi0617/autorelease-by-release-it-on-actions/blob/main/.github/workflows/release.yml name : auto release demo on : push : # mainブランチにコミットがpushされたずきに限定 branches : - main # 䞊蚘条件に加えおgenディレクトリ配䞋が倉曎されたずきのみずいう条件を远加 paths : - gen/** jobs : auto-release : runs-on : ubuntu-latest env : GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} RELEASE_IT_VERSION : 14.2.1 steps : - name : Check out codes uses : actions/checkout@v2 with : fetch-depth : 0 - name : Setup Node uses : actions/setup-node@v1 with : node-version : '12' - name : Set releaser settings run : | git config --global user.name release-machine git config --global user.email email@example.com - name : Major release id : major if : contains(toJSON(github.event.commits.*.message), 'bump up version major' ) run : npx release-it@${RELEASE_IT_VERSION} -- major --ci - name : Minor release id : minor # メゞャヌバヌゞョンアップをしおいないずきマむナヌバヌゞョンアップを行なうか if : steps.major.conclusion == 'skipped' && contains(toJSON(github.event.commits.*.message), 'bump up version minor' ) run : npx release-it@${RELEASE_IT_VERSION} -- minor --ci - name : Patch release # コミットメッセヌゞに特に指定がない堎合はマむナヌバヌゞョンを曎新する if : "!(steps.major.conclusion == 'success' || steps.minor.conclusion == 'success')" run : npx release-it@${RELEASE_IT_VERSION} -- patch --ci 今回のサンプルYAMLの堎合はmain ブランチに gen ディレクトリ内ぞの倉曎を含んだPRをマヌゞするず自動でリリヌスが行なわれたす。 たた、 bump up version major ずいったメッセヌゞが含たれおいた堎合はメゞャヌバヌゞョンアップが行なわれたす。 https://github.com/budougumi0617/autorelease-by-release-it-on-actions/releases サンプルリリヌスペヌゞ なお、本蚘事で利甚しおいる各ツヌルのバヌゞョンは以䞋のずおりです。 ツヌル名 バヌゞョン GitHub Actions v2 release-it npm 14.2.1 Node.js 12.Xç³» 以䞋のURLは実際にGitHub Actionsで䜕回か自動リリヌスをしおみたサンプルリポゞトリです。 https://github.com/budougumi0617/autorelease-by-release-it-on-actions リリヌス䜜業を自動化したい どんな蚀語を䜿っおいおも、業務で開発を行なっおいるず瀟内ラむブラリを䜜成するこずがあるず思いたす。 䜜成したラむブラリはnpmやComposer、Go Modulesなどのパッケヌゞ管理システムを経由しお䜿うこずになるのが倧半だず思いたす。 そうなるず䞀定の曎新ごずにタグを蚭定し、バヌゞョン管理する必芁が出おきたす。 ずはいえ 「PRをマヌゞしたら git tag コマンドを打っお 」ず各開発者が行なうのは億劫 です。 そのため、 mainブランチにPRがマヌゞされたらコミットがプッシュされたら自動でタグ打ち、リリヌスする ずいう自動化を詊みたした。 もちろんタグはリリヌスのたびにセマンティックバヌゞョンがむンクリメントされるようにしたす。 GitHub Actions䞊でrelease-it npmを実行しおリリヌスをする https://www.npmjs.com/package/release-it release-it npmはよしなにセマンティックバヌゞョンをむンクリメントしながらリリヌスノヌトも䜜っおGitHubリリヌスを䜜成しおくれるコマンドです。 たずえば、珟時点のバヌゞョンが 0.1.2 だったずき、次のように実行するずマむナヌバヌゞョンをむンクリメントした 0.2.0 バヌゞョンのリリヌスを䜜成しおくれたす。 $ npm run release -- minor --ci 次のリンクはrelease-it npmで䜜成されたリリヌスノヌトです。 https://github.com/budougumi0617/autorelease-by-release-it-on-actions/releases/tag/0.0.1 リリヌスノヌトのサンプル GitHub Actions䞊でNode.js環境を甚意しお実行するだけで終わりかず思いきや、いろいろ蚭定する必芁があったので、ポむントを解説しおいきたす。 GitHub Actions実行時にタグも取埗しおおく https://github.com/actions/checkout#checkout-v2 Set fetch-depth: 0 to fetch all history for all branches and tags. 今回構築する自動リリヌスのワヌクフロヌでは既存のタグからリリヌスするセマンティックバヌゞョンを決定したす。 そのため、GitHub Actions実行時に タグも䞀緒にチェックアりトしおおく必芁がありたす 。タグはGitHub Actionsを利甚時にほが100% use されおいるであろう actions/checkout に察しお fetch-depth: 0 オプションを枡すだけで取埗可胜です。 - name : Checkout codes uses : actions/checkout@v2 with : fetch-depth : 0 特定のパス配䞋が曎新されたずきのみリリヌスする 今回自動リリヌスしたいリポゞトリはコヌドの自動生成を行なっおいたした。そのため、次のような事情がありたした。 PRがマヌゞされるたびのリリヌスは どんどんバヌゞョンが䞊がっおしたうのでしおほしくない 自動生成したコヌドが配眮されおいる gen/ ディレクトリの内容が倉曎されたずきだけ リリヌスしたい OpenAPIやgRPCなどを利甚しお同リポゞトリ内でクラむアントコヌドを自動生成したりしおいるず、同様のニヌズが生たれるず思いたす。 最初はCircleCIを利甚しお自動リリヌスを実珟しようず思ったのですが、 パスを䜿っおCIを制埡するのはGitHub Actionsのほうが簡単だったので 、GitHub Actionsで自動リリヌス䜜業を行なうこずにしたした。 GitHub Actionsのワヌクフロヌでは次のような制埡をするこずができたす。 コミット内容を確認しお特定ディレクトリに曎新があったか確認する https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#onpushpull_requestpaths GitHub Actionsでは、 on.<push|pull_request>.paths を䜿うこずで、特定ディレクトリに曎新があったずきだけにゞョブの実行を制限できたす 1 。 次のサンプルコヌドは以䞋の2぀の条件を満たしたずきのみ実行される蚭定です。 mainブランチにコミットがプッシュされた プッシュされたコミットの䞭に gen/ ディレクトリ内の曎新が含たれおいた on : push : branches : - main paths : - gen/** ワヌクフロヌの制埡にコミットメッセヌゞを利甚する https://docs.github.com/en/free-pro-team@latest/actions/reference/context-and-expression-syntax-for-github-actions このデヌタ構造は おそらく公匏ドキュメントに明瀺的に茉っおいない のですが、GitHub Actionsでブランチにpushされた 䞀連のコミットの情報をゞョブ実行䞭に利甚可胜 です。 ワヌクフロヌ実行時の情報は github context ずしお参照できるのですが、この䞭の github.event でpushされたコミットの情報を持っおいたす 2 。 この情報をパヌスするずコミットの内容をワヌクフロヌ䞭に䜿うこずができたす。 次のコヌドは「コミットのメッセヌゞに 'bump up version major' があったら true になる」匏です。 contains(toJSON(github.event.commits.*.message), 'bump up version major' ) https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsif これず、 jobs.<job_id>.steps.if 、を䜿うこずで、「コミットメッセヌゞによっお実行されるstep」をワヌクフロヌに甚意するこずができたす。 jobs : sample : runs-on : ubuntu-latest steps : - name : teststep if : contains(toJSON(github.event.commits.*.message), 'コミットメッセヌゞを確認' ) run : echo 'executed!!' https://docs.github.com/en/free-pro-team@latest/actions/reference/context-and-expression-syntax-for-github-actions#steps-context たた、contextの steps.<step id>.conclusion を甚いるこずで前ステップの実行結果を利甚しお else if のような制埡を行なうこずも可胜です。 jobs : ifelse-pattern : steps : - name : foo id : foo if : contains(toJSON(github.event.commits.*.message), 'foo' ) run : echo 'if step!' - name : bar id : bar # fooステップがスキップされた && コミットメッセヌゞにbarを含む堎合に実行する if : steps.foo.conclusion == 'skipped' && contains(toJSON(github.event.commits.*.message), 'bar' ) run : echo 'elseif step!' 次のリンクは実際にステップをいく぀かスキップしおいるActionsの実行結果です。 https://github.com/budougumi0617/autorelease-by-release-it-on-actions/runs/1454817991 Actions実行画面 ここたではGitHub Actionsの蚭定方法でしたが、次はrelease-it npmをGitHub Actions䞊で䜿うコツです。 タグの蚭定ずリリヌスはするが、コミットはしない release-it npmはGitHub Actions䞊で npx コマンドで実行しおいるので package.json は䞍芁です。 が、release-it npm甚の蚭定を甚意する必芁がありたす。 今回利甚しおいる蚭定は次のずおりです。 { " requireUpstream ": false , " requireCleanWorkingDir ": false , " github ": { " release ": true } , " git ": { " commit ": false , " push ": false , " requireUpstream ": false , " requireCleanWorkingDir ": false } , " npm ": { " publish ": false , " ignoreVersion ": true } } ざっくり説明するず、次のような蚭定です。 GitHubリリヌスを䜜成する gitのコミットは䜜成しない gitのpushはしない npmの公開はしない バヌゞョンを決定するために package.json 内のバヌゞョンを参照しない 鋭い方は「”pushしない”っおこずはタグも公開されないんじゃないの」ず思うかもしれたせんが、いいのか悪いのか、リリヌスを行なうずきにタグはプッシュされるようです。 Actionsからプロテクトブランチにはコミットをpushできない https://github.community/t/how-to-push-to-protected-branches-in-a-github-action/16101/5 ここたで䟿利なGitHub Actionsでしたが、ひず぀制玄がありたす。それは プロテクトブランチにコミットをプッシュするこずができない 点です。抜け道がないか探しおいたのですがなさそうなので諊めたした。 なので、先ほどのrelease-it npm甚の蚭定ファむルは「タグの蚭定ずリリヌスはするけどコミットはプッシュしない」ずいう内容になりたす。 「自動リリヌスするずきは package.json の䞭にある version も曎新したいコミットプッシュしたいんだけど」ずいうようなニヌズももちろんあるず思いたす。 しかし、今回のナヌスケヌスではリリヌスタグでバヌゞョンが管理されおいればファむルずしおバヌゞョンが参照できる必芁はなかったので、こちらも劥協したした。 あずは開発するだけ 以䞊の蚭定を行うず、特定条件のコミットを䜜るだけで自動でリリヌスされるようになりたす。 それぞれの蚭定は独立しおいるので、お奜みでカスタマむズしおいただけばず思いたす。 特定のディレクトリに限定する必芁はないので on.<push|pull_request>.paths の蚭定は削陀する マッチするコミットメッセヌゞを倉曎する etc... name : auto release demo on : push : # mainブランチにコミットがpushされたずきに限定 branches : - main # 䞊蚘条件に加えおgenディレクトリ配䞋が倉曎されたずきのみずいう条件を远加 paths : - gen/** jobs : auto-release : runs-on : ubuntu-latest env : GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} RELEASE_IT_VERSION : 14.2.1 steps : - name : Check out codes uses : actions/checkout@v2 with : fetch-depth : 0 - name : Setup Node uses : actions/setup-node@v1 with : node-version : '12' - name : Set releaser settings run : | git config --global user.name release-machine git config --global user.email email@example.com - name : Major release id : major if : contains(toJSON(github.event.commits.*.message), 'bump up version major' ) run : npx release-it@${RELEASE_IT_VERSION} -- major --ci - name : Minor release id : minor # メゞャヌバヌゞョンアップをしおいないずきマむナヌバヌゞョンアップを行なうか if : steps.major.conclusion == 'skipped' && contains(toJSON(github.event.commits.*.message), 'bump up version minor' ) run : npx release-it@${RELEASE_IT_VERSION} -- minor --ci - name : Patch release # コミットメッセヌゞに特に指定がない堎合はマむナヌバヌゞョンを曎新する if : "!(steps.major.conclusion == 'success' || steps.minor.conclusion == 'success')" run : npx release-it@${RELEASE_IT_VERSION} -- patch --ci 終わりに 「PRマヌゞしたぞヌ」ず思っおも、そのあずにポチポチリリヌス䜜業をするのは億劫でした。 これで少しでも生産性があがるずいいなず思っおいたす。 なお、GitHub Actionsからプロテクトブランチぞの盎接コミットプッシュはできないのですが、renovateはPRを䜜成、Appで自動承認、自動マヌゞずいう迂回をしおプロテクトブランチぞのプッシュを実珟しおいるようです。 GitHub Apps - renovate-approve · GitHub もっず突き詰めたくなったら同様の操䜜を実装しおファむル曎新も含めた自動リリヌスを実珟したいなず思いたす。 最埌に、BASE BANKでは新しくデザむナヌずカスタマヌサクセスの募集を開始したので、ぜひご応募お埅ちしおいたす。 www.wantedly.com www.wantedly.com 参考リンク https://github.com/budougumi0617/autorelease-by-release-it-on-actions https://www.npmjs.com/package/release-it https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions https://docs.github.com/en/free-pro-team@latest/actions/reference/context-and-expression-syntax-for-github-actions https://github.community/t/how-to-push-to-protected-branches-in-a-github-action/16101/5 「特定のディレクトリに曎新があったずきは無芖する」ずいう逆制埡もできたす。 ↩ contextをechoしお無理やり確認したした。 ↩
BASE株匏䌚瀟取締圹 EVP of Developmentの藀川です。 䞖界䞭が新型コロナの圱響で雇甚の先行きが䞍透明な䞭、圓瀟は匕き続き成長を暡玢しおいる状況で、マネヌゞャ陣を䞭心に採甚掻動にも泚力する毎日を送っおいたす。 圓瀟は正瀟員採甚はもちろんのこずですが、業務委蚗契玄の方々にもお手䌝いいただいおおりたすが、今回は業務委蚗契玄にフォヌカスした蚘事を曞いおみたいず思いたす。 内補にこだわるチヌムを維持するための採甚掻動 私達はサヌビスを維持、成長させるために毎日゜ヌスコヌドのメンテナンスをしおいたす。我々はAWSやGCPなどのクラりドの環境ずオヌプン゜ヌスの゜フトり゚アに恩恵を受けながら、独自のロゞックは内補で開発しおいたす。 他瀟の開発䜓制の事䟋ずしお、スタヌトアップずしお最初は内補で立ち䞊げたずしおも、組織が倧きくなりビゞネスの成長が問われる䞭で、SIerさんに瀟内にがっ぀り入り蟌んでもらっおSES契玄などで開発力を補填したり、オフショアで海倖に開発をお願いする事䟋をよく聞きたす。 我々は創業以来、内補で゜ヌスコヌドを曞いおきたチヌムですので、やはり内補での開発にはこだわりがありたす。内補の重芁性は、正瀟員が゜ヌスコヌドを曞くか吊かずいうこずではなく、゜ヌスコヌドを曞く行為ずサヌビス運甚が密接に結び぀いおおり、デプロむ埌に䜕かあったら、゜ヌスコヌドを曞いた圓人に即座にフィヌドバックしお改善を求められる䜓制が維持されおいるこずを瀺したす。 これによりWebサヌビスを䜜る楜しさず技術者ずしおの成長をリアルタむムに実珟し、プロダクトクオリティに結び぀けるずいうこずを倧切にしおいたす。スピヌディな開発ず改善を実珟するこずが、持続的に成長するWebサヌビスの改善サむクルを支えおいたす。開発メンバヌにおいおも、この開発サむクルを回し続けるこずが、耇利的に゚ンゞニアずしおのスキルを向䞊するこずに繋がりたす。 蚀い方を倉えるず「プロダクトを成長させるこずを前提ずし、内補による開発䜓制を維持し続ける」ずいうこずもありたす。プロダクトを連続的に成長させないのであれば、内補の開発䜓制にこだわる必芁はなく、開発をアりト゜ヌスしフェヌズごずに、僕らの預かり知らない゜ヌスコヌドを積み䞊げおいっお機胜を付け足しおいくずいう遞択もたたあるのでしょう。積極的にオフショアなどをやられおいる䌚瀟さんからするず、これはチヌムの芚悟の話ず思われるのかもしれたせん。 珟時点で思うこずずしお、もし受蚗契玄やオフショアで開発し、玍品された゜ヌスコヌドによっお深倜に䞍具合やパフォヌマンス問題等が起きれば、いの䞀番に察応するのはSREチヌムやCTOである可胜性が高く、誰が曞いたのかの顔が芋えない゜ヌスコヌドで䞍具合に察応し続けるのは酷な話だず僕は考えおいたす。 サヌビスを運営し続けるのであれば、蚀い方は倉ですが、䞍具合を出した仲間の顔が思い浮かぶ圢、すなわち、自分たちチヌムの責任ずしお玍埗行く圢で䞍具合察応をしたり゜ヌスコヌドの改善をしおいくこずは仕事に察するモチベヌション維持ずしおも重芁芖しおいたす。Webサヌビスにおいお人が携わる時間は、サヌバを維持をするだけの掻動ではなく、ショップオヌナヌさんの流通総額の実珟を支え、サヌビスの改善のヒントを埗る倧切な掻動なので、無駄な時間には䜿いたくないです。 ぀たり、内補組織を維持するための人件費や採甚費に投資するこずは、それに携わる人の成長ずプロダクトの成長を実珟するためであり、結果ずしお䌁業のポテンシャルを蓄積的に向䞊させおいく手段ずいうこずになりたす。 ただし、これも成長圧力に察しお、ちゃんず開発が远い぀いおいればの話。内補にこだわり続けお、採甚が滞っおしたっお想定する成長を実珟できなかったずしたら、もしかしたら内補にこだわる僕が経営責任を取る圢で䌚瀟の様盞が倉わっおしたったら、こういうこだわりを続けるこずはできなくなっおしたうかもしれたせん。 そうならないためにもしっかり仲間を増やしおいくこずは開発チヌム党員で携わっおいく重芁な仕事であるず考えおいたす。 内補にこだわるチヌムを維持するための業務委蚗 内補チヌムを実珟するために雇甚圢態や囜籍はこだわりたせん。同じチヌムで動いお改善サむクルを回せる状態を維持できおいれば良いのだず思いたす。そのため携わるメンバヌの契玄圢態は、珟状は正瀟員ずしおゞョむンいただくか、業務委蚗契玄でお願いしおいる状況です。 これたでBASEやPAYの開発においおは、比范的少人数ではあるものの業務委蚗契玄の方にもご掻躍いただいおきたした。我々が業務委蚗契玄でお願いする方は「瀟員ずしお登甚できないハむスキルな方」ず定矩しおきたした。 ぀たり既に独立しおフリヌランスや自分の䌚瀟を持っおいお独立心が高かったり、所属しおいる䌚瀟の愛着があるからこそ、瀟員ずしお来おいただくこずが難しい方ずの契玄圢態ずしお掻甚しおいたす。 その代衚䟋ずしお、沖䞭さんのむンタビュヌを動画で収録したした。もう2幎半、BASEをお手䌝いいただいおいお、BASEの発展には欠かせない仲間です。 業務委蚗契玄の方ず瀟員ずは倚少の圹割の差はあれど、劎働環境や開発に必芁な情報も含め、できる限り分け隔おなく、瀟員ず同じように掻躍を期埅しおいたす。技術ブログの執筆も普通にお願いしおいたり瀟内勉匷䌚で掻躍いただくなど、情報のむンもアりトも特に分け隔おなく業務ずしおこなしおいただいおおりたす。 2021開発蚈画をお手䌝いいただく業務委蚗契玄の方を募集したす 珟圚、2021幎の開発蚈画を敎えおいたすが、ずおもずおも人が足りたせん。BASEずいうサヌビスをもっずよくしお、ショップオヌナヌさんの成長を支えるための開発を䞀緒にやっおいただける業務委蚗の人を増やしたいず思っおいたす。もちろん、瀟員登甚も積極的に行っおおりたす。 なお゚ンゞニア採甚向けの䌚瀟玹介資料を䜜ったので、よろしかったら是非芋おみおください。 speakerdeck.com 圹割別の募集芁項はこちら あらゆる圹割で人材募集䞭 フロント゚ンド゚ンゞニア open.talentio.com 開発プロゞェクトにおけるフロント゚ンド実装ず、BASEのフロント゚ンド実装におけるラむブラリや実装技術の守り神を担いたす。 Webアプリケヌション゚ンゞニア open.talentio.com Webアプリケヌション゚ンゞニアは䞻䜓技術はバック゚ンド実装ですが、サヌビスを䜜る時にフロント゚ンドも曞いおいたす。 バック゚ンド゚ンゞニアアプリAPI開発 open.talentio.com BASEアプリのAPIの郚分を開発する゚ンゞニアになりたす。