TECH PLAY

KINTOテクノロジーズ

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

936

こんにちは こんにちは!KINTO ONE開発Gの中川原です。 参加しているプロジェクトではフロントエンドエンジニアとしてNext.jsとTypeScriptを用いて開発を行なっています。 今回はチームで開発を進める上で欠かせない、コードレビューについてのお話です。 私がコードレビューをする際に気を付けていることをレビュイー、レビュワーそれぞれの場合に分けてご紹介したいと思います。 レビュイーとしてコードレビューを依頼するとき 早速本題に入っていきます。 まず自分がプルリクエスト(以後「PR」と記載)を作成してコードレビューをしてもらう際に気を付けていることを2点ご紹介します。 1. コミットのコメントを分かりやすく記載する 分かりやすく簡潔に書こうと意識することで自然と適切な粒度のコミットになると考えます。 必要があれば2行目以降に補足説明や参考リンクを記載します。 また、コミットメッセージに絵文字のprefixを付けています。 視覚的にどんなコミットなのか分かりやすくなる のと、絵文字に意味を持たせているので必然的に 一つのコミットに修正を詰め込みすぎるのを防ぐ というメリットがあります🌈 以下は実際にFEチームで使用しているコミットテンプレートです。 # ==== Format ==== # :emoji: PBI_id Subject # # Commit body... # ==== Emojis ==== # 🐛 :bug: バグ修正 # 👍 :+1: 機能改善 # ✨ :sparkles: 部分的な機能追加 # 🎉 :tada: 盛大に祝うべき大きな機能追加 # 🎨 :art: 見た目の追加・修正 # 🔧 :wrench: 機能の修正 # ♻ :recycle: リファクタリング # 🚿 :shower: 不要な機能・使われなくなった機能の削除 # 📝 :pencil: ドキュメントやコメントの追加・修正 # 🚚 :truck: ファイルの移動 # 👕 :shirt: Lintエラーの修正やコードスタイルの修正 # 🤖 :robot: テストの追加・修正 # 🚀 :rocket: パフォーマンス改善 # 🆙 :up: 依存パッケージなどのアップデート # 👮 :cop: セキュリティ関連の改善、Warningの解消 テンプレート作成にあたり、以下記事を参考にしました。 atom Emojiで楽しく綺麗なコミットを手に入れる そして実際のコミットがこちら👇 その コミットを単体で見た時に何をしているか分かる ように意識しています。 2. テンプレートを利用してPRを充実させる FEチームではPRのテンプレートが用意されています。 レビュワーがレビューをする際にどのような観点でチェックすれば良いのかが明らかになるため、レビュー効率の向上が期待できます。 以下は実際に使用しているテンプレートです。 JIRA を使用してタスクをチケット管理しているためその チケットへのリンク 、 このPRで対応すること・しないこと 、それによって 何ができるようになるのか などを記載します。 ## チケットへのリンク * https://example.com ## やったこと * このプルリクで何をしたのか? ## やらないこと * このプルリクでやらないことは何か?(あれば。無いなら「無し」でOK)(やらない場合は、いつやるのかを明記する。) ## できるようになること * 何ができるようになるのか?(あれば。無いなら「無し」でOK) ## できなくなること * 何ができなくなるのか?(あれば。無いなら「無し」でOK) ## その他 * レビュワーへの参考情報(実装上の懸念点や注意点などあれば記載) テンプレート作成にあたり、以下記事を参考にしました。 Pull Requestのテンプレートを作って効率よくレビューしよう! 上記に加え、必要に応じて情報を付け加えるよう意識しています。 例えば バグ対応のPRの場合は原因も合わせて記載 したり、 UIの変更がある場合は修正前後のスクリーンショットや動画を添付 したりします。 それによりPRの意図やコードの理解がスムーズに進むと考えるためです。 レビュワーとしてコードレビューをするとき 続いては、反対にチームメンバーのPRを見る際に気を付けていること3点についてです。 1. PRの概要を理解する 前段でテンプレートを使用してPRを丁寧に書くとお話しました。 なのでまずちゃんと概要を読みます。 背景や意図、 ここではやらないこと を理解した上でコードを見た方がレビュー効率も良く、的外れな指摘をしないで済むと思っています。 2. ローカルで確認する PRの変更ファイルからもコードは確認できるのですが、以下の理由から挙動に関わる修正の場合はローカル環境にブランチを落として確認するようにしています。 挙動・見た目の確認をするため コード全体を見るため 挙動・見た目の確認をするため 実際に自分で動かすことで期待する挙動・見た目となっているかを確認するほか、変更の目的や意図を理解することができます。 コードだけ見てもなぜその変更に至ったかが理解できていないと適切なレビューができなかったり、今後自分がその箇所に手を入れる際にデグレしてしまう可能性があります。 なのでできるだけ自分の目で処理を追いコードを理解するようにしています。 また、シンプルに対応漏れの場合や、その修正により別の箇所に影響が出てしまった場合に事前に気づくことができるので 思わぬバグの発生防止 にも繋がります🐛 コード全体を見るため 処理を理解するのはもちろん、「同じような処理をしているからこことここはまとめられそう」など、最適化ができそうな箇所に気づくことができるかもしれません。 3. レビューコメントにラベルを記載する コメントの先頭に [imo] や [nits] などのラベルを記載することで温度感が分かるようにしています。(まだ結構書き忘れるので徹底したい) おしまい 長々と書きましたが、まとめると 自分がレビュワーの場合に何が書いてあるとレビューしやすいか、レビュイーの場合にどのようにレビューしてもらえると助かるか を意識しています。 今後の課題としては丁寧さだけでなくレビューの速度も意識していくことと、自分なりの観点表を作成しレビュー品質のムラをなくしていくことだと考えます。 そのレビュー観点についてチームで認識共有をしてみるのも面白そうだなと思いました。 この記事が少しでもコードレビューのヒントになれば幸いです。 最後まで読んでいただきありがとうございました!
アバター
チームの紹介と仕事内容 我々のチームはWoven Payment Solution開発Gです。 早速ですが我々のチームについて伝える前に Woven City について知ってもらう必要があります。 Woven Cityとはトヨタ自動車が「幸せの量産」を目的に開発を進める、モビリティのためのテストコースであり実証実験の街です。 Woven Cityはトヨタグループ内のWoven Planet Holdingsが主導して開発を進めています。 我々のチームはWoven Planet内のPayment Solutionチームのメンバーや他のチームのメンバーと一緒にWoven Cityで使われる決済サービスの開発を行なっています。KINTOテクノロジーズとWoven Planetは別会社なのですが、開発においては特にそれを意識することなく一つのチームとして働いています。 Woven Cityは未来の当たり前を発明するモビリティのためのテストコースであり、我々にもそれに資する機能を開発することが求められています。Woven Cityでは全ての住民や関わる人は、何かしらあたらしい価値を作り出す発明家、あるいは発明を一緒に創る人であるとしています。つまりそれら発明家がより良い製品、サービスなど、何かを作るにあたって必要となる機能やデータを提供することが求められます。このことが一般的な決済サービスと、我々が作る決済サービスの大きな違いとなります。 例えばあるサービスがユーザーからの支払いを受け付けるにあたって、UXとして前払い、後払い、あるいは定期払いや他の方法がよいのかなどを検討しやすくしたり、またデータの提供についても、支払いの情報だけでなく、Woven Cityの他のデータと組み合わせて多角的に検討できるような形で提供するということを考えています。 もちろんこれらは発明家の方たちに提供するだけでなく、Woven Cityというしくみそのものをカイゼンしていくことにも用いられます。 (当然ですが、個人に関わる情報をご本人の同意なしで取得するということはありません) 働き方 Woven Planet側のメンバーも含めて、Payment Solutionのチームは自宅からリモートで開発しています。 ただし週一回水曜日はオフィスに出社し、直接相対してコミュニケーションを取る機会を作っています。 コミュニケーションツールとしてはGoogle MeetとSlackを利用しています。 Woven Planetは英語がコミュニケーションの前提となっているため、特に日本語話者以外がいる場合は英語での会話を行なっています。 またSlackや文書においては日本人同士であっても英語でやりとりを行っています。独り言みたいな投稿も英語で行っているので、悩んでいることを書き込むと、他のチームから助言を貰えたり議論がはじまることもあります。また他のチームから相談されることもあり、時にはそのままhuddleで口頭での会話がはじまるなど、リモートであっても活発なコミュニケーションが行われています。 出社した時には、直接顔を合わせて議論をしたり、タイミングが合えば一緒に社食を食べたりと実際に会うことで得られる刺激を楽しんで仕事をしています。 また開発にあたってWoven City建設予定地に見学に行く機会があります。現時点ではWoven Cityは街そのものが建設中であるため、見学のタイミングによって違う表情を見せてくれており、まだまだ更地の部分は多いものの、実際に使われるイメージを膨らませる役に立てています。 利用している技術 プログラミング言語 Kotlin 我々のチームのスコープはサーバサイドアプリケーションとなっており、その開発にはKotlinを利用しています。 Kotlinを選択した理由についてですが、Javaとの高い相互運用性が大きな理由です。 KINTOテクノロジーズおよびグループ内にはすでにJavaエンジニアが多く在籍しており、彼ら彼女らを我々のチームに素早く加入させられるのではないかという目論見があります。 私自身過去にJavaの経験があり、導入にあたってKotlinで簡単なWebアプリを何度か構築してみたのですが、公式ドキュメントを多少参照するだけで特に問題なくJavaと同程度にはスラスラかけるようになりました。 Go, C#, Rubyといった他言語でのサーバサイド開発経験があるものの、Java自体は未経験のメンバーも参加していますが、彼らも特に問題なくKotlinを使えるようになっています。 最初はBetter JavaとしてのKotlinとして使っていたのですが、最近ではJavaを忘れてKotlinを書くという意識で使うようになっています。 またプロジェクト管理にはgradleを使っているのですが、その設定ファイルもKotlin Scriptで記述しています。 利用している主なライブラリ Ktor, Koin, Exposed, Kotest, MockK, etc 我々のサービスは複数のアプリケーションサービスから構成されているのですが、その多くはREST APIを持つWebサービスです。KotlinでもSpring MVCやSpring Bootを使うことは出来るのですが、我々はKtorを選びました。Springを採用しなかったのは、アノテーションを駆使するような魔法のようなコードを可能な限り避けたかったというのがあります。ですがDependency Injectionの仕組み自体はテストのためや依存性の管理のために利用したいと思い、DIライブラリとしてKoinを採用しています。 KoinにもSpringのようなアノテーションによる設定方法が用意されているのですが、DSLでの設定方法も用意されており我々はこちらの方法を利用しています。 KoinやDSL自体の知識は要求されるのですが、アノテーションと比べるとDSLの方が通常のKotlinコードの中に自然に織り込むことが出来るため、意図を明確に表現出来るように感じています。 ほかにもORMにはExposedであったり、テストのためにKotestやMockKを使うなど、様々なFOSSライブラリを利用しています。 Ktor 公式サイト Koin 公式サイト Exposed Github Repository Kotest 公式サイト MockK 公式サイト これはチームというより、完全に個人の興味になりますが、Ktorは GraalVM でも動作するため、チャンスがあればGraalVMを使ったネイティブビルドに挑戦したいと思っています。 参考: https://ktor.io/docs/graalvm.html#prepare-for-graalvm アプリケーション基盤 Kubernetes 我々の開発しているアプリケーションはKubernetes上にデプロイされており、自分達の開発しているサービスについての設定は、自分達でYAMLを書いています。 Kubernetes環境全体の開発や運用については別チームが担当しているのですが、このチームがCDの仕組みも準備してくれており、基本的には新しい設定をPRにし、Github上でレビュー&マージすると、自動的にデプロイまで行われるようになっています。 設定についてやアーキテクチャ、こちらからのリクエストにも対応してもらえており、いつも助かっています。 開発の進め方 テストコースとしての街という前例のないプロジェクトの性格上、自分達のチームが担当しているところだけでなく、全体として未知のことが多く、当たり前に求められる機能を足がかりにして、大まかに仮説と開発プランを考え、作りながら我々自身が自分達のサービス、さらにWoven Cityについて学んでいます。 具体的には四半期ごとに大きなテーマを設定し、それに必要な機能を追加したり更新し、小規模なデモをオフィスで実施して確認するというプロセスをとっています。 そのためアジャイルな開発手法を採用し、JIRAでバックログを管理しながら、二週間をタイムボックスとして反復的に開発を行なっています。厳密なScrumのプラクティスに則っているわけではないですが、作っていくうちに判明した事実や発生した要件の変更に適応的に開発するようにしています。 おわりに このプロジェクトの難しいところは、今この時点でWoven Cityというリアルなテストコースがまだ存在しておらず、当然ユーザーも潜在的にしか存在していないことにあります。 これは我々のチームだけでなく、全てのチームに言えることです。他のチームが開発中の機能を使いたいと思っても、それがまだまだ不安定であることはしょっちゅうです。一方で一般ユーザーがいないということは、ある程度不安定であっても(少なくとも今は)構わないとも言えます。 不安定だから使わないのではなく、お互いに使って叩いて磨き上げるという精神で、この不安定な状況をお互いに楽しみ、尊重し合いながらも率直に指摘して、よりよいものを目指したい人は是非、我々のプロジェクトに参加してもらいたいです。
アバター
初めに KINTOテクノロジーズのグローバル開発グループに所属しているパンヌウェイ(PannNuWai)です。グロバール開発グループでテスト自動化チームの担当としてプロダクト開発チーム用のテスト自動化環境の構築と整備をしていたり、プロダクトのテストチームでテストスクリプトを書いています。 私は、KINTOテクノロジーズに入社するまでもテスティングは担当していましたが、入社してから初めてAppiumの自動化テストを経験し、この間、様々なものを学びました。 Appiumは経験が無く、ゼロから勉強するところからのスタートでした。最初の環境設定から手探りで行いサーバーのアーキテクチャデザインまで行うことができようになりました。 この自動化テストでは、スマホアプリをメインにテストしましたが、その中で解決した課題を共有いたします。 本記事では自動化テストためAppium version 1.22.3を使ってDarkMode(ダークモード)に切り替える方法を話したいと思います。 自動化テストとは ソフトウェアテストは不具合のある製品をリリースしてしまわないよう、ソフトウェアの問題を発見するために行う作業のことです。 本記事で「自動化テスト」とは支援ツールを用いてソフトウェアテストのプロセスを自動化することと言います。 自動化テストのメリット ^1 不具合の早期発見 コストを抑えながら品質を高められる 人的リソースが不足していてもテストできる テストを高速で実施できる ヒューマンエラーを排除できる 営業時間外でもテストできる Appium とは iOSアプリ、Androidアプリ、およびデスクトッププラットフォームではネイティブ、ウェブビュー、ハイブリッドアプリをテストするためのオープンソースツールです。[^2] [^2]: https://appium.io AppiumはJava,PHP,Pythonのプログラミング言語をサポートしているのでテスト者が好きな言語を選びながら簡単に使える自動化テストツールです。 Appiumのアーキテクチャでは Appium Client Appium Server End Device という三つのコンポーネントが有ります。 Appium Clientの中にはモバイルデバイスとアプリの詳細を設定されています。 Appium ServerにはNode.js言語を利用してjsonファイルを起動しながらシミュレーター(iOS)またはエミュレータ(Android)の接続を行います。 最後には起動されたAppium ServerによってEnd Deviceが発行されます。 Appium Inspector とは Appium InspectorはモバイルアプリのUI要系を一意に識別するための標準的な手順です。実際のデバイスまたはシミュレーター(iOS)またはエミュレータ(Android)の両方で動作します。 注意点- Appium Inspectorツールはネイティブモバイルアプリケーションの属性のみを取得するように特別に設計されているため、Web ブラウザ(Chrome)でロケーターを見つけることをサポートしていません。 Appiumデスクトップアプリケーションは、Appiumサーバー自体とElementインスペクタの組み合わせで、テストスクリプトの開発中にモバイルアプリケーションのすべての目に見える要素を検出できるように設計されています。 ^3 Dark Mode(ダークモード)とは ダークモードはスマートフォンやノートパソコンなどのユーザーインターフェースの表示設定です。 明るい画面に対して暗いテキスト(ダークモード)が表示されている代わりに、黒い画面に対して明るい色のテキスト(ライトモード)が表示されることです。 現在ではスマートフォンのAndroidとiOS両方の既存ダークモード機能だけではなく、アプリの中にもダークモード機能をよく使います。モバイルアプリの自動化テストを行う場合はダークモード機能のテストも重要なチェック項目になりました。ですので、今回はAppiumを利用してモバイルアプリのダークモードについて話したいと思います。 問題点 Appiumを利用してダークモードのテストを行う場合、問題点があります。例えば、ログイン画面に username と password の文字が表示されているかをテストする際、Appium inspectorから username と password のelement存在する場所を取得します。通常は以下の通りでelementが表示されているのをチェックするのみです。 AssertTrue(driver.findElementByXPath("USER_NAME").isDisplayed()); AssertTrue(driver.findElementByXPath("PASSWORD").isDisplayed()); ですが、ダークモードの場合、 element の存在する場所を取得して表示をチェックするだけは不十分です。画面が黒い色に変更されているかをチェックするのはダークモードの大事な点です。黒い色と白い色のhexadecimal値をチェックする必要があります。 テスト方法 では、実際にAppiumでダークモードテスケースのソースコードを書いてみましょう。 changeToDarkTheme ステップ 1 Appium inspectorからelementの存在する場所(ElementId)を取得します。 ステップ 2 デフォルト設定がライトモードになっているかどうかを assertElementColorMode(MobileElement elementId, ColorMode colorMode) で確認します。 ステップ 3 ダークモードのボタンを押下します。 ステップ 4 Display設定が ダークモードに変わるかどうかを assertElementColorMode(MobileElement elementId, ColorMode colorMode) で確認します。 public class DisplayChangePage extends Base { public static final String THEME_CELL_ID = "id/theme_parent"; @Test(groups = "DisplayChangePage", dependsOnGroups = "Setting") public void changeToDarkTheme() { driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS); MobileElement themeCell = getDriver().findElementById(THEME_CELL_ID); assertElementColorMode(themeCell, ColorMode.LIGHT); themeCell.click(); driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS); tapElement( findElementByTextContains(ViewType.CHECKED_TEXT, resourceText("darkTheme")) ); themeCell = getDriver().findElementById(THEME_CELL_ID); assertElementColorMode(themeCell, ColorMode.DARK); } } assertElementColorMode Theme cellが存在しているElementIdと変更したいColorModeをパラメータとして設定しています。 ステップ 1 Theme cellが存在しているElementのエビデンスを取得します。 getElementBufferedImage(MobileElement element) を使ってエビデンスを画像ファイルとして保存します。 ステップ 2 保存されている画像ファイルが null にならないようにチェックします。 ステップ 3 画像ファイル(x = 10, y = 10)のポイントからカラーを取得して変更したいダークモードのカラーをチェックします。 public interface AppiumHelpersInterface extends FindElementsInterface { AppiumDriver<MobileElement> getDriver(); Device getDevice(); /** * Get buffered image of mobile element * * @param element Mobile element * @return Buffered image */ default BufferedImage getElementBufferedImage(MobileElement element) { File image = element.getScreenshotAs(OutputType.FILE); try { return ImageIO.read(image); } catch (IOException e) { return null; } } /** * Assert element's color mode * * @param element Mobile Element * @param mode Color mode */ default void assertElementColorMode(MobileElement element, ColorMode mode) { BufferedImage image = getElementBufferedImage(element); Assert.assertNotNull(image); Assert.assertTrue(Utils.getColorString(image, 10, 10).matches(mode.cellRegex())); } } getColorString 取得した画像のx-point, y-pointのカラーをhexadecimalに変更して配列を返却します。 /** * Get color string from image at point x and y * * @param image BufferedImage * @param x int * @param y int * @return Hexadecimal Color String */ public static String getColorString(BufferedImage image, int x, int y) { int rgba = image.getRGB(x, y); int[] rgb = new int[]{ (rgba >> 16) & 0xff, (rgba >> 8) & 0xff, (rgba) & 0xff }; return String.format("%02x%02x%02x", rgb[0], rgb[1], rgb[2]); } cellRegex ダークモードとライトモードの値を判断します。 public enum ColorMode { LIGHT, DARK; public String cellRegex() { // 22222 - lighter black if (this == DARK) return "2[(0-9|a-f)]2[(0-9|a-f)]2[(0-9|a-f)]"; // ffffff return "f[(0-9|a-f)]f[(0-9|a-f)]f[(0-9|a-f)]"; } } public interface ColorModeInterface { String darkModeScript(); Map<String, Object> darkModeSettings(); Map<String, Object> lightModeSettings(); default void configureDarkMode(ColorMode mode) { getDriver().executeScript(darkModeScript(), mode == ColorMode.DARK ? darkModeSettings() : lightModeSettings()); } } 注意点 この方法はAppiumを利用したケースなのでNative Appのダークモード機能だけ使えます。 まとめ 本記事では、ダークモードの切り替える方法について説明しました。 ダークモードの自動化テストのためiOS(version13以上)とAndroid(version 5.0以上)両方で使えます。 今回はNative Appのダークモードテスト機能を行いましたが、今後はWeb Appのダークモードテストも試してみたいと思います。 グローバル開発内のテスト自動化チームは12月から増員しました。今後は、チームメンバーと一緒に、Appiumだけでなく、Katalonなど他のツールも用いた自動化テストに取り組んでいきたいです。 参考 DarkMode Appium Architecture
アバター
はじめに はじめまして。KINTOテクノロジーズ オウンドメディア&インキュベート開発グループ マネージャーの近藤です。 長いので社内でも誰も正確にグループ名を呼んでくれません。通称 メディアインキュベG でお願いします。 本記事では私のグループの紹介をさせていただきます。 グループの概要 成り立ち メディアインキュベGは、2022年8月に誕生した新生グループです。 もともとは弊社の主力サービスである 「クルマのサブスク」KINTO ONEのお客さま向けサイト の開発を一手に担う「KINTO開発グループ」というグループだったのですが、だんだんメンバーが増えてきたため、それぞれのチームをより深くマネジメントできるよう、2022年8月から2つのグループに分かれました。 ひとつが KINTO ONE開発グループ 、 そしてもうひとつが私たち オウンドメディア&インキュベート開発グループ です。 担当プロダクト 各グループが開発を担当している主なプロダクトをご紹介します。 KINTO ONE開発グループ プロダクト 概要 URL KINTO ONE 新車サブスクリプションサービスの申し込み機能、お客さまのアフターケア・サポートを行う機能の実装 https://kinto-jp.com/customer/login オウンドメディア&インキュベート開発グループ プロダクト 概要 URL KINTO ONE 新車サブスクリプションサービスのトップページ、取扱車種一覧、利用規約、ランディングページなどのコンテンツ制作 https://kinto-jp.com KINTOマガジン KINTO発のMaaS情報を提供するメディアサイト https://magazine.kinto-jp.com モビリティマーケット 「新しい移動のよろこび」を発見できるサービスサイト https://mobima.kinto-jp.com Prism Japan お出かけ先インスピレーションAIアプリ https://ppap.kinto-jp.com/prismjapan/index.html 中古車プロダクト KINTOが新たに手がける中古車モビリティサービス - 販売店向けプロダクト トヨタ販売店担当者向けのKINTO ONE販促ツールの開発 - ミッション 私たちメディアインキュベGのミッションは、 オウンドメディアと新規ビジネス創出において、テクノロジーとクリエイティブの力でお客さまに KINTOの価値を最大限にお届けする ことです。 グループの名前どおり 「オウンドメディア(自社保有メディア)」 と 「インキュベート(新規ビジネス創出支援)」 の二本柱です。 オウンドメディア(自社保有メディア) KINTOのモビリティサービス・プロダクトの価値をお客さまに有効にリーチさせるためのメディアを創り出す 該当プロダクト:KINTO ONE(ユーザー訴求コンテンツ)、KINTOマガジン、モビリティマーケット、販売店向けプロダクト インキュベート(新規ビジネス創出支援) KINTO ONEに続く新しいモビリティサービスをお客さまに提供すべく、KINTOと共に新規ビジネスを創出し、テクノロジーで支援する 該当プロダクト:Prism Japan、中古車プロダクト グループで取り組んでいること・取り組もうとしていること 品質担保施策 KINTO ONEのユーザー訴求コンテンツは、お客さまのご契約プロセスにおいて大変重要な情報を提供しています。 また、取扱車種やサービスの更新などのビジネスの動きに合わせ、デリバリースパンは平均して1週間です。タイミングによってはそれより短い期間でデリバリーすることもあります。 このような条件下で、一定のアジリティを出しつつクオリティも担保していかなくてはなりません。 従って、今よりさらに品質を担保できるようにするための施策検討と適用は常に行っています。たとえば次のようなものです。 CI/CDパイプラインでの自動チェック 弊社には自前のQAチームがおり、 プロダクトチームが依頼すればテストのプロフェッショナルに品質チェックを実施いただける仕組みが整っています。 ただ、ビジネスの都合によっては、QAテストまでに素材や原稿がどうしても予定通りに揃えられないケースも発生します。 そんな状況でも、抜け漏れなくデリバリーするためにはどうしたらいいか? 私たちはこんな施策をとりました。 改修発生時点で、特定のダミー文字列を入れた仮の状態でコミットする 正しい原稿が届き次第差し替えていき、テスト環境にデプロイする QAテストまでに原稿が間に合ったものは、「正しい原稿が上がっている」という観点でテストいただく QAテストまでに原稿が間に合わなかったものは、どこがダミーであるかをQAチームに伝えた上で「ダミー原稿が上がっている」という観点でテストいただく GitHub Actionsで「特定のダミー文字列が含まれているか」のテストジョブを構築し、mainブランチへのマージ時にチェックが発動するよう設定する こうすればQAのテストも通せて、かつ本番デプロイ時にダミー原稿のまま上げてしまうことも防止できます。 コンフリクト解消時のペアプログラミング必須化 短期間で広範囲のコンテンツ改修が走るため、マージ時点でコンフリクトが発生することはままあります。 このような場合、ひとりだけの判断で解消作業をせず、必ずペアプロで同じ画面を見ながら複数メンバーで確認しつつ解消作業を行うようルール化しています。 また、コンフリクトが発生していないプルリクでも、少なくともひとり以上のレビュアーがApproveしないとマージできないようにGitHubを設定しています。 スキルアップ 様々な経歴やスキルのバックグラウンドを持つメンバーが集まっているメディアインキュベGですが、 自分の所属するプロダクトチーム以外のメンバーが今なにをやっていて、どんな課題で悩んでいるのか、 日々の業務をこなしているだけではなかなか知る機会がありません。 そこで、日常業務以外で時間をとって、各人のスキル発表や技術情報共有の機会を設けています。 勉強会 直近だと、フロントエンドエンジニアによる「デザインシステム+アトミックデザイン勉強会」を企画しています。 バックエンドエンジニアは日々の業務でこのへんになかなか触れる機会がないので、楽しみにしているようです。 技術交流会 KINTO ONE開発グループのメンバーを含め、フロントエンドエンジニア全員参加で技術交流会をやろうとしています。 出社参加メンバーはお菓子やコーヒーなどいただきつつ、オンラインでも参加できる形式で予定しています。 グループ所属チーム・メンバー 前述の通り様々なプロダクトを手がけているメディアインキュベGですが、グループ内のチーム構成としては3つに分かれています。 各チームについて次にご紹介しますが、それぞれのチームがメインで担当しているプロダクトで表すのが分かりやすいと思いますので、 実際のチーム名とは若干異なりますがご容赦ください。 1. KINTO ONE等 メンバー(2022年12月時点) 8名 仕事の進め方 事業会社のエンジニアとして、 KINTO ONEのビジネスを理解した上でシステムとしてどうしていくべきかを考える のが最も重要な仕事です。 言われたことをただこなすのではなく、案件の内容を自分の頭で理解し、わからないことはすぐ問い返して解決し、 影響範囲や最適なロジックを自ら判断した上で案件を進めるのがこのチームの仕事のやり方です。 チームの雰囲気 メンバーの学習意欲が高く、スキルレベルの個人差はあれど、現状に満足してとどまろうとするメンバーはいません。 半期の技術スキルアップ目標もチャレンジングなものが多いです。 チームのこういった空気を牽引している技術リーダーの記事がこちらです。 SvelteKit + Svelte を1年間くらい使ってみた知見など 2. 中古車 メンバー(2022年12月時点) 4名 仕事の進め方 このプロダクトについては諸事情によりあまり具体的なことはお話しできませんが、仕事の進め方の特徴としては、 部署や所属会社の分け隔てなく、全員が意見を出し合えるワンチームとして機能している ことかと思います。 テーマ別の定例を週7本実施、KINTOビジネス側とのミーティングも毎週実施しています。 それ以外でもJiraとSlackで都度やりとりを行います。 チームの雰囲気 プロダクトマネージャーとリードエンジニアがかなり前のめりにビジネス側のプロダクトオーナーに突っ込んでいくので、 エンジニアメンバーは正直全員が全員は追いつけていない面もあるのですが、 それぞれの役割の中でスキルを上げつつ業務理解を深めようとしています。 というかそのリードエンジニアは私なんですけどね。 2021年9月に入社してすぐこのプロジェクトが始動し、以来ずっとリードエンジニアを担当していました。 とはいえ、2022年11月時点ではエンジニアメンバーも当時より増えたので、そろそろスキルトランスファーの段階に入ってきています。 新たなリーダーがチームをしっかり牽引してくれることを期待しています。 3. Prism Japan メンバー(2022年12月時点) 5名 仕事の進め方 プロジェクトマネージャーとプロダクトマネージャーがそれぞれ1名ずつ、エンジニアが3名の体制です。 2022年8月にPrism Japanをローンチして運用フェーズに入っています。 運用・リファクタのフェーズ体制はアジャイルを採用 し、そのためにQAチームから専任QAメンバーをアサインしました。 チームの雰囲気 全員が当事者意識を持って自走できているチームです。 メンバーが互いに尊敬しあい、それぞれの専門分野で長所を生かして短所を補いあう働き方ができているなと感じています。 私のすぐ後ろの席で、いつも課題や改善策についてみんなで論じ合っているのをよく耳にします。 こんな仲間を募集しています 1. KINTO ONE等 PdM システム開発の立場からプロダクトのあるべき姿を考え、提案できるようなPdMチームの設立を目指しています。 【PdM(KINTO ONE等)】の応募はこちらから フロントエンドエンジニア・バックエンドエンジニア プロダクトのあるべき姿の実現のためには、実際に手を動かせるエンジニアも不可欠です。 新しい技術を貪欲に学習し、かつKINTOのビジネスを理解してKINTOと並走していけるポテンシャルを持ったメンバーにジョインしてもらいたいと思っています。 【フロントエンドエンジニア(KINTO ONE等)】の応募はこちらから 【バックエンドエンジニア(KINTO ONE)】の応募はこちらから 2. 中古車 フロントエンドエンジニア・バックエンドエンジニア 中古車ビジネスを理解しKINTOとタッグを組んでシステム開発を進めていけるエンジニアをもっと増やしたいと考えています。 そのノウハウは、現在のプロダクトだけではなく、これから生まれるKINTOの新しいサービスやプロダクトにも必ず活かせます。 つまり、この中古車プロダクトの業務を通じて、KINTO/KTCの企業価値に大きく貢献できるエンジニアになれるはずです。 【フロントエンドエンジニア(中古車)】の応募はこちらから 【バックエンドエンジニア(中古車)】の応募はこちらから 3. Prism Japan バックエンドエンジニア ネイティブアプリの開発を通じて新たなモビリティ市場の開拓に貢献したい方、チャレンジしてみたい方にぜひジョインいただきたいです。 【バックエンドエンジニア(Prism Japan)】の応募はこちらから
アバター
Introduction On this second part about localization at KINTO Technologies, we would like to share with you what the team has accomplished so far. The task at hand On my previous article I explained how as data type software translations are often stored as a key-value pair and today we will go through how we manage this data. Having these pairs of keys and terms in mind, we proceed to determine how localization project managers handle the base English and request our Language Service Providers (LSPs) to deliver us back the translations. It is common to see -also in my experience as a freelance translator- engineers create an Excel sheet with one column of translation keys and a second column with the source language terms that are then sent to translation by adding as many columns as target languages needed. There are three main problems I see with this management style: Lack of context Inconsistency issues down the line Prone to human error First, Excel sheets are simple rows of text without any context for the translators: is the term a button? Are there any space limitations design-wise? In the case of storytelling, who is speaking and to whom in what kind of situation? The second problem is that those terms without being fed into a Translation Management System (TMS) will not be recorded anywhere. That can potentially lead to inconsistencies in quality and customer experience in the long run: are we calling it "reservation" or "booking"? And that is only with the source language; imagine this issue multiplied by the number of languages. Finally, it has a high risk of causing human errors on the development side. When the translations are stored in Excel files, they will eventually need to be painstakingly copy-pasted manually into the source code one by one (the "localizable.strings" file in our example previously). This can lead to copy-paste errors, typos, or even bugs if there is no proper QA to do the final check. How we solved it To solve these issues, we have decided not to manage translations in Excel and instead introduced a dedicated tool to manage the translation of our products, called Lokalise . Lokalise is a Translation Management System that manages translation tasks and allows us to have all terms centralized in one place. Another benefit of the tool is the ability to maintain a Translation Memory (a database that records how sentences have been translated before) and start a glossary creation -a vocabulary list- that can be applied across all our products. It also has the capability to connect to GitHub where the source files are stored, which allows us to "pull" the keys that our developers create for a new screen or new functionality, thereafter, "pushing" back all the target languages translations' key-and-term pairings with a pull request to GitHub. Automating the process this way not only raises productivity but also reduces the working time for both developers and the localization team. Furthermore, we can also maintain consistent quality, while ensuring that the integrity of the terms is kept and handed over to our engineers accurately. Another enormous benefit of using Lokalise is that it allows us to import screenshots for each of the terms from our design tool Adobe XD to Lokalise, so translators have visual context when translating in the tool and are not blindly typing away on an information-deprived Excel sheet. Below are the flow diagrams before and after implementing Lokalise for our Global KINTO app, where we also needed to deal with file conversions to have it available for both iOS and Android. Lokalise also takes care of the format conversion when exporting, saving us time: Next Steps One of our next steps is to think about scalability. We were able to automate the updates in the source files through Lokalise, but as the pull requests to each of the files are done one by one, it can quickly become a heavy task as the number of GitHub repositories and products grow over time. One solution we are considering is to create an in-house small management tool that would go in-between Lokalise and GitHub, allowing us to centralize all the pull requests with the updates needed on the source files. As part of our efforts to strengthen our QA processes, another plan is to create a series of style guides, akin to our existing Brand Guidelines. This would further ensure that even translations which are requested to our language service providers are easily understood, maintain the brand's tone and manner without gaps between translators, or even between languages. There are still more ideas and exciting projects awaiting us on the horizon, such as the potential to apply yokotenkai (horizontal deployment) of our activities to other KINTO services around the world. I might talk about these at a later point, but for now, I thank you for your interest in my post! I hope I was able to spark a bit of curiosity on this topic, and that next time you download an app, use a streaming service or play a video game, you think about the technical complexities at play for multi-region content.
アバター
はじめに はじめまして。KINTOテクノロジーズでエンジニアの教育研修を担当している熊谷と申します。 私は海外・国内問わず旅行が趣味なのですが、最近では全国各地の空港巡りに興味があります。レストランエリアがとても充実している新千歳空港や、青い海が目の前に広がる那覇空港など魅力的な空港はいくつもあるのですが、私のおすすめは、富山空港。福岡空港ほどではありませんが市街地からも近く、なにより空港内にある寿司屋が本当に美味しいです。北陸の旅に行かれる際は、是非とも立ち寄ってみてください。 さて、今日は我々の組織、エンジニアリング教育研修PJTが普段どういうことをやっているのかをざっくりご紹介させていただきたいと思います。 プロジェクトが始まったきっかけ 私たちは、2022年8月に本格始動した、いわば出来たばかりの組織です。 KINTOテクノロジーズでは積極的に採用活動を行なっており、エンジニア・デザイナー・QAエンジニアなど含め300名近い組織になってきました。 しかしながら、ここ1、2年で急激に拡大をしたため、 これからはこのプログラミング言語で開発をしていくからこういうスキルを持っていてほしい、 あるいは、このキャリアの先にこういったキャリアパスがあってほしい、 といった議論が乏しいままここまで来てしまったという現実があります。 そこで我々は、エンジニア陣が持っているスキルを再整理し、必要なスキルを学びたいときに研修を受けられる環境を作ることを目指して立ち上がりました。 また同時に、エンジニアが抱えている不満や不安を組織の面から改善し、リテンションを上げていく活動もしています。 自走するエンジニア 私たちのミッションとしては、自走できるエンジニアのために何をサポートできるか、を常に考え、行動に移していくことを心がけています。 グループで現在取り組んでいること 教育 研修の一環として、トヨタ生産方式(Toyota Production System:TPS)の研修が実現できました。 私個人としてせっかくトヨタの関連会社に入社したのだから、リーン開発方式の元となったトヨタ生産方式をもっと知りたいと思っておりました。しかし社内でそのような研修はなかったため、トヨタ自動車にお願いして、2回にわたってTPS研修を開催していただき、50名を超える方々にご参加いただきました。「モノ情」と言われる物と情報の流れ図を書くことにより、どこにムダがあるのか、どこに効率化を阻む要素があるのか、を図で分かるようになり、KINTOの業務でも活かすことができています。 グローバル開発グループでは、社内の縦割りが不満に感じているエンジニアが多いことに加え、勉強会でも座学だけだと飽きるという声を受けて、Innovation Dayという企画をやってみようということになり、サポートしています。 また、KINTOテクノロジーズではAWS(Amazon Web Service)やGCP(Google Cloud Platform)といったパブリッククラウドを全面的に採用しており、AWSやGCPの中で私たちをサポートしてくださる方々とも交流が活発になってきています。サポートエンジニアの方々を定期的にお招きして勉強会を実施する等、AWS、GCPの方々と皆で一緒にパブリッククラウドを盛り上げています。 組織開発 社員サーベイにおいて、社内の情報共有が少ないという不満が多く上がっていました。KINTOテクノロジーズでは月一回全社でおこなっているミーティングはあったのですが、一方的な伝達ばかりのことも多く、相互に情報を共有する場になっていないと感じていました。そこで本部会の運営を見直し、本部長からの開発・事業報告の時間に加え、新たに開設したオフィスの紹介を生中継で行ったり、チャットをオープンにしてタイムリーに質問を受け付ける等の改善をおこなっています。そうすることによって、社内のことがよく分かった、社内の風通しが良くなった、との声が多くいただいています。まだまだ改善の途中ではありますが、引き続きオープンで双方向のコミュニケーションを取れるように尽力していきます。 また、毎月多くの中途採用者に入社いただくのですが、自グループ以外のマネージャーとの接点がないため話しかけづらいという声も耳にしています。そこでOJT期間中に他グループのマネージャー、リーダー陣とコミュニケーションが取れるよう、ビルドアップ(関係性の構築を意味するサッカー用語ではありますが)をしていただくように推奨しています。これにより、社内の多方面でのコミュニケーションがより活発になることを期待しています。 グループメンバー メンバーは今のところ2名体制の少数精鋭チームです。私の他に人材エージェントから転職してこられた方もいますので、その営業力を活かし、カンファレンスのスポンサードや生産性指標を測るツールの導入などを積極的に社内提案しています。その生産性指標のツールの導入をきっかけにオンラインのイベントへの登壇依頼をいただくなど、日々の活動がさまざまな新しい出会いを産み出し、活動の輪をより広げていけています。 また、チームはスクラムのメソッドを使っています。2週間を1スプリントとして、スプリントごとに予定タスクと実績を洗い出しています。私たちは長期にわたる施策を実施することも多いのですが、長期施策は抽象的な話が多く具体的に進めることが時に困難です。ですがスクラムを用いることによって、短期的にチェックポイントを設けそれにコミットすることを通じ、長期的な施策もより具体性を持って進められるメリットがあると感じられるからです。 これから挑戦したいこと まずは、エンジニアスキルを明文化したいと考えています。KINTOテクノロジーズにはこういう人材が集まっていて、こういう点は強みを発揮できる、けれどもこういうスキルが足りないと思われるから研修でそれを補おう、という戦略を立てやすくしたいと思っています。 また、定期的に社員サーベイを取れる仕組みを導入することを検討しています。組織開発は一度に成果があらわれるものでもなく、さまざまな施策を組み合わせた結果として徐々に社員の離職率が下がるのだと思います。ですので、定期的に社員サーベイを実施して、今月はこの施策が効いたから次はブラッシュアップしてみよう、といったさまざまな改善ができたらいいと思っています。
アバター
こんにちは。KINTOテクノロジーズ、クリエイティブグループでアートディレクションを担当しているアワノと申します。普段は社内全般の視覚に映るコンテンツの方向性をまとめ、決めることなどが仕事です。 今回は、KINTOテクノロジーズテックブログが生まれた時のお話を少しばかりさせていただきます。拙文、読みづらい点ご容赦ください。 はじまりは、 社内エンジニアの情熱がきっかけ 元々TOYOTAから生まれたクルマのサブスクを中心に、モビリティサービスを展開するKINTO。KINTOのテクノロジー部分を担う部署が、KINTOテクノロジーズ。広くモビリティ分野をテクノロジーの力でドライブさせていくことが期待されています。 私たちのヴィジョンやカルチャーに共感してくれる仲間を増やしたい 私たちのヴィジョンやカルチャー、働き方や使っている技術など、どこかに目に見える形になっていたっけ?発信したりしていたっけ?ということで、テックブログで会社の取り組みを発信していこうとなりました。 社内外の人や想いをつなぐ存在になりたい 上述の通り、大きな目的は、社内の取り組みを発信する仕組みを作り知ってもらおう。そして、その中で想いを同じにしてくれる仲間に興味を持ってもらおう。ということで始まりましたが、 次に、人数も増え、組織も拡大したことから、まだまだ社内での情報共有も整っていない部分があり、あの部署では、どんなことやっているのだろうということが普通にあり、ブログを通して普段取り組んでいること、使っている技術、思っていること、興味を持っていることなどを発信することによって、社内でも人と人を繋ぐような存在に育っていけばいいなということも。 私たちの想いをロゴにしたい 発起人のエンジニアの有志グループが中心となって、上述のような目的や要望をまとめ、それを叶えるためのサイトや運用体制などの要件をまとめていきました。社内での共有を経て、無事プロジェクト化。その後、ロゴがあった方がいいということで、クリエイティブグループに声がかかりました。 (さも、自分がかなり関わっていたかのように語ってしまいましたが、私がプロジェクトに関わったのは、ここが最初です。すみません。) そこで、まずは目標や目的、想いなどをコアエンジニアのメンバーにヒアリングさせていただきました。 そこででてきたのがこのような想い。 (すでにまとめられていました) テックブログのVision アウトプットカルチャーをリード テックブログのMission 業務で得た知識を発信する事で理解を深め、世界へ還元する事でテクノロジーの発展に寄与する テックブログのValues 組織の枠を越えたネットワーク構築 情報発信の壁を取り除きアウトプット力強化 文化を醸造する事で採用力を高めエンゲージメント向上 また、KINTOテクノロジーズのメンバーの「舞台裏」を「表舞台」にという想いも。 上述のテックブログのVisionやMissionなどの想いを元に、柔らかくお話しをしながら、造形のヒントとなるキーワードを抽出していきました。 (個人的に、柔らかさは、忌憚のない意見交換に重要だと思っています) このキーワード、方向性を元に社内のデザイナーにラフを作ってもらいます。 (実際のロゴも自分で作るわけではなく、デザイナーと対話しながら詰めていき、実際手を動かして作るのは、デザイナーさんです。) 初回のロゴのラフ案 全体は上述で抽出した方向性をとらえつつ、各案で、それぞれ押し出したいポイントの割合を変えて作っていきます。この時に、より、いろんな使用シーンでの見え方も含めて選んだ方がいいので、PCで表示の場合、スマートフォンで表示の場合、バナーで表示の場合など、いろんな表示場所にロゴを入れたものもセットでつくります。 (違うところで使おうとすると、どうしてもうまくはまらない。なんかぴったりはまってない。ということを後々感じることが極力ないように。) プロジェクトメンバーに見てもらう テックブログのコンセプトを元に、方向性ごとに数案作成し、プロジェクトメンバーからリクエストや感想を引き出し、いいね!というリアクションがもらえれば、よりコンセプトに合う案を絞っていきます。ここで、ん、みたいな空気になると、求めていた期待とギャップがあるということになり、その差を話しながら埋めていく作業まで戻ります。2マス戻るやふり出しに戻るみたいな感じです。)また、ミーティング中にみんなから意見が出たものは、その場でデザインを調整しつつ、タイムリーに意見をデザインに反映しながら方向性を絞っていけたのも良かったです。 大枠の案や方向性が決まり、ここから、決まった案の細部を調整していくブラッシュアップ作業に入っていきます。細かいズレ、バランス、などで受ける印象が結構違ったりするので、地道に詰めていきます。方法は、基準をまず作り、地道にちょっとずつ変化させたパターンを並べて、ベストを探っていくみたいなやり方です。 よし、バランス良いな!他も試してこのバランスがいいなとなったら、使い道に合わせた形状や色のパターンを作っていきます。 最終的に、できたのがこちらです。 (実制作は社内のデザイナーさんです) はめて完成 あとは、実際のテックブログにはめていただき、問題なければ完成です! ガイドラインにまとめる 間違った使われ方がされないように、ルールを決めて、ガイドラインを作成します。「ロゴ周りの余白はこの位確保してね。」とか、「変形や装飾などで違う印象を見る人に与えないようにしてね。」など細かく定義していきます。 終わりに こんな感じで、想いを同じにした仲間たちと一緒により良い形を模索しながら進んでいます。テックブログを読んでいただき、私たちの思っていることや、やっていること、に興味を持っていただけましたら幸いです。それでは、またの機会に。
アバター
はじめに こんにちは。KINTOテクノロジーズでバックエンドを担当している森本です。 KINTO ONE開発グループに所属しています。Javaをメインに利用してKINTO ONEの開発をしています。今回は業務とは別に実施しているGraphQLの勉強会について紹介させていただきます。 GraphQLとは GraphQLとはクエリ言語の一つです。SQLのような他の言語とは異なり、特定のデータストアに限らず複数のデータソースとデータをやりとりすることができます。 バックエンド側でスキーマを定義しておけば、フロントエンド側はその定義に従って自由にオブジェクト内の項目を取得することができます。REST APIとは異なり、フロントエンドがバックエンドから返却してほしい情報を柔軟に指定できます。利用しない情報を無駄に取得する必要がなくなり、またネスト構造になっているオブジェクトを取得するために複数回APIを呼ぶ必要もなくなります。 勉強会の目的 勉強会の目的は以下の2つです。 技術力をアップしたい グループを超えて交流したい 技術力をアップしたい 普段の業務で利用している技術とは別に新しい情報をキャッチアップしたいが、ハードルが高いとメンバーそれぞれが感じていました。例えば言語の知識が足りないことが挙げられます。今回のGraphQLのチュートリアルではTypeScriptが利用されていました。そのため、GraphQLを学ぶ前にまずTypeScriptを学ぶ必要がありました。知識や経験が異なるもの同士で補うことで、このような課題をクリアして学習のコストを下げることができます。 グループを超えて交流したい 所属するグループ、チーム、プロジェクトがそれぞれ異なる年齢の近いメンバー同士が交流するきっかけにしたいという思いもありました。既にお互いを認知している仲の良いメンバー同士ではありますが、定期的に集まることでより仲良くなろうという魂胆です。また勉強会を通してお互いの持っている新たな一面を知ることができる機会になるとも考えました。 実施内容 なぜGraphQLか バックエンドでAPIを普段実装しているメンバーは、要件が発生するたびAPIを作成する必要があることに悩みを抱えていました。もちろんサーバー側で処理を行った方が実行速度が速いものはありますが、情報をそのまま返却するAPIを増やしていくのは面倒だと感じていました。そこでGraphQLが解決策として良さそうだという話を聞き、ぜひ試したいと常々思っていました。 また既にGraphQLを利用したことがあるメンバーもいましたが、全体の処理の流れを把握したいという思いがあり、GraphQLを学習することにしました。 勉強会に利用したチュートリアル GraphQLのライブラリにはApollo GraphQLを選び、チュートリアルは以下リンク先のものを使用しました。 GraphQL Tutorials 理由としては、チュートリアルの量が充実しており、入門編として適切だと感じたためです。また勉強会メンバー内に業務でApollo GraphQLを利用したことがある人がいたため、既に社内で実績があると判断したためです。 勉強会の概要 日時 週に1回、18時以降でメンバーの時間が揃うところで実施しました。 メンバー メンバーは25歳から28歳までの若手8人です。それぞれ所属が異なり、Webアプリのフロントエンド・バックエンド、またモバイルアプリのフロントエンド・バックエンドと多様な経験を持つメンバーが集まりました。 実施した範囲 チュートリアルのLift-off IからVまでの全5章を実施しました。GraphQLを実装するにあたり、基本的な事項が記載されています。 形式と工夫した点 勉強会では以下の流れで実施しました。 もくもく会でチュートリアル実施 チュートリアルの内容を発表形式でアウトプットして知識定着 初めはいわゆるもくもく会を実施しました。もくもく会とは、集まったメンバーがそれぞれ黙々と作業・学習をする勉強会のことを指します。 Apollo GraphQLを利用したことのあるメンバーもいると記載しましたが、それでも処理の全体像を把握しているメンバーはいませんでした。そのため、まずはそれぞれが同じチュートリアルを実施し、分からないことが出てきたタイミングで話し合いをして解決する、という流れで実施しました。 しかし本当に理解できているか怪しく、このまま先に進むよりはまずは復習するべき、との意見が出ました。そこで同じチュートリアルを持ち回りで発表し合うことにしました。 発表形式では、発表者はチュートリアルを一言一句理解する必要がありました。もくもく会ではなんとなく進んでいた箇所も、あらためて読み直すと答えが書いてあったということもありました。発表の際には質問ができたり、ソースコードを変更して試してみたり、1人では見つけられなかった新たな気づきもありました。 勉強会の様子。手前には勉強会用に用意したサンドイッチが写っています。 さいごに まずはGraphQLについて深く理解できました。それぞれが持っている知識・経験を使ってお互いを補い合うことで、1人よりも速く・確実に進められました。また学習を共にする仲間がいることで、挫折しそうなときも諦めずに続けられました。 今後はApollo GraphQLのチュートリアルの残っている章を進めたり、さらに新しい技術事項を取り上げて学んでいったりする予定です。 また、何らかのアプリケーションを作ってみたいという話も上がっています。それぞれがトライしてみたい言語やフレームワーク、アーキテクチャを利用してみて、さらに技術力向上に努めていきたいと思います。
アバター
About me I am Bharath from Global KINTO. I am a part of Global KINTO ID Platform team and product engagement team. I have also been supporting ad hoc projects like TechPortal and UserPool management screen. I am well versed in OIDC and AWS Cognito. Feel free to reach me anytime at bharath.tv@kinto-technologies.com if you would like to discuss these. I am always excited to talk about ID. About today's topic In order to create contact points with overseas group companies, cultivate the ability to play an active role in the global arena, and further evolve as a global technology company, KINTO Technologies (hereinafter referred to as KTC) participated in the global hackathon "toyotaswarm" hosted by Toyota Motor North America (hereinafter referred to as TMNA) on July 2022. Since I participated in this event from Japan remotely as well, today I'd like to share what we did for this event. Regarding TMNA “SWARM“ Hackathon The second year of this initiative was held over three days from July 27 to 29, 2022, with a total of 270 participants in 40 teams from Toyota Group companies around the world. There were 3 challenges announced this year. #1 Safety #2 Innovate to Carbon Neutral #3 Open Global Technology Innovation Since we thought digital identity is a major challenge and my team has been working on this topic so far, we were selected to participate in the hackathon this year. Idea from our team We at Global KINTO, are focused on making it all easy and simple for the end user to access our mobility services. Our Global KINTO App, aims to be the single app that connects all KINTO services. My team, Global KINTO ID aims to make it easy for end users to access any KINTO service across the globe by registering only once. So the problem we wanted to address in the hackathon also was a similar one. How an end user can share their information across services hassle-free. It doesn’t make sense when a user has to share their name and other details repeatedly to start using a different service. We decided to do a PoC (proof of concept) of a service that can share user information with other services upon consent from the user. About our team Due to visa restrictions, we only have 3 members who participated in the event at Dallas (HQ of TMNA in Texas, US) and the remaining members supported the activity from Japan remotely. Onsite team: Captain: Feng Xu (Group manager) PdM: Dai Sasaki FE: Alex Remote team: FE: Chris.L BE: Bharath During the hackathon We got all warmed up in a few days, and finalized our concept and how to achieve it. Finally, even though we only had 3 members onsite, that didn’t stop us from going forward. We brushed up the idea with the team and built 9 screens, 11 APIs, including many AWS components and over 1100 LoC (Lines of Code). The event started upbeat when the Olympic gold medal winner, Erin Jackson joined us in the event. This is the closest we would have ever gotten to a Olympic medal. The teams were given separate tables to start working on their concepts. It was nice to see all the hyped-up teams get into action. Meanwhile, my team had a tough time getting work done due to a few of us working offsite in a different time zone. It was quite clear what actions each of us should do but we have to integrate everything to come up with the working model. Typical problems like connecting our server to a different IP address or working with AWS CDN in a different region happened but overall things went well. As a result, we cleared round 1. Since only half the teams would pass round 2, it was stressful. We did our best but unfortunately that we didn't pass round 2. What impressed me here was the high degree of perfection of the other teams' ideas. As an example, the idea of prevention of drunken driving and the idea of reducing carbon emissions passed round 2. For both of these, they do not only have a software part, but they also had an embedded solution proposal which included both software and hardware. What we learned from participating TMNA senior management was around the hackathon the whole day, anyone can easily talk with them if they wanted. It was a great opportunity to get close to them and understand their thoughts directly. The people who came from other countries were very open and kind to connect with us. It was a perfect opportunity to make connections between several different organizations which hopefully creates some synergy. Since this event is going to be a regular event from now, we are looking forward to participating in it next time as well and bringing more value for Toyota and the whole world through this activity.
アバター
はじめに こんにちは、KINTOテクノロジーズでコーポレートエンジニアをしている及川です。 今回は、KINTOテクノロジーズのIT管理チーム(情シス)ではどのような環境やチームの活動基準で仕事をしていて、何を目指しているのかについて書きたいと思います。 目次 IT管理チームの業務内容や雰囲気 IT管理チームが挑戦したいこと IT管理チームが目指す姿 IT管理チームの業務内容や雰囲気 IT管理チームは幅広い社内業務システムを担当していて、ロケーション的にも遠隔の複数拠点(東京2拠点・名古屋・大阪)で業務をするため自律的に活動していく必要があります。 各拠点のエンジニアが非エンジニアリング業務に割く時間をカットして、エンジニアリングに集中できる時間や環境を提供するために、各拠点にIT管理チームのメンバーを配置しています。 チーム内で前提となる活動基準に合意して、同じ価値を目指して日々業務に取り組んでいるのですが、その活動基準をまとめると以下になります。 Mission ㅤㅤ従業員(社員、パートナー)を中心として、仲間を尊重し、​利便性と ㅤㅤセキュリティーを追求して会社の発展に寄与する。​ Value ㅤㅤ自律​ ㅤㅤㅤㅤ目的​、品質​、プロセス ㅤㅤ協調​ ㅤㅤㅤㅤ相互尊重​、情報共有​、スキルの平準化​ ㅤㅤレスポンス​ ㅤㅤㅤㅤ従業員目線​、素早さ​、正確性​ IT管理チームの立ち位置は、 生活基盤インフラ(電気・水)をイメージして、従業員から頼られる必然の存在を目指す=エンジニアがエンジニアリング以外に時間を取られない環境整備 ために、開発環境をITの側面から支えていくことがIT管理チームの大切な役割となります。 社内システム(SaaS)環境再構築、ゼロトラスト推進、自動化、効率化といった軸で業務を進めて従業員の利便性とセキュリティーを高めつつ、全体最適化を実現するためのソリューションやシステムを導入するプロジェクト業務を実施しています。 日常的なオペレーション業務も実施していて、サービスデスクやオンボーディング、アカウント作成/削除、PCキッティング、PC/スマートフォンやモニターなどのIT備品等の調達・管理といった業務があります。 プロジェクト業務とオペレーション業務の両輪を上手く回転させながらバランスを取りつつ、開発スピードを上げるために必要なことをチーム一丸となって実施しています。 IT管理チームが挑戦したいこと 一年間で従業員が100名以上増え、急成長しているフェーズのため、IT管理チームに求められるスキルセットも変化してきたことにより、上記で書いた、IT管理チームの活動基準、Valueに同意してプロジェクトとオペレーションの2つを実行できるコーポレートエンジニアにJoinしてもらいました。 今ではIT管理チーム内に5つのミニチームがあり、臨機応変かつスピード感のあるスキルを持ったメンバーで業務を推進しています。 なお急速に従業員が増え続ける状況でも、従業員が開発に集中できる環境を構築するため、システムの再設計、ルール構築や変更を実施しています。 KINTOテクノロジーズではWindows、Macの2種類からPCを選択可能ですし、社内システム(SaaS)についても多数活用しているという多種多様な環境です。 多様な環境下でも開発スピードを落とさないことを前提に、適切なシステム環境を実現するため、現状の設計を見直してスピード感を持って最適化を実施しています。 スピード感も必要ですが、環境変更に伴うメリットやデメリットをしっかり把握しチーム内レビューで効果を見極めた上で本番環境へリリースします。本番環境リリース後のレビューもしっかり行い、反省点など次回に活かすことも目的にチーム内プロセスも重要視しながらスキルやノウハウの平準化も進めています。 新しい価値や要望に応えるため現在の使い勝手や内容に満足せず、自分たちで能動的に要望やトレンドをキャッチアップしてシステムやルールをブラッシュアップしています。 IT管理チームが目指す姿 上記で書かせていただいた気持ちの根底は、IT管理チームのやりたいことだけを実現したいという気持ちでは無く、従業員の皆さんをサポートする・したいという気持ちを持ってそれをITで実現することです。 従業員の皆さんに近い運用(現場)にこそ改善のヒントがあり、最上級であるべきだと考えに基づいて、各ミニチームにも様々な運用を担当してもらっています。 その運用業務の中から出てくる改善要望を深堀して、設計やソリューションに当てはめて開発現場が集中できる環境を能動的に創出できるようなチームを目指しています。 私自身、コーポレートエンジニアキャリアの経験はほとんどありませんでしたが、ITで現場環境を改善することや技術には興味がありました。 つまり、バックヤードは様々でも、上記視点やマインドがあればコーポレートエンジニアのキャリアは築けると思います。 従業員に頼りにされる、オープンなIT管理チームを目指して業務に精励していきたいと思います。
アバター
Hello, My name is Shweta Oza. I joined KINTO in April 2022 at the Global Development Group. I am an application developer who has recently gained interest in DevOps. I am currently working in the Coupon Team. Our team develops and maintains Coupon APIs for customers/ merchants all over the world. There are many features that are being continuously developed and deployed. For any project it is important to maintain the databases, including data backup and rollback. This way, if anything goes wrong when releasing a new version, you can safely rollback the changes and restore the backup. As an open-source database migration tool, our company uses solutions such as Flyway. Flyway strongly favors simplicity and convention over configuration. It is based around just 7 basic commands: Migrate, Clean, Info, Validate, Undo, Baseline and Repair. Below are a few concepts and simplified procedures about how to back up the database manually using a script. Overview Coupon System is a tool that easily issues and manages coupons that can be used for KINTO services or other partner services. The coupon system is in continuous development to improve and upgrade with new functionalities. With every new change, it is necessary to manage the databases that the coupon system uses; which plays a key role in any software project. In our case, we use MySQL . In coupon, whenever we have any new release the steps we follow are: Get the functionalities developed. Test them locally and then on AWS test environments. Take a backup of the DB before release. Release the new functionalities. If any issues, roll back to the previous version of the release. In order to achieve these we have backup and rollback scripts to reduce the number of instructions to follow in CLI. This saves time and maintains consistency of structure for backups or rollbacks. Let's learn some basics What is a database backup? A database backup is a copy of data that is stored on a server. What is the purpose of a database backup? Backups are used to prevent unexpected data loss. In an event of failure, if the original data gets lost or corrupted, with the help of a backup, it is easy to restore the data again. What are the types of database backup? Physical backup ^1 Physical database backups are backups of physical files that are used to store and recover databases. These include different data files, control files, archived redo logs, and many more. Typically, physical backup data is kept in the cloud, offline storage, magnetic tape, or on a disc. There are two methods to perform a physical backup : Operating system utilities Recovery manager Advantages: Total control of the data. Storage cost is cheaper. Speedy process retrieving backed up data. Disadvantages: Stored data in any device can get corrupted making it hard to recover data. Data can be ruined by natural disasters. Loss of storage devices. Logical backup ^2 Logical backups contains logical data which is retrieved from the database. It contains a view, procedure, function, and table. This is useful when users want to restore or transfer a copy of the database to a different location. Logical backups are not as secure as physical backups in preventing data loss. It only provides structural details. Every week, complete logical backups should be performed. Logical backups are used as a supplement to a physical backup. Advantages: Useful when the user needs to restore the complete database to a previous instance. It is more complex and provides granular recovery capabilities. Disadvantages: Critical for recovery of special components. Less secure compared to physical backup. It only provides structural details. We are going to see all about Logical Database backups in both local and in AWS CLI. Because it is an important step with reference to a developers' perspective to operate with data in DB. To manage Amazon RDS(Relational database service) using AWS CLI Amazon RDS [^3] [^3]: https://aws.amazon.com/rds/ It is a service that can safely use RDB on the cloud without setting up a server. Amazon RDS supports MySQL, MariaDB, PostgreSQL which are open source and widely used, Oracle Database and microsoft SQL server. Pay for only what you use. Amazon CLI [^4] [^4]: https://aws.amazon.com/cli/ The AWS CLI is an integrated tool for managing AWS services that you run from a terminal on Linux or macOS or a command prompt on Windows. Basically, commands are entered and executed from a dedicated tool, but they can also be used to automate processes by writing them in scripts. One thing to keep in mind when managing Amazon RDS from the AWS CLI is that executing a command may not always be reflected immediately. This is because Amazon RDS has a number of failure countermeasures, and it takes time for the settings to be reflected in all of them. Same we will be writing simple scripts for executing tasks of Backups and Rollbacks easily on different environments. How exactly can we take Backups and Rollback DB from CLI at developer's level? Using mysqldump in SQL Format What is mysqldump [^5] [^5]: https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html The mysqldump client is a logical backup program originally written by Igor Romanenko. Database and is usually in the form of a list of SQL statements ("SQL dump") for backup or transfer to another database server (not necessarily MariaDB or MySQL). The dump typically contains SQL statements to create the table, populate it, or both. Using a dump file What is a dump file [^6] [^6]: https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html A dump file is also useful when you upgrade from one release to the next. You can dump a database using an older release and load it under a new release as part of the upgrade process. QUICK HIGHLIGHTS To take DB Dump with data (i.e. both DDL & DML) mysqldump -u root -p DB_Name > backup.sql # AWS CLI mysqldump -u $user -p$password -h $rds_endpoint > backup.dump To take DB Dump without data (i.e. only DDL) mysqldump -d -u root -p DB_Name > backup.sql # AWS CLI mysqldump -d -u $user -p$password -h $rds_endpoint > backup.dump To Roll Back to previous version mysql -u root -p DB_Name < backup.dump # AWS CLI mysql -u $user -p$password -h $rds_endpoint < backup.dump SCRIPT for Backup Things you will need to edit in script before using directly: pathToParameterStoreKeyValueMYSQL_USER pathToParameterStoreKeyValueMYSQL_PASSWORD pathToParameterStoreKeyValueRDS_ENDPOINT DB_Name ######################################################################### ######################################################################### ##### ##### Description: Shell Script to take backup of existing data AWS ##### 1. Choose the env and switch the db connection ##### 2. Create backup directory with today's date ##### 3. Create dump file to backup folder with current db ##### 4. Check dump file size ##### ######################################################################### ######################################################################### read -p "Enter Your Env(env): " x echo "Welcome to ${x} Env!" # MySQL server credentials MYSQL_USER=$(aws ssm get-parameter --with-decryption --name /${x}/pathToParameterStoreKeyValueMYSQL_USER | jq -r .Parameter.Value) MYSQL_PASSWORD=$(aws ssm get-parameter --with-decryption --name /${x}/pathToParameterStoreKeyValueMYSQL_PASSWORD | jq -r .Parameter.Value) RDS_ENDPOINT=$(aws ssm get-parameter --with-decryption --name /${x}/pathToParameterStoreKeyValueRDS_ENDPOINT | jq -r .Parameter.Value) # Set the folder name with date format(eg: 2022-08-15) DATE_FORMAT=$(date +"%Y-%m-%d") TIMESTAMP=$(date +%H%M%s) # Path to local backup directory BACKUP_DIR="tmp/release/backup/${x}/dbbackup/${DATE_FORMAT}" # Use database's names DB="DB_Name" echo "########################################DATABASE########################################" echo "Using Database (DB_Name)" echo "########################################DATABASE########################################" # Create backup directory with today's date mkdir -p ${BACKUP_DIR} FILENAME_PREFIX="backup_${x}_DDL_DML_${TIMESTAMP}_" FILENAME_POSTFIX=".dump" read -p "Enter version eg: v0.0.1: " d FILENAME=$FILENAME_PREFIX${d}$FILENAME_POSTFIX echo "########################################FILEPATH########################################" echo "Created directory" ${BACKUP_DIR} echo "File will be saved as ${FILENAME} " mysqldump -u $MYSQL_USER -p$MYSQL_PASSWORD -h $RDS_ENDPOINT --databases $DB > ${BACKUP_DIR}/${FILENAME} echo "File saved at ${BACKUP_DIR}/${FILENAME}" echo "########################################FILESPATH########################################" # check File size file=${BACKUP_DIR}/${FILENAME} filesize=$(ls -lh $file ) echo "########################################FILESIZE########################################" echo "$file has a size of $filesize" echo "########################################FILESIZE########################################" Procedure for taking backup Place the shell script in AWS CLI Login to AWS Click AWS management console → AWS Systems Manager → Session Manager→ Click Start session Enter the env you want to take backup eg: {env}-{project_name}-{maintenance_server_name} Start session Check if dbbackupDDL_DML.sh file is present If file is not present place dbbackupDDL_DML.sh file in AWS CLI To execute file sh-4.2$ ls dbbackupDDL_DML.sh mysql.sh tmp sh-4.2$ sh dbbackupDDL_DML.sh Enter Your Env(env): env Welcome to env Env! ########################################DATABASE######################################## Using Database (db_name) ########################################DATABASE######################################## Enter version eg: v0.0.1: v0.0.1 ########################################FILEPATH######################################## Created directory tmp/release/backup/env/dbbackup/2022-08-12 File will be saved as backup_env_DDL_DML_06311660285870_v0.0.1.dump mysqldump: [Warning] Using a password on the command line interface can be insecure. Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions, even those that changed suppressed parts of the database. If you don't want to restore GTIDs, pass --set-gtid-purged=OFF. To make a complete dump, pass --all-databases --triggers --routines --events. File saved at tmp/release/backup/env/dbbackup/2022-08-12/backup_env_DDL_DML_06311660285870_v0.0.1.dump ########################################FILESPATH######################################## #######################################FILESIZE######################################## tmp/release/backup/env/dbbackup/2022-08-12/backup_env_DDL_DML_06311660285870_v0.0.1.dump has a size of -rw-r--r-- 1 ssm-user ssm-user 1.7M Aug 12 06:31 tmp/release/backup/env/dbbackup/2022-08-12/backup_env_DDL_DML_06311660285870_v0.0.1.dump ########################################FILESIZE######################################## sh-4.2$ To check the content of dump file sh-4.2$ less tmp/release/backup/env/dbbackup/2022-08-12/backup_env_DDL_DML_06311660285870_v0.0.1.dump sh-4.2$ Backup will be taken into folder with tmp/release/backup/env/dbbackup/{currentDate}/{FileNameWithTimestamp&Version} If you want to take dump multiple times in a day in individual date folder you will have the file with timestamp. sh-4.2$ cd tmp/release/backup/env/dbbackup/ sh-4.2$ ls 2022-08-09 2022-08-10 2022-08-12 sh-4.2$ cd tmp/release/backup/env/dbbackup/2022-08-12/ sh-4.2$ ls backup_env_DDL_DML_06311660285870_v0.0.1.dump backup_env_DDL_DML_06371660286257_v0.0.1.dump sh-4.2$ SCRIPT for Rollback Things you will need to edit in script before using directly: pathToParameterStoreKeyValueMYSQL_USER pathToParameterStoreKeyValueMYSQL_PASSWORD pathToParameterStoreKeyValueRDS_ENDPOINT DB_Name ######################################################################### ######################################################################### ##### ##### Description: Shell Script to rollback to target SQL ##### 1. Choose the env and switch the db connection ##### 2. Create rollback directory with today's date ##### 3. Choose and input the backup file ##### 4. Input the version of dump file ##### 5. Copy backup dump file to ROLLBACK folder ##### 6. Create dump file to ROLLBACK folder with current db ##### 7. Rollback db with backup dump file ##### 8. Comparison.... ##### ######################################################################### ######################################################################### read -p "Enter Your Env(env): " x echo "Welcome to ${x} Env!" # MySQL server credentials MYSQL_USER=$(aws ssm get-parameter --with-decryption --name /${x}/pathToParameterStoreKeyValueMYSQL_USER | jq -r .Parameter.Value) MYSQL_PASSWORD=$(aws ssm get-parameter --with-decryption --name /${x}/pathToParameterStoreKeyValueMYSQL_PASSWORD | jq -r .Parameter.Value) RDS_ENDPOINT=$(aws ssm get-parameter --with-decryption --name /${x}/pathToParameterStoreKeyValueRDS_ENDPOINT | jq -r .Parameter.Value) # Set the folder name with date format(eg: 2022-08-15) DATE_FORMAT=$(date +"%Y-%m-%d") TIMESTAMP=$(date +%H%M%s) # Path to local rollback directory history ROLLBACK_DIR="tmp/release/rollback/${x}/dbRollback/${DATE_FORMAT}" # Use database's names DB="DB_Name" echo "########################################DATABASE########################################" echo "Using Database (DB_Name)" echo "########################################DATABASE########################################" # Create rollback directory with today's date mkdir -p ${ROLLBACK_DIR} read -p "Enter full dumpFile Path to which you want to rollback: " df echo "dumpFile ${df} selected!" FILENAME_ROLLBACK_PREFIX="rollback_${x}_DDL_DML_${TIMESTAMP}_" FILENAME_BACKUP_PREFIX="backup_${x}_DDL_DML_${TIMESTAMP}_" FILENAME_POSTFIX=".dump" read -p "Enter version eg: v0.0.1: " d FILENAME_ROLLBACK=FILENAME_ROLLBACK_PREFIX${d}$FILENAME_POSTFIX FILENAME_BACKUP=FILENAME_BACKUP_PREFIX${d}$FILENAME_POSTFIX echo "########################################FILEPATH########################################" echo "Created directory" ${ROLLBACK_DIR} # copy dump file to backup folder cp ${df} ${ROLLBACK_DIR}/${FILENAME_ROLLBACK} ROLLBACK_FILE=${ROLLBACK_DIR}/${FILENAME_ROLLBACK} BEFORE_ROLLBACK_DUMP=${ROLLBACK_DIR}/"BeforeRollback_${FILENAME_BACKUP}" AFTER_ROLLBACK_DUMP=${ROLLBACK_DIR}/"AfterRollback_${FILENAME_BACKUP}" mysqldump -u $MYSQL_USER -p$MYSQL_PASSWORD -h $RDS_ENDPOINT --databases $DB > ${BEFORE_ROLLBACK_DUMP} echo "Dump Before Rollback ${BEFORE_ROLLBACK_DUMP}" echo "Rollback to DDL_DML of sql file located at ${ROLLBACK_FILE} " mysql -u $MYSQL_USER -p$MYSQL_PASSWORD -h $RDS_ENDPOINT --databases $DB < ${ROLLBACK_FILE} echo "Rollback successfully done with ${ROLLBACK_FILE}" mysqldump -u $MYSQL_USER -p$MYSQL_PASSWORD -h $RDS_ENDPOINT --databases $DB > ${AFTER_ROLLBACK_DUMP} echo "Dump After Rollback ${AFTER_ROLLBACK_DUMP}" echo "########################################FILESPATH########################################" # check File size before Rollback fileBeforeRollback=${ROLLBACK_DIR}/${BEFORE_ROLLBACK_DUMP} filesizeBeforeRollback=$(ls -lh fileBeforeRollback ) echo "########################################FILESIZE BEFORE ROLLBACK########################################" echo "$fileBeforeRollback has a size of $filesizeBeforeRollback" echo "########################################FILESIZE BEFORE ROLLBACK########################################" # check File size after Rollback fileAfterRollback=${ROLLBACK_DIR}/${AFTER_ROLLBACK_DUMP} filesizeAfterRollback=$(ls -lh fileAfterRollback ) echo "########################################FILESIZE AFTER ROLLBACK########################################" echo "$fileAfterRollback has a size of $filesizeAfterRollback" echo "########################################FILESIZE AFTER ROLLBACK########################################" Footer Procedure for Rollback Place the shell script in AWS CLI Login to AWS Click AWS management console → AWS Systems Manager → Session Manager→ Click Start session Enter the env you want to take rollback eg: {env}-{project_name}-{maintenance_server_name} Start session Check if dbRollbackDDL_DML.sh file is present If file is not present place dbRollbackDDL_DML.sh file in AWS CLI To execute file sh-4.2$ ls dbRollbackDDL_DML.sh mysql.sh tmp sh-4.2$ sh dbRollbackDDL_DML.sh Enter Your Env: env Welcome to env Env! ########################################DATABASE######################################## Using Database (DB_Name) ########################################DATABASE######################################## Enter full dumpFile Path to which you want to rollback: tmp/release/backup/env/dbbackup/2022-08-12 Enter version eg: v0.0.1: v0.0.1 ########################################FILEPATH######################################## Created directory tmp/release/rollback/env/dbRollback/2022-08-13 Dump Before Rollback tmp/release/rollback/env/dbRollback/2022-08-13/BeforeRollback_backup_env_DDL_DML_06311660285870_2022-08-13.dump Rollback to DDL_DML of sql file located at tmp/release/rollback/env/dbRollback/2022-08-13/backup_env_DDL_DML_06311660285870_2022-08-13.dump Rollback successfully done with tmp/release/rollback/env/dbRollback/2022-08-13/backup_env_DDL_DML_06311660285870_2022-08-13.dump Dump After Rollback tmp/release/rollback/env/dbRollback/2022-08-13/AfterRollback_backup_env_DDL_DML_063116602859099_2022-08-13.dump ########################################FILESPATH######################################## ########################################FILESIZE BEFORE ROLLBACK######################################## tmp/release/rollback/env/dbRollback/2022-08-13/BeforeRollback_backup_env_DDL_DML_06311660285870_2022-08-13.dump has a size of -rw-r--r-- 1 ssm-user ssm-user 1.7M Aug 13 06:31 tmp/release/rollback/env/dbRollback/2022-08-13/BeforeRollback_backup_env_DDL_DML_06311660285870_2022-08-13.dump ########################################FILESIZE BEFORE ROLLBACK######################################## ########################################FILESIZE AFTER ROLLBACK######################################## tmp/release/rollback/env/dbRollback/2022-08-13/AfterRollback_backup_env_DDL_DML_063116602859099_2022-08-13.dump has a size of -rw-r--r-- 1 ssm-user ssm-user 1.6M Aug 13 06:31 tmp/release/rollback/env/dbRollback/2022-08-13/AfterRollback_backup_env_DDL_DML_063116602859099_2022-08-13.dump ########################################FILESIZE AFTER ROLLBACK######################################## sh-4.2$ How can you use this in your daily work? You can take quick backups by using script or commands like above to avoid multiple inputs, references to many documents and links for login etc. This will save your time and errors while writing commands by hand. This will provide you systematic and clutter-free folder structure which you can refer whenever you need one. You will need this procedure in case your DB is upgraded, there is data inconsistency, in case you need to release the next version of your system or rollback the data when there is a failure.
アバター
こんにちは こんにちは、KINTOテクノロジーズ CIO室でアシスタントをしてます村山です! 本記事ではオフィスや社員のデスク環境をゆるりとご紹介します( ˘ω˘ ) オフィス紹介 まずはオフィス紹介から。 本社の名古屋オフィスです。 社長小寺さんの強い想いが込められていて、 『ナチュラル』『明るさ』を前面に押し出した内装となっています。 また、小寺さんこだわりポイントの右下の焚火は時間によっては炎がつきます。 オフィスの中心位置にあり、ランチ時にはみんなが集まります! 2つめの拠点は室町オフィスです。 室町オフィスには2フロアあり、東京ジャンクションも併設されています。 撮影にも利用されており、おしゃれなスポットですね! コレド室町2の中に入っているので近くにお店が多くて助かります。 食べたいと思ったもの、なんでもありますヨ。 3つめの拠点は神保町オフィスです。 大きい会議室にプラットフォームGのみなさんがいたので撮らせていただきました。 神保町オフィスは会議室が一番多く人気です。 あと、神保町周辺はランチの価格が安いのもいいですよね  おいしいカレーやさんがたくさん!行く度カレーをたべてます🍛 写真右下は神保町オフィス限定KINTOテクノロジーズロゴ入りの自動販売機です。 4つめの拠点はOsaka Tech Labです。 大阪オフィスではないです。Osaka Tech Labです!(ここ重要) 4月に開設されたばかりでまだ社員の少ない拠点ですが みんなで意見を出し合いTech Labをアップデートし続けています。 写真右下の屋上が開放的で人気です。 心斎橋もランチが安い!粉ものおいしい! 関東出身なので、お好み焼き定食は慣れません・・ デスク環境の紹介 つぎはデスク環境の紹介をします。 仕事のしやすい環境というのは人それぞれで、 無駄がなく機能的であることは”環境が整っている”ことになると思いますが、 それだけじゃないですよね。 という前置きをしておいて・・っと! わたしのデスクです。 大量の応援部隊です。なんと整った環境でしょう・・! 副社長景山さんのデスクにもいます。 たまに一匹転がってたりして、あれ、一匹いなくなった!と探している姿にほっこりします。 みなさんもシルバニアを手にしていただけるとわかると思いますが、母性がわきます。 あれ、気が付いたらシルバニアの布教ブログになってしまいそうなのでここら辺で次のデスクにいきますか。 ![社員からひとこと](/assets/blog/authors/uka/member-02.jpg =450x) キーボードもかっこいい! PCとガンプラを作成するのが好きとのこと。良い趣味! 自宅のデスク環境ではたくさんのガンプラに見守られているようですが、 オフィスにも小さいのを連れてきたようです。 シルバニアひとつあげたら仲間が増えてました。いまではシルバニア布教部の一員です! ![社員からひとこと](/assets/blog/authors/uka/member-03.jpg =450x) こんなこと言ってますが仕事できるひとです。 KINTOテクノロジーズのコミュニティにe-sports部があり、先日もみんなでスプラトゥーンをしました。 IT系の会社なだけあってか、ゲーム好きが多いです。 最近の社内ブームは麻雀です! ![社員からひとこと](/assets/blog/authors/uka/member-04.jpg =450x) わかる。 各オフィスを簡単に行き来できたらいいのにな~とか夢みたいなことはおいといて・・ 用があれば他オフィスにも出張させていただいてますが、 各オフィスそれぞれの良さがあって、どのオフィスで仕事するのもすきです! ![社員からひとこと](/assets/blog/authors/uka/member-05.jpg =450x) 書籍が好きな方も多く、弊社の貸出書籍もたくさんありますが 社員同士で書籍の貸し借りをしているのもよく見られます。 あと、KINTOテクノロジーズにきてからSlackというツールを知ったのですが、 かわいい絵文字がたくさんでゆるーいかんじでコミュニケーションとれて 素晴らしいツールですよね・・! ![社員からひとこと](/assets/blog/authors/uka/member-06.jpg =450x) トリプルディスプレイ、エンジニアっぽい!! 機能的でありつつささやかな癒しもありでステキ環境ですね ここまでくればシルバニアは万人受けということがわかっていただけたでしょうか。 さいごに リモートワークが流行ってるご時世ですが、 出社して好きな環境でみんなとコミュニケーションとりつつ仕事するのが いちばんだなーってわたしは思います( ˘ω˘ ) その上で髪色や服装、デスク環境も自由にさせてもらえて 働きやすい環境で仕事できるので楽しいです! それでは、ここまで読んでいただきありがとうございました!
アバター
はじめに こんにちは。共通サービス開発グループで複数のサービスが利用する決済プラットフォームの開発チーム[^1][^2]に所属している鳥居です。 この記事をご覧の皆さんは、ローカル開発環境の構築時にこんな経験ありませんか?IDE の設定を環境構築手順書に従って構築したが動かなかったり、プロダクト毎に異なるバージョンの SDK をどちらも動く方法を調べてインストールしたりなど、経験ある方は多いのではないかと思います。 ローカル開発環境構築は、新たに入ってきたプロダクト開発メンバーに襲いかかる、面倒な作業のひとつです。 本記事では Visual Studio Code (以下 VS Code)の Dev Container で開発環境の構築と簡略化・共通化をした事例を紹介します。 VS Code の Dev Container とは Dev Container 環境とは VS Code の拡張機能 Dev Containers を使って構築する開発環境で VS Code と Docker が使うことが出来れば利用可能です。(Windows / Mac / Linux) 次の図のように、Dev Container を立ち上げると VS Code から Docker コンテナをフル機能の開発環境として使用できます。 ホストマシンからソースコードをマウントし、VS Code の拡張機能は コンテナ内にインストールされます。 そのためすでに入っているライブラリとの競合の考慮の必要がありません。 例えばホストマシンで開発をする場合、別のプロジェクトの node.js の指定バージョンが違う場合は n package で node.js のバージョン管理、状況に応じてバージョンの切り替えが必要となるかもしれません。 Developing inside a Container より引用 Dev Container 環境の VS Code の設定や拡張機能、インストールするライブラリや起動するサービスなどは devcontainer.json 、 Dockerfile 、 docker-compose.yml に定義することが出来ます。 Dev Container 環境をビルドする際はこれらの設定を利用して自動的に行わるので、別個にインストールするのに比べ大幅に手順が簡略化されます。 環境構築手順書も Dev Container のビルドまでの手順のみとなります。複数人で開発する際の OS の差異の考慮も不要です。 Dev Container 環境構築手順 今回は Create React App で新しい React アプリケーションの構築を目指します。 今回使用した環境 PC: Surface Laptop4 Windows10: 21H2 (WSL2) WSL2: Ubuntu 20.04 VS Code: 1.73.0 前提 VS Code のインストール Docker のインストール (Windows の場合は WSL2 上にインストール) Docker Desktop for Windows/Mac のインストール 1. 拡張機能 - Dev Containers のインストール まずは Workspace としたいディレクトリで VS Code を開きます。 そして VS Code の拡張機能 Dev Containers をインストールします。 Dev Containers が含まれている Remote Development でも OK です。 2. Reopen in Container でセットアップ開始 左下のアイコンをクリックし、画面上部のメニューから Reopen in Container を選択 (Create Dev Container は別のディレクトリに Dev Container を構築してしまいます) 3. 作成したい Dev Container 環境の設定を選択 今回は Ubuntu を選択しました。 4. Docker コンテナイメージのバージョンを選択 5. 追加する機能を選択 今回は React アプリケーションの作成に必要な Node.js (via nvm) and yarn を選択しました。 追加する機能を選択し 🆗 をクリックすると、Dev Container のビルドが開始されます。 6. Dev Container のビルド完了 ビルドが完了すると、自動で Dev Container に接続された VS Code が起動します。 .devcontainer/devcontainer.json というファイルが生成されており、左下の表記が Dev Container となっていることがわかります。 (以前は .devcontainer/Dockerfile も生成されていました。) VS Code 内のターミナルを開き( ctrl + shift + @ )、次のコマンドを実行すると必要なライブラリがインストールされていることがわかります。 $ node -v v18.12.1 $ yarn -v 1.22.19 次に Create React App を実行します。 $ npx create-react-app typesript プロンプトが表示され、このまま構築できることがわかります。 (React アプリケーションの構築と起動確認は本題からそれるため割愛します。) いかがでしょうか。手動で node.js yarn をインストールして create-react-app をしたことがある方には如何に簡略されているかおわかりいただけるかと思います。 次は今回構築した Dev Container 環境をビルドしてみましょう。 既存の Dev Container 環境のビルド 前提 前提条件は環境構築手順と同様とします。 VS Code のインストール Docker のインストール (Windows の場合は WSL2 上にインストール) Docker Desktop for Windows/Mac のインストール 1. Dev Container の Workspace をホストマシンで開く まずはホストマシンの VS Code で先程作成した Workspace を開きます。 * 拡張機能 Dev Containers がインストールされていない場合 拡張機能 Dev Containers がインストールされていない場合は、次の図のように拡張機能のインストールを推奨されるので、表示に従いインストールしてください。 2. Reopen in Container を選択 拡張機能 Dev Containers をインストール済みの場合は、次の図のように Dev Container の設定ファイルがあるので Dev Container で開き直すかを聞かれます。 Reopen in Container を選択すると Dev Container のビルドが開始されます。 2. 環境構築完了! 構築済みの Dev Container 環境をビルドする際は以上だけです。 2 回目以降の起動も同様に Reopen in Container の選択で開くことが出来ます。Windows の場合は次の図のようにタスクバーの VS Code コンテキストメニュー から直接開くことも出来ます。 React アプリケーションの起動を構築完了とする場合は以下のようなコマンドが必要ですが、そちらについての設定は後述いたします。 // node.js packageのインストール $ yarn install このように構築済みの環境構築は非常に少ない手順で構築出来ます。 devcontainer.json のサンプル 次に私の Dev Container の設定の例を紹介します。 VS Code の設定や拡張機能は linter や formatter などを定義しています。 その他開発支援の機能も設定していますので興味がありましたら調べてみてください。 { // Dev Container の名称設定 "name": "test-devcontainer", // コンテナ立ち上げ時のオプションの指定 // --name ビルドするDocker containerの名称の指定 // これを指定しないとランダムに生成される "runArgs": ["--name=test-devcontainer"], // Docker コンテナイメージ "image": "mcr.microsoft.com/devcontainers/base:jammy", // VS Codeの設定 "settings": { "stylelint.validate": ["css", "scss"], "scss.validate": false, "css.validate": false, "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.codeActionsOnSave": { "source.fixAll.eslint": true, "source.fixAll.stylelint": true }, // sticky scrollの設定 "editor.stickyScroll.enabled": true, "editor.stickyScroll.maxLineCount": 5, "workbench.colorCustomizations": { "editorStickyScroll.background": "#00708D", "editorStickyScrollHover.background": "#59A2B5" }, // typescript で絶対パスで import する設定 "typescript.preferences.importModuleSpecifier": "non-relative" }, // 追加する VS Code の拡張機能 "extensions": [ "ms-vscode.live-server", "dbaeumer.vscode-eslint", "stylelint.vscode-stylelint", "Syler.sass-indented", "esbenp.prettier-vscode", "ms-python.python", "streetsidesoftware.code-spell-checker", "naumovs.color-highlight", "burkeholland.simple-react-snippets", "formulahendry.auto-rename-tag", "MariusAlchimavicius.json-to-ts", "dsznajder.es7-react-js-snippets", "styled-components.vscode-styled-components", "Gruntfuggly.todo-tree", "42Crunch.vscode-openapi", "mhutchie.git-graph" ], // コンテナ内の実行ユーザーの設定 (推奨設定) "remoteUser": "vscode", // インストールするライブラリ "features": { "ghcr.io/devcontainers/features/node:1": { "version": "lts" }, "ghcr.io/devcontainers/features/python:1": { "version": "3.9" } }, // Dev Container 作成時に実行するコマンド "postCreateCommand": "sh .devcontainer/post-create.sh" } 先程の構築済み環境で別途 yarn install を実行しなかった件は、 postCreateCommand オプションに定義することで環境構築時に自動で実行できます。 私の場合は別途スクリプトを作成しコンテナ構築後に実行する必要がある一連のコマンドを実行しています。 .devcontainer/post-create.sh #!/usr/bin/env sh # bashのgitコマンド補完の追加 echo 'source /usr/share/bash-completion/completions/git' >> ~/.bashrc # yarn global のpathを通す設定 echo 'export PATH="$HOME/.yarn/bin:$PATH"' >> ~/.bashrc # openapi-generator-cliのインストール yarn global add @openapitools/openapi-generator-cli yarn install 導入してみて感じたメリット・デメリット Dev Container 環境で開発をしていて感じたメリット・デメリットを記載します。 メリット 環境構築の手順が単純化出来る 複数人で開発する際にホストマシンの OS を気にしなくて良い 各種ライブラリ、パッケージの手順が不要 バックエンドの場合 mysql や redis を利用することが多いのでより強力 環境構築を宣言的に定義して、共通化出来るので個人によるばらつきが出ない VS Code の設定や拡張機能も定義できる バージョン違いによる思わぬバグの遭遇が起きない ローカル環境を汚さない、別 Workspace との競合が発生しない デメリット VS Code 以外の IDE を使いたい人の要望に応えられない 好みのターミナルが使えない そこそこのマシンスペックが要求される Zoom の画面共有しながらだと厳しい Windows は WSL2 がなんだかんだ重い Mac はファイル I/O に問題を抱えている devcontainer.json の Named Volume の設定で解決できるようです[^3] さいごに いかがでしたでしょうか。Dev Container の便利さが少しでも伝わっていれば幸いです。 私自身、過去には長い環境構築手順書に沿って環境構築をしていた記憶もあり非常に楽な時代になったなと感じています。 また、実際にモブプロに別プロダクトを担当しているメンバーをゲストに迎えた際もすぐに実装に取り組んでもらうことが出来たので Dev Container の利便性を実感しました。 今後の試行錯誤としては以下のようなことを実践してみたいと考えています。 公式記事を参考に Dev Container のパフォーマンスチューニング Amazon EC2 上に Docker を入れて Remote Development using SSH 経由で Dev Container を利用してみたい 応用で IntelliJ IDEA の Remote Development での開発 GitHub Codespaces 上での環境構築 [^1]: 決済プラットフォームの他の取り組みその1、[ グローバル展開も視野に入れた決済プラットフォームにドメイン駆動設計(DDD)を取り入れた ] [^2]: 決済プラットフォームの他の取り組みその2、[ 入社 1 年未満メンバーだけのチームによる新システム開発をリモートモブプログラミングで成功させた話 ] [^3]: 公式記事 Improve container performance
アバター
自己紹介・記事要約 my route開発Gのグループマネージャーをやっております、岩元です。 KINTO Technologies(以下KTC)の前身であるKINTO開発部立ち上げ時から在籍している最古参開発メンバーでもあります。 今回は、私が担当しているmy route開発Gの紹介をさせていただきます。 my routeとは my route by KINTO (以下my route)とは何かということを一言で言うなら、 トヨタグループのMaaSアプリ です。 MaaSとはモビリティ・アズ・ア・サービスの略であり、直訳すれば「サービスとしてのモビリティ」という意味になります。 「さまざまな形態の輸送サービスを統合した、オンデマンドでアクセス可能な単一のモビリティサービスとしており、MaaSオペレーターは利用者の要求を満たすべく、公共交通、ライドシェア、カーシェア、自動車シェア、タクシー、レンタカーなどさまざまな交通手段のメニューを用意すること」 ※MaaSアライアンスの定義より 簡単に言うなら、「ICTを活用してマイカー以外の移動をシームレスにつなぐ」ということでしょうか。 トヨタグループでは2018年の福岡での実証実験を皮切りに順次エリアを拡大してきています。 そのためのモバイルアプリとして生まれたものがmy routeであり、実証実験開始当時はトヨタ自動車で開始されたプロジェクトです。現在はKINTO親会社のトヨタファイナンシャルサービス社が主管として運営されており、KTCが開発・運用を行なっています。 これまでとこれからと 内製開発化とリニューアル 2018年のmy routeの実証実験開始時はまだKTCどころかKINTOも存在していませんでした。そのため開発・運用は全て委託先パートナー企業に外注されていました。 そのため、KTCが開発携わるようになって最初に取り組んだ事は、なにはともあれ内製化を進めることでした。また、元々が実証実験用に作られたものから建て増しを繰り返して発展してきたという経緯もあり内部構造的にも疲労限界を迎えていたため、アーキテクチャの刷新も喫緊の課題となっていました。 その第一弾として、まずはAPIを提供するバックエンド部分のリニューアルが行われました。これはマイクロサービスアーキテクチャの導入、開発言語の変更、プラットフォームのAWS化などを含む大規模なものであり、委託先パートナー企業からの巻き取りも同時に進めていたためかなり困難なプロジェクトでしたが、2021年の8月に無事リリースを完了させることができました。このリニューアルにより従来の数倍の速度での地域展開が可能となり、現在に至るまで無事に運用を行い、ほぼ完全に開発の内製化も実現できました。 現在進行中プロジェクト そして現在は、バックエンドリニューアル完了から間も無く開始された新プロジェクトを2023年1月のリリースに向けて絶賛開発中です。 詳細についてはまだオープンにはできないのですが、my route開発エンジニア総勢20名ほどが関わった一大プロジェクトになります。 基盤となるアーキテクチャも大幅に刷新されるため非常に大変なプロジェクトでしたが、完成の見えてきた今、プロジェクトメンバー一丸となって開発にあたっています。 my route開発グループについて my route開発グループはmy routeサービスに紐づいたグループですので、最大のミッションは my routeサービスの成長・発展に寄与すること に尽きます。 そのため、事業とワンチームという意識を持って開発・運用を行う人たちが集まっています。 グループ内は主に以下の3チームに分かれています。 バックエンド開発チーム 運用チーム モバイルアプリ開発チーム 現在はモバイルアプリ開発チームは別グループとして独立してしまいましたが、引き続きmy route開発チームの一員として活動しています。 先述のリニューアル関係の開発だけではなく、現行アプリに関しても、日々の運用、地域展開を通して多くの改善要望が寄せられています。これらを事業と相談し、優先度を付けながら開発を進めています。 新しい仲間へ 元々、実証実験の委託開発プロジェクトとして始まったmy routeですが、2023年1月リリースのプロジェクト完了により完全に内製化され、本当にやりたいことができる準備が整います。そういう意味では、2023年はmy routeにとって勝負の年だと考えています。 この記事を読んで興味を持たれた方、是非とも一緒にmy routeを日本一のMaaSアプリとして成長させていきましょう!
アバター
はじめに こんにちは。プラットフォームGでDevOpsエンジニアをしている島村です。 KINTOテクノロジーズのプラットフォームGのDevOpsサポートチーム(とSREチーム)では、CI/CD以外にも、監視ツールの整備やモニタリングツールの改善を実施しています。 プラットフォームGは他にもSystemAdministratorチーム、CCOE、DBREなどがあり、AWSを中心としたインフラの設計・構築運用の他にも会社全体のシステム改善や標準化・最適化を担っています。 その中で、昨年にGAとなったAmazon Managed Service for Prometheus(以降Prometheus)とAmazon Managed Grafana(以降Grafana)とX-Rayを使用したAPMの仕組みを導入しましたので、そのことを記事にしようと思います。 背景 私が入社した2021年5月時点でKINTOテクノロジーズ(当時はKINTO)では、AWSリソース監視・ログ文言の監視を行っていました。ただし、CloudWatchを使用したもので、プラットフォームGが設計・設定を行っていました。 当時はアプリケーション運用としてのメトリクスなどは取得されていませんでした。ログ監視も設定の柔軟性は低く、エラー検知はAWSのメトリクスもしくはログによるものか、外形監視からの通知による受動的な検知と対応が主でした。 よく言われるようなO11yの成熟度からすると「Lv0:計測を始める」もできていない状態です。ただ、プラットフォームG内部では問題と認識していたので、まずは計測を始めようということで、APM+X-Rayを導入することとしました。 O11yの成熟度モデルとかの参考はこちら 要素 APM(Application Performance Management) アプリケーションやシステムの性能を管理・監視すること。アプリケーションパフォーマンス管理とも言い換えられます。アプリケーションやシステムの応答時間や構成要素のパフォーマンスを調査することで、アプリケーション全体の稼働状況を把握し、ボトルネックやシステム障害の要素を素早く把握し、改善に役立てるために使用します。 X-Ray AWSで提供している分散トレーシングの仕組みです。 システム全体におけるサービス間の呼出関係の可視化 特定リクエストにおけるサービス間の呼出関係の可視化 (特定リクエストの処理経路の可視化) システム全体のボトルネックを迅速に特定する 上記のことが可能となります。 タスク(Action) 検討する まずは「Lv0:計測を始める」を満たすことを考えました。実装時には、「Prometheus+Grafana」という前提が提示されており、ちょうどAWSでマネージドサービスとしてプレビューされていたタイミングだったので、そちらを選択しました。 Datadog / Splunk / NewRelic / DynaTraceなど、一般的によく使われているSaaSもありますが、前提条件から検討せずにAWSを使用することとしました。あとから、ここらへんのSaaSを使わなかった理由も分かってきました。その理由だと思うことは後述で。 実装する Prometheus Prometheusへのメトリクス出力については Amazon Managed Service for PrometheusにECSからアプリケーションメトリクスを収集する としてまとめています。2021のKINTO Technologiesのアドベントカレンダーとして作成した記事です。 X-Ray 検討当時のメンバーの資料を引継ぎしまして、 AWS X-Ray SDK for Java をベースとして、ECSタスク定義への取り込みなどを整理し、資料化を行いました。 初期構成 改善する X-Ray SDKのOpenTelemetory化 Java17を使い始めたチームから、X-RayのServiceMapがうまく表示されないという相談がありました。よくよく見ると、 AWS X-Ray SDK for Java はJava8/11には対応を明言していますが、Java17への対応は明言されていません。今は AWSDistro for OpenTelemetry Java が推奨されているようなので、全体的にこちらに切り替えることにしました。APMのCollectorと同居できることも良いことの1つです。 Java aws-observability/aws-otel-java-instrumentation から最新のReleaseのjarファイルをダウンロードし、 src/main/jib 以下に保存するだけで導入ができます。SDK for Javaではサンプリング設定の定義ファイルなどもありましたので、導入が簡素になっている印象です。 ECSタスク定義の環境変数 JAVA_TOOL_OPTIONSにAgentの定義を追加します。OTELの環境変数も追加しています。ECSのタスク定義のjsonを確認すると { "name": "JAVA_TOOL_OPTIONS", "value": "-Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=128m -XX:MetaspaceSize=128m -Xss512k -javaagent:/aws-opentelemetry-agent.jar ~~~~~~" }, { "name": "OTEL_IMR_EXPORT_INTERVAL", "value": "10000" }, { "name": "OTEL_EXPORTER_OTLP_ENDPOINT", "value": "http://localhost:4317" }, { "name": "OTEL_SERVICE_NAME", "value": "sample-traces" } のような形になります。(実際はParameter Storeなどを使うのでちょっと変わりますが) OpenTelemetryColletorのConfig Configuration を参考にしつつ、以下のような形でCollectorのConfigを修正します。 APMとX-Ray両方が入っているかつ、タスクごとにメトリクスにラベルがついている形です。 exporterとして使用している「awsprometheusremotewrite」はAWS-OTEL-COLLECTORのv0.18から非推奨に、v0.21からは機能が除かれており、「PrometheusRemoteWrite」+「Sigv4Auth」を使用するようになってますので、ご注意ください。 receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 awsxray: endpoint: 0.0.0.0:2000 transport: udp prometheus: config: global: scrape_interval: 30s scrape_timeout: 20s scrape_configs: - job_name: "ktc-app-sample" metrics_path: "/actuator/prometheus" static_configs: - targets: [ 0.0.0.0:8081 ] awsecscontainermetrics: collection_interval: 30s processors: batch/traces: timeout: 1s send_batch_size: 50 resourcedetection: detectors: - env - ecs attributes: - cloud.region - aws.ecs.task.arn - aws.ecs.task.family - aws.ecs.task.revision - aws.ecs.launchtype filter: metrics: include: match_type: strict metric_names: - ecs.task.memory.utilized - ecs.task.memory.reserved - ecs.task.cpu.utilized - ecs.task.cpu.reserved - ecs.task.network.rate.rx - ecs.task.network.rate.tx - ecs.task.storage.read_bytes - ecs.task.storage.write_bytes exporters: awsxray: awsprometheusremotewrite: endpoint: [apm endpoint] aws_auth: region: "us-west-2" service: "aps" resource_to_telemetry_conversion: enabled: true logging: loglevel: warn extensions: health_check: service: telemetry: logs: level: info extensions: [health_check] pipelines: traces: receivers: [otlp,awsxray] processors: [batch/traces] exporters: [awsxray] metrics: receivers: [prometheus] processors: [resourcedetection] exporters: [logging, awsprometheusremotewrite] metrics/ecs: receivers: [awsecscontainermetrics] processors: [filter] exporters: [logging, awsprometheusremotewrite] 現行構成 使ってもらう 特に難儀した点です。 「はじめに」に記載した通り、私はプラットフォームGの所属で、ツールを検討して提供しています。いびつな形ではありますが、DevOpsとしてツールなどを全体最適としたかったので、全社横断(横串)で活動するプラットフォームGに所属しています。そのため、 (問題と思っている)プラットフォームG (そこまで問題と認識していない)アプリケーション担当 という状態に陥りました。最近は地道な活動を通じて、必要性を理解をしてもらえて来ていると思います。 SaaSを使わなかった話 ここは個人的な考えです。 特にO11y関連のSaaSってデータ量も多く、総じてお値段がお高くなるイメージがあります。上記の必要性を理解してもらうまで、「使わない」ツールに対して多額の費用を払うというのは、やはり費用対効果を考えると難しいところです。 O11yの成熟度Lv2の積極的対応くらいまで進むと、俯瞰的にボトルネックやパフォーマンスを見たいという要望が出てきて、そこで使用する価値が生まれてくるのではないかと思います。ログやメトリクスとイベントと紐づけたりなど。受動的な対応までなら、ツールが分割されていても、各人のタスク負荷的や量としては許容されるのかなと思っています。 一時的にGrafanaダッシュボートおじさんができるのは仕方がない。ダッシュボートおじさんのコストよりも、SaaSのコストが低くなれば移行していく…はず。 所感 GrafanaもPrometheusもX-Rayも、マネージドサービスであり導入はSaaSほどは簡単ではありませんが、コストという意味では比較的安価で導入できるものです。DevOpsやSRE活動の初期として、O11yを導入するにあたっては、検討する価値はあるのではないでしょうか。 SaaSを使わなかった話にもありましたが、使い始めてからO11yの価値を見て、改善や活動を見直し、コストを比較してから各種SaaSを使い始めるということでも、良い気はしています。 いや、DatadogとかNewRelicのダッシュボードとかHostMapとか、画面上は綺麗に見えますしなんか動いてて監視・モニタリングしている実感を感じますし、見栄えが良いから(`・ω・´)イインジャネ!!と考えるのは、よくわかります。カッコイイもの…
アバター
グローバル開発グループ紹介記事の最終弾として、本日はプロダクト開発チーム、導入開発チーム(導入・DevOps・保守・テスト )、業務エンハンスチームの紹介をいたします。 目次 目次 プロダクト開発チーム はじめに プロダクト開発チームとは メンバーの雰囲気 業務の進め方 これから挑戦したいこと 導入開発チーム 概要 ミッション チームの様子 業務の様子 これからのチャレンジ 業務エンハンスチーム 業務エンハンスチームとミッション 現在取り組んでいること 1言語面での一貫した顧客体験 2グローバルKINTOの社会的責任担保 3グローバル開発グループ全体のポテンシャル底上げ チームの雰囲気 今後挑戦していきたいこと グローバル開発Gで一緒に働く仲間を募集中 プロダクト開発チーム はじめに KINTOテクノロジーズのグローバルKINTO開発グループでアシスタントマネージャーをしている石原です。 本記事ではGlobalグループのプロダクト開発チームの紹介をさせて頂きます。 プロダクト開発チームとは グローバルKINTO開発グループは親会社のトヨタファイナンシャルサービス、海外現地法人、外部パートナー、KINTOテクノロジーズの4社間で進めるKINTOサービスの世界展開を迅速に行えるように、ID、グローバルアプリ、クーポンシステムといったプラットフォーム等を開発しています。 メンバーの雰囲気 ECサイト開発、ソーシャルゲーム開発等多種多様なバックグラウンドを持つメンバーで構成されており、 国籍も様々で中国、インド、フィリピン、ベトナム、フランス、韓国、日本等のメンバーが在籍しています。 コミュニケーションは基本的には日本語がメインですが、英語をメインに使っているチームもあります。 上記の通り様々なスキルを持っているメンバーが集っているので色々な観点での意見がでる事が多く、それぞれの意見を尊重しあう雰囲気です。 業務の進め方 プロダクト毎に開発メンバーをアサインしており、プロダクトマネージャーと共に仕事を進めています。 開発の進め方はチームによって様々ですが、2週間のスプリントでアジャイル開発を行っているチームが多いです。 どういったものを作るのかを決めるのはプロダクトマネージャーの意見だけではなく、エンジニアからも意見を出し合い、より良いプロダクトを作り続けています。 また、プロダクトを成長させる為に様々な技術の取り込みや自分達で必要だと思う仕組みの開発も行っています。 例えば下記のような仕組みを利用しています。 名称 利用プロダクト 導入目的 KMM Global KINTO App iOS・Androidで共通のビジネスロジックを1コードでSDK化する事により、開発効率・テスト効率を促進させる Gatsby Global KINTO Web 高速なWeb Siteを開発する為 マイクロサービスDevelopment Kit(GKMDK) バックエンド、バックオフィス管理画面 サブスクサービス、リースサービスをマイクロサービスで容易に構築する事ができる自社エンジニアによって開発を行った仕組み 認証サービスパッケージ IDプラットフォーム IDサービスを容易に導入する為に作られたパッケージ。Global Login機能(KINTO IDで連携先のサービスの利用が可能な機能)、Social Login機能、Sign up/Sign in機能などIDサービスに必要な機能を持つ自社エンジニアによって開発を行った仕組み KMMやGatsby等の世の中に普及している技術を利用するだけではなく、プロダクトにあった仕組みを自分たちで創り出しています。 例えばマイクロサービスDevelopment Kit(GKMDK)はサブスク、リースサービスを立ち上げる際に短期間でバックエンド及び管理画面の開発を行えるようにする為にエンジニアの発案を基に開発を行っています。 このようにプロダクト開発チームでは決まった要件をただ開発するのではなく、自分で必要だと思う事、良くする為には何が必要かを考え動く自主性・積極性を重要視して業務を行っています。 これから挑戦したいこと 今までは基本機能をメインとして新規開発、改善を行っていましたが、これから世界中に通用するようなプロダクトにアップデートしていきたいと思っています。 導入開発チーム 概要 導入開発チーム(導入チーム、DevOpsチーム、保守チーム、テストチーム)のマネジメントをしている水野です。 私たちは、基盤開発チームで開発したプロダクトを元に各国へグローバルKINTOサービスのIT導入や運用をしています。 表題のチームは多いですが、みなさん各国へKINTOサービスを導入する仲間なので、まとめて紹介します。 ミッション 各チームで細かいミッションは違いますが、共通して3個のミッションがあります。 開発の生産性を上げること 必要としているITサービスを提供すること グローバルKINTOサービスを横展開すること 私たちは、実際にKINTOサービスをカスタマへ提供しようとしている各国KINTO事業者向けにGlobal KINTO AppやKINTO BackOfficeシステムを導入して、各国KINTO事業の迅速な立ち上げに貢献することを目標にしています。 チームの様子 現在、グローバル開発Gの約2割の方が所属しています。 所属メンバーの出身地域は日本、インド、中国、台湾、韓国、ミャンマー、エクアドルなど国際色豊かです。国籍、経歴、文化、年齢が違いますが、それぞれ得意なことを主力に、導入に必要なことは経験が無くてもチャレンジして自分たちの力で開発しています。 まだまだ、勉強中のエンジニアもいますが、周りが手厚くフォローしていて着実に育ってくれています。 また、仕事終わりに出身国のレストランへ食事へ行ったり、スポーツを楽しんだりしている人もいます。 業務の様子 KINTO事業を実施している国は世界中なので、事業者とのコミュニケーションは英語が中心です。 自社内では関係する他のグループとのコミュニケーションは日本語で、自グループ内は英語だったり日本語だったり得意な言語で話しています。 各プロジェクトでは2週間のスプリントでAgile開発を標準にしているチームが多く、パートナーのエンジニアとも活発に意見交換しながら業務を進めています。 それぞれのチーム別に見ると。 チーム 業務内容 導入チーム 現在導入を進めている国の事業メンバーと日々コミュニケーションを取り、ニーズを捉えて必要な機能を導入しています。 DevOpsチーム 各プロジェクトやプロダクトチームのインフラ構築、CICDの構築、運用のサポートを行い、開発の生産性を上げています。 保守チーム 最近発足したチームで、KINTOサービスが稼働している国の事業者の求めに応じて迅速な改善を行っていきます。 テストチーム テスト自動化基盤の構築、将来的にはグループ全体のテストを自動化することを目標に活動しています。 これからのチャレンジ もっと世界にKINTOサービスを展開するため、より迅速なKINTO事業者への貢献が求められていると考えています。 そこで。 旧来の組織やアーキテクチャ・技術に固執せず、生産性を上げる施策を取り続けて世界最速のテックチームになりたい。 特に勉強中も含めた各エンジニアからのボトムアップ提案力を上げて技術力の底上げを行い続けられるチームになりたい。 もっといろいろな経歴を持つ仲間と切磋琢磨していきたい。 これを目指した先により良く、迅速にKINTOサービスを提供できるチームができます。 業務エンハンスチーム 業務エンハンスチームとミッション グローバル開発グループ業務エンハンスチームについて、リーダーの森より紹介いたします。 チームは現在5名のメンバーで構成されていて、ほとんどのメンバーが日本語・英語の両方を話します。 我々はグローバルKINTOビジネスのPublic Relationsとして、以下の3つを提供することをミッションとしています。 言語面での一貫した顧客体験 グローバルKINTOの社会的責任担保 グローバル開発グループ全体のポテンシャル底上げ 現在約60人規模のグローバル開発グループは、社内でも最も大きな組織であり、異なる国籍・カルチャー、経歴を持ったメンバーで構成されています。そんな中、グループ全体を横断したタスクを関係各所を巻き込みながら遂行するのが我々です。 現在取り組んでいること 具体的に我々がどんなタスクをもっているか、先述した3つのミッションに分けてご説明します。 1言語面での一貫した顧客体験 こちらはいわゆるローカライゼーション ^1 の対応となります。 実際に翻訳を行うだけではなく、グループ内で開発しているプロダクトの多言語化の進捗管理やプロセス改善、スタイルガイドの作成など、多言語化に関する全てのタスクを管理しております。 2グローバルKINTOの社会的責任担保 こちらは法務タスクです。関係各社との契約締結や、個人データ保護の対応 ^2 などを担当しております。グローバル開発グループで取り扱う案件は海外案件がほとんどなので、日本の法令のみではなく海外の法令も加味してタスク遂行する必要があります。法務エキスパートではないですが、法務目線を持ちながら、ビジネス・プロダクトの詳細を理解した上で間に立って会話するのが我々です。 3グローバル開発グループ全体のポテンシャル底上げ 冒頭でも記載の通り、国籍・言語・経歴など、多種多様なメンバーが所属しております。その方々が自身の持つ力をストレスなく、最大限に、効果的に発揮できるように環境を整えるのも我々のタスクです。以下がその一例です。 上記はあくまで一例ですが、他にもこのタスクの一環として、12月末にチーム内で”KINTO Global Innovation Days”と題し、社内ハッカソンのようなイベントを実施予定です。この様子は後日、別の記事として公開いたします。 チームの雰囲気 グループ内外様々な業務を広く浅めに多数のタスクを並行してこなしていくことが多いので、チーム内ではコミュニケーションを重視して誰がどのようなタスクを持っているか、工数に無理はないか、などを確認しあっています。「困ったことがあれば業務エンハンスに」と宣言しているので、チーム内でも困ったら常に相談しあえるような雰囲気づくりを心掛けています。 今後挑戦していきたいこと グローバル開発グループはKINTOテクノロジーズ全社でも最大の組織です。 一般的なことですが、コミュニケーションの取り方が難しくなったり、プロセスが複雑になったり、組織が大きくなるにつれて出てくる課題は多々あります。今後組織がさらに拡大した場合にも対応できるよう、各タスクにおいてまずはきちんとプロセスを整備したいです。特にローカライゼーションの部分に関しては今後ビジネスが拡大する上でもプロセスの整備は急務です。 また、コミュニケーションの部分についてはグループ全体のモチベーションを向上できるようなイベントやしかけを今後も企画してまいります。 🔻業務エンハンスチーム主催English Cafeの様子 ※普段はリモートでも対応していますが、写真撮影のタイミングだけ同じ部屋に集まりました。 グローバル開発Gで一緒に働く仲間を募集中 これまで3日連続でグローバル開発Gの紹介をしてまいりました。チームメンバーのインタビューは KINTOテクノロジーズのコーポレートサイト にも掲載しておりますので、ぜひこちらもご覧ください。 KINTOサービスは展開が始まって約2年経ちますが、KINTOサービスを立ち上げたり、リプレイスする国はまだまだこれから出てきます。私たちはこれから各国の期待に応えるため成長できるチームメンバーが必要です。ご興味のある方は 弊社採用サイト からご応募ください!
アバター
自己紹介 グローバル開発グループのBharath (バラト) です。 Global KINTO ID Platformチームとプロダクト・エンゲージメント・チームに所属しています。また、Technology PortalやUserPool管理画面など、アドホックなプロジェクトのサポートも行っています。 OpenID Connect (OIDC)とAWS Cognito関係に詳しいので、これらについてご相談があればいつでもお気軽に bharath.tv@kinto-technologies.com までご連絡ください。IDの話ができるのを楽しみにしております。 ハッカソンのテーマ KINTOテクノロジーズは、海外グループ会社とのコネクションを作ること、グローバルな舞台で活躍する力を養うこと、グローバルテクノロジーカンパニーとしてさらに進化することを目的に、2022年7月、Toyota Motor North America(以下、TMNA)が主催したハッカソン「toyotaswarm」に参加しました。 私も日本からリモートで参加しましたので、今回の記事ではその時の様子をお伝えしたいと思います。 TMNA "SWARM" Hackathonについて 2回目の開催となる今年は、2022年7月27日~29日までの3日間、世界中のトヨタグループ各社から40チーム、総勢270名が参加しました。 今回のチャレンジは以下の3つでした。 #1 Safety(安全) #2 Innovate to Carbon Neutral(カーボンニュートラル) #3 Open Global Technology Innovation (オープンイノベーション) もともと我々は「デジタルアイデンティティー」を大きなチャレンジと捉えており、私のチームは本業でもこれまでこのテーマに取り組んできたので、今回のハッカソンに参加することとなりました。 目指すべき姿 我々グローバル開発グループは、エンドユーザーがいかに簡単にモビリティーサービスを利用できるようにするか、を重視しています。例えば同グループで開発しているGlobal KINTO Appは、すべてのKINTOサービスをつなぐことを目指していますし、私の所属するGlobal KINTO IDチームは、エンドユーザーが一度サインアップするだけで世界中のあらゆるKINTOサービスを簡単に利用できるようにすることを目標としています。このハッカソンで解決したかった課題も同様で、「どのようにしてサービス間でエンドユーザーの情報を簡単に共有するか?」というものです。ユーザーが別のKINTOサービスを利用する度に、氏名等の情報を何度も入力しなければいけないのは効率的ではありません。そこで、ユーザーの同意を取得した上で、ユーザー情報を他のサービスと共有できるサービスのPoC(Proof of Concept)を行うことにしました。 チームについて ビザの問題で、ダラス(USのテキサス州にあるTMNAの本社)現地で参加したメンバーは3名のみで、残りのメンバーは日本からリモートでサポートしました。 現地参加メンバー キャプテン: Feng Xu (グループマネージャー) PdM: Dai Sasaki FE: Alex リモート参加メンバー FE: Chris.L BE: Bharath ハッカソンイベント中: 数日間で準備しコンセプトとその実現方法を決めました。現地には3人だけでしたが、大きな障壁とはなりませんでした。アイデアをチーム内でブラッシュアップし、9画面、11API、多くのAWSコンポーネントと1100以上のLoC (Lines of Code)を構築しました。 イベントの具体的な内容としては、まずオリンピック金メダリストであるエリン・ジャクソン選手が登壇し、オープニングを盛り上げてくれました。オリンピックのメダルを最も近い距離で見た瞬間です。 その後、各チームは別々のテーブルを与えられ、コンセプト作りに取りかかります。気合いの入ったチームが一斉に動き出したのは見ていて気持ちよかったです。一方、我々のチームはオフサイトメンバー数人が異なるタイムゾーンで作業をしていたため、作業完了までは少し苦労しました。各自が遂行すべきタスクは明確でしたが、すべてを合わせてしてワーキングモデルを作り上げなければならなかったので、そこに労力を費やしました。サーバーを異なるIPアドレスに接続したり、異なる地域のAWS CDNと連携したりといったよくある問題が発生しましたが、全体的にはうまく進めることが出来たと思います。 結果、我々はラウンド1をクリアすることができました。ラウンド2を通過するのは全体の半分だけなので、さらに大変でした。我々もベストを尽くしましたが、残念ながらラウンド2を通過することはできませんでした。 印象に残ったのは、他チームのアイデアが、非常に完成度の高いものだったということです。たとえば、飲酒運転防止のアイデアやCO2排出量削減のアイデアがラウンド2を通過しました。この2つのアイデアは、いずれもソフトウェアだけでなく、ソフトとハードの両方を組み込んだソリューションでした。 イベント参加から学んだこと TMNA役員の方々は常にハッカソン会場にいて、誰でも気軽に話しかけられたので、彼らをとても身近に感じることができ、また、彼らの想いをダイレクトに理解できました。私にとって素晴らしい経験でした。また、様々な国から来た参加者たちもとてもオープンで、親切に我々に接してくれ、他の参加企業とのコネクションを作るのにも非常に良い機会でした。このイベントから企業同士の相乗効果が生まれることを期待します。今後も、同イベントは定期的に開催される予定ですので、ぜひ次回も参加して、トヨタそして世界中にさらなる価値を提供したいです。
アバター
グローバル開発グループ紹介記事の第2弾として、本日はPdMチームとUIUXチームの紹介をいたします。 目次 目次 PdMチーム はじめに PdMチームの役割 メンバーの経歴 手がけているプロダクト KINTOで働くことの難しさと醍醐味 UIUXチーム ミッション Design System Global KINTO App 課題と今後 PdMチーム はじめに グローバル開発グループの佐々木と申します。担当プロダクトのProduct Manager(以下PdM)をやりつつ、PdMが所属するPdMチームのマネジメントもしている私から、チーム紹介をさせて頂きます。 PdMチームの役割 PdMチームは、海外の各KINTOサービスを支えるプロダクトの開発ライフサイクルの中で、各国へどのようなものを提供すべきかに関するプロダクト企画を行っています。もっと具体的に言うと、各国のニーズを確認し、各種リサーチ結果に基づいて、解決すべきペインそして提供すべき価値を特定してプロダクトのあるべき姿を描く。そのうえで、それを実現していくロードマップを策定してプロダクト開発を推進していく役割を担っています。 メンバーの経歴 KINTOはモビリティサービスを提供するブランドなので、PdMチームもその領域の経験者が揃っていると思われがちなのですが、実はそんなことはありません。結構多様なバックグラウンドを持つ人達で構成されているんです。例えば、日本の大手テック企業出身の人、新聞を中心としたメディア企業でPdMだった人、中国大手テック企業にいた人、金融業界の経歴がすごく長い人など、いろいろな経歴やスペシャリティを持つ人が、まだ歴史の浅いモビリティーサービスという領域へ強い興味を持ち、KINTOテクノロジーズへジョインしてくれました。 手がけているプロダクト グローバル開発グループでは複数のプロダクトを開発していますが、どんなプロダクトなのか、1つ実例を紹介してみましょう。複数国のカーシェアリングやレンタカーを1つのアプリで提供できる Global KINTO App(GKA) がそれです。アジアのAという国へ行ったときはその国のカーシェア、中東のBという国へ行ったときはその国のレンタカー、といったように、そのアプリにおいて、複数の国にあるKINTOサービスを切り替えて迷わずスムーズに使うことができる体験を提供するものです。グローバルでサービスを提供しているKINTOならではのスケール感だと思いませんか? KINTOで働くことの難しさと醍醐味 海外の各KINTOサービスへプロダクトを提供し、そのプロダクトを通じてビジネス成果を最大化することがPdMチームのミッションですが、それゆえに困難なこともあります。例えば、各地へプロダクトを提供するにあたっては、事業を運営している現地法人と話して現地のニーズやターゲットを理解しようと考えます。しかし、物理的な距離や商習慣の距離、また文化的な距離、など様々な”距離”が存在するため、実際にどんな人がどのようにプロダクトを使ってKINTOを利用しているのかを把握することに、高いハードルがあります。それでも何とかして有益な情報を入手しなければなりません。そのため、現地とのコミュニケーションにおける深さや質の向上は、私達が提供する価値を左右する非常に重要な要素になっています。 (↓の写真は今年世界各地のTOYOTAグループ企業を集めてアメリカで開催されたHackathonイベントの模様。このような場でグローバルのメンバーと交流することも私達にとっては非常に意義があります。ちなみにこのイベント、2023年も実施予定のようです!) 上記で書いたこと以外にも困難なことはいろいろあるものの、まだ正解がわからないモビリティーサービスにおいては試行錯誤しながらやるからこその魅力があります。各地で実施する新しい取り組みや、新しい形での「移動の喜び」の届け方へ今の段階から関わることができるのは、他の組織ではなかなか味わえないKINTOならではの醍醐味なのではないでしょうか。 モビリティーサービスの将来像について、いろいろな人や各企業が想像力を膨らませて考えています。それでも、この領域では確定的なものがまだまだはっきり見えません。その中で、世界各国にいるKINTOユーザーの気持ちへ寄り添いつつ「移動の喜び」を具現化するプロダクトの実現に興味がある方は、ぜひ一緒に前進させていきましょう。 UIUXチーム ミッション UIUX担当の渡辺です。 「KINTO」のブランドで世界展開している各種モビリティサービスに対して、UIUXチームでは Global KINTO App(GKA) というアプリの制作から、 Global KINTO Entrance Web まで規模の大小問わずたくさんの開発活動に関わっています。 ビジュアル的な制作と論理的な情報設計が私達のミッションです。 トヨタグループという大きなバックボーンがあるのでルールや制約が多いと思われる方もいると思いますが、実は決まっていないことも作っていないものもたくさんあります。 Design System 最近一段落ついた大きなプロジェクトはDesign Systemの構築です。 サービスを構築していくには、職種や技術力の壁を超えて同じクオリティを制作することはとても困難です。その問題を解決する1つがDesign Systemでした。 簡単に言えばデザイナーもエンジニアもコピペするだけで同クオリティのものが簡単に作れるコンポーネント集です。 ゼロからの作成だったので、ロゴ規定やカラートーン、アイコンにいたるまで約1年の製作期間は本当に大変でした(本当に…) 現在は社内での導入はもちろん世界のKINTO各社から導入についてお問い合わせが来るようになりつつあり、その1件1件に涙が出そうなくらい嬉しいです。 Global KINTO App GKAの愛称で親しまれています。「世界中のKINTOサービスを1つのアプリでつなぐ」というコンセプトを持たせたモバイルアプリです。現時点ではタイとカタールのKINTOサービスが実装されています。 GKAではアジャイル開発の1つであるスクラムをベースに体制を作っているためプロデューサー・エンジニア・デザイナーがとても近い距離で話し合いながら進められています。 スクラムといえばエンジニア以外は敷居が高いイメージですが、社内では著名な方を講師に迎えてのワークショップの実施などを積極的に行っているので、とても参加しやすくなってきました。 課題と今後 一方、理想通りにはいかないことも多くあります。グループ企業との関係性が複雑な部分があり、ステークホルダーが多すぎて「なかなか判断が進まず長い期間足踏みをしている場面」もあります。「仮説を立てる段階でのリサーチや検討が不十分な場合」もありプロセス整備をしていくことも今後の課題です。 学ぶことも挑戦することも多いので大変ですが裁量も大きいので、やりたいことに手を上げて発言しやすい環境です。チームメンバーの言語も経歴も様々がゆえに新しい発想や表現に出会う毎日でもあります。未来のモビリティーを想像し、いま無いものを生み出すことにやりがいを感じて、想像力全開で取り組める人にぜひ参加して欲しいと思っています。
アバター
こんにちは KINTOテクノロジーズ モバイルアプリ開発Gの小山です。 モバイルアプリの開発・運用に携わっています。担当はiOSです。 今回はGlobal KINTOのモバイルアプリ開発の中でMVVMを採用した内容を紹介したいと思います。 MVVM と Combine 話をする前にまずこれらについて軽く説明をしておきたいと思います。 MVVM ソフトウェア開発におけるアーキテクチャのひとつです。 MVCモデルの派生系で Model-View-ViewModel という構成を取ります。 細かいことを言うとややこしいので簡潔に示すと、 Model データをひとまとめにした存在であり、データのまとまりと簡単な処理を担います。複雑な処理は行いません。 View 画面描写を担う存在です。画面を生成するのに必要なデータを受け取り、ただ描写します。 ViewModel ModelとViewの中間地点の存在で、複数のModelのデータをまとめたり、Viewの状態を保持するための値を持つ役割を担ったりします。 といった感じです。個人の見解です。 ただこれでもiOSやり始め当初の私には理解が難しかったです。 そこでiOSの開発に当てはめるとこんな感じになります。 Model 扱うデータをただひとまとめにします。基準として辞書型を採用するくらいならModelを一つ作ります。Model内のデータに関わるシンプルなメソッドのみを持ちます。 View ViewControllerや個別のViewがこれに当たります。描写に関わるコーディングのみ行い、データの操作は行わず、受け取ったデータをただ描写します。基準としてif文が全くない状態を目指します。 ViewModel ViewControllerからトリガーを受け取ってデータを返却します。ViewControllerとは1対1で、個別のViewに関しては場合によって上位のViewControllerのViewModelが役目を担っても良いです。 これを実現していきたいと思います。本記事の中では特にViewとViewModelの分割をご紹介したいと思います。 Combine 2019年の6月に登場した、Apple公式のリアクティブアーキテクチャを実現するフレームワークです。 それまではリアクティブアーキテクチャを実現するにはサードパーティ製のRxSwiftを使うことがほとんどでしたが、公式でサポートの厚いライブラリがリリースされました。 ちょ、ちょっと待ってリアクティブアーキテクチャってなんだっけ と、思った方もいるかと思います。 私がそうでした。Wikipediaによると以下の通りです。 reactive programming is a declarative programming paradigm concerned with data streams and the propagation of change. -- Wikipedia | Reactive programming これを和訳すると以下の通りです。 データストリームと変更の伝播に関係する宣言型プログラミングパラダイムです。 いまいち分からないですね。 こちらもややこしくせず理解するには、表計算ソフトをイメージすると良いと聞いたことがあります。 以下のような簡単な計算式を入力したとします。 A B C 10 20 =A1+B1 これを入力完了するともちろんC1セルに計算結果が入ります。 A B C 10 20 30 この状態でA1セルを20に書き換えた場合はどうなるでしょうか。 A B C 20 20 40 もちろんC1セルが40に書き変わります。 このようにA1の変更に対応してC1に直接手を加えずに変更を伝播させていくことを、リアクティブアーキテクチャと呼びます。 初めにデータ処理の宣言( =A1+B1 )のみを行い、最後に実データを流す(A1に20を代入)、といったイメージが私はしっくりきました。 背景 前置きが少々長くなりました。我々がなぜCombine、MVVMを採用するに至ったかという話です。 Global KINTOの開発案件を担当した当初、外注していたソースコードを内製に切り替えて間もない状況だったこともあり、既に出来上がっている部分はいわゆるスパゲッティコードの状態でメンテナンス性が非常に悪い状態でした。 あらゆるところでグローバル変数が呼ばれ、どのクラスがどのクラスと依存関係にあるか全く分からない状態でした。 しかし幸いなことに、コードと画面数が比較的少なかったため全体的にアーキテクチャを見直すことで解決をしようと試みました。 この際に、モバイルアプリ開発GにてCombineを使ったMVVMの知見があったため、MVVMのアーキテクチャに則り進めることとなりました。 アーキテクチャに則った設計をきちんとすることで、新規参入したメンバーでも理解しやすく、安全に改修できるようなプロジェクトにすることが目標です。 いざ、実装! 今回はMVVMに則ると決めたので、ViewとViewModelは責務を分離します。 なお、今回の実装ではUIKitを使用します。 View - Part1 Viewでは一切の演算処理を行わない代わりに、イベント発火のタイミングだけをViewModelに伝えたいです。 これを実装するために、CombineのPublisherを利用していきます。 例えば、viewDidLoadのタイミングを送信する必要がある場合、PassthroughSubjectにVoid型を持たせて定義しておきます。 private let didLoad: PassthroughSubject<Void, Never> = .init() これをviewDidLoad時に送信するようにします。 override func viewDidLoad() { super.viewDidLoad() didLoad.send() } また、ボタンのタップ時にはtapPublisher ^combineCocoa を利用するのがスマートです。 まず、対象のボタンをOutlet接続し、送信用のPublisherを準備します。 もしボタンを押したタイミングで表示されている画面のString値を渡したい場合は、VoidではなくStringでPublisherを定義します。 @IBOutlet weak var button: UIButton! @IBOutlet weak var textArea: UITextField! private let tapButton: PassthroughSubject<String, Never> = .init() その後、tapPublisherを利用してイベントを検知してViewModelに送信します。 button .tapPublisher .sink { [weak self] in self?.tapButton.send(textArea.text ?? "") } .store(in: &cancellables) 続いて、ViewModelを見てみましょう。 ViewModel ViewModelではViewから受け取ったイベントトリガーを元に、情報を取得したり生成したりすることで、Viewに必要な情報を集めて返してあげます。 こちらではCombineのOperator、Subscriberを使って実現していきます。 初めに、View側との接続準備のため、ViewModelとは別にInput,Outputの構造体を定義します。 InputはViewから渡されるデータ、Outputはその結果ViewModelから渡したいデータです。 データのやり取りの際に、渡されるデータとエラーの型がきちんと決まっていれば処理は可能であるため、型は一律AnyPublisherを使います。 struct ViewModelInput { let viewDidLoad: AnyPublisher<Void, Never> // 画面が最初に表示されたときにトリガーが欲しい! let tapButton: AnyPublisher<String, Never> // ボタンがタップされたときにテキストが欲しい! } struct ViewModelOutput { let onShowWelcome: AnyPublisher<String, Never> // Welcomeテキストを画面に表示してほしい let onShowText: AnyPublisher<String, Never> // 任意のテキストを画面に表示してほしい let onShowOnlyFirst: AnyPublisher<Void, Never> // 最初にボタンを押された時のみ固定値を画面に出してほしい } 続いて、データの処理部分を作成します。Inputを受け取ってOutputに変換する部分の実装になります。 例えば、viewDidLoad時に特定のAPIを実行するような動作であれば、viewDidLoadのPublisherからOperatorを繋げてAPIリクエストを実行します。 func transform(input: ViewModelInput) -> ViewModelOutput { let apiResponse = input .viewDidLoad .flatMap { api.requestData() } 同様にボタンタップ時、画面上のテキストを基にデータを生成するような動作をしたい場合は、mapを使います。 let text = input .tapButton .map { createText(text: $0) } また他にも、viewDidLoadが呼ばれ、且つボタンのタップもされたときに処理させたいことがあるとします。 そういった場合はPublisher同士を接続することができます。いくつか接続方法がありますが、今回はzipを使います。 let didLoad = input .viewDidLoad let buttonTap = input .tapButton let didLoadAndButtonTap = didLoad .zip(buttonTap) .map { _ in } このように様々なOperatorがCombineやその拡張ライブラリにはすでに準備されているため、コードをシンプルに保ちながら複雑な処理を実現することができます。 Operatorはいくつもありますが、個人的に便利でこれさえ覚えておけばOKというものを以下に挙げておきます。 map flatMap compactMap filter share materialize ^combineExt merge zip combineLatest withLatestFrom ^combineExt そして最後にOutputの型に合わせてreturnしてあげます。 Combineを利用する場合、Operatorを接続するたびに型がどんどん拡張されてしまうため、最後にAnyPublisherにまとめてから生成したデータをViewに返します。 return .init( onShowWelcome: apiResponse.eraseToAnyPublisher(), onShowText: text.eraseToAnyPublisher(), onShowOnlyFirst: didLoadAndButtonTap.eraseToAnyPublisher() ) } View - Part2 ViewModel側が完成したので、Viewと接続して画面描写を行います。 先ほど用意したtransformメソッドを呼び出して、ViewModelでの処理結果を受け取りましょう。 let output = viewModel.transform( input: .init( viewDidLoad: didLoad.eraseToAnyPublisher(), tapButton: tapButton.eraseToAnyPublisher() ) ) 処理結果を受け取ったら、各結果の際にどんな画面描写をするか実装して完成になります。 output .onShowWelcome .receive(on: DispatchQueue.main) .sink { [weak self] in self?.textArea.text = $0 } .store(in: &cancellables) output .onShowText .receive(on: DispatchQueue.main) .sink { [weak self] in self?.textArea.text = $0 } .store(in: &cancellables) output .onShowOnlyFirst .receive(on: DispatchQueue.main) .sink { [weak self] in self?.showCustomMessage("First!") } .store(in: &cancellables) 完成 こうして完成したコードがこちらになります。 class ViewController: UIViewController { @IBOutlet weak var button: UIButton! @IBOutlet weak var textArea: UITextField! private var viewModel: ViewModelProtocol! private let didLoad: PassthroughSubject<Void, Never> = .init() private let tapButton: PassthroughSubject<String, Never> = .init() private var cancellables: Set<AnyCancellable> = .init() func configure(viewModel: ViewModelProtocol) { self.viewModel = viewModel } override func viewDidLoad() { super.viewDidLoad() bind() didLoad.send() } func bind() { let output = viewModel.transform( input: .init( viewDidLoad: didLoad.eraseToAnyPublisher(), tapButton: tapButton.eraseToAnyPublisher() ) ) button .tapPublisher .sink { [weak self] in self?.tapButton.send(textArea.text ?? "") } .store(in: &cancellables) output .onShowWelcome .receive(on: DispatchQueue.main) .sink { [weak self] in self?.textArea.text = $0 } .store(in: &cancellables) output .onShowText .receive(on: DispatchQueue.main) .sink { [weak self] in self?.textArea.text = $0 } .store(in: &cancellables) output .onShowOnlyFirst .receive(on: DispatchQueue.main) .sink { [weak self] in self?.showCustomMessage("First!") // あらかじめメソッドが準備されている想定 } .store(in: &cancellables) } } protocol ViewModelProtocol { func transform(input: ViewModelInput) -> ViewModelOutput } struct ViewModelInput { let viewDidLoad: AnyPublisher<Void, Never> let tapButton: AnyPublisher<String, Never> } struct ViewModelOutput { let onShowWelcome: AnyPublisher<String, Never> let onShowText: AnyPublisher<String, Never> let onShowOnlyFirst: AnyPublisher<Void, Never> } struct ViewModel: ViewModelProtocol { let api: SomeApiProtocol init(api: SomeApiProtocol) { self.api = api } func transform(input: ViewModelInput) -> ViewModelOutput { let didLoad = input .viewDidLoad .share() let apiResponse = didLoad .flatMap { api.requestData() } // Future<String, Never> が返される想定 let buttonTap = input .tapButton .share() let text = buttonTap .map { createText(text: $0) } let didLoadAndButtonTap = didLoad .zip(buttonTap) .map { _ in } return .init( onShowWelcome: apiResponse.eraseToAnyPublisher(), onShowText: text.eraseToAnyPublisher(), onShowOnlyFirst: didLoadAndButtonTap.eraseToAnyPublisher() ) } func createText(text: String) -> String { "\(text) show!!" } } このようにViewとViewModelで明確に役割分担を行うことでコード内に秩序が生まれます。 どのViewでも同じ構成をとることができるため、コードの可読性が向上しメンテナンスもしやすく、役割が決まっているので無理矢理なコーディングが生まれにくいです。 ただしデメリットとしてはCombineやRxSwiftなどのリアクティブプログラミングを経験していない場合、それまでのSwiftとは 言語が変わったかと思うほど理解が難しい 点です。 Global KINTOのiOSのプロジェクトでは、全てのViewをこの構成に則って作成しています。 可読性が向上したことでメンテナンス性も上がり、新規のViewを作成する場合でも作成の仕方にばらつきが出づらくなりました。 最後に モバイルアプリ開発Gでは、本記事のような知見をGlobal KINTO以外のプロダクトに共有したり、これとは全く別の新しいアーキテクチャに挑戦するといったようなことも実践しています。 引き続き、モバイルアプリ開発Gの責務として、iOSの様々な開発手法に挑戦していきたいと思っています!どうぞよろしくお願いします。
アバター
KINTOのグローバル展開をサポートしている開発組織を紹介します。 目次 目次 自己紹介 グローバル開発グループの体制について 今後の活動方針の紹介 おわりに 自己紹介 KTCでグローバル開発グループでグループマネージャーをしているFengです。 私は中国でソフトウェア開発を学び、2002年より日本の大学院に進学し、その後は大手電気機器メーカーでソフトウェアエンジニア、自動車部品メーカーでプロジェクトマネージャー、プロダクトオーナーを経て、前職はモビリティ関連部品を取り扱う外資系メーカーの日本トップを務めていたことでKINTOに入社しました。 KINTOに入社してから、各国のステークホルダーたちと密に連携し、KINTOとして必要と思われるグローバル共通なものはどういうものなのかを常に考えながらプロダクト開発及び組織作りをやってきました。 グローバル開発グループの体制について 2019年グループ立ち上げの初期頃は、私がPdMを兼任しながら数名メンバーしかいない中で開発をスタートしていましたが、ちょうど3年経った今(2022年11月)は社員59名になり、その内39名が海外出身ということで、かなりダイバーシティな環境となってきたと感じています。 我々のグループとして、常に海外のKINTOチームとコミュニケーションを取りながら、下記のような業務を遂行してきました。 要件・ニーズを確認してプロダクトを企画・検討 グローバルで共通化できるようなプロダクトを基盤として開発 開発してきたプロダクトを必要に応じて各国への導入開発を実施 よって、今の開発体制もそれらの業務をサイクルとして回せるよう、下記のように構築しています。 PdMチームが企画したプロダクトを、開発チームが開発し、導入チームが各サービスへ導入する流れです。 また、各プロダクトやグループ全体に係る共通のチームとしてUIUXチームと業務エンハンスチームが存在します。 今後の活動方針の紹介 モビリティ事業はまだまだ分からないことがいっぱいある中で、各国KINTO事業をより効率よく支えるために、グローバルで共通化可能なものを念頭に置いて下記四つの方面から活動していく予定です。 おわりに KTCのグローバル開発グループ全体について、簡単ではありますが紹介しました。 各チームの詳細についてはこのあと第二弾でPdMチーム・UIUXチーム、第三弾で開発チーム・導入チーム・業務エンハンスチームの紹介をいたします。 まだ組織として成長している最中であるので、色々課題はありますが、KINTOが目指している Ever Better Mobility For All を実現するために、少しずつ居心地の良い組織をメンバーと一緒に仕上げていきたいと思っています。 また、この記事を見てグローバルでKINTOはどのようなサービスを展開しているのか、グローバル開発グループの雰囲気に興味・関心を持っていただいた方は、ぜひ下記のサイトにもアクセスしてみてください。 KINTOのグローバルポータルサイト KTC採用ページ内グローバル開発Gの紹介記事
アバター