TECH PLAY

KINTOテクノロジーズ

KINTOテクノロジーズ の技術ブログ

936

はじめに KINTOテクノロジーズでモビリティマーケットの開発・運用を担当しているリナです! 普段はフロントエンドエンジニアとして、Next.jsを用いて実装しています。 またテックブログの運営チームとして、記事のリリース管理なども行っています。 最初の記事 をリリースしてから早いもので、1年が経ちました🎉 今回はテックブログ公開1周年を記念して、テックブログ「ローンチ後の開発」にまつわるお話を記事にしました。 なお、ローンチまでの開発は「 Next.jsでテックブログを作った話 」という記事で紹介しています。 あわせてご覧ください🙌 インナーソースを目指して KINTOテクノロジーズのテックブログをローンチしてから現在に至るまで、デザインや機能開発は「インナーソース」で進めてきました。 インナーソースとは インナーソースの世界最大のコミュニティであるInnerSource Commonsによると以下のように定義されています。 企業内のソフトウェア開発にオープンソースの実践と原則を適用したものです。 参考: InnerSource Commons つまりインナーソースとは、オープンソースのようにソースコードを開発者が自由に利用・改修できる開発スタイルを社内で実践することを指しています。 実際の取り組み KINTOテクノロジーズでは、テックブログのリポジトリを社内の全エンジニアに公開し、新規機能の開発や機能改修および開発された機能に対するレビューができるようにしています。 また、開発予定の機能はすべてGitHub Issuesに列挙しており、「リソースに空きがなく、自分は開発できないけど、誰かにやってほしい・・・!」といった改善要望もGitHub Issuesに書いてもらっています。 GitHub Issuesの内容をもとに、有志のメンバーが機能修正してPRを出したり、レビューをしたり、すぐに対応したい事項はテックブログ運営チームで対処することもあります。 なぜインナーソースか? テックブログをインナソースにした理由は、主に2つあります。 新しい技術の実験場所として使ってほしい 組織を超えたコラボレーションを促進したい 新しい技術の実験場所として使ってほしい まず1つ目は、エンジニアが新しい技術や自身で学んでいる技術を検証する場として使ってもらいたいと考えたためです。これは、テックブログ運営チームのリーダーである 中西さん が繰返し言っていることでもあります。 KINTOテクノロジーズのテックブログは、外部のブログサービスを利用することもできましたが、あえて 自前 でテックブログを創っています。 ときには、自己学習によって習得したプログラミング言語やフレームワークを検証する場として、各プロジェクト・プロダクトに要件などの都合で導入できなかった仕組みを実行する場として、またはABテストの場として・・・など、テックブログを自前で創ることで「エンジニアが新しい技術にチャレンジできる場づくり」に努めました。 また最終的には、テックブログの開発でチャレンジ・実験して得られた知見を各プロダクト・プロジェクトに還元することを目指しています。 組織を超えたコミュニケーションを促進したい そして2つ目は、組織を超えたコミュニケーションをより強化したいと考えたためです。 組織の構造 上、部門ごとの縦のコミュニケーションは盛んに行われていますが、部門を超えた横のつながりはもっと強化できると考えています。 他部門のメンバーとコミュニケーションをとることで、新たな発見や知見が得られるかもしれません。 もしくは、新しいアイディアが生まれたり、気の合う自己研鑽仲間ができたりするかもしれません。 組織を超えたコミュニケーションが今よりもっと盛んになることで、エンジニアの成長および非エンジニアがエンジニアリングを楽しむきっかけに繋がることが理想です。 上記の2つの理由から「インナーソース」によって、エンジニアの学びを推進し、非エンジニアもエンジニアリングを楽しめる文化を創っていくことができると考えています。 これまでに追加した機能 インナーソースによってこれまでに開発された機能のうち、特に目立つ機能を5つご紹介します。 これらの機能は、異なる部門の開発者とレビュアーで構成された有志のチームで実装されています。 ① RSS ② SNSシェアボタン ③ 最新/関連記事 ④ 目次 ⑤ ページネーション おわりに 今回はテックブログのローンチ後から現在に至る「インナーソース」の取り組みをご紹介しました。 今後は、テックブログの全体的なデザイン修正やカテゴリ機能のリリースを予定しております! 毎週の記事リリースだけでなく、より見やすいテックブログになるよう機能面も充実していきたいと思っているため、今後もご期待ください🙌 またこの場を借りて、テックブログ読者のみなさま、そして日頃からテックブログの執筆・開発・運用にご協力くださっているみなさまにお礼を申し上げます。 Thank you!!✨
アバター
Hello, My name is Ashi Singh. I joined KINTO Technologies in Feb 2022, and am part of the Global Development Group. I am an application developer and currently working as an engineer on the back office system being developed by Global Development G. Overview My team is in charge of developing and maintaining microservices as a base package for use of other global teams. Authentication and authorization are the main features that we want to include in this base package. We want an authentication solution that does not depend much on cloud technology so we decided to investigate Keycloak as a possible choice. What is Keycloak? Keycloak is an open-source identity access and management (IAM) solution that adds authentication to applications and secure services with minimum effort. Keycloak provides user federation, strong authentication, user management and more. Keycloak supports mainly three types of protocols, which include OpenID Connect, OAuth 2.0, and SAML 2.0. It supports both Single Sign-On and Single Sign-Out fully. It is fast and flexible and has the capability to manage the accounts of users seamlessly and maintain data as well as sessions. Keycloak Official Page Keycloak was interesting to us because in the future we wanted to use it with different cloud architectures and we did not want to restrict ourselves to a single one. Problem In order to start our investigation of Keycloak, the first step is to test it out on our local environment. In our team, we have equal number of developers using Windows and MacOS. (KINTO Technologies lets us use whichever OS we are most comfortable with!) During this initial set-up, we found that Windows users as well as MacOS with Intel chip users have no problem with the Keycloak docker image. However, those with newer MacOS machines - mainly the M1 chip - ran into an error whenever you tried to start it up. Settings used before errors are given below : Keycloak Docker Image Version : jboss/keycloak:16.1.1 [This image was used because image jboss/keycloak:16.1.1 was the latest one used in the project . Also easy to do configuration with that] My Local PC Version : MacBook Air (M1, 2020) Apple M1 [macOS Monterey] Solution As when I was working with M1 machine in the team, I got assigned to the task. During my deep dive into the problem, I found that the JBoss image that Keycloak is using is not compatible with the M1 chip. The one solution I found was changing the docker image in the Mac M1 machine. So in Mac M1 we are using wizzn/keycloak:14 as the Keycloak docker image instead of the usual jboss/keycloak:16.1.1 image. Changes in the configuration files are needed as well in order to make it work. Changes needed docker-compose.yml The first step to run Keycloak on local is to change the docker image to wizzn/keycloak:14. Change the order in the volumes section like this: volumes: - ./custom-scripts/:/opt/jboss/startup-scripts/ - ./import/backoffice-realm.json:/tmp/backoffice-realm.json.orig #move to after startup-scripts - ./keycloak/themes/your-default-theme:/opt/jboss/keycloak/themes/your-default-theme - ./keycloak/configuration/mysql/change-database.cli:/opt/jboss/tools/cli/databases/mysql/change-database.cli #move to the last All the other scripts that are required to be added in the volume section can be added in the middle of ./import/backoffice-realm.json and ./keycloak/configuration/mysql/change-database.cli change-database.cli Then we remove the explicitly defined database settings that are already defined in database (change-database.cli) file. In this file, we make the changes as shown in green Changes in the Dockerfile In the Dockerfile change the docker image as wizzn/keycloak:14 Run the Keycloak Run the Keycloak using docker compose up -d Keycloak: Good or Bad? After this initial hiccup, we manage to run Keycloak efficiently on both Windows and MacOS systems. We were able to confirm Keycloak features like out-of-the-box user and role management, MFA authentication, session management, among others. Using Keycloak would save us time compared to us developing those features by ourselves. There is also an option to link various social networks like facebook, twitter, etc., so that you can easily implement social login if needed. But still, there are some areas that need to be addressed. In Keycloak the customization is quite difficult and it needs more time for the developers to do the changes. Keycloak is still an open-source project so you do not have any guarantee provided by its developer about the road map, and things like bugfixes are taken care of via GitHub issues with no hard deadlines for response time. But as said if there is a solution then it will have some cons, but the ability to easily manage and run this solution outweighs other criteria as it can be used as a major solution going forward.
アバター
はじめに こんにちは!KINTOテクノロジーズの開発支援部に所属する「 きんちゃん 」です。 普段はコーポレートエンジニアとして「全社利用するITシステムの維持管理」を行っています。 今回、私が社内で実施している「アジャイルな活動を組織横断的に推進する」取り組みについて、ご紹介します。「自身に熱い想いがあり、ゼロから新しい取り組みを推進していきたい!」と考えている方のご参考になれば幸いです。 ※この記事は「アジャイル」をテーマにした一連の連載記事となります。 私たちは「組織としてアジャイルな状態」になっていくために、 さまざまな課題や困難に立ち向かってきました。 時には失敗もありましたが、それでも着実に成長を続けています。 この連載記事では、そんな私たちの実際の取り組みをご紹介していきたいと思います。 背景 私は2023年1月にKINTOテクノロジーズへ入社しました。 これまで、社内外を問わず様々な「アジャイルについての活動」に関わってきた経験から、ここKINTOテクノロジーズにおいても、入社当初より「社内にいるアジャイル有識者の方々と組織横断的に交流していきたい」という想いを持っていました。 これまでの経験としては 社内でスクラムマスターやスクラムコーチとしてソフトウェア開発チームへ関与 管理部門において、アジャイルを軸にした業務改善の取り組みを推進 社内の実践者と定期的に活動内容を共有する実践コミュニティ活動の推進 社外のアジャイルコミュニティやカンファレンスへの定期的な参加 等になります。 そんな想いを持っていた私ですが、実際にコーポレートIT部門として業務を開始した時に持った印象としては「思った以上にプロダクト開発のチームが遠いな」という感覚でした。 「プロダクト開発部門とコーポレート部門」という「組織上の距離」ももちろんですが、「物理的な距離」も大きな要因としてありました。私が勤務するのは名古屋オフィスなのですが、プロダクト開発のエンジニアの多くは東京のオフィスに在籍していた、というのがその理由です。 この距離感がなかなかのハードルとなり、元来コミュ障である自分の性格も相まって、入社後しばらくは他部署の方々とも積極的に関われず、「(アジャイルなマインドを心に秘めた)真面目なコーポレートエンジニア」として過ごす日々が続いていました。 きっかけ 私の所属する開発支援部では、定期的に上長との「1on1」が実施されています。 入社し2ヶ月が経った頃、当時のマネージャー(現在の部長)に「社内のアジャイル有識者と交流したい」旨を相談しました。 その際に、色々な方の名前を挙げてもらったのですが、そこで一番マッチしたのが「少し前にスクラムマスター研修を受けた木下さん」でした。木下さんはエンジニアでもあり、社内のテックブログチームにも所属し、「 認定スクラムマスターになった記事 」も書かれている方でした。私もKINTOテクノロジーズに入社する前に木下さんの記事を読んでいたため、「ぜひ木下さんとコミュニケーションを取りたい」と要望を出し、結果としてテックブログチームと交流の機会をいただく事となりました。 テックブログチームと出会って 初めてテックブログチームの方々と交流した時に感じたのは「何だか個性豊かで楽しそうな人たちだな」といった感想です。皆さんそれぞれ異なる本業を持ちながら「テックブログ」という一つのプロダクトを育てる活動に積極的に関わり、結果として「組織内の色々な方々とコミュニケーションを取り、横断的にひとつのうねりを作り上げる」事ができている。僕としては「理想的な組織内コミュニティのひとつの形」が、そこにありました。 また、このテックブログチームは「 中西さんという、一人の熱い想いを持った人の行動 」から始まった活動であるという事。私は何回かテックブログチームの方々と交流を続ける中で、「一緒になって良い文化を社内に広めていきたい」と思うようになりました。 そして、ひとつの転機がやって来ました。 テックブログチームの方々から「木下さんの記事が安定したPVを得られており、アジャイルについての記事は人気が出るのではないか?」という話が挙がった事と、もともと私が「アジャイルについての熱量が大きい人間」であった事が掛け合わさり、「テックブログでアジャイルについての連載記事を作る」という企画が立ち上がったのです。 さあ、何からはじめよう? 「アジャイル連載」の企画はとても良さそうに見えましたが、いざ考えてみると「KINTOテクノロジーズにおけるアジャイルな活動」についてまったく私の知見がない状況であったため、コンテンツがほぼ何もない状態です。 そのため、まずは「有識者を紹介」してもらうことから始めました。 テックブログチームの方々の人脈を軸に 過去、社内で認定スクラムマスターを取得した方 前職での経験を元に、KINTOテクノロジーズでこれからScrumに取り組もうとしている方 これから認定スクラムマスター研修を受講しようとしている方 と交流する場をセッティングしていただき、「KINTOテクノロジーズのアジャイル」について色々とインタビューする流れが出来ていきました。 最初は「名古屋と東京」という物理的な距離に対して、勝手に心の距離を感じてしまっていた私ですが、この頃には「特に距離は関係なく、ちょっと離れたところにいる仲間」という感覚で皆さんに接する事ができるようになっていました。 最初の一歩を踏み出すまでは足が重いものですが、ほんのちょっと一歩を踏み出すきっかけさえあれば、後は自然と身体がついていってくれるものですね、という気付きでした。 次回予告 今回の内容はここまでとなります。 次回は、ここから更に話が進んだ後の 社内の有識者と交流し、皆さんのアジャイルに対する想いを直接感じられたこと 実際のスクラムイベントに参加させてもらい、熱い現場を間近に見られたこと 「とは言え、うまく行くことばかりではないよね」という「アジャイルあるある」の話ができたこと インタビューをきっかけに「アジャイルの有識者が集まる社内交流の場」を始められたこと といった内容をご紹介する予定です。 そして、この「アジャイル連載」は「KINTOテクノロジーズのアジャイル」が中心となりますので、「社内で活躍されている有識者」や「そのチームの方々」、また「ソフトウェア開発以外の場面で目にしたアジャイルな活動」についてもどんどん順を追ってご紹介できればと思います。 楽しみにお待ちください!
アバター
はじめに こんにちは!KINTOテクノロジーズの開発支援部に所属する「 きんちゃん 」です。 突然ですが、8/3(木)に「 KINTOテクノロジーズ MeetUp!~情シスによる情シスのための事例シェア4選~ 」というタイトルで「コーポレートIT領域に特化した、事例発表+座談会形式の勉強会」を開催します。 今回、この勉強会を開催するまでに至るあれこれを、ご紹介します。 「自社でゼロから勉強会を立ち上げ、推進していきたい!」と考えている方のご参考になれば幸いです。 「勉強会」ってどんなイメージ? 突然ですが、「勉強会」というと皆さんどのようなイメージを持たれるでしょうか? 業界・領域の有識者の話を聴き、新しい知識を身に付ける 同じテーマに興味を持つ人たちが集まり、相互に研鑽し合う チームのスキルアップを目的に、半ば強制的に業務として開催・参加させられる (コロナ禍では下火だったが)懇親会での会話や食事を目的に参加する このように、様々な目的やスタイルを持った勉強会があると思っています。 私自身の「勉強会観」をお伝えすると、過去に私が運営にも関わっていた「 DevLOVE 」という勉強会コミュニティのコンセプトに立ち戻るのですが、 自分たちの現場を前進させるために、現場の中と外で知識や経験を循環させる「学びの場」 という考えを持っています。 もともと「勉強会」や「コミュニティ」に一定の価値を持っていた私であったため、KINTOテクノロジーズに入社する際にも「できれば社内で交流・研鑽する場に関わっていきたい」と考えていました。 ※この考えに基づく行動ついては、後日公開予定の「アジャイル連載」で具体的にお伝えする予定です。 よろしい、ならば勉強会だ 私がKINTOテクノロジーズに入社した時、既に社内には「勉強会を定期的に開催する文化」があり、多くの「学びの場」が存在していました。例として以下のようなものです。 定期的に開催される「任意参加の全社エンジニア向け勉強会」 自社の事業やビジネスについて学ぶ「事業部門主催のビジネス勉強会」 各プロダクトチームで個別に開催される「個別勉強会・読書会」 何よりも素晴らしいと感じたのは、「社内外の勉強会や読書会への参加」を「業務として取り組んでも良い文化」や、「学びに必要な書籍を、会社負担で購入可能な制度」でした。 KINTOテクノロジーズという会社自体が、「社員の学び」を積極的に支援している姿勢が感じ取れます。 そのような文化の中で、私も「自チーム向けの勉強会や輪読会」を小さく実施し、仲間と共に学習する日々を過ごしていました。心のどこかで「もっとこの文化を多くの人に知ってもらいたい」と思いながら…。 そんなある日、所属チームの中で「コーポレートエンジニア採用への取り組み」についての議論が起きました。色々な施策の話が議論される中、私の頭の中で「どうすれば、我々の強みや良い文化を多くの方々に知ってもらえるか?」という課題と、前述の「学びに対する自社の文化を多くの人に知ってもらいたい」という想いが繋がりました。 その結果「社外の人を交えた勉強会をやってみませんか?」という提案が出てくる事となったのです。 一人じゃ無理だ!みんな助けて! その後、勢いで「コーポレートIT勉強会の企画書」を作成し、チームリーダー陣に正式な案として提案しました。各リーダーからは「いいね!」という反応を得られたので、前向きに検討する事となりました。 いざ「やりましょう」となったところまでは良いのですが、考えるべき事はたくさんあります。 何をテーマに開催するのか?誰が話すのか? 場所は?時期は?タイムテーブルは? さすがにこれらを一人で進めるのは限界があるため、翌週のチームメンバーが全員集まる場で「 勉強会を開催します!事務局メンバーと登壇者を募集します! 」と同志を募りました。 結果として、有志や推薦を含め、全員で6名のチームが結成されたのです! さっそくSlack上に専用のチャンネルを作成し、関係者を集めたコミュニケーションを開始します。さしあたっては確実にゴール達成への目線を合わせるための事務局キックオフの実施です。最初の企画構想時点で話に加わっていないメンバーもいるため、主に そもそもの主旨は何で、どのような開催概要であるか? 到達すべきゴール状態は何か? ゴール到達に向けた、「検討済み事項/未検討事項」は何か? 未検討事項をどのようにして解決していくのか? といった、「目指すべきゴール」と「現状把握」を揃えるところから丁寧に実施し、その上で「次に目指すべき到達点」を定め、それぞれが準備を進めていく事としました。 俺たちだけじゃ無理!!もっとみんなを頼りたい! 次に事務局メンバーで実施したのは「未検討事項のディスカッション」です。大きく コンテンツ 開催方式と利用設備 開催日時・タイムスケジュール 集客・広報 効果測定 といった点について、より解像度を上げていく議論を実施します。 その結果、「自分たちだけでも進められるもの」と「他部署の協力を得たいもの」が見えてきました。それらを踏まえ、他部署の関係者も踏まえた会議体をセッティングする流れが作られました。 ※「勉強会の実施」が決まった段階で、我らが部長からヘルプが必要になりそうな他部署への声がけを進めてもらっていた事もあり、全体でのキックオフMTGも、スムーズに実施が可能となりました。 ありがたい事に、合同キックオフに参加してくださった方々はとても前向きな方が多く、我々の「やりたい」に対して「こういう事をやるのはどうか?」「こういうものは過去に前例があるので、すぐに対応が可能」といった、「ゴールにより近づくための意見」をたくさん出していただきました。 フワッとしたプロジェクト管理が必要だ! 「何をやるべきか?」の解像度が高まったところで、「具体的なアクションプラン」が並列でいくつも見えてきました。 さすがにこれらを「できる人が良い感じにやっていく」と「現在地の把握」つまり「プロジェクトの透明性」が下がる懸念があったので、一定の「見える化」と「進行管理」と「役割分担」を定める事にしました。 見える化 Jiraを利用し、「Epic>Task」の階層をもったタスクの見える化と優先度設定 進行管理 Epicの粒度で、週単位で「ここまでやる」ゴールを設定 週次で「達成度を確認」し、必要があれば軌道修正。問題無ければ次ゴールの設定 役割分担 Epic単位で担当者を決める 誰かの進行が滞ったり、週のゴール達成が難しそうな場合は、他メンバーがフォロー このような形で、イテレーティブかつインクリメンタルな事務局運営を実現しています。 【余談】事務局運営に見る「Agile Kata」の実践 余談ですが、今回のこのような仕事の進め方は「 Agile Kata 」に書かれた「改善のカタ」を参考にしています。「Agile Kata」には、以下のステップを繰り返す事で、日々の行動をアジャイルに実践する事が可能である、と書かれています。 方向性やチャレンジを理解する 現状を把握する 次のターゲット状態を設定する ターゲット状態に向かって実験する(これを反復的なアプローチで実行する) Scrumのような決まったフレームワークを利用せずとも、カタを理解する事で「アジャイルな状態」はいくらでも作る事が可能です。 そして現在 まさにこの記事を書いている現在も、毎日毎日「勉強会に必要な議論やアクション」が進められ、ゴールに近づいています。 テーマ毎に個別に同期型のWeb会議が実施され、Slack上では非同期で会話が進み(1日で50件を超える返信が付くようなスレッドもあり)、ガンガン前に進んでいる感じがあります。みんなすごい!! このような形で準備が進められ、いよいよ開催が見えてきた「 KINTOテクノロジーズ MeetUp!~情シスによる情シスのための事例シェア4選~ 」、皆さまぜひ楽しみにお待ちください!!
アバター
はじめに はじめまして。 KINTOテクノロジーズ 開発支援部所属で、グローバル開発部のアシスタントを担当している三浦です。 普段はオフィス回り、グローバル開発部のツール手配などを含めて、メンバーが仕事をしやすいような環境を整えるお手伝いや、問い合わせ等の対応をしています。 最近のマイブームは、推し活!1年限定で活動中の某バンドをあちこちへ追いかけ応援しています! さて、事務回りの細々とした作業が多いなか、だからこそ日々少しでも業務改善をしていくぞと考えています。本記事ではKINTOテクノロジーズで実践してきた業務改善について紹介します! これまでの「カイゼン」について トヨタグループであるKINTOテクノロジーズ社内では改善ではなく「カイゼン/Kaizen」というワードがよく使われています。その定義は以下です🔻 カイゼンとは、作業や業務の中にあるムダを排除し、より価値が高いものだけを行えるように、作業や業務のやり方を変える活動を行うことを指します。 ^1 入社してからこれまでに、以下のようなカイゼン活動を行ってきました。 [1] メーリングリストの棚卸しと管理方法を変更 [2] セキュリティカードの貸出管理台帳と承認ルートの変更 [3] テスト端末の管理 [4] 置き傘用の名札作成 ここからは、きっかけ・背景、実施した内容と効果についてです。 [1] メーリングリストの棚卸しと管理方法変更について 📧 入社1か月目の事、ミーティングのメンバー招集をする際に、メーリングリストの登録者が分からない…というのが始まりでした。 私自身、開発支援部に所属していますが、開発支援部では部内で使用するメーリングリストの登録者一覧があったのに、グローバル開発部にはない!! ならば同じように作ってみようと考えました。 対象のメーリングリスト自体がわからないので、メーリングリストを抽出することからはじめましたが、なんと使用中のメーリングリストが94個も!?ホントに使っているの??という疑問から、棚卸を実施することに。 まずは見様見真似、開発支援部で使っているメーリングリスト一覧のExcelをもとに 縦(Y):登録メンバー、横(X):メーリングリスト、登録者:●で表にしました。 メーリングリスト一覧(目隠しだらけで失礼します🤣) この表を各チームリーダーに確認してもらい、管理者の設置・用途の明記・登録メンバー確認という形で棚卸を実施しました。 メーリングリスト一覧は誰でも閲覧することが出来るように、クラウドストレージのBOXで共有し、内容変更依頼はJIRAチケット起票として、リストが陳腐化しないようにデータ更新の権限は私だけに付与しました。 一覧にしているので登録者や種類などの確認が容易になるとともに、グローバル開発部のメンバー全員がメーリングリストは自動更新ではない、という認識を持つことができたと思います。 また、全メーリングリストを見える化したことで、似たような用途で重複作成になっていないか確認できるという効果もありました。開発支援部に所属しながらグローバル開発部のサポートをしていたからこそできたヨコテン(横展開)でした。 [2] セキュリティカードの貸出管理台帳と承認ルートの変更 について 神保町オフィスに週2日以上出社する外部ベンダーの方には、オフィスのセキュリティカードをお渡しすることになっています。こちらも単純なことですが、これまで履歴が残らない仕様だったExcelを履歴管理できるように変更し、さらに、未使用のセキュリティカードがわかるように変更しました。 条件付き書式と関数を使って、未使用カードしか選択が出来ないようにしています。 これにより、使用者情報の誤削除もなく、棚卸もしやすくなりました。 自動で枚数や空きカード番号を見えるようにしました 承認ルート変更については、私が開発支援部の所属のため、これまではセキュリティカードの交付依頼を受けても、グローバル開発部のメンバーに代理で申請をしてもらわないと、正しい承認ルートで起票できませんでした。 この変わった習慣が全く実務に沿っていなかったため、「このおかしなフローは変えた方が良いのでは?」と考え、主管する部署へ相談しました。その後、二部署の兼務という役割・体系の整理を行い、私の申請の際には開発支援部とグローバル開発部の承認ルートを選択できるように変更しました。 これにより、以前まで代理で対応してもらっていた方のリソースや個別調整の必要がなくなりました ✨ [3] テスト端末の管理 について 📱 これまでシステム開発時に使用するスマートフォン等のテスト・検証端末は、Confluenceの表で管理していたのですが、誰が使用しているか所在が一目でわかりづらく、その表自体が更新されないまま、ある特定の端末などは個人管理となっているケースもありました。 そもそも、テスト端末の使用状況がわからないので、確認せずに追加購入しようとする未遂事件が発生したのですが、そのころ、会社で購入した書籍をJIRAで一括管理することになった事を知り、書籍管理と同じようなことが出来ないかと考えました。 ➡️ 書籍の管理方法をラクにした話 こちらもJIRA化するタイミングで棚卸を行ったのですが、紛失していないか、壊れてはいないか、本当に使っているのかがよく見えました。(実際にパスワード不明でロックかかったままなどもありました🔒) テスト端末は日常的に使用しているため、棚卸と同時進行で現物を確認し、パスワード設定や、端末自体の写真をJIRAに掲載することで、機種名だけではわかりにくかった点も改善されたと思います。 管理をJIRA化したことで、メンバー全員が貸出状況を一目で確認できるとともに、貸出期限を設定したので、使用状況を追えるようになりました。 貸出状況の可視化、チケット内には端末の詳細情報を記載しています また、貸出・返却時にコンフルの更新漏れや、都度Slackで連絡するなどの手間がなくなりました。 何より、担当者と使用端末の紐づけに加えて、返却期限を設けたので、メンバー全員に 「借りている」 という認識が強まったと感じられます。 期限が近づくとJIRA管理者に通知が来るように設定しましたが、このあたりは書籍管理をJIRA化されたリナさんにお助けいただきました。ご協力いただき本当にありがとうございました!!! [4] 置き傘用の名札作成 について☔ エントランスの傘立てに「置きっ放しの傘があるので片づけてほしい」という依頼から、他の傘立てを含めて確認し、数日置きっ放しの傘はオフィス内でアナウンスして処分しました。 そのアナウンス内で、貸出傘についてのコメントをもらったことをきっかけに、処分する傘の中でもきれいなものはオフィス貸出用としてリサイクルできるようにテプラを貼って、誰でも使用できる共用傘とすることにしました。 オフィス内の傘立ては、意外とビニール傘や無地の似たような傘が多く、今後も放置されてしまう傘は増えるのかな、きっと取り間違いも出るだろうな、と考えたとき、過去に自分の傘に養生テープで名前を書いて輪ゴムで名札を作っていたことを思い出しました。笑 自分一人の場合はそれだけでいいですが、できれば皆さんにも名札があれば良いかなと思いキーホルダを用意しました。 名前入りのキーホルダーで置き傘を確保します👍 この改善はまだまだ浸透していませんが、傘に限らず、冷蔵庫保管の私物につける名札としても使用できるので、どんどん利用して欲しいなと思っています。 カイゼンマインドはどこからくる? 私のカイゼンマインドの起源についてお話しします。 子供のころから想像することが好きでした。 通学の時「道が勝手に動いたらいいな ✨」「雨の日勝手にシールド張ってくれたらいいな✨」(ドラえもんの世界に近いですよね、、😅) のように、「いいな✨」の想像を昔からよくやっていました。カイゼンはこの延長にある気がします。 偉人達はこの発想から研究者や開発者に繋げていると思いますが、人並みの勉強をしてこなかった私の場合は、目の前の課題をなんとかクリアさせたいので「こうなったら楽なのに🤔」という発想になるのだと思います。 仕事に関しても 「楽に仕事をしたい」=「仕事は楽しく」 が根本にあります。 少しでも自分の仕事を楽できたらうれしいですよね。いずれその楽は当たり前になる日も来るのですが。。 「自分が楽になる」がきっかけですが、それにプラスして相手や使う人のことを考えて進めていく感じです。 常に自分がやっている仕事(特に定期的にやらないといけない業務)は「こうなったらいいな」を考えています。 「こうなったら楽なのに」を最終的に自分で実現するのは難しいかもしれないけど、 今の「楽になったこと」が業務上当たり前になって、引き継いだ人がそこからさらに楽にしてくれたらいいなというのが理想です。 自分がやった改善が最終形ではなく、自分の手を離れ、その後の状態がさらに進化してると嬉しく思います。なんかそういう想像はワクワクしますよね。 Next Kaizen~次に取り組みたい課題~ Excelを使用している定期業務をマクロ化等でもう少し簡単にしたいと考え、先日社内で公開されたSherpa ^2 やChatGPTを使って試行錯誤で開始しております!これからもカイゼンマインドを胸に、楽しく仕事に励みます ✨
アバター
Svelte Tips こんにちは(こんばんは)、Svelte不定期連載その5です。 過去の記事はこちら SvelteKit + Svelte を1年間くらい使ってみた知見など※SvelteKit メジャーリリース対応済み Svelteと他JSフレームワークとの比較 - Svelte不定期連載-01 Svelteでユニットテスト - Svelte不定期連載-02 SvelteでStorybookを使ってみる - Svelte不定期連載-03 SvelteでStorybookを使ってみる - Svelte不定期連載-04 なかなかに書きましたね…。 今回は実際に今までプロジェクトで使ってきて、 「ここ詰まった!」「??」 となった点をわかりやすく書いていこうの回です。 目次は以下の4つです。 SSGの際の設定 .page.tsと .server.tsの違い metaと使い方(プラグイン紹介) それぞれのライフサイクルのつかいどころ SSGの設定 SvelteKitではAdapterというモジュールを使用することで簡単にデプロイ先を設定できます。 デフォルトでは adapter-auto というSSR用のAdapterになっているため、adapter-staticというモジュールを導入する必要があります。 筆者は最初ここで躓いてしまい、autoって命名されているくらいだし、よしなにしてくれるんじゃないか・・・?とこねくりまわしていた記憶があります。 だがしかし、そうではありませんでした。 adapter-staticを導入してドキュメント上のコードを書くだけで、すぐさまに静的ホスティングに最適化されたビルドファイルが出来上がりました。 (ちゃんとドキュメントを読もう…。) Svelteの公式サイトは和訳PJもあるので日本語ドキュメントもありとても助かります :) // これがなければSSGとしてビルドできない import adapter from '@sveltejs/adapter-static'; /** @type {import('@sveltejs/kit').Config} */ const config = { // 割愛 kit: { adapter: adapter({ pages: 'build', assets: 'build', fallback: null, precompress: false, strict: true }) } }; export default config; 詳細: https://kit.svelte.jp/docs/adapter-static .page.tsと .server.tsの違い これもSvelteKit v1がリリースされ大きく変わった際に躓いた点です。破壊的な変更だったのでみなさま覚えているのではないでしょうか。 v1がリリースされてから、SvelteKitではページ内でデータfetchなどをする場合、以下の2ファイルを置くことがデフォルトになっています。 *.svelte ⇒ UIなどのファイル *.page.server.ts || *.page.ts ⇒ fetchなどデータを定義するファイル そしてデータを定義するファイルは page.tsと page.server.tsというものに分類がされます。 *.page.tsと *.page.server.tsの違いを最初わからず作ってしまい、 SSGにしたつもりが 遷移時にデータをAPIなどに取りに行く挙動 になっていました…。ナンダッテー。 *.page.tsの場合は クライアントサイド・サーバーサイド の両方で実行 *.page.server.tsの場合は サーバーサイド のみ実行 なのでSSGでJAMSTACKしたい場合は*page.server.tsが正解なのでした。 https://kit.svelte.jp/docs/load#universal-vs-server これもドキュメントを読めば…!といったところですね。ドキュメントは最高。 サーバーサイドのみで実行したい場合の正解例 export async function load({ params, fetch }) { const pagesReq = await fetch(`APIURL`); let data = await pagesReq.json(); return { data }; } meta管理方法 どのフレームワークも、もっといえば、どのウェブサイトでもそうですが、 meta情報をどのように管理するかという悩ましい問題があります。 フレームワークを知る前はpugとjsonとgulpもしくはwebpackの三種の神器で頑張っていたりしたのですが、 Svelteではこんな形で簡単に行なえました。 <script lang="ts"> import { siteTitle, siteDescription } from '$lib/config'; interface META { title: string; description?: string; } export let metadata: META; </script> <title>{`${metadata.title}|${siteTitle}`}</title> {#if metadata.description} <meta name="description" content={metadata.description} /> {:else} <meta name="description" content={siteDescription} /> {/if} <script lang="ts"> import Meta from '$lib/components/Meta.svelte'; let metadata = { title: 'title, title, title', description: 'description, description, description, description' }; </script> <Meta {metadata} /> こんな感じでmetaコンポーネントを作って読み込むことができます。 またわざわざ作らなくても、こんな素敵なプラグインもあります。 https://github.com/oekazuma/svelte-meta-tags 感謝…!!!!! それぞれのライフサイクルのつかいどころ 最後に避けては通れぬライフサイクル関数について Svelteには onMount , onDestroy , beforeUpdate , afterUpdate , tick と全部で5つのライフサイクル関数があります。 onMount その名の通りコンポーネントが初めてDOMにレンダリングされたあとに実行されます。 Vueのmountedとほぼ同義がタイミングです。 onDestroy これも名前の通りでコンポーネントが破棄されたタイミングで実行されます。 処理が不必要になったタイミングでコンポーネントを破棄することでメモリリークなどを防ぐことができます。 またサーバーサイドコンポーネントの場合、このライフサイクル関数のみが使えます。 beforeUpdate コンポーネントがDOMがレンダリングされる前のライフサイクル関数です。 また状態の変更を先に、反映したい場合などもbeforeUpdateを使う場合が多いです。 DOMレンダリング前のライフサイクル関数になるので、DOMにまつわる処理を書く場合は注意が必要です。 afterUpdate コンポーネントがDOMにレンダリングされ、データが反映されたあとに実行される関数です。 Svelte上では最後に実行されるライフサイクル関数ですね。 tick 状態が更新されたあと、その状態がDOMにレンダリングされるまでのタイミングを扱うことができます。 DOMの更新を待ってから何か処理をする、ということが可能になります。 ライフサイクル関数も他のフレームワークと比べ少ないので比較的わかりやすいのではないでしょうか。 以上で今回のSvelte Tipsを終わります。 最後に Software Design 2023年7月号にて Svelte特集「はじめよう Svelte」 を執筆致しましたのでさらに詳しく知りたい方は書籍で :) (SSGでJAMSTACKするチュートリアルも書いてあるのでぜひお試しください) https://twitter.com/gihyosd/status/1669533941483864072?s=20
アバター
はじめに こんにちは。KINTO Technologiesのグローバル開発部でフロントエンド開発をしているクリスです。以前は Storybook と Vue.js について執筆させていただきましたが、今日は技術と少し離れ、マネジメントについて話したいと思います。 実は私は去年の7月からフロントエンドチームのリーダーになり、もうすぐ1年が経ちます。初めてのリーダー経験で、たくさんの出来事がありましたが、次の1年に向けてよりよいリーダーになるために何をすればいいか考え、この1年間リーダーとしてやってきたことの振り返りをテキストに起こしたいと思い、本記事を執筆しました。 チームについて まず去年リーダーに就任した当時に遡ると、チームそのものが、部署の組織変更でフロントエンドに特化した部隊が欲しく作られたチームです。以前の記事でも少し触れましたが、多国籍なチームで、日本語がそこまで堪能ではないメンバーもいるので、チーム内では基本英語でコミュニケーションを取っています。 このチームの主な仕事はグローバル開発部が持つ各プロジェクトのフロントエンド開発を行うことですが、複数のプロダクトに対してメンバーの数も多くないので、一人が複数のプロダクトを担当するのは珍しくありません。また、保守期間になったプロダクトにおいてはずっとフロントエンドのタスクがあるわけでもないので、リファクタリングでコードを改善すると同時にローテーションでメンバーを他のプロダクトに回す時もあります。 チームリーダーとしての役割 私はチームリーダーになる前も、一人のメンバーとしてこのチームでフロントエンドの開発作業に専念し、デザインシステムの開発を行なっていましたが、リーダーになってからは主に以下の仕事に専念し、自ら開発するよりはメンバーに委ねることが多くなりました。 技術と実装方法の選定 一つ目の仕事はチーム全体の技術と実装方法を選定することです。フロントエンド開発においてはたくさんのフレームワークやライブラリーが選べます。実際、選択肢が多すぎて、何がいいか悩む方が多いと思いますが、私ももちろんその一人です。フレームワークの話だと、メンバーが慣れているか、機能面でプロダクトの要件を満たしているか、コミュニティーサポートが十分か、などの面で考慮しないといけないですが、なるべく話題になって、流行ってるフレームワークも使ってみたいという開発者のありがちの気持ちとどうバランスを取るかも重要です。 今グローバル開発部のフロントエンドチームは基本Vue.js/Nuxt.jsで統一していますが、かと言って今後もこのセットでやっていかないといけないというわけでもありません。チーム内には常に新しいことを試す雰囲気があるので、最近では社内の技術交流会で他のフロントエンドチームの影響を受けて SvelteKit やAstroなども試しながら評価しています。そして評価の結果を基に、何を利用するかを決めていきます。 PMとメンバーのコミュニケーションフォローとプロダクトのコードレビュー 二つ目の仕事はPdM/PjMとメンバーとのコミュニケーションが円滑に行えるようにすることです。フロントエンドチームは複数のプロダクトの開発タスクを行うことがあるため、それぞれのPdM/PjMとコミュニケーションを取って作業を進んでもらっています。仕様確認、提案やフィードバックなどをすることによって、プロダクト開発がスムーズに行えることを手伝っています。また、現行各プロダクトにアサインしているメンバーが一人の場合が多いので、リーダーとして品質と情報把握のために全プロダクトのレビューを行っています。 シニアマネージャーとメンバーの架け橋 三つ目はシニアマネージャーとメンバーの架け橋を担うことです。弊社では、マネージャー層になると、所属メンバーが10人以上増えることもあります。例えば私の場合ですと、自分の直上長は他のチームも管理していて、合計20人近くのメンバーを取りまとめています。そのため、多くの場合はリーダー経由でメンバーの管理を行います。 現在私がやっているのは、主に以下のことです: メンバーの能力や志向を踏まえて、それぞれの役割とミッションを設定すること(もちろん最終的にマネージャーにもすり合わせること) 決めたミッションを基づいて、定期的に1on1をセットアップし、フィードバックをしたり、彼らの相談や悩みを聞いたりして、必要に応じて現場の声をマネージャーにもフィードバックすること 動機づけとメンターリング 最後はもちろんメンバーの管理です。前述したように、1on1でのコミュニケーションはもちろん、それぞれの強みを発見し、なるべくそれを活かすというのも重要な役割です。私のチームメンバーは国籍だけでなく、スキルレベルもバラバラですが、共通点としては向上心が高いのが挙げられます。中には細部に気を配って、気づきにくいところまで発見くれるメンバーもいれば、プライベートで勉強して、取得したスキルや知識を業務で活かすメンバーもいます。あとはやる気を維持するのも必要で、なるべくメンバーのやりたいことを実現させてあげたいですが、そうならない時もモチベーションを持たせるコミュニケーションは必要です。 また、メンバーがまだ使ったことがない技術を使う必要がある場合は私がレクチャーしたり、もし私も使ったことがないなら一緒に勉強したりします。 リーダーとして気をつけていきたいこと 適切なコミュニケーションとフォロー コロナ禍以降、リモートワークが増える傾向にありますが、弊社もフルフレックス制度やリモートワーク制度を導入しています。そうするとオンラインでのミーティングが多くなります。対面と比べて相手の表情やジェスチャーからの情報が察知しづらくなり、コミュニケーションミスが発生するリスクがあるので、特に自分がリーダーとして主に話したい時と、メンバーから相談がある時の1on1はなるべくお互いオフィスにいる時に行っています(もちろんミーティング自体は最小限にしています)。 また、私自身は去年部署内で開催された ハッカソン で優勝し、作品を製品化に向けて別のチームで進めているので、兼務の中で素早くメンバーのフォローに回せないという反省もありますので、今は両立できるように手探りしています。 うまく任せて育てること 私のチームは複数のプロダクトを担当しているので、プロダクトへのアサインはメンバーのスキルレベル、好みなどとプロダクトの難易度、課題などを掛け合わせて考慮するようにしています。 そして、アサインした後も定期的に状況をヒアリングしたり、サポートしたりします。たまにメンバーのタスクを見て、自分もやりたい気持ちが強くなる時もありますが、そこは頑張って自分の気持ちを抑えてメンバーにやってもらっています(笑)。 一方、任せた後もどんなことをしたらメンバーが成長するかも考えなくてはいけません。私の一つの答えとしては、なるべく自分で考えてもらうことです。例えばジュニアレベルのメンバーだと、0から何もかも教えるのでなく、レビューで指摘したい時はまず質問して、「何で」という部分を意識してもらって考えさせています。 終わりに 1年リーダーをやってみて、たくさんのことを経験し、今年度のグローバルGフロントエンドチームの展望について述べてこの記事の終わりに迎えたいと思います。 FE分野のスキルアップデート 前述したように、チームにはまだジュニアレベルのメンバーがいるということに加え、技術も日々変わってきます。フロントエンドだけでもここ数年たくさんの新しい話題となるフレームワークが生まれました。例えば他の部署で使っているSvelteや、AstroやQwikなどがあります。 新しいフレームワークやライブラリーを導入するには技術以外の要素も考えないといけませんが、勉強しておくと将来役に立つし、視野が広がるので、メンバーに対して影の年間目標として設定し、チームとしてスキルのアップデートをしていきたいと思います。 BE分野への理解 「フロントエンドだけ特化して、バックエンドへの理解が少ないと、API連携の話で噛み合わない部分がある」というのは自分の経験上でよくある話なので、自社では職種的にフロントエンドとバックエンドで分かれていても、なるべく担当でない領域の基礎知識も身についてもらいたいと考えます。例えば、今の一つやっている施策としては、メンバーをプロジェクトにアサインした後、バックエンドにも迷惑かけないレベルで簡単なタスクを経験させてもらえるようにプロジェクトリーダーと調整したりしています。
アバター
はじめに 先週末にOpenAIの発表があり、ChatGPT(GPT-4)のCode Interpreterという機能が公開されました。内部でPythonが動いており日本語や英語で指示するだけでノーコードでデータの分析などを行うことができる便利なサービスです。 そのままではグラフ描画などで日本語の表示ができないのですが、「 日本語フォント表示する方法を見つけ出した 」のでこちらの記事でご紹介します。 この記事で学べること Code Interpreterを使用して日本語フォントでグラフや画像、PDFファイルを出力する手順 Code InterpreterでTwitterのログ分析の解析方法 前置き不要という方は[Code Interpreterで日本語フォントを使ってグラフや画像、PDFを出力する手順だけを知りたい方はこちらからどうぞ]。(#chatgpt(gpt-4)のcode-interpreterで日本語フォントをつかう方法のまとめ) 自己紹介 自己紹介が遅れましたが、 KINTO FACTORY のリードエンジニアをしている 中西 葵 です。本業の開発とは別にテックブログやイベント運営、Twitterアカウントの運用も行っており、いわゆる技術広報的な取り組みも一部行っております。 前提条件 ChatGPTに課金していること(ChatGPT Plus) Code Interpreterを有効にしていること 以上の2点です。 Code Interpreterの有効化 Code Interpreterの有効化は Settings -> Beta Features -> Code Interpreter から以下の画像の通りに有効化してください。 日本語化までの道のり 指示なしでは自動的に日本語での描画が行われないことがわかったので、ChatGPTに探りを入れていきましょう。 〇〇を日本語表示して! まずは「日本語表示して」と指示してみましたが、現在の環境では日本語フォントを埋め込むことができないと返されてしまいました。 日本語表示できない理由を探る 「 現在の環境では 」という一文に注目し、グラフ画像をどのように生成しているのかを尋ねてみます。 日本語表示のやり方を聞いてみる PythonとMatplotlibを使っていることがわかったので日本語表示する方法を聞いてみます。 例として出てきたコードがこちらになります。 インターネットアクセスが無効化されているため、フォントのダウンロードやシステムの設定変更はできないと言われてしまいました。ファイルのアップロードは可能ですが、ダウンロード等はできないようです。また別で確認したところ、システム関数なども使えないようになっているようです。 日本語フォントファイルのアップロード 「 ダウンロードはできない 」との事なので逆にアップロードはできるのではないか?との疑問から早速聞いてみます。 ファイルのアップロードなら可能とのことなので早速試してみます。 日本語フォントのダウンロード ChatGPTから教えてもらったサンプルコードにもNoto Sansのフォントが書かれていたので今回はNoto Sansを使うことにします。 https://fonts.google.com/noto/specimen/Noto+Sans+JP からフォントをダウンロードします(試していませんが他のフォントでも利用可能) 日本語フォントのをアップロードしてmatplotlibの日本語化 早速日本語でグラフを生成してみましょう 日本語フォントのアップロード 画面の下にあるプラスボタンからファイルをアップロードします。合わせて「 グラフの描画を行う際にはこちらの日本語フォントを利用してください 」のようにグラフ描画時にアップロードした日本語フォントを使用するように指示してください。 ↓ ↓ ↓ ChatGPT(GPT-4)のCode Interpreterで日本語フォントをつかう方法のまとめ 以下の手順で日本語のグラフを表示することができるようになりました。 日本語フォントをローカルにダウンロード ChatGPTに日本語フォントをアップロード ChatGPTにグラフ描画時のフォントを指定 必要なデータをアップロードしてグラフを描画 また、グラフ描画時の凡例が日本語化されない場合は、 凡例も日本語化してください と伝えて再生成することで凡例部分も日本語化することができます。ポイントはChatGPTにアップロードした日本語フォントファイルを使って日本語を描画するように指示するところです。PDF等も同じ手順で日本語を正しく表示可能なファイルを出力することができます。 Twitterログの分析 日本語で分析結果を出力できる準備が整ったので早速Twitterログの分析を行っていきましょう。 https://twitter.com/KintoTech_Dev こちらのTwitterアカウントのデータ分析を行います。Twitterアナリティクスから細かなデータをダウンロードして様々な分析を行うことができますが今回は既にパプリックに公開されているデータを元に分析を行います。利用するデータは以下の通りです。 ツイート本文 ツイート日時 リツイート数 リプライ数 いいね数 これらのデータはアカウントオーナー以外でもアクセスできる一般に公開されているデータとなります。 CSVファイルのアップロード フォントをアップロードしたとき同様にアップロードボタンからファイルを選択し分析対象のデータをアップロードします。今回はCSVファイルをアップロードしましたが、Pythonで扱えるデータであれば基本的に何でも読み取ることができるようです。またアップロード可能なファイルサイズを確認したところ正確な数字は教えて頂けませんでしたが、数百MBのサイズが受け入れ可能とのことです。 ChatGPTにファイルをアップロードし分析を依頼します。いくつかのChatGPTからの質問に答えたあと出てきた分析結果は以下のとおりです。インプレッション数、リツート数、いいね数、本文の分析それぞれの解説もしてもらった結果は以下の通りです。 インプレッション数の分析 ChatGPT: 特定の時間帯や曜日に明確な傾向は見られません。しかし、火曜日の特定の時間帯では他の時間帯よりもインプレッション数がやや高いようです。 KINTOテクノロジーズでは火曜日に記事出すことが多く、公開と合わせてツイートをしているためにこのような分析結果が出ているようです。 リツイート数の分析 ChatGPT: こちらも特定の時間帯や曜日に明確な傾向は見られません。しかし、火曜日の特定の時間帯では他の時間帯よりもリツイート数がやや高いようです。 インプレッション数と比例してリツート数も多いようです。 いいね数の分析 ChatGPT: いいね数も特定の時間帯や曜日に明確な傾向は見られません。しかし、火曜日の特定の時間帯では他の時間帯よりもいいね数がやや高いようです。 インプレッション数、リツイート数、いいね数はそれぞれ相関があることが見て取れますが、 ChatGPT: 今回の分析ではツイートの数が比較的少ないため、結果はあくまで参考程度に留めていただくことをお勧めします。 と言及されているため分析結果のヒートマップを見てもわかりにくい部分もありますのでまずはツイートやフォロワーを増やして行く必要がありそうですね。 ツイート本文の分析 インプレッション数が高いトップ10のツイートをChatGPTを使ってトピックモデリングで分析した結果を以下に示します。意図した内容が分析結果に反映されていることが分かりました。 項目 説明 注目を引く視覚的な要素 ユーザーの注意を引き、エンゲージメントを向上させる ハッシュタグの使用 ツイートが見つけやすくなる 記事の主題の明確な紹介 記事の主題が明確に紹介されている 具体的な行動の呼びかけ 「開発環境の構築や管理にお困りの方は是非ご覧ください!」という具体的な行動の呼びかけが含まれている 今後の記事の予告 新しい記事の公開を通知することで、ユーザーの関心を引き、エンゲージメントを向上させる 特定のテーマの強調 テーマを強調するとイベントや企業の内部の活動に関心があるユーザーの関心を引く ツイート分析結果のまとめ ここまでの分析結果から投稿時間、ツイート内容、URLの活用がツイートの最適化におけるポイントとなっていることが分かりました。 項目 説明 投稿時間の最適化 顕著に出ているわけではないが木曜日と金曜日の夜にエンゲージメントが高まる傾向がある。週末に向けてフリータイムが増えより多くのコンテンツを探求している可能性がある ツイート内容の最適化 イベントや新しい記事のトピックが含まれるツイートがエンゲージメントが高い URLを含むツイート テックブログURLを含むツイートのエンゲージメントが高い 全体のまとめ 本記事ではChatGPTのCode Interpreterを使ってデータ分析を行い日本語でグラフ等の作成を行う方法を解説しました。皆さんの分析ライフにお役に立てましたら幸いです。 これからも続々と役立つ記事を公開していきます。最新情報が気になる方はぜひこちらのアカウントをフォローしてください。 https://twitter.com/KintoTech_Dev KINTOテクノロジーズでは一緒にモビリティの未来を創る仲間を募集しています。カジュアル面談なども行っておりますのでご興味をお持ち頂けましたらぜひお気軽にご連絡ください。 https://www.kinto-technologies.com/recruit/
アバター
はじめに こんにちは。分析グループでデータエンジニアをしている小池です。Slackって便利ですよね。こいつは突然何を言い出すのか。そう思ったかたも多いかもしれません。しかし、安心してください。Slackが便利であることはまぎれもない事実です。そして、その中でも絵文字リアクションは群を抜いて便利だとわたしは思います。そもそも絵文字リアクションが何者かわかりますか。少していねいに説明してみますね。次の画像をご覧ください。 ![Slack絵文字リアクション](/assets/blog/authors/charlie/slack_emoji_reaction.png =660x) これはわたしが自分のtimesチャンネルでぼやいたものです。白く囲んだ部分を見ると、ぽこぽこと泡のようなものがあることがわかると思います。これがまさしく絵文字リアクションです。「🥲」という絵文字の横に「1」とありますが、これは1人が「🥲」絵文字のリアクションをしたことを表しています。この数字が多ければ多いほどうれしいですね。また、ほかに「どんまい」という絵文字があります。これはSlackに標準搭載されているわけでなく、ユーザが追加した「カスタム絵文字 ^1 」というものです。今回は、ChatGPTの力を借りてカスタム絵文字の追加を行ってみます。 背景 そもそも、なぜカスタム絵文字を追加したくなったのかを説明しましょう。わたしの所属している分析グループは、東京、名古屋、大阪の3拠点に分かれて業務を行っています。これは、常時フルリモート状態になっているメンバーがいるということです。東京は東京、名古屋は名古屋、大阪は大阪でオフラインのコミュニケーションが行われることもあるため、全員が自宅からリモートワークをしている状態よりも情報の格差が生じてしまっているかもしれません。こういった事象をなくすべく、テキストコミュニケーションツールであるSlackにもっと力を入れるべきなのではないかと考えました。そして、その手段としてカスタム絵文字の追加を思いついたというわけです。 Slackカスタム絵文字の作成 それでは、さっそくカスタム絵文字を追加していきましょう。以下のような手順で進めていこうと思います。 リアクションに使われた絵文字の利用回数の集計 1で集計した絵文字を感情別にグループ分け 2で作成したグループをもとにChatGPTで単語を生成 3で生成した単語を選定し、絵文字作成ツールで画像にしてSlackへ登録 絵文字の利用回数の集計 カスタム絵文字を追加するといっても、どんなものを追加すればよいのかいきなりはわかりませんね。そこで、まずは日ごろからどのような絵文字が使われているのかをリサーチするところから始めてみます。具体的には、チャンネルと期間をしぼり、それらの投稿の中でなされた絵文字リアクションとその回数を調べて傾向をつかんでみようと思います。 はじめに、SlackのAppを作成して、以下のように権限を設定し(必要そうなものをなんとなく追加したため、過剰な権限になっているかもしれません)、トークンを発行します。 作成したAppをPythonから呼び出して次のように集計作業を行います。 import datetime import pprint import time import yaml from slack_sdk.web import WebClient def main(): get_and_save_messages() reaction_counts = get_reaction_counts() pprint.pprint(sorted(reaction_counts.items(), key=lambda x: x[1], reverse=True)) def get_and_save_messages(): SLACK_API_TOKEN = "SLACK_API_TOKEN" client = WebClient(token=SLACK_API_TOKEN) target_channel_id_to_name = { "id0": "#name0", "id1": "#name1", "id2": "#name2", "id3": "#name3", "id4": "#name4", } unix_times = get_unix_times() messages = get_messages_in_channels(client, list(target_channel_id_to_name.keys()), unix_times) with open("messages.yaml", "w") as f: yaml.dump(messages, f, allow_unicode=True) def get_messages_in_channels(client, channel_ids, unix_times): merged_messages = [] for channel_id in channel_ids: for unix_time_pair in unix_times: merged_messages += client.conversations_history( channel=channel_id, include_all_metadata=False, latest=str(unix_time_pair[0]), limit=100000, oldest=str(unix_time_pair[1]) )["messages"] return merged_messages def get_unix_times(): unix_times = [] today = datetime.date.today() start = 1 end = 15 for _ in range(24): start_date = today - datetime.timedelta(days=start) end_date = today - datetime.timedelta(days=end) start_unixtime = int(time.mktime(start_date.timetuple())) end_unixtime = int(time.mktime(end_date.timetuple())) unix_times.append((start_unixtime, end_unixtime)) start = end + 1 end = start + 14 return unix_times def get_reaction_counts(): with open("messages.yaml", "r") as f: messages = yaml.safe_load(f) reaction_counts = dict() for message in messages: if "reactions" in message: for reaction in message["reactions"]: reaction_counts[reaction["name"]] = reaction_counts.get(reaction["name"], 0) + reaction["count"] return reaction_counts if __name__ == "__main__": main() ソースコードについてかんたんに説明しましょう。 main() では各工程ごとの関数を呼び出すようになっています。 get_save_and_messages() はSlackからメッセージを取得してファイルに保存する関数です。なお、 SLACK_API_TOKEN と target_channel_id_to_name は伏せてあります。メッセージが多すぎると一度に取得できない場合があるため get_unix_times() で期間を分割したものをリストで返し、メッセージを小分けに取得するようにしています。メッセージ取得が終わったら get_reaction_counts() で絵文字リアクションの回数を集計します。その後、回数が多い順にソートして表示して終了です。 実行結果を次に示します。たとえば、 ('man-gesturing-ok', 248) は、 man-gesturing-ok という絵文字が248回リアクションされたことを表しています。また、この実行結果にはデフォルトの絵文字はもちろん、手作りのものや社外のかた[^2]が作成したものも含まれています。 ('man-gesturing-ok', 248), ('eyes', 248), ('arigatougozai', 199), ('承知しました', 64), ('+1', 49), ('thinking_face', 43), ('yorosikuonegaisimasu', 26), ('arigatougozaimasu', 17), ('tada', 15), ('素敵', 14), ('arigato', 13), ('do_ne', 13), ('man-gesturing-no', 11), ('scream', 10), ('kakuninshimasu', 10), ('承知2', 9), ('woman-bowing', 9), ('sob', 8), ('ok', 8), ('faito', 8), ('kami_bl', 7), ('done_hiragana', 7), ('desune', 7), ('naruhodo', 7), ('ok_hand', 7), ('sugoi', 7), ('tasukaru', 7), ('pray_mochimochi', 7), ('done-payment', 6), ('hai-', 6), ('nanto', 6), ('yokata', 6), ('mumondai', 6), ('tashi-crab', 5), ('muscle', 5), ('oh', 5), ('sasuga2', 5), ('uooo', 5), 絵文字のグループ分け 先ほど集計した状態のままだとまだ解像度が低いため、絵文字を感情表現の種類ごとにグループ分けして特徴をつかんでみます。なお、グループ分け方法は独自で考えたものにしました(調べてみると心理学者が考案した感情の区分けがあるようでしたが、仰々しすぎて今回にはそぐわないと判断しました)。 報連相のために行われるものと感情表現のために行われるものに二分され、そこからさらに分かれていくといった構造になっていると考えました。それを次に示します。 - 報連相 - 報告 - チェック - お願い - 感情表現 - 共感 - 褒め - 感謝 - 応援 - 慰め - その他 この区分けを先ほどの集計結果に適用してみます。 ![絵文字グルーピング](/assets/blog/authors/charlie/grouping.png =170x) まじまじとご覧になったかたはわかると思いますが、どこにあてはまるかわからないものはほとんどフィーリングで適当に分けました...🤫 ですが、まずまず納得感のあるグループ分けができたのではないかと思います。 ChatGPTを用いた絵文字生成 絵文字のグループ分けに続いて、それぞれの感情表現の種類ごとに絵文字を生成してみようと思います。また、手段として今はやりのChatGPTを使ってみます。使用したモデルはGPT-4で、プラグインやウェブブラウジング機能は使いませんでした。使用したプロンプトは次のとおりです。 Slackのカスタム絵文字を作りたいです。下記についてそれぞれ10こずつあげてください。 また、ひらがな、カタカナ、漢字のいずれかで4~6文字に収めるよう努力してください。 - メッセージを送ってきた相手に共感を示せるもの(例 : :たしかに:、:ですね:) - メッセージを送ってきた相手を褒められるもの(例 : :すてき:、:神:、:すごい:) - メッセージを送ってきた相手に感謝を示せるもの(例 : :ありがと:、:たすかる:) - メッセージを送ってきた相手を応援できるもの(例 : :ファイト:、:ウオオオ:) - メッセージを送ってきた相手を慰められるもの(例 : :oh:、:なんと:) 実行結果は次のとおりです。 カスタム絵文字の提案です。ひらがな、カタカナ、漢字のいずれかで4~6文字に収めるよう努力しました。 メッセージを送ってきた相手に共感を示せるもの: :わかるよ: (wakaru yo) :同感: (doukan) :納得: (nattoku) :うんうん: (un un) :それそれ: (sore sore) :言いたい: (iitai) :共感: (kyoukan) :感じる: (kanjiru) :ごもっとも: (gomottomo) :思いやり: (omoiyari) メッセージを送ってきた相手を褒められるもの: :すごいね: (sugoi ne) :天才: (tensai) :凄い: (sugoi) :かっこいい: (kakkoii) :素敵: (suteki) :美しい: (utsukushii) :完璧: (kanpeki) :尊敬: (sonkei) :称賛: (shousan) :輝いてる: (kagayaiteru) メッセージを送ってきた相手に感謝を示せるもの: :ありがとう: (arigatou) :感謝: (kansha) :感謝してる: (kansha shiteru) :ありがとうね: (arigatou ne) :ありがとー: (arigatou-) :助かった: (tasukatta) :感謝の気持ち: (kansha no kimochi) :恩返し: (ongaesha) :お礼: (orei) :感激: (kangeki) メッセージを送ってきた相手を応援できるもの: :がんばって: (ganbatte) :ファイト: (faito) :頑張れ: (ganbare) :応援する: (ouen suru) :力になる: (chikara ni naru) :一緒にがんばろう: (issho ni ganbarou) :がんばりましょう: (ganbarimashou) :エールを送る: (eeru wo okuru) :成功を祈る: (seikou wo inoru) :自信を持って: (jishin wo motte) メッセージを送ってきた相手を慰められるもの: :大丈夫: (daijoubu) :頑張れ: (ganbare) :気にしないで: (ki ni shinaide) :がんばったね: (ganbatta ne) :辛いね: (tsurai ne) :つらいよね: (tsurai yo ne) :明日は新しい日: (ashita wa atarashii hi) :落ち込まないで: (ochikomanaide) :前向きに: (zenmuki ni) :頑張ってるね: (ganbatteru ne) Slackで使うには明らかに不自然なものもありますが、なかなかよさそうです。 絵文字の選定とSlackへの登録 先ほどChatGPTに生成させた絵文字から使い勝手のよさそうなものを選んでみるとともに、すでにSlackワークスペースに登録されている絵文字を省いてみます。 - 共感 - :wakaruyo: - :doukan: - :gomottomo: - 褒め - :sugoine: - 感謝 - :kangeki: - 応援 - 慰め - :kinishinaide: こんな感じになりました。 最後にこれらを絵文字作成ツール[^3]で画像にし、Slackに登録して完了です。 うーん、いい眺め! おわりに いかがでしたか。これでSlackでのコミュニケーションが活発になること間違いなし...とはいかず、追加した絵文字を率先して使って組織に浸透させていく作業が重要になってくると思います。また、今回は感情表現の種類ごとにまんべんなくカスタム絵文字を追加しましたが、足りていないところを集中的に作るというアプローチもできそうです。あなたの組織のSlackワークスペースでもやってみてくださいね! [^2]: ¥0 – SmartHR Store [^3]: 絵文字ジェネレーター
アバター
AWSサーバレスアーキテクチャをMonorepoツール - Nxとterraformで構築してみた! こんにちは。DevOpsで開発者を幸せにしたい。KINTO テクノロジーズのCCoEチーム所属の栗原です。 AWS Summit Tokyo 2023:クルマのサブスク「KINTO」のアジリティとガバナンスを両立する DBRE の取り組み でも発表しましたが、弊社DBREチームではSlackからのリクエストをトリガーに、一時的な踏み台サーバーを払い出すプラットフォーム(以降DBREプラットフォーム)を全社に展開しています。 DBREプラットフォームはAWSのサーバレスサービスを組み合わせて実装されています。同サーバレス部分をチームの使い慣れたterraformでIaCしつつ、 Nx というMonorepoツールで開発者体験の向上に成功した話をこの記事で紹介します。サーバレスに限らず、Monorepoでの開発フローに興味がある方にも参考になるかと思います。 背景、課題 DBREプラットフォームのアーキテクチャは以下のようになっています。 上記に加え運用関連も含めるとGolangのLambdaが20個ほどあり、それらをオーケストレーションするStep Functions、DynamoDB、スケジュールトリガーをするEventBridge等の組み合わせで構築しています。 開発を進めるにあたり以下のような課題、要望がありました。 terraformのplan、applyのワークフローと統合し安全なデプロイを実現したい Formatter、Linter等の静的コード解析を適切に組み込みたい サーバレスアーキテクチャを開発するのであれば、 SAM や serverless framework が検討されるかと思いますが、terraformでIaCしたいという要望をクリアできませんし、GolangでのLambdaはケアしてくれない等の理由から別の開発アーキテクチャを検討することになりました。 terraformのlambdaモジュール を眺めてみます。とかくterraformに参照させるLambdaコードの Zip を事前に作れていれば、terrafromでIaCしたい問題はクリアできるだろうと考えました。 resource "aws_lambda_function" "test_lambda" { # If the file is not in the current working directory you will need to include a # path.module in the filename. filename = "lambda_function_payload.zip" function_name = "lambda_function_name" role = aws_iam_role.iam_for_lambda.arn handler = "index.test" source_code_hash = data.archive_file.lambda.output_base64sha256 runtime = "nodejs16.x" environment { variables = { foo = "bar" } } } 更に後者の静的コード解析を適切に組み込みたい要望を考えてみます。サーバレス開発は言うならば 小さいコードベースを組み合わせたもの です。つまりコードベース群の境界をはっきりさせることで開発ツールとの統合を容易にし、ビルドスクリプトもシンプルに保てるのではという考えからMonorepoツールの導入を検討しました。 Monorepoツールとは 結論から言うと、 Nx というTypeScript製のMonorepoツールを導入しました。 導入理由は monorepo.tools というMonorepoツール比較ページでの機能の網羅性が高かったのと、将来の横展開を考えた際Javascript製というのも魅力を感じたためです。(フロントエンド界隈への導入障壁が低いという仮定。) 実例は次の章で説明しますが、前提としてMonorepoとはなんなのか?またNxは何をしてくれるのか?を簡単に説明します。 用語定義 Nxの用語に合わせ、本資料で使う用語を定義します。 プロジェクト : monorepo内の1つのリポジトリのような塊(例: 単一のLambdaコード、共通モジュール) タスク : テスト、ビルド、デプロイなどアプリケーションを構築するうえで必要な処理の総称 Monorepoとは 関連するプロジェクトが isolated(独立性を保ちつつ) でかつ well-defined relationships(依存関係は適切に定義されている) な状態で格納されている単一リポジトリと説明されています。対してWeb界隈では良くみられるマルチリポジトリの構成を polyrepo と呼ぶそうです。 出典: monorepo.tools monorepo.tools を要約すると、以下の様なメリットがあります。 コミットがシステム単位でアトミックになる 共通モジュールの展開が容易(共通モジュールを更新した際、取り込みなど不要ですぐに利用可能) (マインドセット的に)縦割りにならず、システム全体に意識が向きやすい 新しいリポジトリを立ち上げる時の工数が減る Monorepoツールではないですが、AWSの cdk でもIaCとアプリケーションコードの単一リポジトリ管理を推奨していることもあり、Monorepo化への潮流は一つの流れだと考えられます。 We discovered that failures are often related to "out-of-band" changes to an application that aren't fully tested, such as configuration changes. Therefore, we developed the AWS CDK around a model in which your entire application is defined in code, not only business logic but also infrastructure and configuration. …and fully rolled back if something goes wrong. - https://docs.aws.amazon.com/cdk/v2/guide/best-practices.html Nxがしてくれること 大雑把にいうと、 プロジェクト毎 に 自身のタスク と 依存関係 を定義していけば、Nxが いい具合にタスクをオーケスレーションしてくれる ということになります。 以下はterraformプロジェクトのタスク、依存関係の定義の例です。このように定義すると、 plan-development タスクを実行すると、定義した依存関係のLambdaコードのビルド(コンパイル、zip化)が先に実行され、その後terraformのplanを走らせてくれます。 fmt や test などもterraform専用のタスクとしてシンプルに定義することができます。 このように各コードベースの責務を明確化していくことで、コード全体の見通しをよくしていくことができます。 プロジェクト単位で、それぞれの開発言語にあった開発ツールを組み込むことが可能ですし、ビルド職人に頼らなくとも適切な開発フローを構築していくことが可能になります。 KINTO テクノロジーズでの実用例 前述のDBREプラットフォームの一部を抜粋し、簡素化したうえで実用例を説明していきます。 GolangのLambdaコードが二つあり、双方同じ共通モジュールを利用しています。terraformからデプロイできるように、Lambdaコードのプロジェクトは自身のコードをコンパイルし、Zipファイルを作成するまでが責務となります。 ディレクトリ構成はこのようになります。 プロジェクト定義 上記4プロジェクトの各プロジェクト定義をそれぞれ記載します。 ①: 共通モジュール Golangでは共通モジュールは利用側で参照できれば良いので、ビルドは不要で静的解析、UTのみをタスクとして定義します projects/dbre-toolkit/lambda-code/shared-modules/package.json { "name": "shared-modules", "scripts": { "fmt-fix": "gofmt -w -d", "fmt": "gofmt -d .", "test": "go test -v" } } ②、③: Lambdaコード 共通モジュールを依存プロジェクトとして登録することで、 共通モジュールのコードが変更されるた場合、タスクの実行が必要 といった定義になります build タスクはgo buildを実行して生成されたバイナリーをZip化するまでが責務になり、後にterraformプロジェクトで利用されます projects//dbre-toolkit/lambda-code/lambda-code-01/package.json { "name": "lambda-code-01", "scripts": { "fmt-fix": "gofmt -w -d .", "fmt": "gofmt -d .", "test": "go test -v", "build": "cd ../ && GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o lambda-code-01/dist/main lambda-code-01/main.go && cd lambda-code-01/dist && zip lambda-code.zip main" }, "nx": { "implicitDependencies": [ "shared-modules" ] } } ④: IaC plan-${env} 、 apply-${env} を実行すると、依存関係に指定されているLambdaコードの build が先に実行されます(plan、apply実行時には必要なzipが生成されている状態になる) projects//dbre-toolkit/iac/package.json { "name": "iac", "scripts": { "fmt": "terraform fmt -check -diff -recursive $INIT_CWD", "fmt-fix": "terraform fmt -recursive -recursive $INIT_CWD", "test": "terraform validate", "plan-development": "cd development && terraform init && terraform plan", "apply-development": "cd development && terraform init && terraform apply -auto-approve" }, "nx": { "implicitDependencies": [ "lambda-code-01", "lambda-code-02" ], "targets": { "plan-development": { "dependsOn": [ "^build" ] }, "apply-development": { "dependsOn": [ "^build" ] } } } } terraformのモジュールからは、以下の様に前段で生成されているZipファイルを参照させます。 local { lambda_code_01_zip_path = "${path.module}/../../../lambda-code/lambda-code-01/dist/lambda-code.zip" } # 中略 resource "aws_lambda_function" "lambda-code-01" { function_name = "lambda-code-01" architectures = ["x86_64"] runtime = "go1.x" package_type = "Zip" filename = local.lambda_code_01_zip_path handler = "main" source_code_hash = filebase64sha256(local.lambda_code_01_zip_path) } タスク実行 各プロジェクトの分割、タスク定義ができたので、タスクの実行について見ていきます。 Nxでは run-many サブコマンドで特定プロジェクトの特定タスク、全プロジェクトの特定タスクの実行が可能です。依存関係に基づき、可能な場合はパラレルに実行されるので速度も高速です。 nx run-many --target=<定義したタスク名> --projects=<プロジェクト名のカンマ区切り> nx run-many --target=<定義したタスク名> --all iac プロジェクトの plan-development を実行する例。依存関係があるタスクは、定義した依存関係に基づいてタスクを実行してくれる まさにやりたかったポイントです。依存プロジェクトのタスクを先行して実行してくれるため、terraform実行時には適切にLambdaのコードがZip化されている状態を担保することができます。 $ nx run-many --target=plan-development --projects=iac --verbose > NX Running target plan-development for 1 project(s) and 2 task(s) they depend on: - iac —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— > nx run lambda-code-01:build updating: main (deflated 56%) > nx run lambda-code-02:build updating: main (deflated 57%) > nx run iac:plan-development Initializing modules... Initializing the backend... Initializing provider plugins... - Reusing previous version of hashicorp/aws from the dependency lock file - Using previously-installed hashicorp/aws v4.39.0 terraform has been successfully initialized! 〜〜中略 } Plan: 0 to add, 2 to change, 0 to destroy. 全プロジェクトの test タスクを実行する例。タスクに依存関係がないので全てパラレルに実行される UTなど依存関係がないタスクはパラレルに実行できます。 CIでの実行はもちろん、『GitHubにpushする前に必ずUTを実行する』といった開発ルールがあった場合も一つのコマンドで解決することができます。 $ nx run-many --target=test --all --verbose > NX Running target test for 4 project(s): - lambda-code-01 - lambda-code-02 - shared-modules - iac —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— > nx run shared-modules:test ? github.com/kinto-dev/dbre-platform/dbre-toolkit/shared-modules [no test files] > nx run lambda-code-01:test === RUN Test01 --- PASS: Test01 (0.00s) PASS ok github.com/kinto-dev/dbre-platform/dbre-toolkit/lambda-code-01 0.255s > nx run iac:test Success! The configuration is valid. > nx run lambda-code-02:test === RUN Test01 --- PASS: Test01 (0.00s) PASS ok github.com/kinto-dev/dbre-platform/dbre-toolkit/lambda-code-02 0.443s —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— > NX Successfully ran target test for 4 projects > nx run lambda-code-02:test Nx、Monorepoツールの強力な機能 プロジェクトを適切に定義していくとことで、タスクをオーケストレーションできる様子が伝わったかと思います。 ただし、これだけでは普通のタスクランナーと変わらないので、Nx、Monorepoツールを使う大きなメリットをいくつか紹介します。 変更プロジェクトのみタスク実行 最も早いタスク実行とは そもそもタスクを実行しないこと です。 affected コマンドという変更プロジェクトのみのタスクを実行してくれる機構が用意されており、CIを高速に完了することが可能です。 以下がコマンドのシンタックスです。2つのGitポインターを渡してあげることで、同ポインター間で変更があったプロジェクトのタスクのみ実行してくれます。 nx affected --target=<タスク名> --base=<two dots diffのbase> --head=<two dots diffのhead> # lambda-code-01にだけ変更がある状態 $ git diff main..feature/111 --name-only projects/dbre-toolkit/lambda-code/lambda-code-01/main.go $ nx affected --target=build --base=main --head=feature/111 --verbose > NX Running target build for 1 project(s): - lambda-code-01 ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— > nx run lambda-code-01:build updating: main (deflated 57%) ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— > NX Successfully ran target build for 1 projects 依存先のプロジェクトに変更があれば、依存関係に基づきタスクを実行してくれます。 # shared-moduleにだけ変更がある状態 $ git diff main..feature/222 --name-only projects/dbre-toolkit/lambda-code/shared-modules/utility.go # shared-moduleに依存しているプロジェクトのタスクが実行される $ nx affected --target=build --base=main --head=feature/222 --verbose > NX Running target build for 2 project(s): - lambda-code-01 - lambda-code-02 ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— > nx run lambda-code-01:build updating: main (deflated 56%) > nx run lambda-code-02:build updating: main (deflated 57%) ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— > NX Successfully ran target build for 2 projects CI/CDパイプラインの簡素化 タスク名が変わらなければ、プロジェクトを追加していってもCI/CDパイプラインの変更が不要なため、メンテナンスコストが下がります。 加えて、前述の affected コマンドにより、CI/CDの処理を高速化することができます(変更したプロジェクトのタスクのみ実行してくれるため)。 以下はGitHub ActionsのCIの例です。 name: Continuous Integration on: pull_request: branches: - main - develop types: [opened, reopened, synchronize] jobs: ci: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 with: fetch-depth: 0 # --immutable オプションは、yarn.lockに記載の固定バージョンのdependenciesをインストールさせるオプション - name: install npm dependencies run: yarn install --immutable shell: bash - uses: actions/setup-go@v3 with: go-version: '^1.13.1' - uses: hashicorp/setup-terraform@v2 with: terraform_version: 1.3.5 - name: configure AWS credentials uses: aws-actions/configure-aws-credentials@v1-node16 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: 'ap-northeast-1' # タスク実行箇所はこの記述量で完了する - name: format check run: nx affected --verbose --target fmt --base=remotes/origin/${{ github.base_ref }} --head=remotes/origin/${{ github.head_ref }} - name: test run: nx affected --verbose --target test --base=remotes/origin/${{ github.base_ref }} --head=remotes/origin/${{ github.head_ref }} - name: build run: nx affected --verbose --target build --base=remotes/origin/${{ github.base_ref }} --head=remotes/origin/${{ github.head_ref }} - name: terraform plan to development run: nx affected --verbose --target plan-development --base=remotes/origin/${{ github.base_ref }} --head=remotes/origin/${{ github.head_ref }} Git Hookと組み合わせてさらに生産性の向上 『Gitでpushする前に静的解析とUnit Testくらいはローカルでやってほしい。Gitの履歴も汚れるし』といった開発ルールも簡単に解決することができます。 affected コマンドの --files 、 --uncommitted オプションと、Git Hookを組み合わせることで、変更ファイルが属するプロジェクトのみを対象にでき、開発者のストレスを最小限に(実行に時間をかけずに)実現が可能です。 例えば以下の様な affected コマンドを pre-commit フックに仕込んでおけば、コミット履歴も汚れず、レビューのノイズも軽減することができます。 nx affected --target lint --files $(git diff --cached --name-only) : nx affected --target unit-test --files $(git diff --cached --name-only) nx affected --target fmt-fix --files $(git diff --cached --name-only) その他のメリット タスクの実行結果はプロジェクトのコードに変更がなければキャッシュされる タスクの実行結果は、生成されたファイル、標準出力/エラーともキャッシュされます。(詳細は こちら ) $ tree .nx-cache/ ├── ce36b7825abacc0613a8b2c606c65db6def0e5ca9c158d5c2389d0098bf646a1 │   ├── code │   ├── outputs │   │   └── projects │   │   └── dbre-toolkit │   │   └── lambda-code │   │   └── lambda-code-01 │   │   └── dist │   │   ├── lambda-code.zip │   │   └── main │   └── terminalOutput ├── ce36b7825abacc0613a8b2c606c65db6def0e5ca9c158d5c2389d0098bf646a1.commit ├── nxdeps.json ├── run.json └── terminalOutputs ├── 1c9b46c773287538b1590619bfa5c9abf0ff558060917a184ea7291c6f1b988c ├── 6f2fbb5f2dd138ec5e7e261995be0d7cddd78e7a81da2df9a9fe97ee3c8411c5 ├── 88c7015641fa6e52e0d220f0fdf83a31ece942b698c68c4455fa5dac0a6fd168 ├── 9dc8ebe6cdd70d8b5d1b583fbc6b659131cda53ae2025f85037a3ca0476d35b8 ├── c4267c4148dc583682e4907a7692c2beb310ebd2bf9f722293090992f7e0e793 ├── ce36b7825abacc0613a8b2c606c65db6def0e5ca9c158d5c2389d0098bf646a1 ├── db7e612621795ef228c40df56401ddca2eda1db3d53348e25fe9d3fe90e3e9a1 ├── dc112e352c958115cb37eb86a4b8b9400b64606b05278fe7e823bc20e82b4610 └── eb94fd3a7329ab28692a2ae54a868dccae1b4730e4c15858e9deb0e2232b02f3 これをCI/CDでもキャッシュしておけば、例えばコードレビューで一部分だけ修正が必要になった場合、修正後のPushに対するCI処理のタスクの大部分はキャッシュが使われるため、更に高速に開発を回すことが可能です。 - name: set nx cache dir to environment variables id: set-nx-version run: | echo "NX_CACHE_DIRECTORY=$(pwd)/.nx-cache" >> $GITHUB_ENV shell: bash # nxのキャッシュをGitHubのキャッシュに登録 - name: nx cache action uses: actions/cache@v3 id: nx-cache with: path: ${{ env.NX_CACHE_DIRECTORY }} key: nx-cache-${{ runner.os }}-${{ github.sha }} restore-keys: | nx-cache-${{ runner.os }}- graph コマンドにより、プロジェクトの依存関係をビジュアライズできる コードベースの境界が明確になったとはいえ、依存関係を網羅的に確認したい時はあります。 graph サブコマンドが整備されており、プロジェクト間の依存関係を可視化することができます。そのあたりもケアしてくれている点もNxの魅力の一つです。 DBREプラットーフォームの現状 DBREプラットフォームでは現状28プロジェクトを有するMonorepoとなっています。前述の例だとプロジェクト数が少なかったため、メリットがわかりづらかったかもしれませんが、これくらいの規模になってくると affected コマンド等の恩恵を十二分に享受できています。 $ yarn workspaces list --json {"location":".","name":"dbre-platform"} {"location":"dbre-utils","name":"dbre-utils"} {"location":"projects/DBREInit/iac","name":"dbre-init-iac"} {"location":"projects/DBREInit/lambda-code/common","name":"dbre-init-lambda-code-common"} {"location":"projects/DBREInit/lambda-code/common-v2","name":"dbre-init-lambda-code-common-v2"} {"location":"projects/DBREInit/lambda-code/push-output","name":"dbre-init-lambda-code-push-output"} {"location":"projects/DBREInit/lambda-code/s3-put","name":"dbre-init-lambda-code-s3-put"} {"location":"projects/DBREInit/lambda-code/sf-check","name":"dbre-init-lambda-code-sf-check"} {"location":"projects/DBREInit/lambda-code/sf-collect","name":"dbre-init-lambda-code-sf-collect"} {"location":"projects/DBREInit/lambda-code/sf-notify","name":"dbre-init-lambda-code-sf-notify"} {"location":"projects/DBREInit/lambda-code/sf-setup","name":"dbre-init-lambda-code-sf-setup"} {"location":"projects/DBREInit/lambda-code/sf-terminate","name":"dbre-init-lambda-code-sf-terminate"} {"location":"projects/PowerPole/iac","name":"powerpole-iac"} {"location":"projects/PowerPole/lambda-code/pp","name":"powerpole-lambda-code-pp"} {"location":"projects/PowerPole/lambda-code/pp-approve","name":"powerpole-lambda-code-pp-approve"} {"location":"projects/PowerPole/lambda-code/pp-request","name":"powerpole-lambda-code-pp-request"} {"location":"projects/PowerPole/lambda-code/sf-deploy","name":"powerpole-lambda-code-sf-deploy"} {"location":"projects/PowerPole/lambda-code/sf-notify","name":"powerpole-lambda-code-sf-notify"} {"location":"projects/PowerPole/lambda-code/sf-setup","name":"powerpole-lambda-code-sf-setup"} {"location":"projects/PowerPole/lambda-code/sf-terminate","name":"powerpole-lambda-code-sf-terminate"} {"location":"projects/PowerPoleChecker/iac","name":"powerpolechecker-iac"} {"location":"projects/PowerPoleChecker/lambda-code/left-instances","name":"powerpolechecker-lambda-code-left-instances"} {"location":"projects/PowerPoleChecker/lambda-code/sli-notifier","name":"powerpolechecker-lambda-code-sli-notifier"} {"location":"projects/dbre-toolkit/docker-image/shenron-wrapper","name":"dbre-toolkit-docker-image-shenron-wrapper"} {"location":"projects/dbre-toolkit/iac","name":"dbre-toolkit-iac"} {"location":"projects/dbre-toolkit/lambda-code/dt-list-dbcluster","name":"dbre-toolkit-lambda-code-dt-list-dbcluster"} {"location":"projects/dbre-toolkit/lambda-code/dt-make-markdown","name":"dbre-toolkit-lambda-code-dt-make-markdown"} {"location":"projects/dbre-toolkit/lambda-code/utility","name":"dbre-toolkit-lambda-code-utility"} terraformでのIaCもコンポーネント単位で4つのプロジェクトに分割しています。このように気軽にプロジェクトを分割できることで、単一リポジトリでも各コードベースのサイズをスリムに保つことが可能です。 affected コマンドによりCI/CDも高速に完了するため、開発体験を下げることなく生産性を上げることができています。 $ yarn list-projects | grep iac {"location":"projects/DBREInit/iac","name":"dbre-init-iac"} {"location":"projects/PowerPole/iac","name":"powerpole-iac"} {"location":"projects/PowerPoleChecker/iac","name":"powerpolechecker-iac"} {"location":"projects/dbre-toolkit/iac","name":"dbre-toolkit-iac"} 課題 この開発アーキテクチャが完成するまでに課題になった点と、どう解決したかも紹介させていただきます。 導入で触れた様にLambdaコードのZip化が重要ポイントだったのですが、実行環境やZipのメタデータ(更新日時等)を完全に同じにしないと、コードに変更がなくてもterraformで差分が発生してしまうという課題がありました。解決策として、コードのビルド、Zip化はコンテナ内で実行し、タスク定義からはそれを呼ぶことで解決しました。 Dockerfile FROM golang:1.20-alpine RUN apk update && \ apk fetch zip && \ apk --no-cache add --allow-untrusted zip-3.0-r*.apk bash COPY ./docker-files/go-single-module-build.sh /opt/app/go-single-module-build.sh ./docker-files/go-single-module-build.sh #!/bin/bash set -eu -o pipefail while getopts "d:m:b:h" OPT; do case $OPT in d) SOURCE_ROOT_RELATIVE_PATH="$OPTARG" ;; m) MAIN_GO="$OPTARG" ;; b) BINARY_NAME="$OPTARG" ;; h) help ;; *) exit ;; esac done shift $((OPTIND - 1)) cd "/opt/mounted/$SOURCE_ROOT_RELATIVE_PATH" || exit 1 rm -f ./dist/* CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o "./dist/$BINARY_NAME" "$MAIN_GO" cd ./dist || exit 1 # for sha256 diff chown "$HOST_USER_ID":"$HOST_GROUP_ID" "$BINARY_NAME" touch --no-create -t 01010000 "$BINARY_NAME" ./*.tmpl zip "$BINARY_NAME.zip" "$BINARY_NAME" ./*.tmpl chown -R "$HOST_USER_ID":"$HOST_GROUP_ID" ../dist 他にもローカル実行が現状できていないなどの課題もあります。今後terraformに限らず、 SAM や cdk のMonorepo化もチャレンジしていきたいと思っています。 まとめ 本記事ではMonorepoツールでAWSのサーバレスの管理方法の紹介をベースに、Nxの強力な機能について紹介させていただきました。コードベースの境界が明確になったことで、プロジェクト毎に適切な開発ツールとの統合、terraformでのIaCを実現することができました。僕も、私もMonorepoしたい!と思っていただけた方は是非 プラットフォームG で一緒に働きませんか?ご拝読ありがとうございました。
アバター
はじめに こんにちは。プラットフォームGのOperationToolManagerチームでPlatformEngineeringとかツール周りの開発・運用の役割の島村です。 同じくプラットフォームGのOperationToolManagerチームで内製ツールの開発を行っている山田です。 KINTOテクノロジーズではAmazon ECS+Fargateをアプリケーション実行基盤として使用しています。また、CICDについてはGitHubActionsを使用しています。 AWSのECSにおけるBlueGreenDeploymentの仕組みは、DeploymentControllerとして「CODE_DEPLOY」が主として使用されており、「EXTERNAL(サードパーティーでの制御)」を使用している実例は少ないと思います。 CI/CD Conference 2023 by CloudNative Daysでも、BlueGreenDeploymentをするために、ECSからKuberenetesへ移動された事例もお伺いしました。 小さく始める Blue/Green Deployment とはいえ、ECSでもCodeDeployの条件に制限されないBlueGreenDeploymentができるのでは?ということと、アプリケーション開発部門にはデプロイ方式を複数提供するべきと考え、準備を開始しました。 やはり通常はCODE_DEPLOYを設定するほうが多く、EXTERNALの設定のドキュメントなども少ない状態でしたが、アプリケーション側への仕組みの提供を行うことができました。 外部のパイプラインツール+ECS(Fargate)を対象としたBlueGreenDeploymentの実装事例としてご紹介いたします。 背景 課題 ECSのローリングアップデートだけだと今後のリリースの際に要件とマッチしない可能性がある 複数のデプロイ手法を選べるようにして、アプリケーションの特性に合ったデプロイを行うべきである 解決方法 ということで、まずは第一歩として、ECSでのBlueGreenDeploymentを提供することにしました。カナリアリリースなどは今後の課題としますが、最終的にはこの形で実装できたので、流入量などをCLIで設定する形で実装できると想定しています。 設計 CODE_DEPLOYでの確認 「ECS BlueGreenDeployment」で調べれば、色々と出てきます。 が、それだけで済ますのもよろしくはないかなというので、概要などをまとめたいと思います。 このような構成です。CodeDeployに各種の設定をして、新しくTask定義に紐づいたTaskを作成、Deployment設定に則って流入を変更させていきます。一括で切り替えたり、一部だけを確認して徐々に増やすなどです。 満たせないなと思った仕様 CodeDeployでの環境と動作を確認したところ、こういった点が気になりました。設定次第かもですので、ご存じなら突っ込んでいただけると。 テスト系をある程度期間立ち上げて動作確認したい(カスタマーの確認など) 1日程度は維持できるが、その設定を経過して切り替えボタンを押さない場合デプロイに失敗する 切り替え後に任意のタイミングで古いアプリケーションを落としたい CodeDeployだと、時間制限は設定できるが任意ではなさそう 切り戻しをConsoleからだと煩雑になりそう 権限設計で、SwitchRoleをしないとConsoleから触れないので、操作がややこしくなる EXTERNALでの全体構成 コンポーネント(要素) 名称 概要 Terraform AWSなど色々なサービスをコード化する製品。IaC。社内のデザインパターンとModuleはTerraformで作成されています。 GitHubActions GitHubに包含されているCICDツール。KINTOテクノロジーズではGitHubActionsを使用してアプリケーションのビルド・リリースなどを実行しています。このGitHubActionsからパイプラインを使用して新旧アプリケーションのデプロイや切り替えを行っています。 ECS(ElasticContainerService) アプリケーション実行環境としてECSを使っています。設定上、DeploymentControllerはECS/CODE_DEPLOY/EXTERNALの設定ができますが、本件はEXTERNALでの実装例です。 DeploymentController ECSのコントロールプレーンのようなもの(と個人的には思っている)。 TaskSet ECSのサービスに紐づくTaskのまとまり。CLIからは作成できますがConsoleから作成できないようです。これを使うことで、1つのサービスに複数のタスク定義バージョンを並行で作成できます。 CLIリファレンス 。作成の際にALBやTargetGroupなどが必要で、設定する項目が多い ALB ListenerRule ALB上でTargetGroupに振り分けるルール。BlueGreenDeploymentでは、この紐づけを変更することで新旧アプリケーションの導線を切り替えます。 制限事項 ECSのDeploymentControllerは作成時のみ設定できるので、既存Serviceの変更は不可 EXTERNALの場合、プラットフォームバージョンはServiceで固定されない(TaskSetの際に指定) サービスの起動タイプがEC2に固定される。ただ、TaskSetを作成する際にFargateを指定すればタスクはFargateで起動する 実装 Terraform KINTOテクノロジーズではIaCとしてTerraformを使用しています。Module化もしていますが、そのModuleを修正した際に出た注意点などを整理します。 ListnerRule GitHubActionsでListnerRuleを書き換えてTargetGroupを変更するので、ignore_changeを設定。 ECS Service NetworkConfiguration LoadBalancer ServiceRegisteries の3つはEXTERNALの場合は設定できないため、Dynamicなどで設定をしている場合は作成しないようにする必要があります。その場合、CloudMapに登録されないので、AppMeshなどで組み合わせる場合は、考慮が必要です。BlueGreenDeploymentを設定したServiceからほかのECS ServiceへAppMeshを使った通信は問題ありません。 そもそも、BlueGreenで並行稼働していることから、CloudMapに登録されて通信可能とすると…間違えたアクセスが発生すると思うので、挙動的には正しいかなと思います。 CICD用RoleのIAMPolicy 色々とECS系以外にも権限が必要となります。サンプルとしては以下の通りです。 resource "aws_iam_policy" "cicd-bg-policy" { name = "cicd-bg_policy" path = "/" policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = [ "iam:PassRole" ] Effect = "Allow" Resource = "arn:aws:iam::{ACCOUNT}:role/{ROLE名}" }, { Action = [ "ecs:DescribeServices" ] Effect = "Allow" Resource = "arn:aws:ecs:{REGION}:{ACCOUNT}:service/{ECS_CLUSTER_NAME}/{ECS_SERVICE_NAME}" }, { Action = [ "ecs:CreateTaskSet", "ecs:DeleteTaskSet" ] Effect = "Allow" Resource = "*" conditions = [ { test : "StringLike" variable = "ecs:service" values = [ "arn:aws:ecs:{REGION}:{ACCOUNT}:service/{ECS_CLUSTER_NAME}/{ECS_SERVICE_NAME}" ] } ] }, { Action = [ "ecs:RegisterTaskDefinition", "ecs:DescribeTaskDefinition" ] Effect = "Allow" resources = ["*"] }, { Action = [ "elasticloadbalancing:ModifyRule" ] Effect = "Allow" Resource = "arn:aws:elasticloadbalancing:{REGION}:{ACCOUNT}:listener-rule/app/{ALB_NAME}/*" }, { Action = [ "elasticloadbalancing:DescribeLoadBalancers", "elasticloadbalancing:DescribeListeners", "elasticloadbalancing:DescribeRules", "elasticloadbalancing:DescribeTargetGroups" ] Effect = "Allow" Resource = "*" }, { Action = [ "ec2:DescribeSubnets", "ec2:DescribeSecurityGroups" ] Effect = "Allow" resources = ["*"] }, ] }) } ECSのクラスタや、ECSサービス名、ALB名はCICDのRoleの対象範囲などを考慮して置換・読み替えてください。 Create/DeleteTaskSetの権限は、Resourceでは絞れず、Conditionで起動するServiceを固定しています。DescribeLoadBalancers系の権限とec2:DescribeSubnet、DescribeSecurityGroupsの権限は、ワークフローの中で、状態判定を入れていますので、そのためのものです。 "elasticloadbalancing:ModifyRule"は言わずもがな、ListenerRuleを書き換えてリリースのために必要です。ListenerRuleはARNがランダム値が付与されるので、ALB名までで絞っています。 GitHubActions KINTOテクノロジーズではCICDツールとしてGitHubActionsを利用しています。 運用方法としてはプラットフォームGでCICD標準ワークフローを作成して、それをアプリ開発チームに提供して利用していただいています。 ワークフロー概要 今回のワークフローでは以下のステップに沿った形でBlueGreenDeploymentの仕組みを作成しました。今回ご紹介するのはDeployのワークフローのみとなります。 注意した点など これらのワークフローをアプリ開発チームに提供する側として以下の点に注意しました。 誤操作を発生させないように実行時のパラメータ指定は最小限にする実装 ワークフローは手動実行のため実行時に誤ったパラメータを指定しないよう、CLIで取得できるパラメータは全てワークフロー内で取得する ワークフロー設定の簡略化 シークレットを極力使わないような実装 環境変数でAWSリソース名を設定しているが、システム固有の値以外は固定値にすることでほとんど設定が不要 シークレットに利用するAWSリソースのARNを全て登録しておけば、ワークフロー内でリソース名からARNを取得する処理が不要になりコード量が減ります。 しかし、初期設定の負担をなるべく減らすためにほとんど設定不要のリソース名からCLIでARNを取得して利用する処理で実装しました。 ワークフローの実装 ここでは各ワークフローをサンプルコードを用いながら主となる処理の説明をしたいと思います。 どのワークフローも基本的には、 AWS Credentialsの取得 → CLIで必要なパラメータを取得 → バリデーションチェック → 実行 のような流れになっています。 タスクセット作成 ワークフロー実行時のパラメータは、ECRにあるイメージタグと環境です。 タスクセット作成前にテスト用としてターゲットグループが利用できるか、実行時のパラメータのイメージタグがECRに存在するか、などのバリデーションチェックを入れます。 その後、イメージタグからタスク定義を作成します。 タスク定義の作成後はタスクセット作成時に必要なパラメータ(サブネット、セキュリティグループ、タスク定義)を取得して、タスクセットを作成するCLIを実行する流れです。 jobs: ... ## 利用するターゲットグループの確認 check-available-targetGroup: ... ## ECRのイメージからタスク定義の作成 deploy-task-definition: ... ## タスクセットの作成 create-taskset: runs-on: ubuntu-latest needs: deploy-task-definition steps: # AWS Credentialsの取得 - Set AWS Credentials  ... - targetGroupの取得 ... # タスクセットの作成 - name: Create TaskSet run: | # タスク定義のARNを取得 taskDefinition=`aws ecs describe-task-definition\ --task-definition ${{ env.TASK_DEFINITION }}\ | jq -r '.taskDefinition.taskDefinitionArn'` echo $taskDefinition # サブネットの取得 subnetList=(`aws ec2 describe-subnets | jq -r '.Subnets[] | select(.Tags[]?.Value | startswith("${{ env.SUBNET_PREFIX }}")) | .SubnetId'`) if [ "$subnetList" == "" ]; then echo ※サブネットが取得できないため、処理を中断します。 exit 1 fi # セキュリティグループの取得 securityGroupArn1=`aws ec2 describe-security-groups | jq -r '.SecurityGroups[] | select(.Tags[]?.Value == "${{ env.SECURITY_GROUP_1 }}") | .GroupId'` if [ "$securityGroupArn1" == "" ]; then echo ※セキュリティグループが取得できないため、処理を中止します。 exit 1 fi securityGroupArn2=`aws ec2 describe-security-groups | jq -r '.SecurityGroups[] | select(.Tags[]?.Value == "${{ env.SECURITY_GROUP_2 }}") | .GroupId'` if [ "$securityGroupArn2" == "" ]; then echo ※セキュリティグループが取得できないため、処理を中止します。 exit 1 fi echo --------------------------------------------- echo タスクセットの作成 aws ecs create-task-set\ --cluster ${{ env.CLUSTER_NAME }}\ --service ${{ env.SERVICE_NAME }}\ --task-definition ${taskDefinition}\ --launch-type FARGATE\ --network-configuration "awsvpcConfiguration={subnets=["${subnetList[0]}","${subnetList[1]}"],securityGroups=["${securityGroupArn1}","${securityGroupArn2}"]}"\ --scale value=100,unit=PERCENT\ --load-balancers targetGroupArn="${createTaskTarget}",containerName=application,containerPort=${ env.PORT } リスナールール切り替え リスナールール切り替えのワークフローでは、まず起動中のタスクセット数を取得して確認します。 本番環境のタスクセットだけが起動している場合に(タスク数は1のとき)、本番環境とテスト環境に関連するリスナールールを切り替えてしまうと、本番環境に紐づくタスクセットがなくなってしまいます。 そのケースを避けるために起動中のタスクセット数を取得して、1つ以下のときはリスナールールを切り替えずに処理を落とす実装をしています。 その後は本番用とテスト用リスナールールの切り替えです。2つのリスナールールを切り替えるCLIがないため、切り替えと言っていますが正確にはリスナールールを変更するCLI(modify-rule)を実行しています。それぞれのリスナールール変更の処理を同時並行で実行しているため、多少の処理時間の差があった場合でも2つのリスナールールがともにテスト環境に紐づかないよう、sleepコマンドで処理タイミングを調整しています。 env: RULE_PATTERN: host-header ## http-header / host-header / path-pattern / source-ipなど PROD_PARAM: domain.com TEST_PARAM: test.domain.com ... jobs: ## 起動しているタスクセットが1つ以下の場合はホストヘッダーを変更できないようする check-taskSet-counts: runs-on: ubuntu-latest steps: ## AWS Credentialsの取得 - name: Set AWS Credentials ... # バリデーション - name: Check TaskSet Counts run: | taskSetCounts=(`aws ecs describe-services --cluster ${{ env.CLUSTER_NAME }}\ --service ${{ env.SERVICE_NAME }}\ --region ${{ env.AWS_REGION }}\ | jq -r '.services[].taskSets | length'`) if [ "$taskSetCounts" == "" ]; then echo※ 起動中のタスクセット数が取得できないため、処理を中断します。 exit 1 fi echo 起動中のタスクセット数: $taskSetCounts if [ $taskSetCounts -le 1 ]; then echo ※起動中のタスクセット数が1つ以下のため、処理を中断します。 exit 1 fi ## ALBリスナールール(本番用、テスト用)の切り替え change-listener-rule-1: runs-on: ubuntu-latest needs: check-taskSet-counts steps: ## AWS Credentialsの取得 - name: Set AWS Credentials ... - name: Change Listener Rules run: | # alb名からALBのARNを取得 albArn=`aws elbv2 describe-load-balancers --names ${{ env.ALB_NAME }} | jq -r .LoadBalancers[].LoadBalancerArn` # ALBのARNからリスナーのARNを取得 listenerArn=`aws elbv2 describe-listeners --load-balancer-arn ${albArn} | jq -r .Listeners[].ListenerArn` # リスナーのARNからリスナールールのARNを取得 listenerRuleArnList=(`aws elbv2 describe-rules --listener-arn ${listenerArn} | jq -r '.Rules[] | select(.Priority != "default") | .RuleArn'`) pattern=`aws elbv2 describe-rules --listener-arn ${listenerArn}\ | jq -r --arg listener_rule ${listenerRuleArnList[0]} '.Rules[] | select(.RuleArn == $listener_rule) | .Conditions[].Values[]'` if [ "$pattern" == "" ]; then echo ※リスナールールが取得できないため、処理を中止します。 exit 1 fi echo --------------------------------------------- echo 現在のルールパターン: $pattern echo --------------------------------------------- if [ $pattern == "${{ env.TEST_PARAM }}" ]; then aws elbv2 modify-rule --rule-arn ${listenerRuleArnList[0]} --conditions Field="${{ env.RULE_PATTERN }}",Values="${{ env.PROD_PARAM }}" else sleep 5s aws elbv2 modify-rule --rule-arn ${listenerRuleArnList[0]} --conditions Field="${{ env.RULE_PATTERN }}",Values="${{ env.TEST_PARAM }}" fi echo --------------------------------------------- echo 変更後のルールパターン aws elbv2 describe-rules --listener-arn ${listenerArn}\ | jq -r --arg listener_rule ${listenerRuleArnList[0]} '.Rules[] | select(.RuleArn == $listener_rule) | .Conditions[].Values[]' ## ALBリスナールール(本番用、テスト用)の切り替え change-listener-rule-2: ... change-listener-rule-1と同様の処理で、listenerRuleArnListの要素の指定のみ異なる ... タスクセット削除 タスクセット削除のワークフローでは、実行時のパラメータは環境のみにしています。 もし削除するタスクセットIDをパラメータに指定するような実装にすれば、ワークフローではそのタスクセットIDを削除するCLIを実行するだけなので一行で済みます(AWS Credentialsの取得などはありますが)。 しかし、もし誤って本番稼働中のタスクセットIDを指定してしまった場合、本番環境のタスクセットが消えてテスト環境のみ残る危険があります。 そのため、実行時のパラメータは環境のみにして、ワークフローの実装でテスト環境のタスクセットを取得して削除するような実装をしました。 env: TEST_PARAM: test.domain.com # テスト用のホストヘッダー ... jobs: ## タスクセットの削除 delete-taskset: runs-on: ubuntu-latest steps: ## AWS Credentialsの取得 - name: Set AWS Credentials ... # テスト用ホストヘッダーに紐づくターゲットグループを取得 - name: Get TargetGroup run: | # ALB名からALBのARNを取得 albArn=`aws elbv2 describe-load-balancers --names ${{ env.ALB_NAME }} | jq -r .LoadBalancers[].LoadBalancerArn` # ALBのARNからリスナーのARNを取得 listenerArn=`aws elbv2 describe-listeners --load-balancer-arn ${albArn} | jq -r .Listeners[].ListenerArn` # リスナーのARNとテスト用のホストヘッダーから、テスト用ルールに紐づくターゲットグループを取得 testTargetGroup=`aws elbv2 describe-rules --listener-arn ${listenerArn}\ | jq -r '.Rules[] | select(.Conditions[].Values[] == "${{ env.TEST_PARAM }}") | .Actions[].TargetGroupArn'` echo "testTargetGroup=${testTargetGroup}" >> $GITHUB_ENV # リスナールールがテスト用ホストヘッダーのターゲットグループに紐づくタスクセットIDを取得 - name: Get TaskSetId run: | taskId=`aws ecs describe-services\ --cluster ${{ env.CLUSTER_NAME }}\ --service ${{ env.SERVICE_NAME }}\ --region ${{ env.AWS_REGION }}\ | jq -r '.services[].taskSets[] | select(.loadBalancers[].targetGroupArn == "${{ env.testTargetGroup }}") | .id'` if [ "$taskId" == "" ]; then echo ※テスト用ホストヘッダーのターゲットグループに紐づくタスクセットが見つからないため、処理を中断します。 exit 1 fi echo 削除予定のタスクセットID echo $taskId echo "taskId=${taskId}" >> $GITHUB_ENV # 取得したタスクセットIDからタスクセットを削除 - name: Delete TaskSet run: | aws ecs delete-task-set --cluster ${{ env.CLUSTER_NAME }} --service ${{ env.SERVICE_NAME }} --task-set ${{ env.taskId }} 次のステップ ALBのListenerRuleの部分をブラッシュアップ、検討をしてカナリアリリースについても可能としたいが、まずは使用してもらって、フィードバックをいただくのが先ということで、アプリケーション側へ展開中です。 GithubActionsのワークフローに関しては、シークレットは極力使わない実装ができましたが、まだ環境変数の設定が多いため今後は減らしていきたいと思います。例えば、システム固有の値だけを環境変数で設定するなど。 また、リスナールールの切り替えは安全かつ瞬時にルールの切り替えはできないかなと模索中です。 所感 最初にもありましたが、ECS + EXTERNAL(GithubActions)でのBlueGreenDeploymentの実例はおそらく少なく、参考にできるドキュメントがない状態からここまで仕組みを作成しました。 振り返るとGithubActionsのワークフローでの実装自体は難しくはないと思いますが、簡単(設定が少ない)かつ安全に利用できるワークフローを目指すために工夫できた点がたくさんありました。 今後はこの仕組みを実際に利用していただき、フィードバックから改善してより良い仕組みを目指していきたいと思います。 まとめ OperationToolManagerチームは、社内向けの横断ツールを統制して必要なものを開発しています。 Platformグループの他チームが作ったものを受け入れたり、必要なものを新規作成や既存のものをマイグレーションしたりしています。 こういった活動に少しでも興味を持ったり話を聞いてみたいと思った方は、お気軽にご連絡いただければと思います。 @ card
アバター
こんにちは、KINTOテクノロジーズ プラットフォームグループ CCoE(Cloud Center of Excellence)チームの多田です。 CCoEチームは、「クラウドサービスを利用したシステム開発の積極的な推進とガバナンスによる統制を通じて、モビリティプロダクトの開発を、よりアジャイルかつセキュアにする」ことをミッションに活動しています。 KINTOテクノロジーズにおけるCCoE CCoEの活動内容 CCoEチームは、上述のミッションの元、クラウドの「活用」と「統制」を幅広く支援する組織として、多くの施策に取組んでいます。代表的なものをいくつかご紹介しておきます。 クラウドの「活用」 ナレッジ共有や人材育成を通じて、効率的な開発が継続的に支援を行う をあるべき姿とし、次のことに取組んでいます。 クラウド人材育成 KINTOテクノロジーズ独自のAWSスキルマップを利用した勉強会や教育コンテンツを整備し、エンジニアスキルをレベルアップする クラウドの「統制」 グループ会社セキュリティポリシーに準拠したクラウド環境を提供し、常にセキュアな状態を維持するための支援を行う をあるべき姿として、次のことに取組んでいます。 クラウドセキュリティガイドライン セキュリティポリシー準拠のためのIaC開発とセキュリティツールを整備する セキュリティプリセットクラウド環境 上記セキュリティガイドラインに則った設定済みのクラウド環境を提供する 我々の活動内容を簡単な絵にすると次のような形になります。 クラウドセキュリティガイドラインを中心として、その内容を事前設定したクラウド環境を提供し、開発グループに利活用してもらう。このクラウド環境をセキュアに維持するために、SIEM(Security Information and Event Management)やCSPM(Cloud Security Posture Management)でモニタリングを行っています。また、セキュリティガイドラインを人材育成や情報共有サイト等にも利活用する。といった活動を行っています。 セキュリティについては、日々情報がアップデートされますし、クラウドサービスも常に進化していきます。そのため、それらに追随するために、ガイドラインを中心とした持続的な活動を目指しています。 ここからは、現在、クラウドの「統制」で進めている、「セキュリティプリセットクラウド環境(Google Cloud)」について紹介していきます。 セキュリティプリセットクラウド環境(Google Cloud)の取組み セキュリティプリセットクラウド環境(Google Cloud)とは セキュリティプリセットクラウド環境は、アジリティとセキュリティの両輪を実現し、アジャイルな開発を促進することを目的として開発しています。 開発グループがクラウド環境を自由に利活用できる 企業として、最低限望ましくない利用を制限 では、具体的にどのようなセキュリティを設定しているか、ということですが、ベースとなるセキュリティ基準は以下の2つとなります。 CIS Benchmark グループ会社のセキュリティルール さらに、これらをどこに設定しているのか、ということですが、こちらは、以下の3箇所で設定しています。 組織ポリシー プロジェクト(作成時に設定) CSPM(Cloud Security Posture Management) 以降で、それぞれの箇所にどうようなセキュリティ設定を実装しているか具体的に説明していきます。 組織ポリシーで設定したセキュリティは何か 組織ポリシー は、最低限望ましくない操作を制限するために利用します。これは、予防的ガードレールと呼ばれる考えかたと同様です。 予防的ガードレールは、システムやプロセスにおいて、予防的な制約や制限を設けることで、望ましくない行動やリスクを事前に防止する仕組みやルールの総称で、人為的なミスや意図しない行動によるセキュリティ上の問題やコンプライアンス違反を最小限に抑えることができます。 セキュリティプリセットクラウド環境では、あまり厳しい制限にならないように、本当に最低限実施してほしくない操作に絞って制限するようにしています。最低限の基準として、上述の2つのセキュリティ基準をベースにしています。実際に設定しているいくつかの、組織ポリシーを紹介します。 組織ポリシー 説明 constraints/gcp.resourceLocations リソースを作成できるロケーションを制限。asiaなどのマルチリージョンを設定 constraints/sql.restrictPublicIp Cloud SQLインスタンスへのパブリックアクセスを制限 constraints/storage.publicAccessPrevention Cloud Storageのデータのパブリック公開を制限 constraints/compute.skipDefaultNetworkCreation リソースの作成時にデフォルトネットワークと関連リソースの作成を制限 constraints/iam.disableAuditLoggingExemption 監査ログからプリンシパル除外設定を制限 これらの組織ポリシーを組織全体に設定し、フォルダ配下やプロジェクトにも同様のポリシーを継承しています。万一、プロジェクト側で、これらのポリシーが許容できない場合は、プロジェクト固有でポリシーをオーバーライドする運用となっています。 プロジェクト作成時に設定したセキュリティは何か 組織ポリシーで設定できないが、予防的ガードレールとして設定したいルールについては、プロジェクト作成時に設定しています。 例えば、 CIS Benchmark には、「2. Logging and Monitoring」「2.13 Ensure Cloud Asset Inventory Is Enabled」というルールがあり、Cloud Asset Inventoryの有効化をプロジェクト作成時に自動化して実施しています。 その他、プロジェクト作成時に設定している CIS Benchmark のルールを紹介します。 項目 タイトル 説明 2.4 Ensure Log Metric Filter and Alerts Exist for Project Ownership Assignments/Changes プロジェクトオーナーの割当を監視しアラートを通知する 2.5 Ensure That the Log Metric Filter and Alerts Exist for Audit Configuration Changes 監査設定の変更を監視しアラート通知する 2.6 Ensure That the Log Metric Filter and Alerts Exist for Custom Role Changes プロジェクトオーナー、組織ロール管理者、IAMロール管理者はカスタムロールを作成できる。カスタムロールの作成は過剰な特権を持つ可能性があるため監視しアラート通知する 2.7 Ensure That the Log Metric Filter and Alerts Exist for VPC Network Firewall Rule Changes ファイアウォールルールの作成または更新を監視しアラート通知する 2.8 Ensure That the Log Metric Filter and Alerts Exist for VPC Network Route Changes VPCネットワークのルート変更を監視しアラート通知する 2.9 Ensure That the Log Metric Filter and Alerts Exist for VPC Network Changes VPCネットワークの変更を監視しアラート通知する 2.10 Ensure That the Log Metric Filter and Alerts Exist for Cloud Storage IAM Permission Changes Cloud StorageのIAM権限変更を監視しアラート通知する 2.11 Ensure That the Log Metric Filter and Alerts Exist for SQL Instance Configuration Changes SQLインスタンスの設定変更を監視しアラート通知する また、プロジェクト作成時ではないですが、以下の CIS Benchmark のルールを組織全体に設定としています。 項目 タイトル 説明 2.1 Ensure That Cloud Audit Logging Is Configured Properly すべてのアクティビティ、ユーザデータへの読み取り、書き込みアクセスを追跡するために監査ログを設定する CSPMで設定したセキュリティは何か CSPM(Cloud Security Posture Management)で実現したセキュリティを説明します。CSPMでは 組織ポリシー でも、プロジェクト作成時にも設定できない、リスクのある操作についての検知・通知を実現するために利用しています。 これは、発見的ガードレールという考え方に一致します。 発見的ガードレールは、システムやプロセスにおいて異常な活動やセキュリティ上のリスクを検出し、早期に発見するための仕組みやルールであり、インシデントや異常な活動の発見・分析に重点を置きます。予防的ガードレールと発見的ガードレールは相補的な役割を果たすものです。 セキュリティプリセットクラウド環境では、発見的ガードレールの考え方のもと、CSPM製品を使ったリスクの検知・通知を実現しているのですが、CSPM製品の選定に少し紆余曲折がありました。 採用したCSPM製品は何か CSPM(Cloud Security Posture Management)は、クラウド環境における、クラウドリソースのセキュリティ設定や構成を監視し、ベストプラクティスに基づいたポリシーやガイドラインに準拠しているかどうかを評価・管理するためのツールです。 Google Cloudでは、 Security Command Center と呼ばれるサービスがあり、StandardとPremiumの2つのティアが存在します。 Standard Premium Security Health Analytics (重大な構成ミスの特定を含む) ○ ○ Security Health Analytics (PCI,CIS,コンプライアンスレポート等) X ○ Web Security Scanner X ○ Event Threat Detection X ○ Container Threat Detection X ○ Virtual Machine Threat Detection X ○ Rapid Vulnerability Detection X ○ 費用 無料 サブスクリプション 我々としては、 CIS Benchmark 等を基準に「発見的ガードレール」を実現したいと考えていたため、要件的には、Premiumの利用となるのですが、費用的には高価で、現在のGoogle Cloudの利用規模でいうと割にあいません。 では、CSPM製品をどうしたかというと、以下の観点でいくつの製品をピックアップし、机上調査とPoCを実施しました。 CIS Benchmark 等のコンプライアンス基準が利用できる 独自ルールも実装できる 安価である(Security Command Center Premiumの費用と比べて) 主な製品と評価コメントは次のとおりです。 Forseti Security(Open-source security tools for GCP) Google Cloudリソースのインベントリ情報を収集して、定期的に監査ルールをチェックする。監査ルールは、「IAMポリシー」、「バケットACL」、「BigQueryデータセットのACL」、「Cloud SQLネットワーク」等であり、CIS等のコンプライアンス基準が利用できない Cloud Custodian(OSS) CIS等のコンプライアンス基準のデフォルトルールセットがないため、各ルールを0から実装する必要がある サードパーティ製品(S社) CIS等のコンプライアンス基準がデフォルトで準備されており、独自ルールも Rego で実装することができる。SaaS製品であるが価格も非常に安価でマーケットプレイスから購入もできる これらの調査結果をもとに、サードパーティ製品(S社)を採用することに決めました。Cloud Custodianと迷いましたが、製品のインテグレーションやルール実装のスピード感を優先し決定しています。この製品を具体的にどのように利用しているかは、また別の機会にブログにしようと思いますが、CSPM製品を導入し、 CIS Benchmark 等を基準にリスクのある操作を検知・通知し、改善を行うことでセキュアな状態を維持することに努めています。 :::message 実は、今年の2月ごろに、Security Command Center Premiumは組織単位ではなく、プロジェクト単位でも有効化できるようになり、費用的にも使いやすくなりました。Premiumでは、CSPM以外にも多くの機能があるので、今後は、サードパーティ製品とうまく使い分けることを検討していきたいと思います。 ::: プロジェクトのIAM権限はどうしているか もう一つ重要なことがあります。それは、開発グループに払い出すプロジェクトのIAM権限をどうするかという問題です。結論からいうと、利用者には「編集者」権限を付与しています。 もちろん、「編集者」権限を付与することは、バッドプラクティスであることは理解しているのですが、開発グループ側の利便性とセキュリティをトレードオフし、まずは、この権限でスタートしています。その代わり、 Policy Intelligenceツール の運用を徹底し、最小権限の原則に近づけるような運用をしていくこととしています。このあたりも別の機会にブログにしたいと思います。 まとめ セキュリティプリセットクラウド環境についてまとめると、以下となります。 開発グループが自由に利活用でき、かつ、最低限の望ましくない操作が制限されているクラウド環境を実現 実現には、「予防的ガードレール」と「発見的ガードレール」の考え方を採用 予防的ガードレールは 組織ポリシー 、発見的ガードレールは、CSPM製品を利用することで実現 IAM権限は、最小権限の原則に近づける運用を Policy Intelligenceツール で徹底 今後のCCoE活動 最後に今後のCCoE活動についてふれておきます。 今回は、Google Cloudのセキュリティプリセット環境を紹介しましたが、AWSについても同様のコンセプトでセキュリティプリセット環境を準備しています。さらにセキュリティプリセット環境をセキュアに維持するため、セキュリティのモニタリングサービス/ツールを充実させようと考えています。今回は、CSPMについて少し紹介しましたが、CSPM以外のCNAPP(Cloud Native Applicaiton Protection Platform)とよばれる領域のツールについても整備を進めようとしています。また、最近、少しずつ耳にするようになった、X.1060フレームワークを使って、セキュリティ対応組織力の継続的な向上にも着手していく予定です。機会があれば、この辺りも紹介できればと思います。 ここまで読んでいいただきありがとうございました。
アバター
AstroでSvelte使ってみた こんにちは(こんばんは)、Svelte不定期連載その4です。 過去の記事はこちら SvelteKit + Svelte を1年間くらい使ってみた知見など※SvelteKit メジャーリリース対応済み Svelteと他JSフレームワークとの比較 - Svelte不定期連載-01 Svelteでユニットテスト - Svelte不定期連載-02 SvelteでStorybookを使ってみる - Svelte不定期連載-03 今回はAstroでSvelte使ってみたの回です。 今回はSvelte連載ではあるものの、少し毛色を変えてみます。 巷を騒がせているAstroというフレームワークをご存知でしょうか。 デフォルトでクライアントサイドのJavaScriptを一切使用せずにウェブサイトを構築する、といったフレームワークです。デフォルトではJavaScriptを読み込ませずに、コンポーネントに明示的な指定をすることでJavaScriptが読み込まれます。Astroではアイランドというネーミングで親しまれています。また公式にもある通り、色々なフレームワークをAstroにマウントして使用することが出来ます(!) https://astro.build/ Astroの特徴を掻い摘んでみます。 ゼロJavaScript マルチページアプリケーション(MPA) 様々なUIフレームワークをAstro上にインテグレーションできる 今回はAstro上でSvelteを動かしてみましょう。propsやバインディングなど色々試してみようと思います。 環境用意 AstroにSvelteコンポーネントをimport AstroとSvelteでpropsしてみる AstroとSvleteバインディングで行う 環境用意 AstroとSvelteをインストールしてみる yarn create astro astro-svelte Astroのcliを用いて astro-svelteディレクトリにAstroをインストールします。 これでAstroを動かす用意は出来ましたが、これだけではSvelteを使えません。 次にAstro上でSvelteを動かせるようにSvelteとAstro用のSvelteモジュールをインストールしましょう。 yarn add @astrojs/svelte svelte Astro + Svelteを動かすモジュールが揃いましたので、AstroのConfigファイルであるastro.config.mjsにSvelteを使う旨を書きます。これでAstro上でSvelteを動かす準備ができました。 CLIのおかげでとても手順が少なくてEASYです。 import { defineConfig } from 'astro/config'; // ここを追加 import svelte from '@astrojs/svelte'; // https://astro.build/config export default defineConfig({  // ここを追加 integrations: [svelte()], }); 用意出来たので実際にAstro上でSvelteを動かしてみましょう。 AstroにSvelteコンポーネントをimport <script> let text = 'Svelte' </script> <p>{text}</p> まずは子となるSvelteコンポーネントを作りました。 タグの中にSvelteという文字列が挿入されるコンポーネントです。 では次にAstroの親コンポーネントにSvelteコンポーネントをimportします。 --- import Sample from '../components/Sample.svelte' --- <Sample /> 表示されましたね、とても簡単。というかすごいですね…! AstroはMPAなのでルーティングだけAstroに任せてコンポーネントはSvelteみたいな使い方も出来そうです。 AstroとSvelteでpropsしてみる 先程のSvelteコンポーネントの値をexportします。 <script> export let text = '' </script> <p>{text}</p> Astro側で文字列を挿入します。 --- import Sample from '../components/Sample.svelte' --- <Sample text="Svelte" /> 同じようにSvelteという文字列が表示されました。 では、逆にSvelteを親としてPropsはできるのでしょうか。試してみます。 Astroの子コンポーネントを定義して… --- export interface Props { astrotext: '' } const {astrotext} = Astro.props --- <p>{astrotext}</p> Svelteのコンポーネントで読み込む! src/components/Sample.svelte <script> import Child from './Child.astro' export let text = '' </script> <p>{text}</p> <Child astrotext="Svlete" /> NGでした。 どうやら親はAstroである必要ありそうです。 では親も子もSvelteの場合はどうでしょう。 まずSvelteの子コンポーネントを作ります。 <script> export let svelteChild = '' </script> <p>{svelteChild}</p> それをSvelteの親コンポーネントで定義…! <script> import SvelteChild from "./SvelteChild.svelte"; export let text = '' </script> <p>{text}</p> <SvelteChild svelteChild="SvelteChild" /> 無事に表示されました! 当たり前といっちゃあたりまえなのですがSvelte to Svelteはいけるようです。 またpage配下のファイルも*.astroファイルである必要がありそうです。 NGケース src/pages/+page.svelte src/pages/index.svelte 異なるUIフレームワーク拡張子のファイルをimportするには、*.astroが親である必要があることが判明しました。 SvleteのバインディングをAstroで行う 最後にバインディングを行ってみます。 Svelteでバインディングします。 <script> export let text = '' let name = ''; </script> <input bind:value={name}> <p>{name}</p> <p>{text}</p> nameという文字列部分がバインディングされていく想定です。 src/page/index.astroは変わらないので画面を見てみます。 入力しても反映されません・・・。 Astroでは、一部のクライアントサイド特有の機能(例えばこのようなインプットフィールドへのユーザー入力)はデフォルトでは機能しません。 これらの機能を利用したい場合は、import しているComponentに対してAstroのclient:loadディレクティブを使用することでバインディングが可能になります。 --- import Sample from '../components/Sample.svelte' --- <Sample text="Svelte" client:load /> 無事に動きました。 clientディレクティブも:loadだけではないので色々試してみると面白いかもです。 https://docs.astro.build/ja/reference/directives-reference/#client-directives まとめ 本当に動くの・・・?みたいな半信半疑で始めましたがAstro x UIフレームワーク プロダクトで使えそうなくらいの実用性がありますね。 コーポレートサイトなどは特にAstro使いやすそうです、ここでは触れてませんがsitemap周りの機能も強力です。 以上、AstroでSvelte使ってみたでした。 次は連載最後、Svelteの実用的なTipsです(経験則)。
アバター
はじめに こんにちは、KINTOテクノロジーズで、決済プラットフォームの開発チームに所属している西田です。 今回は、以前 こちら でも紹介した社内向けの決済に関する業務システムのバックエンドを AWS SAM で構築したお話をしたいと思います。 AWS SAM とは まずはじめに AWS SAM(Serverless Application Model)とは、Lambda や API Gateway などのサーバーレスなサービスを簡単に構築・デプロイができるツールです。AWS SAM を利用することで、我々開発者がインフラに対しての知識を深く持つ必要がなくなり、サーバーレスアーキテクチャを利用したアプリケーション開発部分に集中することができます。 AWS SAM を採用したきっかけ KINTOテクノロジーズへ入社してすぐに決済に関する業務システムの開発に参画、開発期間は2~3ヶ月程度であったこともあり、バックエンド側の技術選定では素早く開発できる技術の選定が求められました。 社内向けのシステムであったため、アクセス数が限定である点と前職では AWS SAM を利用して環境構築していた経験を活かして AWS SAM を利用して開発を進めることにしました。 AWS SAM の使い方 AWS SAM を利用して、REST API を APIGateway と Lambda を使ったサーバーレス構成で構築してみたいと思います。 ディレクトリ構成はこちらです。 . ├── hello_world │ ├── __init__.py │ └── app.py └── template.yaml はじめに AWS SAM を公式の ドキュメント からインストールします AWS SAM では template というファイルを利用して、AWS のリソースの管理を行います。 AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > sam-app Sample SAM Template for sam-app Resources: HelloWorldFunction: Type: AWS::Serverless::Function Properties: FunctionName: HelloWorldFunction CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.9 Events: HelloWorld: Type: Api Properties: Path: /hello Method: get import json def lambda_handler(event, context): body = { "message": "hello world", } response = { "statusCode": 200, "body": json.dumps(body) } return response SAM コマンドを使ってデプロイをします。 今回は --guided を使って対話形式でデプロイしてみます。 sam deploy --guided スタック名やリージョンなどを入力していきます。 Stack Name [sam-app]: # デプロイするスタック名を入力 AWS Region [ap-northeast-1]: # デプロイするリージョンを入力 #Shows you resources changes to be deployed and require a 'Y' to initiate deploy Confirm changes before deploy [y/N]: # 変更内容を確認するかを入力 #SAM needs permission to be able to create roles to connect to the resources in your template Allow SAM CLI IAM role creation [Y/n]: # SAM CLI が IAM ロールを作成するかを入力 #Preserves the state of previously provisioned resources when an operation fails Disable rollback [y/N]: # ロールバックを無効にするかを入力 HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: # Lambda に対する認可を設定するかを入力 Save arguments to configuration file [Y/n]: # 設定を保存するかを入力 SAM configuration file [samconfig.toml]: # 設定ファイルの名前を入力 SAM configuration environment [default]: # 環境名を入力 デプロイが完了したら、Lambda のコンソールから HelloWorldFunction が作成されていることを確認します。 Lambda のトリガーになっている API Gateway を選択することでエンドポイントが確認できます。 curl でリクエストを送ってみます curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello リクエストが成功すると以下のようなレスポンスが返ってきます {"message": "hello world"} 導入してみて 過去に AWS SAM を利用していたこともあり、基盤的な構築自体は当日である程度形にできるくらいにスムーズに行え、目標としていた計画通りに開発を進めることができました。 慣れてくるとサーバーレス構成で API を簡単に作れるところが良いところだと改めて感じました。 また、APIGateway や Lambda だけでなくバッチ処理といった定期処理で利用される EventBridge や SQS も AWS SAM で構築していたりします。 公式のドキュメントも整備されてきているので、利用する上でのハードルも下がっているように思います。 まとめ 今回は、決済に関する業務システムのバックエンドを AWS SAM でゼロから素早く構築したお話をしました。 AWS が提供しているツールでもあるので親和性が高く、環境の構築負荷を下げ、より実装部分に集中できる良いツールだと思いますので、ご興味ある方はぜひ触ってみてください。
アバター
はじめに KINTOテクノロジーズでプロトタイピングエンジニアをしている木下です。 本ブログにて、アジャイルについての連載記事を発信しようという動きがあり、その前振りとしてScrum Inc.認定スクラムマスター資格の更新についてまとめます。 認定スクラムマスター資格の取得やセミナー内容については、 前回の記事 でまとめてありますので、ご興味あればご一読ください。 また前回の記事時点では、ライセンス名が「LSM:Licensed Scrum Master」という名称だったのですが、 2022年7月29日に「RSM:Registered Scrum Master」に名称が変更 されました。 取得したライセンスは自動で名称を更新していたみたいで、自分のライセンスもRSM(Registered Scrum Master)になっていましたので、併せて過去記事に名称の変更を入れました。 更新について 前回ライセンスを取得して1年を過ぎて、保持していた有効期限が近づくと更新しないと無効になるというメールが届きます。 ただ自分はメールに気づかず、前回のセミナーを一緒に受けた同僚に教えてもらうまで更新期限が来ていることを知りませんでした。 更新するかどうかを判断する期間として、60日間の猶予があります。 更新する場合は、 会員向けのサイト に行き更新費用を支払って、更新資格試験のロックを外す必要があります。 更新は1年毎で50ドルが必要という理解でいたのですが、どうやら5年プランと生涯有効プランがありました。 今回は割引が効いているようで、 5年プランが250ドルから199ドル へ、 生涯プランは500ドルから399ドル になる表示がされていました。 KINTOテクノロジーズにはセミナー補助はありますが資格補助は無いため、今回の更新費用は自費となります。 割引が効いているとはいえ円安で「1ドル:138円(支払時)」のため、それぞれの換算は 「199ドル:約27,500円」 と 「399ドル:約55,000円」 になります。 ドルだと金銭感覚があまり分からなかったのですが、円換算したらお財布と心への痛みを大変深く感じました。 なぜ更新したのか 学んだスクラム知識を活かす場面も少なかったことや自費でもあるため、正直に更新する気は全然ありませんでした。 ステークホルダーにアジャイルの理解や抵抗を払拭させることの難しさや、チーム・グループが大きいことに加え、アジャイルやスクラムをやりたい人ばかりではないこともあり、そもそもが難しいなと感じていました。 そのため、周りを巻き込んだり、少しづつでも空気を作っていくための仲間を見つけて行く活動が大切で、様々な面でライセンスの有無よりも何よりも「やるぞ!!」っという思い・マインドが大事だとを強く思いました。 意識が変わったのは、今回の記事を書いたのもそうですが、社内での繋がりが広がったり、接したことない人とスクラムマスターについて何度か話す機会を持ちました。 その中の一つに、アジャイルへ大変な熱量を持つ きんちゃん が入社して早々に行動してくれたおかげで、開くことができた座談会で他のチームと話すことがありました。 話を聞いてみて、自分の中で閉じていたのではと反省したり、似た悩みにどう解決できるのかと気持ちが少し戻ってきていました。 今後も持っていることで輪が広がること、輪が広がれば少なかった活かす場面も増やすことができるのではとの思いから更新することを少し意識しました。 くしくも近いタイミングで、前回の記事を読んで声を掛けてきた社内の同僚が、更新費用を知り背中を強く押してきたことは大変大きな要因になりました。 どうせ受けるなら思考と背中を押されたことから生涯有効プランを選択しました。 本意と不本意が合わさり複雑な心境であったのと試験中もお財布の痛さに頭がいっぱいでしたが、無事に試験に合格できました。 この心とお財布に負った傷を少しでも癒すべく、会社に置いてあった誰かのお土産を1つもらい、5万5千円のお菓子だと思って味わって食べました。 前回のセミナーを一緒に受けた同僚も更新したのですが、年間更新を受けたようで試験を受けてみたら、けっこう忘れてることも多く、振り返る意味でも年に1回の更新試験は受けて良かったと言っていました。 更新試験について 更新試験の挑戦の回数は1回だけではなく、前回のセミナー受講後の試験と同様に2回まで受けるチャンスがありました。 問題を説いた後は、点数と回答の正誤が表示されるので、どこを間違えたのかは確認できます。 出題される問題の内容・難しさに関しては、昨年のセミナーの受講後に受けた問題と同じレベルに感じました。 合格するとメールが届くのと証明書の右下あたりにある公式マークの下に有効期限が記載されているのですが、そこが「Valid Until Lifetime」に変わります。 これで生涯認定スクラムマスターになり、今後は更新試験を受ける必要は無くなりました。 有効期限が切れるごとに更新するかどうか気にしなくて良くなりました。 終わりに・宣伝 前回のセミナーを受けてから1年が過ぎ、ライセンスの更新を問われる時期になりました。 この1年でライセンスを保持するほど活きることがあったのかと言われると個人的にはあまり無く感じていましたが、人との繋がるきっかけという当初思っていたこととは違う形で活きることに価値を感じて更新をしました。 KINTOテクノロジーズでは、座談会をしたチーム以外にも多くのチームやプロジェクト・プロダクトで、アジャイルやスクラムを行ったり、取り組もうと挑戦しています。 これらについては、 アジャイルへ大変な熱量を持つきんちゃん が冒頭にお話したアジャイルの連載記事で発信します。 きんちゃんは開発の枠にとらわれず広い視野でアジャイルを俯瞰しており、実際に社内でも熱い行動を何度も起こしています。 個人的に様々な見方での内容を書かれてるのではないかと期待しています。 それでは連載記事の公開を楽しみお待ちください。
アバター
こんにちは(こんばんは)、Svelte不定期連載その3です。 過去の記事はこちら SvelteKit + Svelte を1年間くらい使ってみた知見など※SvelteKit メジャーリリース対応済み Svelteと他JSフレームワークとの比較 - Svelte不定期連載-01 Svelteでユニットテスト - Svelte不定期連載-02 今回はSvelteとStorybookを使ってみようの回です。 Storybookとは UIであるコンポーネントを管理・運用しやすくするためのツール、だと認識していますが、様々な機能を内包していたりします。 https://storybook.js.org/ 今回やること 今回は以下の3つを行ってみます。 実際のプロジェクトに導入 Storybookにコンポーネントを登録 Storybook上のテストを実行 ではやっていきましょう。 実際のプロジェクトに導入 今回は0からではなく実際のプロジェクトにStorybookを入れてみようと思います。 導入するプロジェクト URL https://noruwaaaaaaaay.kinto-jp.com/ SvelteKit + microCMS + [S3 + Cloudfront] の構成で作られているプロジェクトです。 面白いコンテンツが揃っているので是非みてみてください! おすすめ記事 https://noruwaaaaaaaay.kinto-jp.com/post/93m02vm8chf3/ https://noruwaaaaaaaay.kinto-jp.com/post/fe35u405761/ 導入手順 npx storybook@latest init こちらのコマンドをプロジェクトがあるディレクトリで実行します。 これだけで、プロジェクト内にStorybookの初期構築が完成します。 .storybook というディレクトリとsrc配下に stories というディレクトリが作られました。 これで初期構築は終わりです。 Storybookにコンポーネントを登録 Storybookを動かしてみる Storybookを立ち上げてみます。 yarn storybook を実行します。 このような画面が立ち上がりますね。 src/stories/ 配下にあるコンポーネントや **.stories.ts などはプロジェクト内では使ってないファイルのため、 一度stories配下にあるファイルを全て消して、 Button.stroies.ts を改めて配置し、実際にのるウェイで使っているコンポーネントをStorybookに登録してみます。 Storybookにコンポーネントを登録してみる 実際にプロジェクト内でコンポーネント化されているボタンのビジュアルとコードがこちらです。 <script lang="ts"> export let button: { to: string; text: string }; </script> <div class="button-item"> <a href={button.to} class="link-block" > <span class="link-block-text">{button.text}</span> </a> </div> 実際にStorybookへ上記のボタンコンポーネントを登録してみましょう。 import type { Meta, StoryObj } from '@storybook/svelte'; // ボタンコンポーネントを登録 import Button from '$lib/components/Button.svelte' const meta: Meta<Button> = { title: 'Example/Button', component: Button, tags: ['autodocs'], }; export default meta; type Story = StoryObj<Button>; export const Primary: Story = { // ボタンコンポーネントのexport letになっているオブジェクトを登録 args: { button: { to: '', text: '' } }, }; このような画面に更新されました。 では実際にstorybookの画面上でテキストの差し替えなどしてみます。 実際に変わることが確認出来ました。 本当に最小限ではありますが、これだけでボタンコンポーネントの配置が終わりました。 Storybookでテストをしてみる storiesを追加したコンポーネントに対して実際のstoriesファイルが破損していないかのテストを簡単にしてみます。 導入手順 まずテストに必要なモジュールをインストールします。 yarn add --dev @storybook/test-runner storybook上のテストを実行 実際にテストをしてみます。 yarn test-storybook を実行すると、 テストがパスされるとこのような出力に。 どの部分で失敗したかにもよりますがテストに失敗すると以下のように こちらでストーリーブックが破損していないかのテストが行えました。 たくさんのオプションも用意されているのでもっと詳しく知りたい方は下記をご覧ください。 https://storybook.js.org/docs/svelte/writing-tests/test-runner おわり インストールから、コンポーネントに対してのストーリーの追加、そしてStorybookが破損していないかのテストまでが、簡単に行うことが出来ました。 余談ではありますが、HTMLオンリーのプロジェクトにStorybookを追加しようとしてとても大変だったことがあるので、今回やってみて非常に簡単にできたので良い時代になったな、と感じました。 以上、SvelteでStorybookを使ってみようの会でした。 次回は少し毛色を変えて、 Astro上でSvelteを動かしてみよう です。 次回もお楽しみに!
アバター
1. はじめに こんにちは。共通サービス開発グループ[^1][^2][^3]で複数のサービスが利用する決済プラットフォームの開発チームに所属している鳥居です。 前回の記事 ^4 では、Visual Studio Code(以下 VS Code)の Dev Container を活用し、快適な開発環境を構築する方法を紹介しました。Dev Container は非常に便利である一方、ローカルマシンのリソースを利用するため、パフォーマンスがマシンスペックに依存するという課題がありました。特に Mac での使用では、ファイルシステム間の相互作用が原因で遅延が生じる場合がありました。 今回の記事では、私たちのチームでも実際に活用している Dev Container による開発環境構築をさらに進化させた GitHub Codespaces について解説します。GitHub Codespaces を利用することで、クラウドベースの開発環境を手軽かつ効率的に構築する方法をご紹介します。 2. GitHub Codespaces の概要 GitHub Codespaces は、クラウド上で完全な開発環境を提供するサービスで、VS Code、VS Code Web、IntelliJ、JupyterLab などの主要な開発ツールをサポートしています。これらのツールは Windows、Mac、そして Linux のすべての主要なプラットフォームで使用することができます。これにより、開発者は自分の好みに応じた環境で開発作業を行うことができます。さらに、VS Code Web を使用する場合は、ブラウザがある場所ならどこでも開発環境にアクセスし、ローカルマシンとクラウド間での作業をシームレスに行うことが可能です。 3. GitHub Codespaces の具体的な活用シーン GitHub Codespaces は、以下のようなシーンで活用することができます。 3.1 プロジェクトのクロスプラットフォーム開発 クラウドベースの開発環境であるため、GitHub Codespaces は開発者のデバイスや OS に依存しないのが特長です。これにより、各種環境における開発環境の構築や設定を一から行う手間が省かれます。開発者は自分の好きな OS を利用しつつ、他の全ての人と同等の開発環境を享受できます。 3.2 教育やワークショップでの使用 開発環境のセットアップが容易であるため、教育やワークショップなどの場では GitHub Codespaces が特に有用です。参加者は環境設定に時間を取られることなく、学習や実践に専念することが可能となります。 3.3 プルリクエストのレビュー GitHub Codespaces は、GitHub と深く連携しているため、プルリクエストを直接開くことが可能です。これにより、現在作業しているブランチから切り替えることなく、プルリクエストのレビューをスムーズかつ迅速に行うことができます。 4. GitHub Codespaces のセットアップ手順 GitHub Codespaces を構築するには、Dev Container と同様に、 .devcontainer ディレクトリ内に設定ファイルを作成する必要があります。以下では、GitHub Codespaces のセットアップ手順を紹介します。 4.1 前提環境 GitHub アカウント 対象のリポジトリ 4.2 Dev Container の構築手順 対象のリポジトリに .devcontainer ディレクトリを作成します。 .devcontainer ディレクトリ内に Dockerfile 、 docker-compose.yml 、および .devcontainer.json を作成し、それぞれの設定ファイルに適切な内容を記述します(次章の 設定ファイルのサンプル を参考にしてください)。 設定ファイルをリポジトリにコミットし、プッシュします。 GitHub リポジトリにアクセスし、リポジトリページの右上にある緑色の "Code" ボタンをクリックします。 ドロップダウンメニューから "Codespaces"タブ を選択します。 新しい Codespace を作成するか、既存の Codespace を選択して開くことができます。 今回は初回なので、"Create new codespace on main"を選択します。 オプションとして、リモートマシンのスペックやリージョンを指定できます。 三点リーダーから "New with options..." を選択します。 Codespaces の起動画面に遷移し、準備が整うまで数分かかります。準備が整ったら、ブラウザ上で Visual Studio Code のインターフェイスが表示されます。 これで、Codespaces が起動し、リポジトリのコードを編集できるようになりました。また、ターミナルも利用可能で、開発環境にインストールされているツールを使用できます。 5. 設定ファイルのサンプル 5.1 .devcontainer.json のサンプル .devcontainer.json は、Dev Container や Codespaces の設定を記述するためのファイルです。このファイルでは、開発環境の構築、使用する拡張機能、設定などを定義します。 docker-from-docker は開発環境から Docker を利用するための設定項目です。この設定を追加することで、Dev Container 内からホストマシンの Docker を利用することが可能になります。この設定を追加しない場合、Dev Container 内から Docker を利用することはできません。 ghcr.io/devcontainers/features/sshd [^5]は、JetBrains Gateway Codespaces 用の設定項目です。JetBrains Gateway Codespaces は、JetBrains IDE で GitHub Codespaces を利用するための機能です。この設定を追加することで、JetBrains IDE から GitHub Codespaces へのアクセスが可能になります。 { "name": "sample-app", "build": { "dockerfile": "Dockerfile" }, "service": "devcontainer", "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", "postCreateCommand": "sh .devcontainer/post-create.sh", "features": { "ghcr.io/devcontainers/features/go:1": { "version": "latest" }, // ホストマシンのDockerを利用するための設定 "docker-from-docker": { "version": "latest" }, // Jetbrains Gateway Codespaces用 "ghcr.io/devcontainers/features/sshd:1": { "version": "latest" } }, "settings": { "editor.guides.bracketPairs": true, "editor.stickyScroll.enabled": true, "editor.stickyScroll.maxLineCount": 5, "workbench.colorCustomizations": { "editorStickyScroll.background": "#00708D", "editorStickyScrollHover.background": "#59A2B5" }, "editor.formatOnSave": true, "[go]": { "editor.formatOnSave": true, "editor.defaultFormatter": "golang.go" }, "go.formatTool": "gofmt" }, "extensions": [ "golang.go", "GitHub.vscode-pull-request-github", "GitHub.copilot" ] } 5.2 Dockerfile のサンプル devcontainer や Codespaces の Docker コンテナを構築する際に使用する Dockerfile です。 ARG VARIANT="jammy" FROM mcr.microsoft.com/vscode/devcontainers/base:1-${VARIANT} 5.3 .devcontainer/docker-compose.yml のサンプル devcontainer や Codespaces のコンテナを構築・実行するための docker-compose ファイルです。このファイルでは、開発環境に必要なサービスや環境変数、ボリュームの設定を行っています。 コンテナ内から MySQL や LocalStack にアクセスする場合、 localhost ではなく、 mysql や localstack というホスト名でアクセスする必要があります。そのため、 MYSQL_HOST や LOCALSTACK_HOST のように、ホスト名を環境変数として設定しています。 version: "3" services: devcontainer: build: context: . dockerfile: .devcontainer/Dockerfile environment: TZ: Asia/Tokyo MYSQL_USER: developer MYSQL_PASSWORD: password MYSQL_HOST: mysql:3306 # localstack LOCALSTACK_HOST: localstack:4566 DEFAULT_REGION: ap-northeast-1 AWS_ACCOUNT_ID: "000000000000" AWS_ACCESS_KEY_ID: dummy-access-key AWS_SECRET_ACCESS_KEY: dummy-secret-key volumes: - ..:/workspaces:cached command: /bin/sh -c "while sleep 1000; do :; done" 5.4 docker-compose.yml のサンプル こちらは一般的なアプリケーション開発で利用されている docker-compose.yml のサンプルです。 このファイルでは、 MySQL [^6]や localstack ^7 などのアプリケーションに必要なサービスや環境変数、ボリュームの設定を行っています。これにより、アプリケーションを構成するコンテナを一括で構築・実行することができます。 version: "3" services: app: build: context: . dockerfile: Dockerfile volumes: - .:/workspace ports: - "3000:3000" mysql: container_name: mysql build: ./docker/mysql environment: MYSQL_DATABASE: sample MYSQL_USER: developer MYSQL_PASSWORD: password MYSQL_ROOT_PASSWORD: password volumes: - ./docker/mysql/sql:/docker-entrypoint-initdb.d ports: - 3320:3306 localstack: image: localstack/localstack:latest environment: - HOSTNAME=localstack - SERVICES=s3 - DEFAULT_REGION=ap-northeast-1 - DATA_DIR=/tmp/localstack/data volumes: - "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack" - "/var/run/docker.sock:/var/run/docker.sock" ports: - 4777:4566 6. VSCode、JetBrains IDE から利用 Codespaces は、Web ブラウザから利用できますが、VSCode、 JetBrains IDE からも利用できます。ここでは、それぞれの利用方法を紹介します。 6.1 VSCode で Codespaces を起動する 「VSCode GitHub Codespaces」拡張機能をインストールする VSCode で Codespaces を利用するためには、「VSCode GitHub Codespaces」拡張機能をインストールする必要があります。 拡張機能パネルを開くために、左側のアクティビティバーから拡張機能アイコンをクリックし、検索ボックスに「GitHub CodeSpaces」と入力します。検索結果に表示される「GitHub CodeSpaces」拡張機能をインストールします。 または、 こちら からインストールすることもできます。 GitHub にログインする VSCode で「GitHub CodeSpaces」拡張機能を起動し、GitHub アカウントでサインインします。 6.2 JetBrains IDE で Codespaces を起動する JetBrains Gateway をインストールする JetBrains Gateway は、JetBrains 製の IDE(IntelliJ IDEA、WebStorm、PyCharm など)で GitHub CodeSpaces を利用するためのツールです。[^8] JetBrains Gateway で CodeSpaces を起動する手順は以下のとおりです。 なお、先程の例に示したように、JetBrains Gateway で CodeSpaces を利用するためには、 .devcontainer.json に以下の設定を追加する必要があります。 { "features": { "ghcr.io/devcontainers/features/sshd:1": { "version": "latest" } } } JetBrains Gateway のインストールページ にアクセスし、インストーラをダウンロードしてインストールします。 または、 JetBrains Toolbox からインストールすることもできます。 GitHub CLI をインストールする JetBrains Gateway は、GitHub CLI を利用して GitHub にログインします。 GitHub CLI をインストールするには、 こちら の手順に従ってください。 Windows を利用している場合は、 こちら のインストーラを利用することもできます。 GitHub にログインする JetBrains Gateway を起動し、 GitHub Codespace をインストールします。 次に、メニューの GitHub Codespaces > Sign in to GitHub をクリックし、 GitHub にログインします。 ワンタイムコードと認証ページへのリンクが表示されます。リンクをクリックし、GitHub にログインします。 ワンタイムコードを入力し、[Continue] ボタンをクリックします。 次に、 [Authorize github] ボタンをクリックします。 CodeSpaces を起動する Your Recent Codespaces から起動したい Codespace を選択し、[Open] ボタンをクリックします。 もし、 Codespaces を作成していない場合は Click here から Codespaces の作成画面を開くことができます。 7. 導入してみて感じたメリット・デメリット 7.1 メリット 開発環境がどこからでもアクセス可能:物理的な場所に縛られずに開発作業が可能 チーム内での環境構築が容易:環境設定を共有することで、新たなメンバーのセットアップが迅速かつ簡単 devcontainer と設定を共有できる:開発環境の一貫性が保証される 新しいデバイスでのセットアップが迅速:ハードウェアの変更がプロジェクトの進行を妨げない 複数の開発ツールで利用可能:Visual Studio Code, Visual Studio Code for the Web, JetBrains IDE, JupyterLab(Dev Container では VS Code に限定されていた) 7.2 デメリット 費用がかかる場合がある:利用時間やリソースに応じて、費用が発生する可能性がある[^9][^10] JetBrains Gateway はまだ Beta で不安定な場合がある:この機能がまだ開発段階にあるため、一部の機能が期待通りに動作しない可能性がある インターネット接続が必須:オフラインでの作業ができない クラウド上で実行されるため、パフォーマンスやセキュリティへの懸念がある場合もある:ネットワーク遅延やデータ保護などの問題が生じる可能性がある リポジトリ管理されていないファイルや MySQL などに投入したデータは Codespaces が削除されると消えてしまう:永続的なデータストレージが必要な場合は、適切なバックアップ戦略が必要 8. さいごに いかがでしたでしょうか。参考になれば幸いです。 設定ファイルのサンプルは、実際に開発で利用しているものから抜粋したもので、各メンバーがそれぞれローカル環境、Dev Container、Codespaces でシームレスに開発をおこなっています。 さらに、VS Code の Code Tour 拡張機能と組み合わせて、新規メンバーのオンボーディングや、ワークショップ形式の勉強会にも活用しています。 ワークショップでは、環境構築手順の手間を省いてすぐに本題の作業に取り組むことが出来るので、Codespaces の利便性を大いに感じています。 また、Google Cloud からも Cloud Workstations [^11] がリリースされました。興味がありましたらぜひ触ってみてください。 GitHub Codespaces は、クラウドベースの開発環境を手軽に構築するための強力なツールです。Dev Container を利用することで、チーム全体での環境構築を効率化することができます。GitHub Codespaces を利用することで、さらに手軽に開発環境の構築を行うことができ、チームの生産性の向上につながります。ぜひ、GitHub Codespaces を活用してみてください。 [^1]: 共通サービス開発グループメンバーによる投稿 1 [ グローバル展開も視野に入れた決済プラットフォームにドメイン駆動設計(DDD)を取り入れた ] [^2]: 共通サービス開発グループメンバーによる投稿 2 [ 入社 1 年未満メンバーだけのチームによる新システム開発をリモートモブプログラミングで成功させた話 ] [^3]: 共通サービス開発グループメンバーによる投稿 3 [ JIRA と GitHub Actions を活用した複数環境へのデプロイトレーサビリティ向上の取り組み ] [ [VSCode Dev Containerを使った開発環境構築](https://blog.kinto-technologies.com/posts/2022-12-10-VSCodeDevContainer/) ] [^5]: devcontainers/features sshd について [ devcontainers/features sshd ] [^6]: docker-compose での MySQL 設定方法 [ MySQL と Docker Compose を使ってマルチコンテナー アプリを作成する ] [ [GitHub localstack](https://github.com/localstack/localstack) ] [^8]: JetBrains IDE でのリモート開 [ JetBrains IDE でのリモート開発 ] [^9]: GitHub Codespaces の請求について [ GitHub Codespaces の請求について ] [^10]: Default idle timeout の設定を短くすることで、無駄なコストを抑えることができます。 [ Codespaces の設定 ] [^11]: Google Cloud - Cloud Workstations [ Cloud Workstations ]
アバター
はじめに こんにちは。 モバイルアプリ開発グループ 沖田です。 とあるサービスのプロジェクトにて、 スマホアプリ開発に携わっています。 東京のメンバーと一緒に開発をしていますが、 日頃はOsaka Tech Labに生息しております。 というわけで、 私からは「Osaka Tech Lab 紹介」をお届けします! Osaka Tech Lab ヒストリー 2022年4月 誕生。 IT エンジニア会社として実力を上げたい、 エンジニアの採用を含めて極力幅広く門戸を開きたい、 という想いから生まれた Osaka Tech Lab。 なんと、、ひとりからスタートしました! フロアを広々と独り占め状態です。 名古屋オフィス 室町オフィス 神保町オフィス Osaka Tech Lab 4つの拠点から成る弊社。 「どうして大阪だけOsaka Tech Labなのですか?」とよくご質問をいただきます。 どうしてかと言いますと。。 「大阪分室」や「大阪オフィス」よりも格好よく「Osaka Tech Lab」とすることでいろいろな人に興味を持っていただけると考えたからです! 2022年7月 初めてのOsaka採用。4名が集う。 そこから徐々に仲間が集まり、、 2023年5月現在 16名になりました! Osaka Tech Lab って どこにあるの!? 最寄りは心斎橋駅です! Osaka Tech Lab 地下鉄御堂筋線・長堀鶴見緑地線「心斎橋駅」3番出口 徒歩1分 ※敷地内禁煙(屋内喫煙可能場所あり) Osaka Tech Lab ってどんな雰囲気!? 写真を添えてご紹介します。 エントランスです 本棚です 棚の上には、KINTOのロゴ入りミニカーが並んでいます。 サボテンたちもいます。 フリースペースです ソファー席とテーブル席があります。 ここでわぃわぃご飯食べたり、ちょっと休憩したり、集中コーナーとして使ったり。 お菓子エリアです 日頃は異なる業務をしているメンバーの集まりです。 「ちょっと一息」で雑談するきっかけになれば、、 という願いを込めて創設されました! 大活躍ですw 時計です 雑談がきっかけで購入に至った、みんなで選んだ時計です。 こんな感じです。 「ふと見たときに時間がわかるとうれしいよねー」 「あ、おんなじこと思ってた!」 「設置しても良いか、ちょっと聞いてみよう」 「おしゃんなやつがいいねー」 「地震対策もしておこう!」 こんな感じで、ふと思い立ったことを口頭やslackでわぃわぃやっています。 季節感もあるよ クリスマスシーズンはクリスマスツリーも飾っちゃいます。 Osaka Tech Lab ってどんなメンバーがいるの!? 総勢16名ではありますが、 いろんなグループのメンバーが集まっています。 プロジェクト推進G オウンドメディア&インキュベート開発G プラットフォームG 共通サービス開発G 分析G コーポレートITG 人事採用G モバイルアプリ開発G どっしり構え、時には引っ張り、時には見守ってくださるベテラン勢。 いろんなアイディアを積極的に発信してくれるジュニア勢。 年齢層のバランスもとても良いように思います。 Osaka Tech Lab の魅力ってなに!? 「ヒト」「未知なる未来」でしょうか。 「ヒト」 居心地、良きです。 いわゆる、アットホームな雰囲気というやつです。 出張で来られた方からも、 「はじめて来たけど、Osaka Tech Labって良い雰囲気なんだね」ってお褒めの言葉をたくさんいただいております(//∇//) なぜ居心地が良いのか、考えてみました。 役割が違っても、互いにリスペクトしあって仕事に取り組むメンバーが 集まっているからだと思います。 みんな、自身の意見は持っています。 でも、ヒトの意見も聞くことができて、良くするためのディスカッションをすることができます。 これって、当たり前のようで、当たり前ではなかったりしませんか!? これがOsaka Tech Labの強みだと思います! 「未知なる未来」 オフィス立ち上げに携われるってなかなかない!そんな経験をしてみたい! と思って入社を決めたわたくし。 「やってみたーい」って手を上げると、「どーぞどーぞ」ってなりますw もちろん、なんでもありというわけではありませんが、 目的を掲げて道筋を描いたことであれば、どんどん挑戦させてもらえます。 1つ事例を紹介します! Osaka Tech Labメンバーで 情報共有会 を立ち上げました。 目的はこんな感じです。 Osaka Tech Labメンバーのコミュニケーション活性化 Osaka Tech Labの仲間がどんな業務をしているのかを知り、横のつながりを強化 チームや個人の経験をシェアし、新しい取り組みにつなげること で、こんなことをやっています! グループ紹介 LT Osaka Tech Lab をより良くするためのディスカッション 2023年1月 メンバーの仲が深まってきたころ。 普段は他拠点にいる各グループのマネージャーも招いて、第3回を開催。 語って語って語り尽くす​ 〜 Osaka Tech Lab の 未来を作る第1歩 〜​ マネージャー陣がOsaka Tech Lab に期待することを聞いたり、 各メンバーがココロの中で思い浮かべていることを伝えあったり。 いま思えば、これが大きな第一歩だったように思います。 最初は、10人でスタートしたこちらの会。 人が人を呼び、他拠点にも広がりました。 いまでは、Osaka Tech Lab のメンバーの人数よりも、 他拠点からの参加人数の方が多いです。 所属グループの他拠点のメンバーとは、出張で会うことができますが、 情報共有会を通じて、日頃、関わりのない方とのつながりもできるようになりました。 Osaka Tech Lab 野望 いまは、それぞれが東京主体のプロジェクトにjoinしており、 スピード感あふれる、刺激多き日々を過ごしています。 いつか。。いつの日か。。 Osaka Tech Lab で 1サービスの立ち上げ・開発・運用をしたい。。 そんな想いを秘めているメンバーは、実は多いようですw まだ見ぬ未来が楽しみです♪ さいごに いかがでしたでしょうか。 未知なる未来に向かって、 一緒にOsaka Tech Labを創りませんか!? ご応募、お待ちしています! KINTOテクノロジーズ株式会社採用TOP wantedly
アバター
はじめに こんにちは。プラットフォームGでDevOpsエンジニアだったものからOperationToolManagerチームでPlatformEngineeringとかツール周りの開発・運用の役割になった 島村 です。 KINTOテクノロジーズのプラットフォームGでは、Terraformを使用したIaCを推進しています。社内でよく使われるデザインパターンを定義し、リファレンスアーキテクチャとして提供しており、そのパターンをベースとして各環境を構築しています。開発~本番環境の各環境では、統制のために、チケットベースの依頼にて構築を実施しています。 開発環境を構築する前に、アプリケーション部門の検証のためにサンドボックス環境(AWSアカウント)を準備していますが、手動で構築されることも多く、プラットフォームGの構築する環境とは差分が多くあります。 デザインパターンがあるなら、開発者のリクエストにより環境が自動で構築されれば、環境構築の依頼から作成されるまでの待ち時間もなくなり、開発効率は向上します。 DevOpsではこのようなリクエストベースでの自動構築は要件として一般的な話かなと思いますが、やはり、アプリケーション実行基盤はKubernetesが多いようです。 KINTOテクノロジーズではAmazon ECS+Fargateをアプリケーション実行基盤として使用していますので、ECSを対象とした自動環境構築の(多分)珍しい事例としてご紹介いたします。 背景 課題 アプリケーション開発担当者が必要なタイミング(検証・走り出し)でシステムが存在しない DevOps活動の一環として、AutoProvisioning(自動環境構築)については調査をして、一般的だなと感じたが社内には存在しない 比較的自由度の高いサンドボックス環境で構築した環境とプラットフォームGによって提供されるデザインパターンに則った環境での差分が大きい IAM権限などセキュリティまわり VPC/Subnet/NAT Gatewayなどの共通系コンポーネントの存在 などなど それに伴い、構築依頼の際の双方のコミュニケーションコストが高くなる 解決方法 自動構築の仕組みを作ればいいじゃない デザインパターンなので不足するAWSサービスもありますが、そこは許容して手動追加を前提としています。 最初の第一歩として、1時間程度でAWS上の環境を自動構築して、アプリケーション動作確認やCICDの準備ができるという状態にすることは価値がある。 作ってみる ありがたいことに、Terraformの1ファイル(locals.tf)を書くだけで色々なパターンで環境構築できるようにModule化が進んでいるので、こちらをベースに考えます。 社内作成のModule群を使うこと(Must) 社内のデザインパターンをベースに構築すること(Must) DNSは自動で設定されて、HTTPSで通信ができること locals.tfを自動生成できること GolangのHCLWriteで構造化して生成できるかアプリケーションを試作 構造化が難しいことが試作して判明したため、最終的には自動生成を諦めた Templateファイルから一部パラメータを置換することで対応 置換での処理となったので、各コンポーネントの細かい設定は不可 できたもの CMDB上のGUIから、 プロダクト デザインパターン を選択して新規作成を押すと、プロダクトに紐づいた部署のサンドボックス環境に、指定された構成が10分~40分(構成次第)で構築される。 全体構成 個別説明 Terraformコードを作成する部分と実際にサンドボックス環境に構築する部分は分けており、個別にテストできるようにしました。 Terraformコード生成パーツ ProvisioningSourceRepo Issue管理 GitHubActions実行 作成したサンドボックス環境のTerraformコード サンドボックス環境ごとのCIDRリスト ProvisioningAppRepo デザインパターンのTemplate CodeBuildのYaml(buildspec.yml) CodeBuild上で動かす各種ShellScript InfraRepo TerraformModule AWS環境構築部分 S3 CodePipelineのSourceとArtifact EventBridge CodePipelineのTrigger CodePipeline/CodeBuild 実構築環境 Route53(Dev) 本番のDNSから権限移譲をしてDev環境のRoute53を使用 Terratest(Apply) Terratestのサンプルはこのような形。Init、Plan、Applyのどこかで失敗したらテストを終わらせるという条件の関係で入れ子に。Apply途中で失敗した場合は、途中までのものをDestroyする。Golangの知識があればもっと綺麗にかけると思う。 package test import ( "github.com/gruntwork-io/terratest/modules/terraform" "testing" ) func TestTerraformInitPlanApply(t *testing.T) { t.Parallel() awsRegion := "ap-northeast-1" terraformOptions := &terraform.Options{ TerraformDir: "TerraformファイルがあるPATH" + data.uuid, EnvVars: map[string]string{ "AWS_DEFAULT_REGION": awsRegion, }, } // InitでErrorがなければPlan、PlanでErrorがなければApplyと // IFで入れ子構造の対応を実施(並列だとInitで失敗してもテストとしてすべて走る) if _, err := terraform.InitE(t, terraformOptions); err != nil { t.Error("Terraform Init Error.") } else { if _, err := terraform.PlanE(t, terraformOptions); err != nil { t.Error("Terraform Plan Error.") } else { if _, err := terraform.ApplyE(t, terraformOptions); err != nil { t.Error("Terraform Apply Error.") terraform.Destroy(t, terraformOptions) } else { // 正常終了 } } } } 要素 名称 概要 CMDB(内製) Configuration Management Database。構成管理のデータベースのこと。リッチな機能までは不要でしたので、KINTOテクノロジーズではCMDBを内製しています。その上に自動構築のリクエストフォームを構築しています。また、構築後にFQDNなどをCMDBに自動で登録しています。 Terraform AWSなど色々なサービスをコード化する製品。IaC。社内のデザインパターンとModuleはTerraformで作成されています。 GitHub ソースコードを保存するバージョン管理システム。構築リクエストはIssueを起票する形でログに残るようにしています。また、削除する際などにTerraformのコードが必要なので、サンドボックス環境の各コードも保存しています。 GitHubActions GitHubに包含されているCICDツール。KINTOテクノロジーズではGitHubActionsを使用してアプリケーションのビルド・リリースなどを実行しています。今回はIssue起票をトリガーに、Create/Deleteを判断して必要なコード群を選択し圧縮してAWSに連携するために使用しています。 CodePipeline/CodeBuild AWSが提供しているCICD関連のツール。Terraformコードを実行するために使用しています。GitHubActions上でTerraform/Terratestを走らせてもよいのですが、GitHubActionsはアプリケーションビルドなどで日々使用しているので、Usage limits などによる各プロダクトチームへの影響を避けるためこちらを使用しました。 Terratest インフラコードなどをテストするためのGoライブラリ。モジュールのテストもできますが、今回はTerraformのApply途中で失敗した際にリカバリすることを目的に使用しています。 公式はこちら 制限されること 各開発チームに紐づく複数のサンドボックス環境(AWSアカウント)を対象にしますが、作成できるのは同時1つまでにしています(排他) DNSの関係でCodePipeline/CodeBuildを1つの環境で動かしているため アプリケーションが動く部分以外も作成します 無駄も多い気もしますが、構築デザインパターンの関係上こうなりました FQDNからDBまで一気通貫のラインとして構築されます VPCなどを事前にModuleに設定する必要があります 使用する前にVPCなどの共通コンポーネント構築一式が必要 Module群がない場合はどうするのか KINTOテクノロジーズでは以前からデザインパターン化を進めていましたので、CloudFrontからRDSまでをすべて含めた構築が容易にTerraformでできる利点があります。 そこまで進んでいないけどAutoProvisioningをECSで実現したい場合はどうする方法があるでしょうか。 考えてみた ECSのClusterまでは事前に作成しておき、 ECS Service ECR Repository ALB TargetGroup ALB ListenerRule IAM Role Route53 を書いたTerraformファイルを準備して構築するのが楽なのかなと。TaskDefinitionは権限あれば作れるので、使用する側でよしなに。 構成案 GitHubActionsの代わりにCodePipeline/CodeBuildでもいいと思ってますが、CodeCommitとかGUIの準備を考えるとGitHubにまとめたほうが簡単なんじゃないか?ということで、この構成に。AWS Protonはまだ触れてないので、未検討です。 locals.tfなどのParameter部分を分離しておいて、sedコマンドや、GolangのHCLライブラリをつかって作成できれば行けるかなと思います。Terratestなどで構築が確認出来たら、任意のFQDNをALBのエイリアスに追加して、ListenerRuleと合わせる形。 次のステップ もともとはプレ提供でフィードバックをもらおうと思っていましたが、現状はあまり利用されていません。そのためにGUIを提供したので、今後さまざまな人にまずは使って貰ってそのフィードバックを受領するところから始めようと考えてます。 とはいえ、対応できるデザインパターンを増やすことや、付随したCICDの設定の簡素化などできることは多いかなと考えています。…本当はKubernetes導入をして、事例の多いAutoProvisioningに進めたいところ。 |・ω・`) だめですか? 所感 本当はGolangでテンプレートを自動生成する方向で頑張ったんですが、社内のデザインパターンのHCL構造が解析、再構成しづらい形だったのであきらめたという経緯もあります。 Consoleの再発明じゃないかという話も内部ではありましたけど、そこまで行けると、サンドボックス環境だけでなくSTG環境くらいまでなら自動化できたかなとも思っています。プラットフォームGもGUI上からポチポチちょっと入力と選択するだけで環境ができる。わあ、楽。 そこまで達したかったのが本音ですが、まずは第一歩でも進めることができたことは良かったかなと。 Kubernetesでは、Helmチャートをテンプレートで準備すれば、似た感じで作れるのではと思っています。別方法も検討してみて、いろいろとやってみたいですね。 まとめ OperationToolManagerチームは、社内向けの横断ツールを統制して必要なものを開発しています。 前に執筆しました O11yの記事 もですが、仕組みを整理してアプリケーション開発者側に提示してセルフサービスで使用できるようにする、そういった開発者が価値を創造するための下支えの立場で活動しています。 少し前にPlatformEngineeringのMeetUpが開催されましたが、進む方向性として合致してると安心できますね。 OperationToolManagerチームでは内製ツールの構築部門もいますので、開発者が迅速にかつ集中してアプリケーションの価値を作れるようにしていきます。 またこの活動に少しでも興味を持ったり話を聞いてみたい、と思った方はお気軽にご連絡いただければと思います。 @ card
アバター
はじめに KINTOテクノロジーズにおけるローカライゼーションに関して、後編となる今回の記事では、これまでチームが行ってきたことをご紹介します。 課題 前回の記事 では、ソフトウェア翻訳が翻訳キーと対応するバリュー(文言)のペアで保存されることが多い、と説明しましたが、今回はこのデータをどう管理しているかについて説明します。キーと文言のペアがある前提として、ローカライゼーションのプロジェクトマネージャーはベース言語(KINTOの場合は英語)をどのように扱い、翻訳業者(Language Service Provider =LSP)に翻訳依頼すべきでしょう? 私自身、フリーランスで翻訳を行っていた経験がありますが、その中でもエンジニアがExcelで翻訳キーとソース言語の文言を2列で作成し、それをターゲット言語の数だけ複製して翻訳に回すというのはよくあることでした。しかし、この管理方法には、大きく3つの課題があります。 文脈や言葉の前後関係の欠落 一元管理できず、将来的な不整合が起こりうる 人為的ミスが起こりやすい 1つ目の課題として、Excelシートは翻訳者にとっては何の脈絡もない単純なテキストの羅列です。指定のテキストがボタンなのかどうか?デザイン上どれくらいのスペースがあるか?プレゼンのようなストーリーテリングの場合、どのような場面で誰が誰に向かって話しているか?適切に翻訳するにはこのような情報が必要です。 2つ目の課題は、翻訳管理システム(TMS)などに登録しない限り、翻訳した、文言はどこにも記録されないということです。記録がないため、以前どのように翻訳したかを参照することが難しく、以前は「reservation」としていたものを今回は「booking」としてしまうなど、のちのちサービスのクオリティやカスタマーエクスペリエンスに矛盾が生じる可能性があります。ソース言語(英語)だけでもこの課題は発生するので、これが翻訳対象言語の数だけ不整合が起こりうることを想像してみてください。Excelでは追いきれません。 3つ目の課題は開発側の人為的ミスが起こるリスクが高いことです。翻訳文言がExcelファイルに保存されている場合、最終的には手作業で1つずつソースコードにコピペする必要があります。(前回記事の例では「localizable.strings」ファイル)そのため、コピペミスや誤字脱字、さらには最終チェックを行うQAが適切に行われないと、バグが発生する可能性があります。 どのように解決したか これらの課題を解決するために、Excelでの翻訳管理を行わず、 Lokalise という専用のツールを導入することにしました。 _Lokalise_は翻訳タスクを管理できる翻訳管理システムで、すべての文言を1か所で集中管理できます。また、翻訳メモリ(過去にどう翻訳したかを記録するデータベース)の整備や、全てのプロダクトに適用できる用語集の作成ができるのも、このツールのメリットです。また、ソースファイルが保存されているGitHubに接続する機能もあり、開発者が開発した新しい画面や新しい機能のキーを「プル」し、その後、ターゲット言語の翻訳キーと文言のペアをGitHubにプルリクエストを作成して「プッシュ」可能です。 このようにプロセスを自動化することで、生産性が向上するだけでなく、開発者とローカライズチーム双方の作業時間を短縮することができます。さらに、一貫したクオリティを保ちながら、条件の整合性を確保し、正確にエンジニアに引き渡すことも可能です。_Lokalise_を使用するもう一つの大きなメリットは、Adobe XDなどのデザインツールから_Lokalise_に各用語のスクリーンショットをインポートできることです。これによって、翻訳者はツールで翻訳する際に視覚的に対象文言がどこにあるかわかるので、文脈などを考慮して翻訳することができます。情報量の少ないExcelシートにやみくもに入力するようなことはありません。 以下は、我々が開発しているGlobal KINTO App (GKA)の_Lokalise_導入前と導入後のフローチャートです。iOSとAndroidの両方で利用できるようにするため、ファイル変換にも対応する必要がありました。また、エクスポートする際のフォーマット変換も_Lokalise_が行ってくれるので、工数が節約できます。 Next Step 我々の次のステップとして、スケーラビリティを検討したいと考えています。ソースファイルの更新は_Lokalise_で自動化できましたが、各ファイルへのプルリクエストは1つずつ行うため、GitHubのリポジトリや製品の数が時間とともに増えていくと、すぐに重い作業になってしまいます。_Lokalise_とGitHubの中間的な存在として、社内で小規模な管理ツールを作成し、ソースファイルに必要な更新を伴うプルリクエストを一元管理できるようにすることを、解決策のひとつとして考えています。 また、QAプロセス強化の一環として、既存のブランドガイドラインと同様に、一連のスタイルガイドを作成する計画もあります。スタイルガイドによって、翻訳業者(LSP)に依頼した翻訳でも、翻訳者間、あるいは言語間のギャップなく、ブランドのトーン&マナーを維持したまま、わかりやすく翻訳することができるようになります。 また、世界各国のKINTOサービスに我々のローカライゼーションプロジェクトを_横展開_する可能性もあり、まだまだ今後のアイデアは尽きません。これらについては、後日別の記事などでお話するかもしれませんが、まずは、私のローカライゼーションの記事に興味を持っていただいてありがとうございます!翻訳や言語ローカライゼーション、他言語化というトピックに関して、少しでも心をくすぐれていれば何よりです。次にアプリをダウンロードしたり、動画配信サービスを利用したり、ゲームをする際には、多言語コンテンツがいかに技術的に複雑なことを行っているか、ぜひ注目してみてください。
アバター