カンリーホームページにおける各社ホームページのバージョン管理方法|株式会社カンリー 公式note
株式会社カンリーエンジニア部の角谷(@canly_motsuo)です。 趣味のポーカーに熱中して、マニラやラスベガスに行っていたら前回のテックブログからほぼ1年が経過してしまいました。 有給を使ってラスベガスに行ってきました! ...
https://note.com/canly/n/n024c732fda26
※このストーリーは、noteで発信した記事を転載しています。
株式会社カンリーエンジニア部の角谷です。
趣味のポーカーに熱中して、マニラやラスベガスに行っていたら前回のテックブログからほぼ1年が経過してしまいました。
有給を使ってラスベガスに行ってきました!
そろそろ真面目に仕事をしないと上司から冷たい目で見られてしまうので、今回は私たちのチームで使用しているプロダクトの振り返りと、クライアントごとのバージョン管理の仕組みについてご紹介します!
HP来訪者の実店舗への来訪導線を最適化するHPが「カンリーホームページ」です。 ユーザーによって使いやすい店舗ページを作成することができます。
カンリーホームページ内部店舗検索ページの例
基本的に自由にカスタマイズできるCMSを提供していますが、クライアント様のHPとの整合性を保つために、機能にない設定を個別に対応する必要があります。
(要望の多い機能に関しては、正式な機能としてグロースを進めています。)
一部のお客様からの要望に応えるためにも、特別な仕様を施した機能を追加してしまうと今後のバージョンから切り離され、新しいバージョンに対応していないクライアント様のカンリーホームページが生まれてしまうことになります。
互換性がなくなるため、独自のバージョンからあげられなくなる
新機能や脆弱性のパッチ対応を迅速にクライアント様に提供するため、この課題に対して我々は以下のようなアプローチを取りました。
昨今、プロジェクトに関わる複数のリポジトリを単一のリポジトリで管理するMonorepoの方法が注目されていますが、我々はその逆であるPolyrepoで管理しています。
単純にPolyrepoにしたのではなく、コアとなるリポジトリを作成し、各クライアントのリポジトリはこのコアリポジトリを参照してそれぞれ別のコアモジュールのバージョン環境を作成できるようにしました。
共通リソースを利用し、polyrepoでそれぞれ管理する例
また、テンプレートリポジトリも用意し、cloneすることで容易にクライアントリポジトリを作成できるようにもしています。
ここでなぜ現時点ではPolyrepoにしたのかと言う点については、社内の過去の背景も多少含まれていますが、以下のメリットが大きいと感じてPolyrepoにしています。
テンプレートリポジトリからcloneされたリポジトリはpackage.jsonでコアリポジトリであらかじめ用意してあるタグを参照してバージョンを取得するようにしています。
下記は、クライアント側のpackage.jsonです。(※一部コードをマスクして変数名等を改変しております)
### package.json
"scripts": {
"dev": "npm run copyToCoreModules && next dev",
"updateModules": "npm -f upgrade @canly/canly-core-repository && node ./buildPackageJson.js && npm i",
"updateModules:ci": "npm run updateModules && npm run copyToCoreModules",
"copyToCoreModules": "rm -rf .next/cache/ && node ./copyToCoreModules.js"
},
"dependencies": {
"@canly/canlyhp-core-repository": "github:canly/canlyhp-core-repository#v1.1.0"
},
そして、package.jsonのscriptsに含まれているように、CLIでコマンドを実行することで、特定のスクリプトを呼び出し、自身のnode_modulesの中に特定バージョンのコアモジュールを格納するようにしています。
我々はNext.jsを使用して開発をしており、クライアントリポジトリのフォルダ構成は下記のようになっています。
それぞれのファイルの中では、node_modules内のコアリポジトリのファイルを参照するようにしてコードにしています。
フォルダ構成イメージ
構成順としては下記の通りです。
下記は、クライアントリポジトリがコアリポジトリを取得する例です。
### src/page/index.tsx
import { GetServerSidePropsContext } from 'next'
import {
TopPage,
TopPageProps,
getServerSideProps as coreGetServerSideProps,
} from '@canly/canly-core-repository/src/pages/index'
const Page: React.FC<TopPageProps> = (props) => {
return <TopPage {...props} />
}
export const getServerSideProps = async (
context: GetServerSidePropsContext
) => {
const result = await coreGetServerSideProps(context)
return { props: result.props }
}
export default Page
上記のコードで分かる通り、getServerSideProps内部でAPIからデータを取得した上で、コアリポジトリからTopPageのコンポーネントを取得して描画していることがわかるかと思います。
先述したHeaderやFooterについては、_app.tsx等で全ページのコンポーネントに描画されるようにし、クライアントリポジトリごとに個別のコンポーネントが作成されるようにしています。
上記の構成に変更した上で、現時点での運用方法についておさらいしていきたいと思います。
実際の運用イメージ
といった流れで運用しています。もちろんですが、この一連の中でエンジニアが介在する部分が少しあり、工数を取ってしまっている問題点もあります。
こうした問題を解決するために、GitHub Actionsを使用し、定期的に全クライアントリポジトリの現バージョンを取得し、ワンタップでバージョンを自動的に上げるツールの作成や、PMのタイミングで自動的に作成できるスクリプトを作成し、自動化にも努めています。
いかがでしたでしょうか。今回はカンリーホームページで各クライアントごとに、どのようにバージョンを管理しているかについてのご紹介でした。
詳細については省略させていただきましたが、ご参考になれば幸いです!
弊社ではまだまだ一緒に働く仲間を募集しています!
少しお話を聞いてみたいという方は、カジュアル面談もできますので、お気軽にお声掛けください!