TECH PLAY

KINTOテクノロジーズ

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

936

UUIDとは何でしょう? どのバージョンを使用すればよいでしょうか? 最近、データベース内のキーが重複していたためにサービスがダウンするというインシデントに対応しなければなりませんでした。私のチームと私は、これらがUUIDだったため頭を悩ませていました。ご存知のとおり、これらは「一意」の識別子です。どうして重複が生じるのでしょうか?結局、この問題は、同じUUIDが2回生成されたことではなく、サービスが同じイベントを2回追加しようとしたことが原因であることがわかりました。この出来事がきっかけで、UUIDについて考えるようになりました。UUIDとは何でしょうか?UUIDはどのように生成されるのでしょうか?UUIDの使用例は?そして最も重要なのは、どのバージョンを使用すべきかということです。 UUIDとは何でしょう? UUIDは通常、リソースのIDを提供するために使用されます。UUIDは「Universally Unique IDentifier(汎用一意識別子)」の略称です。その名称を見ると、生成される値の一意性が強く期待されているようです。これには十分な理由があります。例えば、数千兆のUUIDなど、膨大な量のUUIDを生成したとしても、それらが一意である確率は99.999%です。これらの確率の背後にある数学に興味がある方は、 この非常に優れた記事 を読むことをお勧めします。 UUIDは「保証された一意性」ではなく「実質的な一意性」です。衝突の可能性は非常に小さいため、ほとんどのアプリケーションでは、UUIDの衝突が発生する可能性よりも、ハードウェアが故障するか、 宇宙線が原因でビットがマシンのメモリ内で反転する 可能性の方が高くなります。 ただし、これらの確率は適切な乱数発生を前提としていることに注意してください。乱数発生器に欠陥があったり予測可能だったりすると、衝突の実際の確率ははるかに高くなる可能性があります。この記事の後半でもう少し詳しく説明します。 ソフトウェアに携わっている方であれば、UUIDがどのようなものかすでにご存知かと思いますが、念のため:UUIDは128ビット幅で、ハイフンで区切られた5つの部分で構成されます。それらは通常、16進数で表され、次のようになります。 ccba8c00-cbed-11ef-ad79-1da827afd7cd 74febad9-d652-4f6b-901a-0246562e13a8 1efcbedf-13bf-61e0-8fb8-fe3899c4f6f1 01943a0e-dd73-72fd-81ad-0af7ce19104b でも待ってください!これらのUUIDは実際には異なるバージョンのUUIDを使用して生成されました。上記のUUIDのリストにおいて、それらはバージョン1、バージョン4、バージョン6、バージョン7の順で使用して生成されます。UUIDにおいてバージョンがどこに示されているかを調べてみてください。 ヒント:中間あたりにあります。 UUIDのバージョンは、UUIDの真ん中にある、UUIDの3番目の部分の最初の文字に示されていることにお気づきだと思います。4番目の部分の最初の文字にもバリアントが示されています。バージョンはUUIDがどのように生成されたかを示すために使用され、バリアントはそのUUIDのレイアウトを示すために使用されますが、おそらくバリアントについて心配する必要はなく、バージョンが最も重要です。 先ほど説明したように、UUID には複数のバージョンがあります。先ほど発見したバージョンインジケーターの他に、各バージョンの違いは何でしょうか?それらはすべて、一意のUUIDを同様に生成できるでしょうか?また、あるバージョンを他のバージョンよりも優先して使用する理由は何でしょうか?もちろん、最新かつ最良のUUIDバージョンを使用すべきですよね?とても良い質問です!UUIDの異なるバージョンを見てみましょう。 バージョン1とバージョン6 バージョン1および6のUUIDは、UUIDを生成したコンピューターの現在の時刻と MACアドレス を使用して生成されます。タイムスタンプ部分は UUIDの先頭にあり、コンピューターのCPUに応じてランダムビットまたは増分カウンターを含む場合があります。MACアドレス部分は最後にあるため、同じコンピューターを使用していれば、その部分が変化することはありません。興味深いことに、MACアドレスはUUIDから取得できるため、UUIDバージョン1または6を生成するとプライバシーのリスクが生じます。しかし、これはこのバージョンのUUIDの利点の1つでもあり、2台のコンピュータが同じUUIDを生成することはありません。そのため、これらのバージョンは、グローバルな一意性が求められる分散システムで役立ちます。 バージョン1と6の違いは、UUIDでタイムスタンプの各部分が使用される順序です。バージョン1とは異なり、バージョン6のUUIDは時系列で並べ替えることができるため、データベース内での順序付けに役立ちます。 バージョン1および6では予測可能な要素(生成時刻とMACアドレス)を使用するため、UUIDを推測可能であり、UUIDを秘密にしておく必要がある用途には適していません。 バージョン2 バージョン2は、タイムスタンプと、UUIDを生成するコンピューターのMACアドレスを使用する点でバージョン1と似ています。ただし、バージョン2では、POSIX UIDまたはGIDという追加の識別子データも使用します。これにより、バージョン2はバージョン1および6よりもランダム性が低くなり、タイムスタンプの使用が少なくなります。その結果、特定の時点で生成できるUUID v2の数は限られており、ほとんどの用途においてあまり望ましくありません。これが使用されることは稀であり、通常、ほとんどのライブラリでサポートされていません。これは、UUID仕様にも記載されていません。 バージョン3と5 バージョン3と5は他のUUIDとはまったく異なります。他のバージョンはランダム性を目指していますが、バージョン3とバージョン5は決定論的であることを目指しています。これはどういう意味でしょう?いずれもハッシュアルゴリズムを使用してUUIDを生成するため、UUIDを再現可能にします。UUIDを生成するためにランダム性やタイムスタンプは使用されず、与えられた入力は常に同じUUIDを生成する必要があります。バージョン3ではMD5ハッシュアルゴリズムを使用し、バージョン5ではSHA1を使用します。 これらのバージョンは、同じ入力データから同じUUIDを繰り返し生成する必要がある場合に特に便利です。例えば、ユーザーの電子メールアドレスに基づいてユーザーのUUIDを作成するとします。異なるサーバーや時間にわたっても、同じ電子メールで常に同じUUIDが生成されるようにしたいとします。もう1つの良い例としては、重複を避けるために何らかのデータに基づいて主キーを生成する必要があるが、データ自体を主キーとして使用するのは良い選択肢ではない場合が挙げられます。 バージョン3とバージョン5のいずれかを選択する場合、SHA1の方が少し安全ですが、計算負荷も大きくなることに留意してください。それがユースケースで懸念事項である場合は、バージョン3を使用してコンピューティングリソースの使用量を削減することをお勧めしますが、ほとんどの場合、より安全なバージョン5を選択すべきです。また、SHA1よりもMD5と衝突が発生する可能性が高くなりますが、その確率は依然として非常に低いです。 バージョン4 バージョン4は、UUIDの最も広く使用されているバージョンです。バージョン4はランダムビットを使用してUUIDを生成するため、UUIDは一意で予測不可能になります。これは乱数発生に大きく依存していますが、すべての乱数発生器が実際に真の乱数を生成できるわけではありません。衝撃的ですよね。 多くのプログラミング言語では、疑似乱数発生器(PRNG)と呼ばれるものを使用しています。ほとんどの場合はこれで問題ありませんが、UUID生成の場合は、システムが暗号論的にセキュアな疑似乱数生成器(CSPRNG)を使用していることを確認する必要があります。 なぜかって?通常のPRNGは、出力を十分に分析すれば予測可能になる場合があります。一方、CSPRNGは、攻撃者が以前に生成されたすべての値を知っている場合でも、その出力を予測することが事実上不可能になるように特別に設計されています。最近のUUIDライブラリのほとんどがデフォルトでCSPRNGを使用していますが、念のため確認してみる価値はあります。 他のバージョンと同様に、予測可能な部分はバージョンインジケーターのみなので、その部分を推測して友達を感心させてみましょう。 これらは、大量のUUIDを生成する必要があり、後で並べ替えたり再現したりする必要がない場合など、ほとんどの用途に最適です。これらは、データベースにおいてキーとしてよく使用されます。 バージョン7 バージョン7は、バージョン4を時系列順に並べ替えられるバージョンとして設計されています。バージョン4と同様に、バージョン7はランダムビットを使用しますが、タイムスタンプを含むため、UUIDはソート(並び替え)可能かつ一意になります。一意性を保ちつつ、作成時間によって並べ替えたい場合に、バージョン7はバージョン4の優れた代替手段となります。 バージョン7でもタイムスタンプにエポックタイムを使用しますが、バージョン1と6では1582年10月15日以降、100ナノ秒間隔の数値を使用しています。これにより、バージョン7での作業が少し簡単になっています。 バージョン8 バージョン8はカスタムなので少し特殊です。ベンダーは希望どおりに実装できます。バージョン8を自分で実装することもできますが、UUIDの3番目の部分にあるUUIDバージョンを尊重する必要があります。おそらくそれを使用する必要はないでしょう。 では、何を使用すればよいでしょうか? ほとんどの人にとって、バージョン4になります。バージョン4は、一意性の保証が最も大きく、比較的安全です(乱数発生器が予測不可能な限り)。UUIDを作成時間によって並べ替えられるようにしたい場合は、MACアドレスの漏洩によるプライバシーの懸念がない限り、バージョン7またはバージョン6を使用できます。場合によってはバージョン3と5が便利ですが、ほとんどのアプリケーションではそれらの使用は制限されます。 データベースキー? データベースキーにUUIDを使用することに関する議論を見たことがあるかもしれませんが、データベースキーにUUIDを使用することを検討している場合は、覚えておくべき事実がいくつかあります。 UUIDは大きく、128ビットを占めます。大量のデータを保存する予定がない場合は、UUID用に追加で占有されるスペースが大きくなる可能性があります。あるいは、32ビットの自動増分整数(オートインクリメント整数)では約2147483647行が得られますが、それでも足りない場合は、64ビットのBIGINTで最大18446744073709551615になります。ほとんどのユースケースの場合、これで十分でしょう。 一部のデータベースでは、キーにUUIDを使用すると、挿入性能が低下する可能性があります。挿入性能が懸念される場合は、自動増分整数の使用を検討するか、少なくともUUIDを使用してデータベースの性能をテストすることをお勧めします。 UUIDは、データの移行を容易にします。自動増分整数を使用すると衝突が発生しますが、UUIDではその問題は発生しないでしょう。 一部のUUIDはソート(並び替え)可能ですが、読みやすくはありません。2つのUUIDに着目すると、どちらが先に来たのかを知るのは非常に困難です。これは非常に些細なことですが、留意すべきです。 ほとんどのデータベースには、UUIDを生成するための何らかのモジュールまたは関数があるため、データベースのドキュメントをチェックしてUUIDの生成方法を確認できます。UUIDを使用する際に性能上の問題や考慮すべき特別な事項がある場合は、おそらくそこで判明するでしょう。 結論 この記事を読む前よりも、UUIDとそれらのさまざまなバージョンについて少し理解が深まったと思います。 バージョン4 UUIDは、ほとんどのアプリケーションで依然として定番です。バージョン4 UUIDは、強力な一意性保証と予測不可能性を備えており、おそらくこれがUUIDに求められるものです。バージョン4 UUIDは主に、データベースキー、分散システム、および調整なしでグローバルに一意な識別子が必要なシナリオで使用されます。 バージョン7は、ランダム性とソート(並び替え)可能性とのバランスが取れているため、時系列的ソートが望ましい場合に適した代替手段です。 バージョン1と6は、グローバルな一意性が必要な分散システムでは役立ちますが、MACアドレスが含まれるためプライバシーに関する懸念を伴います。 バージョン3と5は、特定の入力からUUIDを再現する必要がある場合に便利ですが、MD5はSHA1ほど安全ではないことに注意してください。 自分のシステムでUUIDを使用する予定の場合は、UUIDバージョンを選択する際に次の要素を考慮してください。 一意性に関する自身の要件 時系列的ソートが必要か否か プライバシーに関する懸念 (特に MACアドレスを含むバージョンを使用する場合) ストレージ スペースの制約 (あなたのキーに128ビットは必要ないかもしれません) UUIDの衝突は理論的には起こり得ますが、暗号的に安全な乱数発生器を使用した適切な実装をしている限り、その可能性は非常に低いため、システム設計において大きな懸念事項にはならないはずです。UUIDの衝突が発生した場合(天文学的な確率を覆した場合!)、実際のUUID生成衝突ではなく、重複したイベント処理などのアプリケーションロジック問題が原因である可能性が高くなります。そのような場合は、UUID生成自体に疑問を抱くよりも、アプリケーションの一意性制約の処理を調べることに重点を置いてください。
アバター
はじめに こんにちは、AIファーストグループのAlexです。 AI技術の急速な発展に伴い、エージェント開発の需要も高まっています。しかし、エージェントに関する最新技術の知見の共有不足や、開発リソースの分散により、効率的なエージェント開発を始めることが難しい状況にあります。そこで私たちは、社内各所で開発したAIエージェントを社内で共有し、技術・ノウハウを集約するためのプラットフォーム「Agent Store v1.0」をリリースしました。 Agent Storeの目的 Agent Storeは以下の2つの主要な目的を持っています: 社内Agent開発の効率向上 既存Agentの再利用により開発サイクルを短縮 テンプレートを活用した迅速な開発を実現 技術・ノウハウの蓄積 社内のAgent関連技術を一元管理 ベストプラクティスの横展開を容易に 利用形態と対象ユーザー Agent Store は、社員が AI エージェントを自由に開発、共有、ダウンロードして再利用するプラットフォームです。 なお再利用に関しては、App Storeのように、ユーザーがエージェントをダウンロードし、自身の環境にデプロイすることを想定しています。 Agent Storeは以下の要素で構成しています。 社内で開発したエージェントを共有するGithubリポジトリ エージェント開発のCI/CDの仕組み Agent StoreのGithubリポジトリ 利用形態 Agent Store v1.0では主にAWS Bedrockエージェントをサポートしています。 エージェントのCI/CDプロセスに関しては、IaC (Infrastructure as Code)を基づいて設計しました。 Agent Storeで共有されたエージェントは、CloudformationでデプロイするためのSAMテンプレートの形でAgent StoreのGithubリポジトリ上で格納されています。 エージェントを再利用したいユーザーは、該当するエージェントのSAMテンプレートをダウンロードし、Cloudformation経由で自分の環境にデプロイする形で利用します。 なお、デプロイに関してはGithub Actionsで自動化しています。 エージェントを新規開発したいユーザーに関しても、Agent Storeが提供している空のSAMテンプレートを利用し、素早くエージェント開発することが可能です。 対象ユーザー(v1.0) AWS Bedrockを利用してエージェント開発を始めたいエンジニア Bedrockで開発したエージェントを社内で共有したいエンジニア 既存のエージェントを探して活用したいエンジニア 想定するユースケース Agent Storeは以下のような利用シーンを想定しています: AIエージェントの新規作成 Agent StoreのCI/CDフローを利用することで開発の高速化を実現 AIエージェントの共有 自作エージェントを社内で共有 共有されたAIエージェントの再利用 既存プロダクトにAIエージェントを搭載 社内業務効率化アプリの開発 一からの開発を避け、開発効率の向上を実現 AIエージェントのPoC 既存エージェントをデプロイして迅速にPoC実施 効果検証の時間短縮 AIエージェント開発ノウハウの取得 類似事例の参照によるベストプラクティスの学習 技術的な障壁の低減 Agent Storeを活用したエージェント開発、共有と再利用のフロー エージェントを新規開発するフロー Agent Storeリポジトリから空のSAMテンプレートを取得し、記入した上でデプロイを行う流れとなります。 SAMについては こちら を参照してください。 なお、エージェントのAction Groupを利用する場合、①Lambda、②エージェントの順番でテンプレート記入・デプロイを行う必要があります。 エージェントを共有するフロー 開発したエージェントのSAMテンプレートを用意し、Agent Storeのリポにプルリクを実行します。エージェントのレビュー担当者にて内容を確認後、問題なければマージを行います。 共有されたエージェントを新たに再利用するフロー 基本の流れはエージェントを新規開発するフローと共通していますが、Agent Storeで共有されているエージェントのSAMテンプレートを取得し、必要に応じて修正・加筆を行った上でデプロイを行う流れになります。 エージェントのアーキテクチャ エージェントのアーキテクチャは以下です。 デプロイしたBedrockエージェントは、必要に応じでAction Groupとして設定されたLambdaを呼び出し実行することができる。 また、スタック管理はCloudFormationで行っている。 また、複数のエージェントが協働するマルチエージェントコラボレーションも構築することが可能です。 今後の展開計画 今後は、Agent Storeの利用促進のために、社内勉強会、ワークショップ、ハッカソンなどを多数企画しています。 また、現在のv1.0は「AWS Bedrockの開発経験があるエンジニア(タイプa)」を対象としていますが、今後は段階的に対象ユーザーを拡大していく予定です: ユーザーの種類 詳細 サポート状況 エンジニア タイプa AWS Bedrockの開発経験があるエンジニア v1.0でサポート中 エンジニア タイプb AWS Bedrock以外のエージェント開発環境を利用したいエンジニア 検討中 非エンジニア、エージェント開発初心者 開発・コーディング経験がない、非エンジニアの社員 検討中 まとめ Agent Store v1.0は、エージェント開発の効率化と知見共有を実現するプラットフォームです。現時点ではAWS Bedrockユーザー向けに機能を提供していますが、今後はより幅広いユーザー層へのサポートを拡大し、様々なエージェントフレームワークにも対応していく予定です。社内のAI開発リソースを最大限に活かし、イノベーションのペースを加速させるため、Agent Storeの機能拡充と進化に積極的に取り組んでいきたいと思います。
アバター
この記事は KINTOテクノロジーズアドベントカレンダー2024 の21日目の記事です 🎅🎄 はじめに こんにちは!iOSエンジニアのViacheslavです。 今年、私は当社の Unlimitedアプリ の新機能である 「これなにガイド」 に取り組む機会を得ました。これなにガイドは、車のダッシュボードをスマホでスキャンすることで、車のボタンやスイッチの上に仮想マーカーを表示できる拡張現実(AR)マニュアルです。特定のボタンに対応するマーカーを選択すると、機能を確認できるマニュアルページにアクセスできます。 今日は、この機能の開発中に遭遇した課題の1つである、「画面上でVisionフレームワークによって認識された物理オブジェクトの座標を正確にキャプチャし、それらの座標をARシーン内の3D座標に変換する」という課題に対する、短くてシンプルな解決策を共有したいと思います。 最初は些細な作業に思えたものが、予想以上に複雑であることが判明しました。いくつかのアプローチを模索し、多くの手動計算を実行した後、ようやく、単純かつ驚くほど簡潔な解決策にたどり着きました。ARKit と CoreML の統合に関する情報は比較的少ないので、始めたときに知っていればよかったと思います。では、知識ベースに追加していきましょう! いくつかの前提条件 実際のコードに進む前に、作業する環境を明確に定義してみましょう。 ARSCNView これは、デバイスのカメラからのビデオフィードを表示し、現実世界をキャプチャして3Dオブジェクトを「ブレンド」させてARエクスペリエンスを実現するビューです。 ARSCNView はAppleの ARKit の一部で、ARシーンでの3Dオブジェクトのレンダリングを処理する SceneKit 上に構築されます。 Core ML オブジェクト検出モデル オブジェクトの座標を決定する前に、まずデバイスのカメラによって提供されるビデオ フィード フレーム内でオブジェクトを認識する必要があります。Visionフレームワークは、この目的のためにCore MLオブジェクト検出モデルを利用します。本記事では、読者がすでに使用できるモデルを持っているものと想定します。そうでない場合は、 YOLOv3-Tiny など、ダウンロード可能な事前訓練済みモデルが多数あります。 こちら から入手できます。 最低限のソリューションに必要なのはこれだけです。 ARSCNView からビデオフレームをキャプチャし、Core MLモデルを使用して ARSCNView ビューポート内のオブジェクトの位置を検出し、「ヒットテスト」と呼ばれる手法を適用して3D AR空間におけるオブジェクトの座標を決定します。 ARSCNViewにおいて認識されたオブジェクトの座標をキャプチャする Vision を使用して認識要求を実行する場合の一般的な設定は以下の通りです。 Core MLモデルと VNCoreMLRequest を初期化して、そのモデルを使用して認識を処理します。 let vnModel = try!VNCoreMLModel(for: myCoreMLModel) let vnRequest = VNCoreMLRequest(model: vnModel) { [weak self] request, _ in guard let observations = request.results else { return } // Observations handling } request.imageCropAndScaleOption = .centerCrop 次に、 vnRequest への参照を適切な場所に保存し、次の引数セットで実行できるように準備します。引数のタイプは、ビデオフィードフレームをどこからキャプチャするかによって異なります。 私たちのシナリオでは、 ARSCNView からフレームを渡し、 ARSessionDelegate の session(_:didUpdate:) メソッドにおいてフレームをキャプチャする必要があります。このデリゲートメソッドは、 ARSCNView で表示できる新しいフレームが利用可能になるたびに呼び出されます。 func session(_ session:ARSession, didUpdate frame:ARFrame) { guard let vnRequest else { return } // 1 let options: [VNImageOption:Any] = [.cameraIntrinsics: frame.camera.intrinsics] // 2 let requestHandler = VNImageRequestHandler( cvPixelBuffer: frame.capturedImage, // 3 orientation: .downMirrored, // 4 options: options ) try? requestHandler.perform([vnRequest]) // 5 } コードを分解する: VNCoreMLRequest の参照 :新しいフレームを受信すると、先ほど初期化したリクエストを実行する準備が整います。 カメラ内部パラメータ : frame.camera.intrinsics は、Visionがシーンの幾何学的特性を解釈するのに役立つカメラ較正データを提供します。 画像入力 : VNImageRequestHandler は、ARフレームから取得された生画像データを CVPixelBuffer として受け入れます。 画像の向き : .downMirrored 方向は、Visionのデフォルト方向と比較して、カメラフィードの座標系の反転を考慮します。 リクエストの実行 :準備されたリクエストは、リクエストハンドラーを使用して実行されます。 Vision にフレームを渡し始めると、オブジェクト検出の結果が VNCoreMLRequest 完了ハンドラー内の VNRecognizedObjectObservation オブジェクトの配列として返されます。これらの結果を信頼度レベルでフィルタリングしたり、その他の処理を実行したりすることもできますが、今日は認識された特定のオブジェクトの座標を抽出することに焦点を当てます。 境界ボックス座標の抽出 最初は、 VNRecognizedObjectObservation に boundingBox プロパティ(認識されたオブジェクトを囲む CGRect )があるため、これは簡単に思えるかもしれません。ただし、いくつかの複雑な問題があります。 boundingBox は、物体認識モデルの入力画像に対する正規化された座標系(座標値は0から1の間)であり、それもY軸が反転しています。 カメラフィード、Core MLモデル入力、そして ARSCNView ビューポートのサイズとアスペクト比はそれぞれ異なります。 つまり、 boundingBox を ARSCNView ビューポートの座標系に変換するには、一連の座標変換と再スケーリングの手順が必要になります。これらの変換を手動で行うのは面倒で、間違いが起こりやすくなります。幸いなことに、 CGAffineTransform を使用すると、これを処理できる非常に簡単な方法があります。方法は次のとおりです。 let sceneView:ARSCNView func getDetectionCenter(from observation:VNRecognizedObjectObservation) -> CGRect? { guard let currentFrame = sceneView.session.currentFrame else { return nil } let viewportSize = sceneView.frame.size // 1 let fromCameraImageToViewTransform = currentFrame.displayTransform(for: .portrait, viewportSize: viewportSize) let viewNormalizedBoundingBox = observation.boundingBox.applying(fromCameraImageToViewTransform) // 2 let scaleTransform = CGAffineTransform(scaleX: viewportSize.width, y: viewportSize.height) let viewBoundingBox = viewNormalizedBoundingBox.applying(scaleTransform) return viewBoundingBox } 説明: ビュー座標への変換 : displayTransform(for:viewportSize:) を使用して、検出された境界ボックスは、入力画像の正規化座標系から ARSCNView の正規化座標系に変換されます。 ピクセル寸法へのスケーリング :正規化された境界ボックスは、 ARSCNView ビューポートのサイズに合わせてスケーリングされ、画面のピクセル寸法での境界ボックスが生成されます。 以上です!これで、 ARSCNView ビューポートの座標系に境界ボックスが作成されました。 3番目の座標を取得する 私は、ARシーンの3D座標空間内で認識されたオブジェクトの座標を取得すると約束しました。 そのためには、「ヒットテスト」と呼ばれる手法を利用します。これにより、ビューポート内の任意のポイントで最も近い物理オブジェクトまでの距離を測定できます。この手法は、デバイスからビューポート内の選択したポイントにある物理オブジェクトとの最初の交点まで直線の光線を投影し、その光線の長さを測定するものと考えることができます。この機能は ARKit の一部であり、非常に使いやすいです。 先ほど検出したオブジェクトの知覚可能な中心の3D座標を見つける方法は以下の通りです。 func performHitTestInCenter(of boundingBox:CGRect) -> SCNVector3? { let center = CGPoint(x: boundingBox.midX, y: boundingBox.midY) // 1 return performHitTest(at: center) } func performHitTest(at location:CGPoint) -> SCNVector3? { guard let query = sceneView.raycastQuery( // 2 from: location, allowing: .estimatedPlane, // 3 alignment: .any // 4 ) else { return nil } guard let result = sceneView.session.raycast(query).first else { return nil } // 5 let translation = result.worldTransform.columns.3 // 6 return .init(x: translation.x, y: translation.y, z: translation.z) } 説明: ここでは、ヒットテストを実行するために1つのポイントが必要なため、前の手順から境界ボックスの中心を計算します。 指定された2Dポイントから始まるレイキャストクエリを作成します。 ヒットテストで、ARKitが推定することしかできない非平面の表面や平面を考慮できるようにします。 水平面と垂直面の両方のヒットテストを有効にします(既定値は水平面のみです)。 ARセッションを使用してレイキャストクエリを実行します。交差がない場合は nil を返します。 各 ARRaycastResult には、ワールド空間で検出されたポイントの3D変換を表す4x4行列である worldTransform が含まれます。 columns.3 には、交点の3D位置を指定する並進ベクトルが含まれています。この並進ベクトルは SCNVector3 として返され、ARKit/SceneKitはこれを使用して3D位置を表します。 完了しました!これで、Visionによって検出されたオブジェクトの 3D座標を取得できました。目的に合わせてご利用ください。:) 最後に Unlimitedアプリでは、これらの3D座標を使用して、車内にARマニュアルマーカーを表示します。もちろん、ユーザーエクスペリエンスをよりスムーズにし、マーカーの位置をより安定させるために私たちが採用している追加テクニックは数多くありますが、これはコアテクニックの1つです。 とはいえ、この方法は、考えられる他のあらゆる目的にも使用できます。お役に立てたら幸いです。 最後に、私たちのテストプロセスと、オブジェクト検出後にARマニュアルマーカーがどのように表示されるかについて少し紹介します。 今日はここまでです。読んでいただきありがとうございました! 楽しいクリスマスをお過ごしください。そして、幸せな新年をお迎えください!
アバター
本記事は KINTOテクノロジーズアドベントカレンダー2024 の21日目の記事です🎅🎄 はじめに 皆さん、こんにちは!DLです。KINTOテクノロジーズ(KTC)のグループコアシステム部で、ビジネスディベロップメントチームに所属しています。今は、保険などの付加サービスを備えた自動車リース事業 KINTO ONE の社内システムを導入するため、ラテンアメリカのKINTO事業部と連携しています。ビジネスアナリスト(BA)として私が注力しているのは、 KINTOの業務分析と、ITソリューションの作成でワークフローを合理化して、効率性を向上させることです。 ビジネス分析がグローバルチームの一部となる前は、システム設計がKINTOグローバルビジネスの期待に十分応えられていないことがよくありました。日常業務の複雑さに対応できる、エンタープライズレベルのソリューションが求められていたのです。ここで活躍するのがBAです。日々の業務プロセスを把握し、懸念材料となる課題に対処する上で、BAは欠かせない存在です。ビジネス分析は、グローバルプロジェクトに価値を付加する戦略的な柱と言えるでしょう。 今日は、なにかと誤解されがちなBAの世界へ、皆さんをご案内します。「ただ数字ばかり気にしてる人じゃないの?」とか、「他の人の言うことをメモしてるだけなのでは?」と思うかもしれません。でも、BAの仕事って、それ以上に奥が深いんです。問題解決や戦略、コミュニケーションも欠かせません。 BAの本質は、技術とビジネスの世界を橋渡しすることです。効率アップ、業務の合理化、テクノロジーの導入など、どんな場面でもBAは耳を傾け、分析し、実用的で効果のあるソリューションを形にしていきます。経営幹部からエンドユーザーまで、関係者を巻き込むことでBAは重要な言葉の架け橋となります。そして、ビジネスニーズを効果的なテクニカルソリューションへと落とし込んでいきます。 ストーリー 1 - 聞く力:ビジネスアナリスト(BA)の役割 BAにとって欠かせないスキルのひとつが、聞く力です。ただ言葉を聞くだけでなく、その裏にある本当のニーズに耳を傾けることが大切です。あるプロジェクトで、とある金融会社の非効率的なレポート作成プロセスに取り組んだことがあります。世界中の事業部門から四半期ごとのレポートがメールで届き、その数は1日あたり100通以上。それが障害になっていました。届いたファイルは手作業でダウンロード、統合、エラーチェックされていました。時間がかかり、ミスも起こりやすい状態だったのです。 実際にその現場を見て、関係者と一緒に課題を洗い出していきました。IT部門と連携し、レポートを直接提出できる安全なLANディレクトリ構造を開発しました。バッチ処理やVBAスクリプトの自動化によって、データ確認、コピー、集計の作業がぐっと効率化されました。その結果、手作業の負担を約70%も削減することができ、より付加価値の高い分析に時間を使えるようになりました。この取り組みがうまくいったことで、部門全体でこの方法が採用されることになりました。 ストーリー 2 - 関係者を見落とした教訓 その後、とあるSaaS製品が、BAやユーザーの十分なレビューを経ることなく導入されました。コスト削減やダッシュボード機能が評価された結果の選定でしたが、既存の自動化ワークフローには対応できず、チームは手作業に逆戻りすることに…。 不満の声が上がりましたが、決定は覆らず、ユーザーの間には落胆と不満が残ってしまいました。この出来事からはっきりしたのは、ユーザーの本当のニーズに合ったソリューションを提供するには、初期段階からBAの関与が欠かせないということです。 物語は続きます… ストーリー2は少し残念な展開に見えるかもしれませんが、とても大事な教訓を教えてくれます。それは、プロセスを変えるにせよ、新しい製品をつくるにせよ、 成功のカギはエンドユーザーの声に耳を傾け 、真のニーズを理解することにある、ということです。ここで、KINTOテクノロジーズのグローバルプロジェクトにおいて、BAが果たす重要な役割についてご紹介します。前にも少し触れましたが、グローバルチームは現在、ラテンアメリカのKINTO各部門と連携し、保険などの付加サービスを備えた自動車リース事業 KINTO ONE に取り組んでいます。 グローバルな製品やシステムを開発するということは、国や言語を超えて多様な仕様に対応することです。課題となるのは、各国の異なるニーズに柔軟に対応できるシステムを、どう構築するかという点です。では、どうアプローチすればよいのでしょうか? 各国のビジネスユーザーは、自分たちのプロセスについてはプロですが、そのプロセスは国によって変わります。一方エンジニアは、それぞれの違いを踏まえたうえで、柔軟性のあるシステムを構築するという難題に向き合っています。そこで登場するのが、BAです。BAはビジネスユーザーとエンジニアの間に立ち、両者の懸け橋となるのです。 BAとして私たちは、以下のような体系的なアプローチを取っています。 ビジネスプロセスの収集:各国特有の業務プロセスを丁寧に文書化していきます。 BAとして、このステップは非常に重要です。というのも、BAは基本的にビジネスプロセスの専門家として、すべての工程を詳細まで完全に理解し、どんなステップも見逃さないようにする必要があるからです。このステップを達成するために、KINTOテクノロジーズのBAたちは実際にラテンアメリカの現地企業を訪問し、現場に赴きました。こうした現場の観察は、各プロセスのニュアンスを掴むために欠かせません。 さらに、このステップで重要なのは、企業が現在どんな懸念材料を抱えているのかを理解することです。なぜでしょう?それは、KINTOテクノロジーズが開発するシステムは、こうした懸念材料を解決し、ビジネスユーザーの日常業務に具体的な価値を付加することが求められているからです。この懸念材料にうまく対処できれば、ビジネスユーザーの手作業が減り、生産性と業務効率を上げられます。その効果は、作業時間の短縮、リードタイムの短縮、ユーザーの働きやすさの向上といった形で評価することができます。 ギャップ分析の実施:この分析では、各国におけるプロセスの違いや共通点が浮き彫りになります。 BAとして、このステップでは特に重要なポイントが2つあります。 作業手順の順序:各国で作業手順の順序が似ていれば、それはかなりの朗報です!でも、もし一方の国だけ順序が逆だった場合、両方に対応できるシステムを設計するのは、はるかに複雑になります。たとえば、車両の修理を行う場合:ケース1では、まず修理がKINTOサービスとして承認されて、その後実際の修理作業が始まります。一方ケース2では、先に修理作業が行われます。そしてその後で、そのサービスがKINTOサービスとして含まれているかどうかが確認されます。このように手順に違いがあると、システム設計の難易度が上がるのです。 外部システムとの統合:このステップで欠かせない、もう1つの重要なポイントがあります。それは、現在さまざまな国で使われている外部システムやプラットフォームに目を向けることです。たとえば、ある国では会計システムにSAPを使用していて、別の国では異なるタイプの会計システムを使用しているかもしれません。こういった違いが、グローバル製品に必要な統合を複雑にしているのです。 ソリューションの共同作業:ギャップ分析を使用して、BAはエンジニアとタッグを組みながら、関連のある国すべての要件に対応できる柔軟な設計を進めていきます。 このステップでは、エンジニアの力を借りて複雑なパズルを解いてくような感じです。BAにとってこのステップはかなり重要です。なぜかというと、BAは基本的に両国のビジネスユーザーを代表する立場なので、どちらのニーズにも応えられるシステムを設計する必要があるからです。例え話ですが、ある国のニーズはセダンで、もう一方のニーズはバンだとします。ここでBAはエンジニアと協力して「じゃあSUVを開発しようか?」となるような感じです(笑)。このステップでは、プロセスの一つひとつを細かく検討し、すべての工程が両国のニーズにちゃんと対応できるかを確認していきます。そうして、すべてのステップがうまくつながり、まとまりのある柔軟なシステムとして作成できることを確認します。こういった複雑な課題を解決していくのって、とても楽しいんですよ! 結果として共同努力が生まれ、グローバル製品はビジネスニーズに応えつつ、システムの柔軟性とのバランスもしっかり取れるようになります。グローバルプロジェクトが成功する上で、BAの役割がいかに重要であるかを物語っていますね。 ビジネスアナリスト(BA)の力とは? BA になるとは、どういうことでしょうか?それは、問題を解決する人にも、コミュニケーターにも、戦略家にもなるということです。つまり、疑問を投げかける好奇心、耳を傾ける忍耐力、そして粘り強く答えを探る力を持つということです。最終的には、組織の運営方法、人の働き方、意思決定の方法に、本当の変化をもたらすことがBAの役割です。 BAは目立つ存在ではないかもしれません。でも、私たちの仕事は成果に影響を与え、リソースの無駄を減らし、誰かの仕事をちょっとラクにしているんです。アイデアを現実に変え、ニーズを形に変える。その架け橋となっているのが、BAです。 ひとつ、覚えておいていただきたいことがあります。それは、「聞く力」をあなどってはいけない、ということです。BAでも、ステークホルダーでも、何かを変えたいと尽力している人でも。本当の前進は、聞くこと、言葉の橋渡し、そしてつなぐことから生まれます。 読んでくださって、ありがとうございました!
アバター
前提条件と範囲 本記事では、Android Composeのナビゲーションを、オブジェクト指向の観点から処理する方法について説明します。基盤となる技術をカプセル化し、開発の利便性を高め、特定の技術へのロックインを防止する機能を開発する方法を網羅します。 これにより、Android Composeアプリ向けの高品質なナビゲーションコードが書けるだけでなく、オブジェクト指向開発の考え方も身につけられます。 本記事では、Dagger/Hiltを使用したMVVMアーキテクチャを前提としています。 ここでは、ナビゲーションルート→ViewModel→UIのパスのみを通じてデータを提供し、ナビゲーションルート→UIの直接的なデータ提供は行いません。 Android Navigationバックスタックに関する事前知識が必要となります。 ナビゲーションボタンの素早い連続クリックによるUXの問題などは考慮していません。 ディープリンクには対応していません。 Android OSレベルでサポートされているバックジェスチャの取り扱いについては説明していません。 厳密な引数の検証やパフォーマンスの最適化については触れていません。 本記事で使用している用語や名称は便宜的なものであり、一般的な技術用語や学術的な表現とは異なる場合があります。 この記事は、 KINTOテクノロジーズ・アドベントカレンダー2024 の16日目の記事です🎅🎄 ナビゲーションタイプ 詳細 詳細情報を提供する画面へ移動する際は、一般的にリスト画面から特定の項目画面へ遷移します。例えば、ニュースフィードからニュース詳細、メニューからメニュー項目への移動などが該当します。各ナビゲーションアクションによって、バックスタックが1つ増えます。前の画面に戻るには、バックスタックの一番上( pop )を削除します。 navController.navigate("sub3_1") のように、route stringを指定して NavController.navigate functionを呼び出せます。 @Composable fun NavigationGraph() { val navController = rememberNavController() NavHost(navController, "splash") { composable("main3") { val viewModel: Main3ViewModel = hiltViewModel() Main3Screen( id = viewModel.id, navMain1 = { /* ... */ }, navMain2 = { /* ... */ }, navMain3 = { /* ... */ }, navSub31 = { navController.navigate("sub3_1") }, navSub32 = { navController.navigate("sub3_2") }, navSub33 = { navController.navigate("sub3_3") } ) } } } 切り替え このタイプのナビゲーションでは、ユーザーは別の画面に移動するのではなく、同じ画面内でコンテンツが変化したと認識します。通常、タブや下部のナビゲーションバーで使用されます。 下部ナビゲーションバーの場合、バックスタックの高さは変わりません。バックスタックの一番下は、 必ず Main#1 、 Main#2 、または Main#3 のいずれかである必要があります。 バックスタックから自身を削除するには、 popUpTo の呼び出しが必要で、必要に応じて UI 状態の保存と復元が求められることがあります。 @Composable fun NavigationGraph() { val navController = rememberNavController() NavHost(navController, "splash") { composable("main3") { val viewModel: Main3ViewModel = hiltViewModel() Main3Screen( id = viewModel.id, navMain1 = { navController.navigate("main1") { popUpTo("main1") { inclusive = true saveState = true } launchSingleTop = true restoreState = true } }, navMain2 = { navController.navigate("main2") { popUpTo("main2") { inclusive = true saveState = true } launchSingleTop = true restoreState = true } }, navMain3 = { navController.navigate("main3") { popUpTo("main3") { inclusive = true saveState = true } launchSingleTop = true restoreState = true } }, navSub31 = { /* ... */ }, navSub32 = { /* ... */ }, navSub33 = { /* ... */ } ) } } } 一方向 このタイプのナビゲーションでは、前の画面に戻れない画面へ遷移します。バックスタックから自身を削除し( pop )、遷移先の画面を追加します ( push )。例えば、フォームを送信した後やスプラッシュ画面から移動した後に、元の画面へ戻れないケースなどが該当します。 戻れないようにするだけなら popBackStack で対応できますが、 必要に応じて popUpTo を使用し、バックスタックから複数の画面を削除することもできます。 @Composable fun NavigationGraph() { val navController = rememberNavController() NavHost(navController, "splash") { composable("splash") { val viewModel: SplashViewModel = hiltViewModel() SplashScreen( timeout = viewModel.timeout, navMain1 = { navController.popBackStack() navController.navigate("main1") } ) } composable("transactional3") { val viewModel: Transactional3ViewModel = hiltViewModel() Transactional3Screen( onClickSave = { /* ... */ }, onClickSubmit = { viewModel.onClickSubmit { navController.navigate("transactional1") { popUpTo("sub1") { inclusive = true } } } } ) } } } トランザクション(分割) このタイプのナビゲーションでは、非常に複雑または長い単一の画面を、複数のステップに分割します。伝える情報が多い場合や、ユーザーにアクションを求める場合に、ストレスを軽減してUXを向上させるために使用されます。ユーザーは途中でフローを終了できますが、再び入るときは最初から開始する必要があります。タスクを完了したり、フローから離れたりすると、フロー全体がバックスタックから削除されます。このアプローチは、フォームを含む複雑なUIの途中放棄を防ぐために、一方向ナビゲーションと組み合わせることができます。 フロー内では前後に自由に移動できますが、フローを終了するときは popUpTo を使ってバックスタックからフロー内のすべての画面を削除する必要があります。 @Composable fun NavigationGraph() { val navController = rememberNavController() NavHost(navController, "splash") { composable( route = "transactional1", arguments = listOf( navArgument("draft") { type = NavType.IntType } ) ) { val viewModel: Transactional1ViewModel = hiltViewModel() Transactional1Screen( id = viewModel.id, onClickBack = { viewModel.onClickBack { navController.popBackStack() } }, onClickSave = { viewModel.onClickSave { navController.navigate("sub2") { popUpTo("transactional1") { inclusive = true } } } }, onClickNext = { navController.navigate("transactional2") } ) } } } ナビゲーション管理 Sub#1 画面と、その関連する遷移(赤で強調)を使用して、オブジェクト指向の方法でナビゲーションを管理する方法を説明します。オブジェクト指向の要素を段階的に導入していきます。 Sub#1 画面には、次の条件があります。 Sub#1 画面を開くには、 draft パラメータ、または param1 、 param2 、 param3 、 Param4 パラメータの組み合わせが必要です。 Sub #1 画面から Sub #2 画面に移動するには、長時間実行される save 関数の完了を待つ必要があります。 Sub #1 画面から Transactional #1 画面に移動するには、長時間実行される start 関数の完了を待つ必要があります。 ViewModel はナビゲーショングラフやUIから独立している必要があります。ナビゲーションルートから直接受け取った引数を使用するか、それを元にデータを取得し、UI に必要なプロパティを設定する必要があります。 @HiltViewModel class Sub1ViewModel @Inject constructor( handle: SavedStateHandle, private val draftModel:DraftModel ) :ViewModel() { val id:UUID = UUID.randomUUID() val draft: Draft? = handle.get<Int?>("draft")?.let { runBlocking { if (null != draft && 0 < draft) { draftModel.get(draft)!!.also { param1 = it.param1 param2 = it.param2 param3 = it.param3 param4 = it.param4 } } } } var param1: String? = handle["param1"] private set var param2: String? = handle["param2"] private set var param3: String? = handle["param3"] private set var param4: String? = handle["param4"] private set fun onClickSave(callback: () -> Unit) { viewModelScope.launch { // Long save task. delay(2_000) callback() } } fun onClickStart(callback: () -> Unit) { viewModelScope.launch { // Long start task. delay(2_000) callback() } } } ガイドドキュメントの基本機能のみを使用する 「 ナビゲーショングラフの最小例 」ガイドを基に記述されたナビゲーションでは、 NavigationGraph に次の役割があります。 画面の登録 画面ルートのパラメータリストの宣言と登録 画面ナビゲーション用の route stringsの作成 NavController.Navigate のカプセル化 画面のUIを実行し、カプセル化された NavController.Navigate ロジックを渡す /** * ガイドドキュメント形式のナビゲーショングラフ */ @Composable fun NavigationGraph() { val navController = rememberNavController() NavHost(navController, "splash") { composable( route = "sub1?${ listOf( "draft={draft}", "param1={param1}", "param2={param2}", "param3={param3}", "param4={param4}" ).joinToString("&") }", arguments = listOf( navArgument("draft") { type = NavType.IntType defaultValue = 0 }, navArgument("param1") { type = NavType.StringType nullable = true }, navArgument("param2") { type = NavType.StringType nullable = true }, navArgument("param3") { type = NavType.StringType nullable = true }, navArgument("param4") { type = NavType.StringType nullable = true } ) ) { Sub1Screen( navBack = navController::popBackStack, navSub2 = { navController.navigate("sub2") { popUpTo("sub1") { inclusive = true } } }, navTransactional1 = { draft -> if (null == draft) { navController.navigate("transactional1") } else { navController.navigate("transactional1?draft=${draft.id}") } } ) } } } /** * ナビゲーション(カプセル化)、`ViewModel`(状態ホイスティング)、UI をつなぐ */ @Composable fun Sub1Screen( viewModel: Sub1ViewModel = hiltViewModel(), navBack: () -> Unit = {}, navSub2: () -> Unit = {}, navTransactional1: (Draft?) -> Unit = {} ) { Sub1Content( id = viewModel.id, param1 = viewModel.param1!!, param2 = viewModel.param2!!, param3 = viewModel.param3!!, param4 = viewModel.param4!!, onClickBack = navBack, onClickSave = { viewModel.onClickSave(callback = navSub2) }, onClickStart = { viewModel.onClickStart(callback = { navTransactional1(viewModel.draft) }) } ) } /** * 引数の状態を表示するだけ */ @Composable private fun Sub1Content( id: UUID, param1: String, param2: String, param3: String, param4: String, onClickBack: () -> Unit = {}, onClickSave: () -> Unit = {}, onClickStart: () -> Unit = {} ) { IconButton(onClick = onClickBack) { Icon(Icons.AutoMirrored.Filled.ArrowBack, "back") } // ... Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { OutlinedButton( onClick = onClickSave, modifier = Modifier.padding(16.dp) ) { Text("SAVE", style = MaterialTheme.typography.labelLarge) } Button( onClick = onClickStart, modifier = Modifier.padding(16.dp) ) { Text("START", style = MaterialTheme.typography.labelLarge) } } } 進行中の課題 長いナビゲーショングラフコード : NavigationGraph のコードは、画面数、各画面の引数、接続された画面、バックスタック操作が増えるにつれて長くなります。 コード順と実行順 の不一致:コードが記述される順序は、そのまま読み込まれる順序になりますが、実行順とは一致しません。この不一致により、開発者は読み取っているコードが現在のコンテキストに関連しているかどうかを常に判断する必要があり、認知的オーバーヘッドが増え、メンテナンスが難しくなります。 UI関数のパラメータが多すぎる :UI関数( Sub1Screen )のパラメータ数は、接続される画面が増えるほど増加します。例えば、詳細な設定項目が多い設定画面では、それに応じてパラメータの数も増えてしまいます。 Navigator の導入 ナビゲーターを導入する目的は、UI 関数のパラメータ数を減らすことです。UI 関数のナビゲーション関連パラメータをナビゲーターオブジェクトにまとめます。 ナビゲータの役割: Sub#1 から移動可能な画面をオブジェクトにグループ化 :ナビゲーターオブジェクトは、 Sub#1 画面から遷移できる画面のナビゲーションロジックをカプセル化します。 ナビゲーション route の作成 :ナビゲーターオブジェクトが、ナビゲーションに必要な route stringsを生成します。 バックスタックの操作 :ナビゲーターオブジェクトは、画面の pop やpush などのバックスタック操作を管理し、適切なナビゲーションフローを維持します。 @Immutable class Sub1Navigator( private val navController: NavController ) { fun back() { navController.popBackStack() } fun sub2() { navController.navigate("sub2") { popUpTo("sub1") { inclusive = true } } } fun transactional1(draft: Drift? = null) { if (null == draft) { navController.navigate("transactional1") } else { navController.navigate("transactional1?draft=${draft.id}") } } } Navigator を導入し、ナビゲーションルートの作成とバックスタック操作コードを分離することで、 NavigationGraph がよりシンプルになりました。 composable( route = "sub1?${ listOf( "draft={draft}", "param1={param1}", "param2={param2}", "param3={param3}", "param4={param4}" ).joinToString("&") }", arguments = listOf( navArgument("draft") { type = NavType.IntType defaultValue = 0 }, navArgument("param1") { type = NavType.StringType nullable = true }, navArgument("param2") { type = NavType.StringType nullable = true }, navArgument("param3") { type = NavType.StringType nullable = true }, navArgument("param4") { type = NavType.StringType nullable = true } ) ) { Sub1Screen(navigator = remember(navController) { Sub1Navigator(navController) }) } Sub1Screen では、ナビゲーション関連のパラメータを 1 つのオブジェクトにまとめることでパラメータ数が減り、オブジェクトメンバーとしてカプセル化することでコールコードがより明確になります。 @Composable fun Sub1Screen( navigator:Sub1Navigator, viewModel:Sub1ViewModel = hiltViewModel() ) { Sub1Content( id = viewModel.id, param1 = viewModel.param1!!, param2 = viewModel.param2!!, param3 = viewModel.param3!!, param4 = viewModel.param4!!, onClickBack = navigator::back, onClickSave = { viewModel.onClickSave(callback = navigator::sub2) }, onClickStart = { viewModel.onClickStart(callback = { navigator.transactional1(viewModel.draft) }) } ) } 進行中の課題 UI 関数は簡素化されましたが、ナビゲーショングラフの複雑さは変わらず、開発者は次の役割のために継続的なコンテキスト切り替えを求められます。 画面の登録 画面ルートのパラメータリストの宣言と登録 Navigator コンパニオンオブジェクト NavigationGraph の機能を簡素化し、ナビゲーション情報を一元化するために、Navigatorクラス内で コンパニオンオブジェクト を使用できます。このアプローチにより、routes と argumentsを1か所で定義できます。方法は次のとおりです。 Navigator クラスの コンパニオンオブジェクト内 でroutes と argumentsを定義する。 これらの定義を、 NavigationGraph 関数で使用する。 @Immutable class Sub1Navigator( private val navController: NavController ) { @Suppress("MemberVisibilityCanBePrivate") companion object { const val ARG_DRAFT = "draft" const val ARG_PARAM1 = "param1" const val ARG_PARAM2 = "param2" const val ARG_PARAM3 = "param3" const val ARG_PARAM4 = "param4" const val ROUTE = "sub1?" + "$ARG_DRAFT={draft}&" + "$ARG_PARAM1={param1}&" + "$ARG_PARAM2={param2}&" + "$ARG_PARAM3={param3}&" + "$ARG_PARAM4={param4}" val ARGUMENTS = listOf( navArgument(ARG_DRAFT) { type = NavType.LongType defaultValue = 0 }, navArgument(ARG_PARAM1) { type = NavType.StringType nullable = true }, navArgument(ARG_PARAM2) { type = NavType.StringType nullable = true }, navArgument(ARG_PARAM3) { type = NavType.StringType nullable = true }, navArgument(ARG_PARAM4) { type = NavType.StringType nullable = true } ) } // ... } ナビゲータークラスで コンパニオンオブジェクト を使用することで、ナビゲーショングラフを単純化し、画面登録と UI 関数の呼び出しに集中できるようになります。UI 関数自体は変更されません。 composable( route = Sub1Navigator.ROUTE, arguments = Sub1Navigator.ARGUMENTS ) { Sub1Screen(navigator = remember(navController) { Sub1Navigator(navController) }) } 進行中の課題 Sub#1 画面のみを考慮する場合、これで十分です。しかし、 Sub #1 画面に移動する必要がある Main #1 や Sub #2 のナビゲーターも含める場合、次のような対応が必要になります。 @Immutable class Main1Navigator( private val navController: NavController ) { // ... fun sub1(item:Main1Item) { navController.navigate("sub1?param1=${item.param1}&param2=${item.param2}&param3=${item.param3}&param4=${item.param4}") } } @Immutable class Sub2Navigator( private val navController: NavController ) { // ... fun sub1(draft: Draft) { navController.navigate("sub1?draft=${draft.id}") { popUpTo(Main2Navigator.ROUTE) { inclusive = true } } } } Sub1Navigator は有効な route フォーマットを管理しますが、実際の route の作成は Main1Navigato と Sub2Navigator が処理するため、 Sub#1 のroute管理が Sub#1 に集中せず、ユーザー側に分散してしまうという一貫性のない状態になります。 共有宛先の処理 有効な route フォーマットと、有効な route 値を構成するロジックを、一緒に管理するのが妥当です。各 companion object に route 作成ロジックを移動させることで、標準化できます。 route 自体とその組み立てをカプセル化する。 オブジェクトベースのナビゲーションを実装する。 @Immutable class Sub1Navigator( private val navController: NavController ) { companion object { // ... const val ARG_DRAFT = "draft" const val ARG_PARAM1 = "param1" const val ARG_PARAM2 = "param2" const val ARG_PARAM3 = "param3" const val ARG_PARAM4 = "param4" fun route(item:Main1Item) = "sub1?$ARG_PARAM1=${item.param1}&$ARG_PARAM2=${item.param2}&$ARG_PARAM3=${item.param3}&$ARG_PARAM4=${item.param4}" fun route(draft:Draft) = "sub1?draft=${draft.id}" } // ... } @Immutable class Main1Navigator( private val navController: NavController ) { // ... fun sub1(item: Main1Item) { navController.navigate(Sub1Navigator.route(item)) } } @Immutable class Sub2Navigator( private val navController: NavController ) { // ... fun sub1(draft: Draft) { navController.navigate(Sub1Navigator.route(draft)) { popUpTo(Main2Navigator.ROUTE) { inclusive = true } } } } 進行中の課題 画面を登録する際は、 route 、 arguments 、そしてナビゲーターインスタンスの作成を同じクラス内でまとめて管理することが重要です。もし誤りがあると、次のような論理エラーが発生する可能性があります。 不整合なルート定義 :routeとargumentsが一貫して定義されていない場合、ナビゲーションが失敗したり、予期しない動作をする可能性があります。 不正なナビゲーターインスタンス :異なる ナビゲーターインスタンスを使用すると、ナビゲーションロジックのエラーが発生し、アプリが誤った画面に遷移したり、ナビゲーションが機能しなくなったりする可能性があります。 composable( route = Main1Navigator.ROUTE, arguments = Transactional1Navigator.ARGUMENTS ) { Sub1Screen(navigator = remember(navController) { Sub1Navigator(navController) }) } Navigator、 コンパニオンオブジェクト の抽象化、および宛先処理の標準化 ナビゲーターとその コンパニオンオブジェクト を抽象化し、次のプロパティを定義できます interface Navigator { val destination: Destination } interface Destination { val routePattern: String val arguments: List<NamedNavArgument> fun route(varargs arguments: Any?): String } ナビゲーターと コンパニオンオブジェクト がそれぞれ Navigator と Destination を実装している場合、ナビゲーショングラフの設定は次のように標準化されます。 @Immutable class Sub1Navigator( private val navController: NavController ):Navigator { companion object:Destination { const val ARG_DRAFT = "draft" const val ARG_PARAM1 = "param1" const val ARG_PARAM2 = "param2" const val ARG_PARAM3 = "param3" const val ARG_PARAM4 = "param4" override val routePattern = "sub1?$ARG_DRAFT={draft}&$ARG_PARAM1={param1}&$ARG_PARAM2={param2}&$ARG_PARAM3={param3}&$ARG_PARAM4={param4}" override val arguments = listOf( navArgument(ARG_DRAFT) { type = NavType.LongType defaultValue = 0 }, navArgument(ARG_PARAM1) { type = NavType.StringType nullable = true }, navArgument(ARG_PARAM2) { type = NavType.StringType nullable = true }, navArgument(ARG_PARAM3) { type = NavType.StringType nullable = true }, navArgument(ARG_PARAM4) { type = NavType.StringType nullable = true } ) override fun route(varargs arguments: Any?): String = when { 1 == arguments.size && arguments[0] is Main1Item -> route(arguments[0] as Main1Item) 1 == arguments.size && arguments[0] is Draft -> route(arguments[0] as Draft) else -> throw IllegalArgumentException("Invalid arguments : arguments=$arguments") } fun route(item: Main1Item) = "sub1?$ARG_PARAM1=${item.param1}&$ARG_PARAM2=${item.param2}&$ARG_PARAM3=${item.param3}&$ARG_PARAM4=${item.param4}" fun route(draft: Draft) = "sub1?draft=${draft.id}" } override val destination = Companion } NavigationGraph の役割は次のとおりです。  ナビゲーターインスタンスの作成 抽象化されたナビゲーションオブジェクトをUI関数と接続する。 Main1Navigator(navController).let { navigator -> composable(navigator.destination.routePattern, navigator.destination.arguments) { Main1Screen(navigator) } } Sub1Navigator(navController).let { navigator -> composable(navigator.destination.routePattern, navigator.destination.arguments) { Sub1Screen(navigator) } } Sub2Navigator(navController).let { navigator -> composable(navigator.destination.routePattern, navigator.destination.arguments) { Sub2Screen(navigator) } } 開発の生産性向上 グローバルナビゲーション Web ブラウザの起動、電話の発信、アプリ設定を開く、アプリの再起動、UI の再読み込みなどは、画面に関係なく必要になることがあります。これらの 共通機能 を、各画面ごとに個別実装するよりも、単一の実装を共有する方が効率的です。 @Immutable class Sub1Navigator( private val navController: NavController ): Navigator { fun web(uri: Uri) { /* Indivisual impl */ } fun call(phoneNumber: String) { /* Indivisual impl */ } } @Immutable class Sub31Navigator( private val navController: NavController ): Navigator { fun web(uri: Uri) { /* Indivisual impl */ } fun settings() { /* Indivisual impl */ } } ソリューション Navigator インターフェースで共通関数を宣言し、ユニバーサル関数を実装した上で、各スクリーンのナビゲーターに委任することで共通化を実現できます。 /** * 共通のナビゲーション関数を定義するインターフェース */ interface Navigator { val destination: Destination fun web(uri: Uri) fun call(phoneNumber: String) fun settings() fun reopen() fun restart() } /** * 共通のナビゲーション関数を実装する基底クラス */ open class BaseNavigator( private val activity: Activity, val navController: NavController ): Navigator { override fun web(uri: Uri) { activity.startActivity(Intent(ACTION_VIEW, uri)) } // ... override fun reopen(){ activity.finish() activity.startActivity(Intent(activity, activity::class.java)) } override fun restart() { activity.startActivity(Intent(activity, activity::class.java)) exitProcess(0) } } /** * 各画面のナビゲーターが共通のナビゲーション機能を委譲 */ @Immutable class Sub1Navigator( private val baseNavigator: BaseNavigator ): Navigator by baseNavigagor { fun sub2() { baseNavigator.navController.navigate(Sub2Navigator.route()) { popUpTo(routePattern) { inclusive = true } } } } @AndroidEntryPoint class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { NavigationGraph(this@MainActivity) } } } /** * `NavController` を `BaseNavigator` インスタンスに置き換える * * @param activity ナビゲーショングラフを所有するアクティビティ */ @Composable fun NavigationGraph(activity: Activity) { val baseNavigator = BaseNavigator(activity, rememberNavController()) NavHost(baseNavigator.navController, SplahNavigator.routePattern) { Sub1Navigator(baseNavigator).let { navigator -> // ... } } } ナビゲーショングラフ設定ユーティリティ 以下のような論理的エラーのリスクがあります。 Sub1Navigator(baseNavigator).let { navigator -> composable(Main1Navigator.routePattern, Transactional1Navigator.arguments) { Sub1Screen(navigator) } } ソリューション ナビゲーターインスタンスと画面登録を処理するユーティリティ関数を追加することで、 fun <N :Navigator> NavGraphBuilder.composable( navigator: N, content: @Composable AnimatedContentScope.(NavBackStackEntry, N) -> Unit ) { composable( route = navigator.destination.routePattern, arguments = navigator.destination.arguments ) { backStackEntry -> content(backStackEntry, navigator) } } ナビゲーショングラフの構成を単純化し、論理エラーの可能性を排除することができます。 composable(Main1Navigator(baseNavigator)) { _, navigator -> Main1Screen(navigator) } composable(Sub1Navigator(baseNavigator)) { backStackEntry, navigator -> Sub1Screen(navigator) } composable(Sub2Navigator(baseNavigator)) { _, navigator -> Sub2Screen(navigator) } @Preview のサポート 静的リソースをバンドルで表示する画面では、引数として別のイベントハンドラを渡すのではなく、ナビゲーターのみを渡すことで ナビゲーションコードを記述できます。 例: @Composable fun StaticResourceListScreen(navigator: StaticResourceListNavigator) { Column { Button(onClick = navigator::static1) { Text("Static#1") } Button(onClick = navigator::static2) { Text("Static#2") } Button(onClick = navigator::static2) { Text("Static#2") } } } @Preview コードでは、 Navigatorインスタンスごとに BaseNavigator(PreviewActivity(), rememberNavController()) を繰り返し記述することになります。 プレビューの種類や数が増えると、プレビューの記述が面倒になります。そして、このオーバーヘッドが原因で開発者がプレビューをスキップしてしまうこともあります。 @Composable @Preview(showSystemUi = true) fun PreviewStaticResourceListScreen() { MaterialTheme { StaticResourceListScreen(StaticResourceListNavigator(BaseNavigator(PreviewActivity(), rememberNavController()))) } } @Composable @Preview(showSystemUi = true) fun PreviewStatic1Screen() { MaterialTheme { Static1Screen(Static1Navigator(BaseNavigator(PreviewActivity(), rememberNavController()))) } } @Composable @Preview(showSystemUi = true) fun PreviewStatic2Screen() { MaterialTheme { Static2Screen(Static2Navigator(BaseNavigator(PreviewActivity(), rememberNavController()))) } } @Composable @Preview(showSystemUi = true) fun PreviewStatic3Screen() { MaterialTheme { Static3Screen(Static3Navigator(BaseNavigator(PreviewActivity(), rememberNavController()))) } } ソリューション BaseNavigator をインスタンス化するユーティリティ関数を作成し、実際のアプリケーションとプレビューを個別に処理 できるように実装します。 @Composable fun baseNavigator( activity: Activity = if (LocalInspectionMode.current) { PreviewActivity() } else { LocalContext.current as Activity } ):BaseNavigator { val navHostController = rememberNavController() val base = remember(activity) { BaseNavigator(activity, navHostController) } return base } @Composable fun NavigationGraph(activity: Activity) { val baseNavigator = baseNavigator(activity) NavHost(navController, SplahNavigator.routePattern) { // ... } } @Composable @Preview(showSystemUi = true) fun PreviewStaticResourceListScreen() { MaterialTheme { StaticResourceListScreen(StaticResourceListNavigator(baseNavigator())) } } @Composable @Preview(showSystemUi = true) fun PreviewStatic1Screen() { MaterialTheme { Static1Screen(Static1Navigator(baseNavigator())) } } @Composable @Preview(showSystemUi = true) fun PreviewStatic2Screen() { MaterialTheme { Static2Screen(Static2Navigator(baseNavigator())) } } @Composable @Preview(showSystemUi = true) fun PreviewStatic3Screen() { MaterialTheme { Static3Screen(Static3Navigator(baseNavigator())) } } カスタムスタート画面 これまで使用していた NavigationGraph 設定機能は、スタート画面の変更は可能ですが、使用できるナビゲーショングラフは 1 つのみ です。そのため、既存の機能の一部だけを活用した デモアプリケーションの開発はできません。 @AndroidEntryPoint class DemoActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { NavigationGraph(this@DemoActivity) // 固定されたスタート画面  } } } @AndroidEntryPoint class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { NavigationGraph(this@MainActivity) } } } @Composable fun NavigationGraph(activity: Activity) { val baseNavigator = baseNavigator(activity) NavHost(navController, SplahNavigator.routePattern) { Sub1Navigator(baseNavigator).let { navigator -> composable(navigator.destination.routePattern, navigator.destination.arguments) { Sub1Screen(navigator) } } } } ソリューション BaseNavigator に destination を実装し、アクティビティからホイストされた BaseNavigator インスタンスをナビゲーショングラフに渡します。 open class BaseNavigator( private val activity: Activity, val navController: NavController, override val destination: Desination ):Navigator { // ... } /** * @param startDestination プレビュー時のみ使用可能なデフォルト値 */ @Composable fun baseNavigator( activity: Activity = if (LocalInspectionMode.current) { PreviewActivity() } else { LocalContext.current as Activity }, startDestination: Destination = if(LocalInspectionMode.current || activity is PreviewActivity) { object: Destination { override val routePattern = "preview" // ... } } else { throw IllegalArgumentException ("本番環境では `startDestination` を指定する必要があります。") } ): BaseNavigator { val navHostController = rememberNavController() val base = remember(activity) { BaseNavigator(activity, navHostController) } return base } @AndroidEntryPoint class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { NavigationGraph(baseNavigator(destination = SplashNavigator.Companion)) } } } @Composable fun NavigationGraph(baseNavigator: BaseNavigator = baseNavigator()) { //追加の共通ナビゲーション機能を実装 NavHost( // Encapsulate the `navigation-compose` dependency in activity(`MainActivity`) and UI(`UiRoot`). baseNavigator.navController, baseNavigator.destination.routePattern ) { // ... } } DEMOアプリ開発サポート ナビゲーショングラフの設定機能( NavigationGraph )では、スタート画面の変更は可能ですが、使用できるナビゲーショングラフとスタート画面は 1 つのみです。そのため、既存の機能の一部だけを活用した デモアプリケーションの開発はできません。 @Composable fun NavigationGraph(baseNavigator: BaseNavigator = rememberBaseNavigator()) { NavHost( navController = baeNavigator.navController, startDestination = baseNavigator.destination.routePattern ) { // ... } } ソリューション ナビゲーショングラフ構成コードを、 navigation-compose のコールから分離します。これにより、ナビゲーショングラフの構築、ナビゲーターと UI 機能の接続、共通ナビゲーション機能の分離 が可能になり、さらに 依存関係のカプセル化 も実現できます。 @Composable fun NavigationGraph(baseNavigator: BaseNavigator = rememberBaseNavigator(), builder: NavGraphBuilder.() -> Unit) { NavHost( navController = baeNavigator.navController, startDestination = baseNavigator.destination.routePattern, builder = builder ) } プロダクションアプリ @AndroidEntryPoint class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { UiRoot(baseNavigator(destination = SplashNavigator.Companion)) } } } @Composable fun UiRoot(baseNavigator: BaseNavigator) { NavigationGraph(baseNavigator) { // ... composable(Sub1Navigator(baseNavigator)) { _, navigator -> Sub1Screen(navigator) } // ... } } デモアプリ @AndroidEntryPoint class DemoActivity : ComponentActivity() { override fun onCreate(savedInstanceState:Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { DemoUiRoot(baseNavigator(destination = Transactional1Navigator.Companion)) } } } @Composable fun DemoUiRoot(baseNavigator: BaseNavigator) { NavigationGraph(baseNavigator) { composable(Transactional1Navigator(baseNavigator)) { _, navigator -> Transactional1Screen(navigator) } } } 用語の統一 ガイドドキュメント では、 screen という用語を ナビゲーションターゲット を指すために使っています。しかし、多くの UI デザインシステム(例: Atomic Design 、 Carbon Design System 、 Ant Design 、 Shopify Polaris など)では、 ページ を使い、ナビゲーションターゲットに使用し、 screen は物理デバイスのディスプレイに使用します。 さらに、ナビゲーショングラフに画面を登録するとき、関数名 composable は @Composable 関数が呼び出されたことを示すために使用されます。 開発者向けの専門用語を 開発以外の分野でも通じる表現に統一することで、混乱や意味の確認が不要になり、スムーズで素早いコミュニケーション ができるようになります。そのため、用語の統一が望ましいというわけです。 fun <N : Navigator> NavGraphBuilder.composable( navigator: N, content: @Composable AnimatedContentScope.(NavBackStackEntry, N) -> Unit ) { composable( route = navigator.destination.routePattern, arguments = navigator.destination.arguments ) { entry -> content(entry, navigator) } } @Composable fun UiRoot(baseNavigator: BaseNavigator) { NavigationGraph(baseNavigator) { composable(Sub1Navigator(baseNavigator)) { _, navigator -> Sub1Screen(navigator) } } } @Composable fun Sub1Screen(navigator: Sub1Navigator, viewModel:Sub1ViewModel = hiltViewModel()) { // ... } ソリューション 設計システムとして Atomic Design を採用していると仮定し、ナビゲーションターゲットには screen ではなく page を使用する形で用語を統一します。 fun <N : Navigator> NavGraphBuilder.page( navigator: N, content: @Composable AnimatedContentScope.(NavBackStackEntry, N) -> Unit ) { composable( route = navigator.destination.routePattern, arguments = navigator.destination.arguments ) { entry -> content(entry, navigator) } } @Composable fun UiRoot(baseNavigator: BaseNavigator) { NavigationGraph(baseNavigator) { page(Sub1Navigator(baseNavigator)) { _, navigator -> Sub1Page(navigator) } } } @Composable fun Sub1Page(navigator: Sub1Navigator, viewModel: Sub1ViewModel = hiltViewModel()) { // ... } 結論 最初は、ガイドドキュメントの基本機能だけを使っていたため、構造はシンプルでした。 オブジェクト指向ナビゲーション設計を取り入れることで、特定のナビゲーション仕様に影響されることなく、それぞれが特殊機能を担当する複数のジェネリック型や機能を実現できるようになりました。 Navigator :UI に関連する グループナビゲーション を管理し、ナビゲーショングラフにどのように登録されるかを決めるプロパティを定義する。 Destination :ナビゲーショングラフにページを登録するためのプロパティを定義する。 BaseNavigator : Application 、 Activity 、およびナビゲーショングラフの統合を定義し、共通・グローバルナビゲーションを実装する。 NavGraphBuilder.page :ナビゲーショングラフと各ページを Navigator ) を通じて接続する。 @Composable fun NavigationGraph : navigation-compose をカプセル化し、共通のナビゲーション機能を実装することで、共通機能と具体的なナビゲーショングラフを分離する。 @Composable fun baseNavigator :開発の利便性を向上させる。 ジェネリックオブジェクトの構造は以下のとおりです。 汎用オブジェクトを使用してナビゲーショングラフを構築すると、どうしても複雑な構造になりがちです。しかし、すでに汎用的な機能が整備されている場合、アプリケーションレベルの開発では考慮すべき要素が減るため、開発期間を短縮できます。その結果、新しい画面を追加するときの平均的な開発コストが低下します。 この設計アプローチが、 すべての分野、製品、開発環境、個人に必要というわけではありません。必要に応じて、優先度を下げたり、別の解決策を選択することが求められます。本記事で紹介しているオブジェクト指向設計あくまで一例です。ただ、ここで紹介した設計上の課題や方向性は、他のソフトウェア開発にも応用可能です。 オブジェクト指向設計とは? オブジェクト指向設計は、必ずしもコードを短くし、シンプルな構造にするためのものではありません。コードは役割ごとに分割されている場合にのみ、見た目がシンプルになります。例えば、このガイドの手法に従っても、ナビゲーショングラフ全体を構築する機能と各画面の機能は別々に記述することになります。極端な話、すべての画面を NavigationGraph 内に実装すること可能ですし、 NavigationGraph をまったく使わずに、 MainActivity では setContent を呼び出してすべての画面を構築することもできます。 オブジェクト指向設計は、コードの役割と、その機能を実現するために必要な責務を分析することから始まります。そこから何をグループ化し、どのようにタイプやファイルに分割すべきかを決めます。各コードは、 import またはオブジェクト参照を通じて接続されています。最終的に、どの開発者がコードを管理し、それに関する調査や保守の責任を負うのかが決まります。 IT業界において、開発者は非常に重要な生産リソースです。そのため、コストと生産性は開発者がどのように時間を使うかに大きく左右されます。このことから、開発者の認知能力は貴重なリソースとなります。技術スキルが高く、製品への理解が深まり、作業履歴に関する知識が豊富であるほど、開発者の集中力が生み出す価値も高まります。現在見ているコードが今のタスクに必要かどうかを判断する認知オーバーヘッド は、最も価値の低い形で開発者の集中力(認知能力)を消費してしまいます。集中力が低下すると、生産性も落ちてしまいます。 オブジェクト指向設計を適用すると、必然的に構造が複雑になり、コードを正しく理解するために 深い技術的知識や過去の開発履歴に関する知識が必要になります。 オブジェクト指向設計_は、表面レベルの機能を迅速かつ容易に開発できる環境を整えるために、事前に大規模な開発と学習を必要とする開発手法です。 オブジェクト指向設計のリスクとコスト オブジェクト指向設計は、大量の汎用機能と複雑な構造 を活用し、高い生産性を実現するための開発手法です。しかし、汎用的な機能や構造には限界があります。そして、これらの制限を超える変更は、いつ発生してもおかしくありません。開発者ではないプランナー、マネージャー、デザイナーは、暗黙の知識(ドメイン知識)を日常的に習得・活用しているわけではありません。そのため、一見シンプルに思える変更が、なぜ実際には難しく、時間がかかるのかを理解するのはほぼ不可能 です。開発者同士であっても、暗黙知を持っていない人は、それを理解するのが難しいと感じるでしょう。この問題は、個人が暗黙知を身につけることや、開発者が繰り返し説明して理解してもらうことで解決できるものではありません。代わりに、これは個人の問題ではなく、組織や企業全体での体系的かつ文化的な解決策が求められる課題です。 特に、企業や組織の生産性向上を目的としてオブジェクト指向設計を導入する場合、開発者同士や、開発者と他の職種との間で生じる暗黙知の違いによる衝突を管理することが重要になります。そして、そこにリスク(またはコスト)が発生します。もちろん、オブジェクト指向設計が適切に機能している場合は問題になりません。その前に、誰がオブジェクト指向設計を担当するのか、そして 組織や企業レベルで責任者をどのように決定するのかが大きな課題となります。もしこの判断を誤ると、組織や企業にとって最も貴重なリソースである「チームワーク」 が損なわれる可能性があります。 参考 Design your navigation graph / Minimal example android/compose-samples > Jetnews > HomeScreens Atomic Design Carbon Design System Ant Design Shopify Polaris
アバター
👋 はじめに こんにちは! Toyota Community by KINTO プラットフォームのプロダクトデザイナーのMoji です。 今回は、このプラットフォーム作成の裏話(コラボレーション、イノベーション、用途に合わせたデザインの道のり)についてご紹介できて嬉しいです。 私にとって、デザインは美しさを追求するだけのものではなく、課題を解決しながら、ユーザーのニーズとビジネスの目標をうまく調和させることだと思います。そういったわけで、Toyota Community by KINTOは私にとってとても刺激的なプロジェクトなのです。 Toyota Community by KINTO のロゴと、プラットフォーム機能を示すモバイル インターフェースのモックアップ 🚀 背景 Toyota Community by KINTO は、 ハッカソンで生まれたシンプルなアイデア から始まり、今ではレスポンスに優れた Webアプリに進化しています。現在、 トヨタの顧客やトヨタ車愛好家たちをひとつのグローバルなプラットフォームでつなぐことを目指して、顧客エンゲージメントを高めるための拡張性のあるソリューションとして提案できるよう、準備を進めています。 過去 2年間、このプロジェクトでは、単純に 設計と開発 に取り組んでいたのではありません。 社内のフィードバックに対応 し、 国や地域による市場の微妙な違い を理解し、 事業目標とユーザーのニーズ の両方に沿った製品を継続的に改良する。このプロセスの連続でした。 2022年 KINTO Global Innovation Days より。優勝したハッカソンチーム、チームコラボレーション、イノベーター・オブ・ザ・イヤー賞の盾の写真。 💡 チャレンジ 分散構造とバリューチェーンのギャップ 自動車業界では、分散型構造で運営されているブランドもあります。このアプローチでは、国や地域で異なる市場ニーズに柔軟かつ的確に対応できるという利点があります。一方で、 グローバルなブランドとしての一貫性を保つことや、購入後の顧客とのつながりを効果的に維持する点 では、課題が生じることもあります。 ここで、集中型ハブを構築する絶好のチャンスが姿を現します。このハブを通じて、ブランドは貴重な顧客の本音をくみ取り、ポジティブかつ影響力のあるかたちでブランドイメージを強化することができます。 競合分析 オンラインコミュニティの現状をより深く理解するために、オンライン上にある従来のカーコミュニティや競合プラットフォームを、 包括的に分析 しました。 重要な気づき 🚗 トヨタ車愛好家の中でも、特に旧車、または復刻モデルの所有者たちは、 Toyota Nation (VerticalScope が運営)や Reddit といった外部プラットフォームにアクセスして、交流したり、フィードバックを共有したり、自分の愛車について語り合っています。 🌐 多くのプラットフォームではすでにコミュニティスペース(フォーラム)が用意されていて、ユーザー同士がつながり、意見を交換し、互いに学び合っているのです。 ですが、その中でひときわ目立ったあるギャップがありました。 車好きは、自分の愛車を披露することにとても強い情熱を持っています。 にもかかわらず、車の所有者が自分専用のバーチャル・ガレージを作って、次のようなことを実現できる特別な場所がなかったのです。 🛠️ 改造やカスタマイズの紹介 📸 車の写真の共有 チャンスの特定 次の3つの戦略的な統合で、私たちのプラットフォームは他のライバルと一線を画す存在になりました。単なる 閉ざされたソーシャル空間 ではなく、ユーザーが本物のコンテンツに触れたり、それについて語り合えるゲートウェイにもなりました。 1.ミスター・ランクルとのつながり TOYOTAの幅広いネットワークの一つとして、トヨタのランドクルーザーの元チーフエンジニアで、 ミスター・ランクル としても知られる 小鑓貞嘉氏 とつながる機会に恵まれました。 このご縁を通じて、 限定動画 および専用の Ask Me Anything (AMA) チャンネルを特集することができました。ユーザーはこのチャンネルでミスター・ランクルと直接やり取りをしたり、質問を投げかけたりしながら、貴重な気づきを得ることができます。 ミスター・ランクルこと小鑓貞嘉さんとのコラボレーション。チームディスカッションや撮影風景など。 2.トヨタイムズから信頼できる自動車ニュースを共有 さらに、信頼性の高い自動車ニュースにも価値があることから、トヨタのオウンドメディアとして知られている トヨタイムズ と交渉し、公式に掲載している記事を当社のWebアプリ上で共有することについて、許可をいただきました。 これにより、ユーザーは 信頼できるブランド 発のコンテンツ にアクセスできるだけでなく、自分自身のストーリーを共有したり、有意義なディスカッションに参加したりできるようになりました。 Toyota Community by KINTO プラットフォーム、ランドクルーザーに関するトヨタイムズ記事スクリーンショット 3.「ガレージ」機能のご紹介 車好きにとって、自分の愛車を披露したり、時間をかけて仕上げたカスタマイズや改造を共有したり、同じ情熱を持つ人たちとつながったりすることは、かけがえのない楽しみのひとつですよね。その気持ち、私たちもよく分かります。 そこで、「ガレージ」機能を導入しました。車のオーナーが、より楽しく、自分らしく愛車を紹介できるようになっています。この機能では、次のようなことができます。 愛車の写真を紹介 カスタマイズや改造の記録、印象的な出来事の記録 自分だけのストーリーを、魅力的なインターフェース上で共有 Toyota Community by KINTOプラットフォーム。バーチャルガレージ内、ユーザーの1981年型ランドクルーザーFJ40ソフトトップのスクリーンショット。改造の詳細や思い出とともに紹介されています。 🎨 ソリューションの設計 ディストリビューターのフィードバック 実用最小限の製品 (MVP)の開発に入る前に、まずは主要な関係者から早期のフィードバックを得ることを目的として、モックアップとプロトタイプを設計しました。得られた意見をもとに何度も改良を重ねて、完成版のプロトタイプをいくつかのマーケットの地域ディストリビューターに提示し、さらなるフィードバックを募りました。 Toyota Community の初期モックアップ。上は、デザイン案に対するフィードバック募るために提案された機能。 受け取ったフィードバックを踏まえ、プラットフォームのデザインを新たなビジネス目標に沿う形に調整し、他と差別化できるポイントを強調しました。 こうして、より多くの時間やリソースを投じる前に概念実証(PoC)を確保することを目標に、MVPの本格的な開発に着手することができたのです。 🛠️ 第1段階 - 開発 実用最小限の製品(MVP)の作成 限られたリソースの中で、ギャップを解消して既存のプラットフォームにはない価値を提供するMVPを設計・開発しました。このプロダクトは、2つの主要機能を軸に、2024年7月に誕生しました。 💬 コミュニティセクション トヨタの文化について語り合えるディスカッションスペースです。ユーザーはスレッドを立てたり、絵文字でリアクションを送ったりしながら交流できます。 ミスター・ランクル専用チャンネル: ミスター・ランクルのガレージ、これまでの体験、インタビューなどを特集した限定コンテンツです。 ミスター・ランクルに何でも質問できる専用チャンネルで、愛好家がミスターと直接交流することができます。 トヨタニュースチャンネル: トヨタについて、信頼できる自動車ニュースを共有する専用チャンネル。 🚘 バーチャルガレージ ユーザーが自分の愛車を写真やストーリーとともに紹介し、ほかのユーザーと共有できる専用スペースです。 Figmaのデザイン画面、各デザイン段階とマイルストーンを示すタイムライン。 Toyota Community by KINTO プラットフォーム上のガレージ、ホーム、コミュニティの3セクションのモバイル画面 ユーザーからのフィードバック収集 製品にとって重要な転機となったのは、当社プロダクトオーナーが、 ドイツで開催されたランドクルーザーのイベント に参加したときでした。 トヨタ車愛好家との直接の交流を通じて、非常に貴重な気づきを得ることができました。参加者からは、小鑓氏のようなトヨタの象徴的な人物と交流しながら、自分の車を披露できるスペースがあるというアイデアに対して、好評の声が寄せられました。 ドイツで開催されたランドクルーザーイベント。改造車両、ランドクルーザーのオーナーや愛好家の集合写真。 このイベントの重要性を実感したことで、私たちはユーザーの記憶に残る、強い存在感というものを築こうと決めました。 KINTOとトヨタ、両ブランドのアイデンティティに自然に調和するロゴとマーケティング資料を作成するため、関係者と緊密に連携しながら、デザインをリードしました。 Toyota Community by KINTOのプロモーション資料のコレクション。バーチャルガレージとコミュニティのメリットを宣伝するチラシを掲載しています。 ユーザーからのフィードバックと、直前でのブランディング作業がうまくかみ合ったことで、 プロダクトの方向性 と ビジュアル アイデンティティ の両方が洗練されて、道筋がぐっと明確になりました。 🔄 第2段階- 改良 導入と拡張 大規模なユーザーに向けてMVPをテストするだけのリソースは、まだ十分にありません。ですが、 ディストリビューターのフィードバックやランドクルーザーイベントで得られた気づきをもとに、プラットフォームの改善は今も着実に進んでいます 。こうした改良が、次の開発段階への足がかりになっています。 Toyota Community by KINTO プラットフォームは、拡張性のあるソリューションとして位置付けられつつあり、断片化されたバリューチェーンに関する課題に応えられる可能性を示しながら、地域ごとの多様なマーケットにも柔軟に対応できる仕組みを備えています。 この先にあるものは? 私たちは今後も、プラットフォームのブラッシュアップを進めながら、さらなる検討に向けて価値をしっかりと伝えられる機会を探っていきます。 ✨ 結論 トヨタの取り組みが広がる未来へ Toyota Community by KINTO は、グローバルなエンゲージメントをひとつの集中型ハブに集約し、再びつなげていくチャンスを提供しています。 さらにリソースを得られれば、このプラットフォームは貴重な資産となり、顧客エンゲージメントを高めるだけでなく、より強力なブランドロイヤルティの機会を育んでいける可能性を秘めています。 このプロジェクトは、単に UX デザイン や 機能の構築 が目的ではありませんでした。ユーザー中心のデザインが持つ真の力。それは、ビジネスの目標にも、文化的なニーズにも 適応 していく力なのだということを実感しました。 この記事を楽しんでいただけましたら、ぜひ私の過去の記事もご覧ください。 多様性とインクルーシブな視点の重要性 や、 TechBlog の再設計プロセス ついても詳しく書いています。
アバター
The very first Appium Meetup Tokyo was held on February 20, 2025, at Autify's Tokyo Office. Around 10 people attended in person on the day, with many more joining online. Opening and Icebreaker The event started with a lively and humorous opening talk by tsueeemura -san from Autify. To check the online connection and break the ice, he asked, "What's everyone having for dinner tonight?" An attendee responded, "Hot pot tonight," which brought a warm and relaxed atmosphere. Autify's Appium Plugin Use Case The first speaker was rerorero -san, who is in charge of mobile product development at Autify. "Autify NoCode Mobile" provided by Autify is a cloud-based service that enables easy mobile app test automation without writing any code. Even without programming knowledge, you can record tests through an intuitive interface and have them automatically re-executed. The biggest advantage of this is that even developers and non-engineers can quickly set up a testing environment. Another key feature is the ability to use real devices and simulators in the cloud, eliminating the need for in-house equipment and significantly reducing capital investment. However, there was a performance issue where the app would significantly slow down on screens with a large number of UI elements. Tap operations that normally took just a few seconds could take up to 40 seconds. To tackle this problem, rerorero-san introduced " IDB (iOS Development Bridge) " developed by Facebook. IDB is an open-source CLI tool that allows fast interaction with iOS simulators and real devices by sending events directly to the Core Simulator Service, dramatically improving response speed. By integrating IDB as an Appium plugin and building a system that can be used directly without complex network settings between servers, Autify succeeded in reducing a 40-second operation to just 40 milliseconds, achieving roughly a 1,000x performance improvement. Key Points from the presentation How to adopt the Appium plugin and implementation examples using JavaScript The technical mechanism behind IDB's fast tapping (sending events directly to the Core Simulator Service) A practical demonstration of performance improvements The plugin can be implemented using the following code: KINTO Technologies: Guidelines and Practices for Efficient App Test Automation Next, Oka-san and Pann Nu-san from KINTO Technologies presented their method for building an automated testing environment and the results they achieved. At our company, the growing number of device and OS combinations had significantly increased the burden of manual testing. To address this, the QA and development teams began collaborating from the early stages of development and introduced a method for setting unified, dedicated test IDs. This greatly reduced the burden of modifying XPATH when changing layouts, and significantly improved test stability. In addition, we also built a system where test results are notified in real time via Slack, while managing detailed logs and test videos through Box. This creates an environment where all involved parties can easily check the test status. Key Points from the presentation Integrating automated testing awareness into the development process Comparing maintenance load before and after introducing dedicated test IDs How to efficiently manage test results using Slack and Box Improving coding efficiency using Github Copilot Presentation Materials https://speakerdeck.com/kintotechdev/xiao-lu-de-naapurizi-dong-hua-notamenogaidoraintoshi-jian-fang-fa 📌 Current Status of E2E Testing and Topics of Interest from the Participant Survey This time, we conducted a survey of everyone who attended the Meetup. Here are some interesting trends that emerged from the results. (1) Participants by Occupation More than half of the participants (54.1%) were QA engineers, but we also had participants from a variety of professions, including SET/SDET, web and mobile application engineers. (2) Experience with Appium More than half (55.7%) of respondents said they had never used Appium, suggesting that many participants were either new to the tool or currently considering adoption. On the other hand, there were also participants with over a year of experience, showing a wide range of maturity in Appium usage. (3) Practical Experience with E2E Testing In terms of E2E testing in general, over half of the respondents were relatively experienced, between 1 and 3 years (27.9%) or more than 5 years (24.6%), confirming that E2E Testing is already being widely used in practice. (4) Topics of Greatest Interest Participants expressed strong interest in the following topics: Case studies and results from adopting Appium for testing Appium usage scenarios, tips, and challenges Integration with CI/CD pipelines and cross-platform (React Native, Flutter, etc.) support Based on these survey results, we'd like to continue to share information that meets your interests and needs in future events. Networking and Future Outlook After the session, participants gathered around enjoyed some pizza for a lively networking session that sparked new ideas and collaborations. Appium Meetup Tokyo will be held regularly, and we're actively looking for speakers and new community members. We'd love to have you join us again next time! For Those Considering Participating Those who want to fully implement automated testing for mobile apps Those who are interested in Appium and seeking specific examples or know-how Engineers and QA personnel interested in CI/CD-based operations Those who want to improve their testing culture by learning from other companies' experiences If any of the above applies to you, we'd love to have you join us at Appium Meetup Tokyo to exchange the latest insights. Future announcements and detailed information will be provided by @AutifyJapan and @KintoTech_Dev . If you have any questions or suggestions, feel free to reach out. We look forward to seeing you at the next "Appium Meetup Tokyo #2"! Archive Distribution https://www.youtube.com/watch?v=zV4WbClGquE
アバター
Hello Hello, I'm Tanachu, a new member who joined the company in October 2024! In this article, we have summarized the impressions of those who joined the company in October and November 2024 immediately after joining the company. I hope this content will be useful for those who are interested in KINTO Technologies, and serve as a reflection for the members who participated in the interview! H.I Self-introduction Nice to meet you! I'm H.I. and I've recently been assigned to the Mobile App Development Group. I've mainly been involved in Android development, but I'm looking forward to growing and contributing together with you all in this new environment. I'm particularly interested not only in development but also in data analysis and service growth, and I hope to contribute as a member of the team. There's still a lot for me to learn, but I'll do my best. I'd really appreciate your continued support along the way! How is your team structured? Our team works in a Scrum framework, and we follow an agile development process. We plan, develop, and review using sprints, striving for continuous improvement in short cycles. What was your first impression of KTC when you joined it? Were there any surprises? Since KINTO Technologies is part of a large corporate group, I expected a more formal atmosphere. But once I joined, I was surprised by how flexible and open it actually is. There are also many study groups, so I'm excited about what's ahead. What is the atmosphere like on-site? Everyone on the team has strong technical skills and a high level of motivation. I think the atmosphere is one where you can easily ask questions or make suggestions. How did you feel about writing a blog post? I'd like to write as much as possible. I want to share what I have learned and my experiences through writing. Questions from Horichan to H.I. Do you have any favorite events within the company (either official or unofficial)? There are a lot of study sessions and opportunities to attend external events. People often share insights about things I didn't know or always wanted to learn, so I think they'll become a great source of my growth in the future. Tell us about your hometown! I'm from an island near Seoul, South Korea. It is rich in nature and known for eel and ginseng production. There are many historical sites such as temples, so it attracts a lot of tourists. Tanachu Self-introduction My name is Tanachu and I joined in October. I am a member of the Cybersecurity Defense Team of the Security and Privacy Group. In my previous role at a security vendor, I was involved in incident response and log analysis related to cybersecurity. In my current team, I am mainly involved in security log monitoring using SIEM and building monitoring systems. How is your team structured? Our group consists of nine members from four different countries, including Japan. We're split into four teams handling incident response related to security and privacy, security guideline assessments, internal cybersecurity frameworks, vulnerability assessments, and SOC. My team has four members, mainly working on vulnerability assessments and SOC. What was your first impression of KTC when you joined it? Were there any surprises? I had heard that KINTO Technologies had people from various countries, but I was still a bit surprised to find that I was the only Japanese on my team. The company is promoting the use of generative AI more strongly than I had expected, and being in an environment where we can easily use it in work was a positive surprise. Beyond just chatting with it, I'm always looking for new ways to use it in my own work. What is the atmosphere like on-site? We have a team lunch once a week with members who can join. It gives the impression that the team really values communication. How did you feel about writing a blog post? It feels a bit strange to be featured in a blog that I used to read before joining the company. Question from H.I to Tanachu Please tell us your own way of relaxing! At the end of the day, I like to unwind by watching the TV Tokyo news program "World Business Satellite." lksx Self-introduction My name is lksx and I joined the company in November. I work as a backend engineer in the DX Development Group. In my previous job, I also worked as a backend engineer. Although I was nervous at first, I'm learning a lot and enjoying my time here so far. Looking forward to working with you. How is your team structured? Our development team currently has eight members. Seven of them work in the Muromachi office, while one joins remotely from the Osaka office. Since the team is spread across locations, we often collaborate online, which makes efficient communication especially important. What was your first impression of KTC when you joined it? Were there any surprises? KINTO Technologies gave me a strong impression of being a startup, and it was very refreshing to see multiple products being developed simultaneously. I was also impressed by several products in the POC stage, which made me feel that the company is willing to take on new challenges. So far, I haven't felt any major surprises, but it's definitely a fast-paced environment, and I'm working on adjusting to it. What is the atmosphere like on-site? Everyone on site is easy to talk to, and the atmosphere is relaxed. Even as a newcomer, I feel comfortable asking for help when I run into questions or issues. How did you feel about writing a blog post? I haven't written a blog post before, so this being my first time, I'm actually kind of excited. Question from Tanachu to lksx What does your typical workday look like? (what do you do right after starting work, what kind of tasks do you mainly do in the afternoon?) Since I've just joined the company, there's still a lot to learn and study. So from 9:30 a.m., I spend about 30 minutes studying to build up my work skills. In the morning, I focus on tasks that require more concentration, and in the afternoon, I tend to work on tasks that are more physically engaging. Kirby Self-introduction I am Kirby and I joined the company in October 2024. After spending six years in Tokyo working at an IT company as a Director and Product Manager, I decided to return to my hometown of Osaka, hoping to make a living there while utilizing my skills. Following a role in planning and managing in-person events, I joined KINTO Technologies. I'm currently working at Osaka Tech Lab as part of the KINTO FACTORY development team in the New Service Development Group. How is your team structured? The KINTO FACTORY development team at KINTO Technologies consists of one manager, two product managers, four frontend engineers, five backend engineers, and one QA member. We develop a website that provides car customization and upgrade services for car owners. At Osaka Tech Lab, development is being carried out by two members, including a backend engineer and myself. What was your first impression of KTC when you joined it? Were there any surprises? Since the teams are spread across Tokyo, Nagoya, and Osaka, I was a bit worried about how communication would work. However, KINTO and KINTO Technologies have a strong "meet in person" culture rooted in the Toyota Group, and we often have opportunities for face-to-face communication, even offline. So, that was a surprise in a good way. (I'm actually writing this blog post from Nagoya!) Osaka Tech Lab members actively engage in cross-project conversations, with strong horizontal connection that inspire many engineers to take on technical challenges. What is the atmosphere like on-site? I am happy to be able to work with members who want to be involved in product and service development and who are passionate about making services better. How did you feel about writing a blog post? I used to read this tech blog a lot before joining, so I'm excited to finally be part of it! Question from lksx to Kirby Is there anything you want to try at KINTO Technologies? Of course, I want to contribute to the growth of the KINTO FACTORY service, but I'd also love to take on the challenge of leading an entire project on my own at Osaka Tech Lab! Jun Self-introduction My name is Jun and I joined the company in November 2024. After gaining experience as a web engineer at a business company for nearly seven years, I decided to join KINTO Technologies in hopes of sharpening my skills in a more challenging environment. How is your team structured? I belong to the backend team in the New Car Subscription Development Group, which has 13 members. There are always multiple projects ongoing in parallel within the team, and for each new project, a small group of about two to four members is selected to drive it forward. What was your first impression of KTC when you joined it? Were there any surprises? I was struck by how many engineers here are highly motivated to learn. In addition to study sessions within the team, company-wide study sessions were also held frequently, with many engineers take part enthusiastically. I used to think engineering was something you studied quietly on your own, so this was a surprise in a good way. What is the atmosphere like on-site? Since everyone joined the company mid-career and brings diverse expertise, there's no rigid way of doing things. This makes our discussions around tech stacks and operational methods very dynamic. I'm inspired every day by the people I work with. How did you feel about writing a blog post? I’ve written tech blogs before, but it's been a while. Writing this made me want to start again. Question from Kirby to Jun Do you have any go-to routines to refresh your mood? I love coffee, so whenever I feel stuck, I take a break and brew a cup to refresh myself. H.I. Self-introduction My name is HI and I joined the company in November. I've worked at several IT startups where I gained experience in marketing, development, and product management. I'm currently working as PdM for KINTO Unlimited, at the Muromachi office in Tokyo. How is your team structured? Our KINTO Unlimited team has three PdMs including myself and around 20 engineers. We've divided roles among the three PdMs. I focus on data analysis and marketing, one handles development, and the other is in charge of UI/UX. I think it's a great balance that allows each of us to play to our strengths. What was your first impression of KTC when you joined it? Were there any surprises? I was a little nervous because the average age here felt a bit higher compared to the companies I've worked for in the past, but everyone is really kind so I can work with ease (really). One thing that surprised me was how big the organization actually is, much bigger than I had expected. Coming from a startup venture company, it was definitely an adjustment to get used to the number of stakeholders and figuring out who does what. What is the atmosphere like on-site? Compared to most companies with products, we have relatively abundant resources, so as long as we have ideas, there's a lot we can try. I also get along well with people from other teams. Recently, near my desk we've had Christmas cake together and even a mini pop-up coffee stand where members bring their beans and grinders. How did you feel about writing a blog post? One day I'd like to write something that isn't a self-introduction! Question from Jun to H.I. Which of your past skills or experiences have been especially useful or valuable at KINTO Technologies? The Python and statistics knowledge I studied as a hobby have been surprisingly useful. My experience in both marketing and development has given me a broad perspective, which I've found very helpful in my role as a PdM. Fúyuán Self-introduction My name is Fúyuán from the Planning and Management Group of the Development Support Division. I joined the company in November 2024. I work at Osaka Tech Lab. I handle back-office operations related to KINTO Technologies' contract-based development projects, including budget planning, invoicing, and payments. How is your team structured? The Planning and Management Group consists of five members, each of whom is responsible for various tasks related to KINTO Technologies' contract development work, such as budgeting, contracts, invoicing/payments, and intellectual property management. Although our team members are based in Tokyo, Nagoya, and Osaka, we stay closely connected through Slack. It feels like we're working side by side despite the physical distance. What was your first impression of KTC when you joined it? Were there any surprises? I came from a more Japanese traditional company, so I was surprised by how fast decisions are made and how flat and open the communication is here. I had a similar impression at my job interview, which attracted me and made me decide to join the company, so it didn't come as a surprise. What is the atmosphere like on-site? There's a strong sense of balance: members are very focused and quiet when working, but when it's time to chat, the conversations are lively and fun. With such a diverse team in terms of nationality, age, and career background, I find myself constantly inspired by them. How did you feel about writing a blog post? I'm usually a Read-Only-Member and don't use social media or blogs in my private life, so I'm a bit nervous... Question from H.I. to Fúyuán What is your morning routine like when working from home? I try to move my body before I start working to get my mind going, so I make a point of doing radio calisthenics. My favorite thing to do is exercise on the balcony while soaking up the sunlight on a nice day! (I just hope allergy season ends soon!) R.O Self-introduction I belong to the Project Promotion Group in the New Service Development Division. I am involved in the KINTO ONE development project as a project manager. In my previous role at an offshore development company, I also worked as a project manager, collaborating with team members in Vietnam on various development projects in the fields of construction, entertainment, and finance. How is your team structured? Including our partner members, we're a team of about 10 people. All of us are project managers, each responsible for a different development project related to KINTO ONE. What was your first impression of KTC when you joined it? Were there any surprises? I had heard that the age group would be a little older than at my previous job and that everyone was hired mid-career, so I was a bit nervous about what the internal atmosphere and relationships would be like. But I found that many people are very smart and open, making it easy to collaborate and ask questions. There are more internal study sessions and participation in external ones than I expected. Many of our members travel to other locations as needed to collaborate offline with members there. I expected most communication to be online, but it's relatively easy to meet in person when needed, which I think is a plus. What is the atmosphere like on-site? Our Project Promotion Group has more of a calm atmosphere rather than a lively one, and both work discussions and casual chats happen in a relaxed manner. We usually communicate through messages using communication tools such as Slack, but we also have many opportunities to visit the development team and directly confirm specifications, so I felt that the atmosphere was conducive to cross-departmental conversations and consultations. I feel that the atmosphere varies from team to team, as some teams with a lot of engineers tend to have more lively conversations around specs and implementation. How did you feel about writing a blog post? I actually enjoy putting my thoughts into words, so I was looking forward to this. I'm happy to have the chance to contribute to the blog that I used to gather information before joining the company. Question from Fúyuán to R.O. How do you keep up with new technologies, products, and services out there? I created a separate account on X (formerly Twitter) to only follow accounts sharing those kinds of updates, so my timeline shows exactly the information I want. I also catch up through casual conversations with friends and acquaintances from other industries (usually over drinks). When I want to get a feel for the excitement surrounding a new service or technology, I attend offline events like conferences. Horichan Self-introduction This is Horichan, who joined the company in October 2024! I'm from Hiroshima, a big Carp baseball fan, and I love sweet potato shochu. I was originally an Android engineer, then transitioned to a PdM role two years ago at my previous job. Now, I’m working as a director on systems designed to solve challenges faced by Toyota dealers, and I'm giving it my all every day! How is your team structured? The DX Solution Group under the Mobility Product Development Division has seven members: one producer, three directors, and three designers, each working on their own assigned projects. What was your first impression of KTC when you joined it? Were there any surprises? My first impression was that it's a company that combines the best of both a large company and a startup company! Things like the rent subsidy and generous paid leave feel like a large company, but the employee-led study sessions (and BeerBash!) and the energy of the CHO All-Hands Meeting definitely bring a startup feel, which I love. If I had to name a surprise, it would probably be the tools. In my previous job, I was in charge of internal system, so I created all of my documents using FigJam or Notion, but here PowerPoint is the main tool. But I'm getting quite used to it! At this rate, I'll aim to become a PowerPoint master.💪 What is the atmosphere like on-site? Everyone in the group is kind and I'm learning in a relaxed environment! Lunch is also fun!🫶 Our project team is made up of professionals from various fields who all work together as one team to solve dealership challenges. How did you feel about writing a blog post? I had written a few blog posts at my previous job, so I was interested in! I'm happy to finally take part!☺️ Question from R.O. to Horichan Is there any company culture or event at KINTO Technologies that you found interesting? I love how many opportunities there are to hear directly from management! During onboarding, we had small group sessions with both President Kotera-san and Vice President Kageyama-san, which was already a surprise. But even after that, there are monthly all-hands meetings, CHO All-Hands Meeting, optional 1-on-1s, and U35 events for younger employees.😳 Kotera-san told us that we could even invite him out for drinks. So a few of us actually did, and we had a great time chatting.🍶 (R.O. and Tanachu were there too!🙌) Closing words Thank you everyone for sharing your thoughts on our company after joining it! There are more and more new members at KINTO Technologies every day! We'll be posting more new-joiner stories from across divisions, so stay tuned! And yes: we're still hiring! KINTO Technologies is looking for new teammates to join us across a variety of divisions and roles. For more details, check it out here !
アバター
This is Nakanishi from the Developer Relations Group. I'm excited to share that we're launching a new community! The mobile app market continues to grow year after year, making fast and high-quality releases more crucial than ever to remain competitive. That's where Appium , a testing tool that works with iOS and Android and feels similar to Selenium, is drawing a lot of attention. That said, implementing and operating Appium comes with its own set of challenges, including OS version differences and the complexity of setting up the environment. To tackle these challenges and share solutions, we've launched a new community: Appium Meetup Tokyo . Reasons for Launching Appium Meetup Tokyo Growing Needs Release cycles for mobile apps are becoming increasingly shorter and manual testing alone is reaching its limits. Appium is a valuable tool for enhancing test automation efficiency, but knowledge about its setup and implementation is still not widely shared. At KINTO Technologies, we've set technical capabilities , development productivity , and release speed as our Core Goals for 2025 , and test automation with Appium plays a central role in achieving all three. With the growing spotlight on development productivity across companies, and as our development speed continues to increase, automated testing is becoming more critical than ever. Lack of information for Japan While English documentation and overseas case studies are on the rise, there's still limited comprehensive Appium information available in Japanese. When putting it into practice, familiar examples and real stories of success and failure can be a huge help. I'm sure many QA engineers and mobile app developers at other companies are facing the same challenges. That’s why we aim to energize the Japanese-speaking community and encourage information sharing to help create an even better automated testing environment. Collaboration with Autify While talking with Autify, a company that provides a mobile app automation testing platform, the idea came up that it would be great to have more opportunities to learn about Appium. As the conversation progressed, we decided to get the community started with small study sessions. Autify uses Appium behind the scenes in their services and has accumulated a wide range of knowledge. Their insights and expertise aren't usually shared publicly, things you wouldn't easily gain just from developing your own apps or in-house automated testing. Personally, I'm really excited about this collaboration. Furthermore, by sharing comprehensive know-how, including not only Appium but also related tools, we aim to build a community that can solve a wider range of problems. We're currently looking for more members to help grow this initiative. Community Activities Regular Study Sessions Introduction to Appium Hands-on sessions using real devices and simulators Explanation of CI/CD pipelines Lightning Talks (LT) and Discussions Case studies from companies that have adopted Appium Sharing issues and know-how unique to the field Sharing the latest updates and useful tips Online Information Sharing Archiving slides and resources Q&As on the community Slack and social media Creating a collection of best practices We're hoping to explore all of these initiatives together with you. First Event Details Date : Thursday, February 20, 2025 19:00-21:30 Location : Autify Tokyo Office (Hybrid event) Main theme : Use case of Appium plugin in Autify (15 min + 5 min Q&A) Guidelines and practices for efficient app test automation (15 min + 5 min Q&A) [Open Call] Lightning Talk 3 (15 min + 5 min Q&A) [Open Call] Lightning Talk 4 (15 min + 5 min Q&A) Check out for details on connpass. https://autifyjapan.connpass.com/event/342867/ If you're interested in presenting or attending, please sign up via the link above! Future Plan Ongoing Events We plan to continue hosting study sessions and workshops to meet the needs of everyone, from beginners and advanced users. Information on Integration with Other Tools We'll also actively cover comparisons and integration examples with other tools like Selenium and Cypress, helping you expand your practical options. Community-Driven Knowledge Sharing As we hold more events, we aim to share a wealth of insights, including stories of success and failure relate to Appium, across the community, contributing to participants' skill development. For Those Considering Participating Those who want to fully implement automated testing for mobile apps Those who are interested in Appium and seeking specific examples or know-how Engineers and QA personnel interested in CI/CD-based operations Those who want to improve their testing culture by learning from other companies' experiences If any of the above applies to you, we'd love to have you join us at Appium Meetup Tokyo to exchange the latest insights. Future announcements and detailed information will be provided by @AutifyJapan and @KintoTech_Dev . If you have any questions or suggestions, feel free to reach out. I'm looking forward to seeing you at Appium Meetup Tokyo!
アバター
About KTC's Engineering Office In January 2025, KINTO Technologies (KTC) established a new organization: the Engineering Office. This article introduces what the Engineering Office is working on, while also helping raise awareness of its purpose within the company. What We’re Aiming For Our primary goal is to "strengthen KINTO Technologies' capabilities as an engineering organization." To achieve this over the medium to long term, we’re actively working to foster new capabilities and shape a supportive, evolving engineering culture. As a team reporting directly to the Vice President , we stay closely aligned with key management issues. Together, we formulate hypotheses about what initiatives KTC truly needs, and each of us leverages our own experiences and expertise to lead cross-functional efforts across the company . Our Mindset It’s easy to look at other teams and wish for what they have. But if we want to unlock new possibilities, we also need to take a closer look at the strengths we’ve already built and make the most of them. Real progress begins when we start asking ourselves questions like, "What if we added this, tweaked that, or took something away? Could we become even stronger?" It is important to correctly understand the current situation and take action based on that context. KTC already has a workforce of over 350 people. Because our existing operations and organizational structures are well established, bringing about change is not easy. Precisely because we are in an uncertain and ambiguous situation where no one knows the right answer for us, we must remain persistent. Instead of rushing to conclusions, we should focus on identifying what is truly necessary. What Not to Do We don’t plan to directly handle the following areas: Planning, promotion and execution of business strategies and development projects Project and program management for development work Recruitment, PR, internal communications, and company culture initiatives While the Engineering Office works to strengthen KTC’s engineering capabilities through planning and promotion, we do not take on responsibilities such as hiring, training, evaluation, or public relations, which are roles that similar departments at other companies may often manage. At present, as we move projects forward, we’re collaborating with the respective dedicated teams at key points when needed. Activity Example 1: Planning to Accelerate Key Initiatives While KTC is steadily bringing together talented individuals, we believe that achieving even greater outcomes as an in-house development team requires further organizational and team maturity. Through ongoing discussions with the Vice President, I was involved in shaping and articulating the key focus themes for 2025. Since AI First already has a dedicated project team, the Engineering Office is focusing on the remaining three themes: Release First User First Organizational Intensity We’re planning initiatives to support internal volunteer efforts and cross-team projects, based on two key pillars: 1. Improving IT literacy across the organization and 2. Creating real examples and encouraging behavioral change . Activity Example 2: Supporting Development Team Process and Communication Y.Naito-san is leveraging her expertise and experience in SPI ( Software Process Improvement ) to support in-house development teams. Specifically, our efforts include facilitating team retrospectives, assisting in the operation of development tools such as JIRA and Findy Team+, organizing study sessions to share knowledge needed for process improvement, and providing mentoring. The initiative aims to improve communication, tools, processes, and empowerment, enabling teams to achieve results that no individual member could accomplish alone. We’re also working to uncover know-how and best practices developed by individuals or specific teams, and to share them across the organization to broaden and deepen collective knowledge, ultimately driving efforts to enhance the company’s overall technical capabilities. Activity Example 3: Creating an Environment Where Individual Growth and Contribution Go Hand in Hand Our Vice President made the following request, in line with our identity as a technology company: "We want to ensure that engineers, designers, and other professionals working as specialists are able to contribute to the company and that their contributions are properly recognized." We’ve only just started the discussion, so nothing is set in stone yet. However, we’ve begun working with HR and are starting conversations with department heads to explore how we can turn this into reality. To continue being a company that contributes through its software development and technical capabilities, we believe it’s essential to build an environment where members can continue growing. This includes initiatives like developing career paths and increasing opportunities for professional challenges. Let's Make Our Work More Interesting! (Hiring Info) We haven't formalized our operations just yet, so we're not officially advertising job openings. But if you’re the kind of person who’s excited to shape your own mission based on your own themes and beliefs. we think you’ll really enjoy being here. Let's make our work more exciting and meaningful, with our own hands! 💪 Requirements Someone who can move independently and take initiative in a high-autonomy environment Someone who can navigate uncertainty and keep moving forward through trial and error Someone who can stay patient and persistent in the face of ambiguity, without rushing to conclusions Someone who can inspire change and bring others along for the ride If you are interested, please feel free to reach out via Open Positions page. If you know someone on the team, you can also message us directly via DM! (・∋・)ノシ https://hrmos.co/pages/kinto-technologies/jobs/0000127 KINTO Technologies is also looking for people to join us across a variety of teams and roles. For more information, please see the recruitment information .
アバター
Introduction Hello! I'm Yao Xie from the Mobile Application Development Group at KINTO Technologies, where I develop the Android app of KINTO Kantan Moushikomi (KINTO Easy Application) . In this article, I’ll be sharing some thoughts on how to implement a hybrid model that takes advantage of both Compose Multiplatform and native UI frameworks. Developing mobile apps often means juggling limited budgets, varied team sizes, and tight timelines: all while ensuring long-term maintainability and a consistent user experience. A hybrid architecture built on Kotlin Multiplatform (KMP), which now includes Compose Multiplatform as a core UI framework, combined with native frameworks such as SwiftUI (iOS) and Jetpack Compose (Android), offers the flexibility to meet these challenges. Whether you’re launching an MVP on a shoestring budget or scaling up for a fully polished app, this approach adapts to your constraints and preserves code quality over time. A Flexible and Maintainable Approach for Diverse Constraints Rapid Development with Consistency For projects constrained by limited budget, small teams, or short deadlines, the benefits I perceive are the following: Shared Business Logic: by writing your core functionality (networking, data models, business rules) once in a KMP module, will ensure consistent behavior across Android and iOS while reducing duplication and ease future maintenance. Shared UI with Compose Multiplatform: Compose Multiplatform is part of the Kotlin Multiplatform ecosystem, which means it naturally builds on shared Kotlin code to build UI components. Develop most of your UI as shared composable components. Android benefits directly via Jetpack Compose, and iOS can embed these components using helpers like ComposeUIViewController. This uniform approach guarantees that both platforms adhere to the same design and behavior guidelines, simplifying long-term support. This strategy minimizes development time while maintaining consistency—a key factor for high-quality user experiences and future-proof code. "The Android robot is reproduced or modified from work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License." Scaling Up with Native Enhancements As your project secures more funding, personnel, or additional time: Incremental Native Integration: With a solid shared foundation, you can gradually replace or enhance key screens using native UI elements. For example, you can enhance critical iOS screens with SwiftUI to better align with platform-specific design standards. Expect/Actual Mechanism: Kotlin’s expect/actual pattern lets you define a generic shared component (like a platform-specific button) and then provide native implementations. This enables you to start with a shared UI and later invest in polished native refinements where they matter most. Adapting to Different Team Sizes and Project Timelines The hybrid approach is designed to flex as your project evolves: For Lean Teams and Tight Schedules: Focus on maximum code reuse. A small team can build and maintain the shared business logic and UI, ensuring consistency while speeding up time-to-market. For Larger Teams or Extended Deadlines: As your team grows or deadlines relax, allocate additional resources toward developing native components to enhance user experience. This phased strategy minimizes risk and ensures that the core logic remains stable and maintainable over time. I find that by keeping the shared logic and UI consistent across platforms, you reduce complexity and technical debt, making projects easier to maintain and evolve. Code Snippets Illustrating the Kotlin Multiplatform Hybrid Mode Shared Business Logic This shared module guarantees that both Android and iOS apps use the same core logic, ensuring consistency and reducing maintenance overhead. // Api interface Api { suspend fun getUserProfile(): User } class ApiImpl(private val client: HttpClient) : Api { override suspend fun getUserProfile(): User { return client.get { url { protocol = URLProtocol.HTTPS host = "yourdomain.com" path("yourpath") } }.safeBody() } } // Repository interface UserRepository { suspend fun getUserProfile(): Flow<User> } class UserRepositoryImpl(private val api: Api) : UserRepository { override suspend fun getUserProfile(): Flow<User> { return flowOf(api.getUserProfile()) } } // ViewModel class ProfileViewModel( private val repository: UserRepository, ) : ViewModel() { private val _uiState = MutableStateFlow(ProfileUiState()) val uiState: StateFlow<ProfileUiState> = _uiState.asStateFlow() @OptIn(ExperimentalCoroutinesApi::class) fun onAction(action: ProfileScreenAction) { when (action) { is ProfileScreenAction.OnInit -> { viewModelScope.launch { // Set loading state to true _uiState.update { it.copy(isLoading = true) } // Retrieve authorization info and then fetch user profile data repository.getAuthorizationInfo() .flatMapLatest { authInfo -> // If authInfo exists, call getUserProfile() to get user data; otherwise, emit null if (authInfo != null) { repository.getUserProfile() } else { flowOf(null) } } // Catch any exceptions in the Flow chain .catch { e -> e.printStackTrace() } // Collect the user profile data and update the UI state .collect { userProfile -> _uiState.update { state -> state.copy( isLoading = false, data = userProfile, errorMessage = if (userProfile == null) "User profile data is null" else null ) } } } } } } } Shared UI with Compose Multiplatform Compose Multiplatform—being an integrated part of Kotlin Multiplatform—allows you to create UI components in shared Kotlin code: @Composable fun ProfileScreen( viewModel: ProfileViewModel = koinViewModel() ) { val uiState = viewModel.uiState.collectAsState().value LaunchedEffect(Unit) { viewModel.onAction(ProfileScreenAction.OnInit) } Column( modifier = Modifier .fillMaxSize() .verticalScroll(rememberScrollState()) .background(White) .padding(16.dp) ) { // Profile header with image and user details Row( modifier = Modifier .fillMaxWidth() .background(White, shape = RoundedCornerShape(16.dp)) .padding(16.dp), verticalAlignment = Alignment.CenterVertically ) { AsyncImage( model = uiState.data.profileImage, contentDescription = "Profile Image", modifier = Modifier .size(64.dp) .clip(CircleShape) ) Spacer(modifier = Modifier.width(16.dp)) Column { Text( text = uiState.data.userName, fontSize = 16.sp, color = Color.Black ) Text( text = uiState.data.email, fontSize = 14.sp, color = Color.Blue.copy(alpha = 0.6f) ) } } Spacer(modifier = Modifier.height(16.dp)) MenuLabel(label = "Account Settings") .... } } Lean Approach: I find using this composable directly on both platforms convenient for a consistent look and behavior. Scaled Approach: Enhance the UI with native components as needed without altering the underlying business logic. Native UI via Expect/Actual Define an expected component: @Composable expect fun PlatformButton( modifier: Modifier = Modifier, label: String, onClick: () -> Unit ) Android Implementation (androidMain): @Composable actual fun PlatformButton( modifier: Modifier, label: String, onClick: () -> Unit ) { Button( onClick = onClick, modifier = modifier ) { Text(text = label) } } iOS Implementation (iosMain): @Composable actual fun PlatformButton( modifier: Modifier, label: String, onClick: () -> Unit ) { UIKitView( modifier = modifier, factory = { // Create a native UIButton instance. val button = UIButton.buttonWithType(buttonType = 0) button.setTitle(label, forState = UIControlStateNormal) // Style the button ... // Create a target object to handle button clicks. val target = object : NSObject() { @ObjCAction fun onButtonClicked() { onClick() } } // Add the target with an action selector. button.addTarget( target = target, action = NSSelectorFromString("onButtonClicked"), forControlEvents = UIControlEventTouchUpInside ) button } ) } Blended UI: A Key Advantage Over Flutter Unlike Flutter, Compose Multiplatform supports blending shared UI and native components seamlessly on a single screen. In many scenarios, you may not need a complete switch from shared UI to native UI—rather, you can blend them on a single screen. This approach allows you to tap into the strengths of both Compose Multiplatform and native frameworks without fully committing to one for an entire screen. For example, you might want to display a shared composable header alongside a native SwiftUI list on iOS. Here’s how you can achieve a blended UI: Embedding Shared Composables in a Native Layout: One of Compose Multiplatform’s strengths is the ability to seamlessly embed shared Compose UI components into native SwiftUI layouts. Developers can gradually adopt shared components without rewriting entire screens, a flexibility that's difficult to achieve with Flutter’s overlay approach. For example, you can use SwiftUI as a container to host Compose Multiplatform’s shared UI wrapped in a UIViewController: import SwiftUI import shared // Import the shared KMP framework struct ComposeContainerView: UIViewControllerRepresentable { let user: User func makeUIViewController(context: Context) -> UIViewController { // Use the Compose wrapper to create the UIViewController return AppComposeUI().createProfileVC(user) } func updateUIViewController(_ uiViewController: UIViewController, context: Context) { } } struct ContentView: View { let user: User var body: some View { VStack { Text("Native SwiftUI Header") .font(.headline) .padding() // Embed the Compose UI inside SwiftUI. ComposeContainerView(user: user) .frame(height: 250) List { Text("Native SwiftUI Item 1") Text("Native SwiftUI Item 2") } } } } Embedding Native iOS UI into Compose Multiplatform Screens Compose Multiplatform also enables embedding native iOS views (e.g., SwiftUI or UIKit) within shared Compose screens—another capability not easily achieved by Flutter. Define a SwiftUI view to embed: import SwiftUI struct MySwiftUIView: View { let user: User var body: some View { VStack { Text("Native SwiftUI Content") .font(.body) Text("Welcome, \(user.firstName)") } .padding() .background(Color.gray.opacity(0.2)) .cornerRadius(8) } } Then integrate this native view into your shared Compose UI using UIKitView: @Composable fun ComposeWithNativeUI(user: User) { Column { // Shared Compose UI header. ProfileHeader(user = user) Spacer(modifier = Modifier.height(16.dp)) // Embed a native iOS view using UIKitView. UIKitView(factory = { // Create a UIHostingController with a SwiftUI view. val hostingController = UIHostingController(rootView = MySwiftUIView(user = user)) hostingController.view }, modifier = Modifier.fillMaxWidth().height(100.dp)) } } This bidirectional inline integration sets Compose Multiplatform apart from Flutter, enabling teams to incrementally adopt shared UI components while maintaining native look and feel. It offers developers greater flexibility and reduces the risk of large-scale rewrites, combining the efficiency of shared code with the richness and quality of native UI. Compose Multiplatform provides a significant advantage over Flutter by enabling more flexible, fine-grained integration between shared UI and native platform UI. Unlike Flutter, which typically renders shared UI components through an overlay mechanism, Compose Multiplatform uses an inline rendering approach, allowing shared and native UI elements to blend naturally together. Pros Best Practices for Flexibility, Maintainability, and Scalability Embrace Rapid Prototyping: I’ve learned the hard way that spending weeks perfecting pixel details before users even touch the app is risky. These days our team spins up a shared‑UI prototype in a week or two, pushes it into stakeholders’ hands, and soaks up feedback early. When we’re confident the idea sticks, we layer on native flourishes—animations, platform‑specific gestures—without throwing away what we built. Plan Incremental Development: Our rule of thumb: launch small, refactor later. We start with a KMP module for core logic and a single shared Compose screen. Once that slice proves itself, we peel off the next screen—or replace a shared widget with a SwiftUI or Jetpack Compose version—one commit at a time. The gradual approach keeps velocity up and rewrites down. Balance Resources, Quality, and Scalability: When it was just two of us, 90 percent of the UI lived in shared code because that’s what we could afford. As head‑count and design ambitions grew, we shifted the critical flows to native, leaving the rest untouched. That staged migration kept the backlog realistic and let us dial quality up without derailing releases. Maintain Consistency: Centralizing business logic in one Kotlin module has saved us countless merge headaches. A single bug fix lands once and rolls out everywhere—no more “iOS fixed, Android still broken” stand‑ups. It’s not flashy, but this shared core is what lets the team sleep at night when deadlines loom. Ensure Elasticity: In my experience leading mixed‑platform projects, the teams that thrive are the ones that treat architecture like a living organism, not a static blueprint. We design every layer so it can flex when budgets tighten, timelines shift, or a surprise hire brings new skills. Because Compose Multiplatform lets us blend shared and native UI on demand, we can pivot from “MVP mode” to “native‑polish mode” in days, not months. That elasticity has repeatedly saved us when product strategy—or the market itself—changed overnight. Conclusion This elastic hybrid architecture, built on Kotlin Multiplatform and Compose Multiplatform alongside native UI frameworks, offers unparalleled flexibility. It allows you to adjust your development strategy based on budget, team size, and timeline constraints while maintaining consistency and long-term maintainability. For lean projects, maximize code reuse to launch quickly; as resources expand, incrementally enhance critical screens with native UI elements without rewriting your core logic. Embrace this flexible, incremental model to reduce duplication, streamline maintenance, and deliver a consistent, high-quality user experience that scales as your project evolves.
アバター
Introduction Hello, I'm Mizuki, and I joined the company in September! In this article, I interviewed the members who joined in August and September 2024 and gathered their first impressions after joining KINTO Technologies. I hope this article will be helpful for those interested in KINTO Technologies and serve as a nice reflection for the members featured here! K.W Self-Introduction I am a PdM (Product Manager) on the JP Membership Platform Team, which is part of the Common Service Development Group in the Group Core Systems Division. I started my career as a PdM at a major web services company straight out of university. KINTO Technologies (KTC) is my second company. How is your team structured? The JP Membership Platform team develops membership-related features for KINTO's web services and mobile apps in Japan. Our team consists of eight members: one team leader, one PdM, six software engineers (including team members from partner companies). What was your first impression of KTC when you joined it? Were there any surprises? Since KTC is made up entirely of mid-career professionals and new members join almost every month, I immediately felt a welcoming atmosphere for newcomers. As for any surprises, this was my first time changing jobs, so I was honestly a bit nervous about whether I could contribute. But thanks to the support of my teammates, I feel like I’ve blended in better than I expected. What’s the atmosphere like on the team? KTC is still a relatively new company, so we’re in the process of establishing rules and structures. That said, I’ve found that each member is proactive and that there’s a culture of actively adopting new development methods and initiatives. How did you feel about writing a blog post? I haven’t had many chances to share things through blogs, so I took my time writing this one while looking at past onboarding posts for inspiration. Question from MK-san: Any recommended items you use in the office? It’s actually something I use at home rather than at the office, but I highly recommend a height-adjustable desk. Here’s the one I use. https://www.amazon.co.jp/dp/B08CXSV3RX Shiori ![](/assets/blog/authors/mizuki/20250123/suda.png =250x) Self-Introduction I work as a Generative AI Engineer in the IT/IS Division on the Generative AI Development Project. My main responsibility is promoting the use of generative AI. This includes conducting internal training sessions, developing use cases, and providing technical support for generative AI. How is your team structured? Our team consists of five members, including myself: three based in Nagoya, one in Jimbocho, and me in Muromachi. What was your first impression of KTC when you joined it? Were there any surprises? I was impressed by the well-established environment for keeping up with technology and sharing knowledge — there are monthly themed study sessions, regular Toyota Group tech meetups, internal training opportunities, and access to external seminars. The company is also proactive in sharing its work through the tech blog and presentations. Just four months after I joined, I had the opportunity to speak at an external seminar about how we’re using generative AI internally. I also learned the term "menchaku" after joining the company. This is a Toyota word that refers to "communicating in person." I felt that this culture of balancing in-person and online communication helps reduce misunderstandings and promotes faster decision-making and value creation. As Toyota’s in-house development organization, we handle much more than just mobility products like KINTO. Our work also includes finance, MaaS, technical support for vehicle systems, dealership digital transformation, and generative AI. This broad scope gives us many opportunities to expand our knowledge across different fields. I also feel that decision-making here is quite democratic. For example, our office drink flavors are rotated seasonally — spring/summer and fall/winter— and each time, a “Flavor Preference Survey” is conducted. The current fall/winter flavors were chosen based on the survey results, which really impressed me! What’s the atmosphere like on the team? Whether it’s on Slack or in person, when someone runs into a problem, others always step in with thoughtful support. It’s a really warm and welcoming environment. It's also easy to invite people to lunch, and I’ve had the chance to connect with team members outside of my division, which has been a lot of fun. How did you feel about writing a blog post? ✌️😆✌️ Question from K.W: Do you have a personal motto? I'm not sure if I’d call them mottos, but I do have two personal themes I’m focusing on for 2024 and 2025: "Pivot" and "Act now." In the field of generative AI, technology and information are updated incredibly fast. Major tech announcements happen frequently, and it’s not uncommon for a worldview that felt new yesterday to become the norm today. In such an environment, it’s important to quickly test ideas, measure their impact, adjust course, and put them into action — all in fast cycles, even when the outcome is uncertain. That's why I try to minimize the time between “having an idea” and “taking action,” whether it’s for work or daily life. Yukki~ ![](/assets/blog/authors/mizuki/20250123/yukki-.jpeg =250x) Self-Introduction Nice to meet you, I'm Yukki. I belong to the Corporate IT Group in the IT/IS Division. My role involves identifying and resolving issues across a wide range of areas, including internal information systems, network infrastructure, and security. How is your team structured? I’m part of the Boost team, which currently has two members. Our team supports the Corporate IT Group by tackling challenges and providing behind-the-scenes support. Each of us focuses on problem-solving in our respective areas of expertise. Currently, I’m involved in infrastructure design related to the renewal of various KINTO systems. I’m working on improvement initiatives while keeping the concept of Shu-Ha-Ri in mind. *Shu-ha-ri is a process of learning: first following the established way (Shu), then breaking it (Ha), and finally creating a new approach (Ri). What was your first impression of KTC when you joined it? Were there any surprises? Before joining, I assumed that, as a subsidiary of a large company, there would be some limitations — even though KTC moves at a startup-like pace. But after joining, I was surprised at how much freedom and autonomy the company offers. It feels fast-paced and venture-like. At the same time, the areas that require governance are well managed, and I think the balance between agility and stability is well maintained. Regarding remote work, the basic guideline is to come into the office twice a week, but I really appreciate the flexibility KTC provides in accommodating family needs and personal circumstances. What’s the atmosphere like on the team? There were more people working remotely than I expected. I was surprised to sometimes be the only one in my seating row. With so many people taking advantage of remote work, I found the environment to be very remote-friendly. That said, the office is well-equipped with video conferencing systems and communication tools like Slack, so it’s easy to talk to people, and I feel reassured by the setup. It’s also been a huge help that my manager is always available when I need to talk. Although it’s a group-wide initiative, we also have a 30-minute casual chat session once a week, which is great. It gives us a chance to connect with colleagues from Tokyo, Nagoya, and Osaka despite the physical distance. How did you feel about writing a blog post? Even though I joined the company at the same time as others, the physical distance made it hard to talk or interact much. Writing this blog gave me a great chance to connect with other new joiners from different locations. Before joining KTC, my previous role didn’t involve much outward communication. I hope to gradually take more opportunities to share and communicate externally. Question from Shiori-san: I heard that photography is your hobby. Do you have any tips for improving photography skills? I’m still learning myself, but lately I’ve been paying more attention to the balance between the background, middle ground, and foreground, as well as how elements are arranged within the frame. I also try to go out and find new subjects each season to increase my shooting opportunities. Mizuki Self-Introduction I’m part of the Talent Acquisition Team in the Human Resources Group, within the Development Support Division. We handle engineer recruitment and also organize hiring events in Osaka! How is your team structured? There are six members on the Talent Acquisition team. What was your first impression of KTC when you joined it? Were there any surprises? There wasn't really any gap. Since I had previously worked as a recruitment agent supporting KTC, I already had a good understanding of the company’s atmosphere and culture! However, I was pleasantly surprised by how much trust and autonomy each employee is given. What’s the atmosphere like on the team? I feel that our team truly lives out the value of "respect for all," which is something we hold dear as an HR team. Until December, I was working at Osaka Tech Lab, and I was honestly amazed at how warm and homey the atmosphere was. I really hope that Osaka Tech Lab can continue to keep that great vibe. How did you feel about writing a blog post? Since I’m based in a different location, I only had a brief chance to meet most of the other new joiners during orientation. So writing this blog felt like a great opportunity to get to know everyone's hobbies and roles. Question from Yukki~-san: What’s your most recommended tsukemen spot? I listed my favorites by location! Please check them out if you get the chance! Tokyo: Dogenzaka Mammoth (Shibuya) https://tabelog.com/tokyo/A1303/A130301/13122700/ Osaka: Miyata Menji (Shinsaibashi) https://miyata-menji.com Nagoya: Hanzo (Fujigaoka) https://www.menya-hanzo.com/hanzo.html R.K Self-Introduction I belong to the Marketing Product Group within the Mobility Product Development Division. I’m currently the PdM for "Prism Japan," a travel app and website. My first company was in the human resources industry, where I worked on app and website growth. KTC is my second company. How is your team structured? Our team consists of one team leader/engineer, two engineers, one marketer, one writer, and one PdM. What was your first impression of KTC when you joined it? Were there any surprises? I had heard that the team was very friendly, and when I actually joined, it turned out to be exactly that. Since this was my first job change, I was honestly a bit anxious about whether I could be of any help. But thanks to the strong support from my teammates, I’ve been able to keep going and do my best! What’s the atmosphere like on the team? Since we're working on a product in its growth phase, everyone naturally goes beyond their job descriptions, contributing in various ways within a cheerful and collaborative atmosphere. How did you feel about writing a blog post? I haven't had many chances to write blog posts, so I referred to everyone else's comments for inspiration! Question from Mizuki-san: Where is the best place you’ve ever visited overseas? Aside from the more common destinations, I really enjoyed New Zealand! I took a road trip around the South Island, visiting lots of different spots. The nature was rich and breathtaking, the food was great, the towns were clean and beautiful, and time just felt slower in the best way. It was a trip that exceeded all my expectations, and I’d love to go back someday! Chen Self-Introduction I’m originally from Xiamen, China, and worked as an engineer in the Internet industry there for about 10 years. KTC is the first Japanese company I’ve worked for. I am currently part of the Platform Development Division, in the DBRE team, where I develop database-related operational tools. My MBTI type is INFP. My hobby is trying out new things. In just three months, I've been to almost every restaurant in the Jimbocho (half of them are curry spots, though). I enjoy visiting art museums in Tokyo, especially the contemporary art ones — part of the fun is not always understanding them. I have a weakness for new product releases. How is your team structured? There are five of us working in the Jimbocho office, and we recently merged with the SRE team, so we now have a total of seven members. What was your first impression of KTC when you joined it? Were there any surprises? My first impression was that the office wasn't flashy, but it didn't feel like a traditional Japanese company either — it actually had a bit of a global/foreign-company vibe. During orientation, there was a lot of information about the internal tools and initial setup, and even with my IT background, it took some time to get used to everything. Since there aren’t many people in the Jimbocho office, it’s a quiet space where I can really focus. I was glad to hear that many people work from home — something that’s still relatively rare in China. What’s the atmosphere like on the team? Our team members are very kind and hardworking. It’s rare to see such detailed support for internal clients (like product teams) and fellow teammates — but that’s exactly what I’ve found at DBRE. During onboarding, I was never ignored for not knowing something — I was always encouraged to ask questions anytime. Also, no one ever put me through the usual “let’s see what you can do” period as a new hire. We always discuss tasks together before starting development. At first, I was surprised by this team-based approach, since I was used to solving things on my own. But once I got used to the pace, I found it really comfortable. There is a lot to learn from how others approach problem-solving, and when everyone’s aligned, it really boosts your confidence in taking on challenges. How did you feel about writing a blog post? I want to improve how I express and share what I know, so I’m going to keep challenging myself to write more. After reading the tech blogs written by my teammates, I realized that what I’ve been missing is the ability to organize and present information clearly. Question from R.K-san: You've been to almost every restaurant in the Jimbocho — what's your favorite lunch spot? Thank you for the question! For reference, I personally love Southeast Asian food — sour, sweet, and full of variety. [Thai food] The best spot is Bangkok Cosmo Shokudo. Even at night, the prices are reasonable and the portions are generous. You can't go wrong with any item on the menu. [Ramen] To be honest, I don't have the patience to wait three hours at Ramen Jiro...😅 So instead, I recommend Yojinbo. I personally like it better than Butayama. Also, "Ebimaru Ramen" is a must-try. The flavor of the soup is really amazing. [Korean food] I went to Keijoen without realizing it had been featured on the TV show "Solitary Gourmet." Their kontan soup set meal is delicious and well-priced. [Indian food] Namaste India (on the first floor) is plenty good in my opinion — though to be honest, I don’t really notice much difference between most Indian places...😂 That said, I recently found a place called Gurgaon in Ginza, and their cheese kulcha was so good, it’s worth the trip. [Curry] Here are my top 3 curry picks: Panch Mahal — their lassi is excellent Takeuchi Jimbocho Main Branch — be warned: some dishes are quite spicy Chantoya Coconut Curry — the coconut-based soup curry leaves a lasting impression T.A. ![](/assets/blog/authors/mizuki/20250123/ki2.jpeg =250x) Self-Introduction I’m in Information Security and belong to the Security and Privacy Group in the IT & Information Security Division. My hobby is doing solo activities. How is your team structured? There are three of us, including the team leader and a contractor. It's currently our busiest season, so I'm feeling the pressure! What was your first impression of KTC when you joined it? Were there any surprises? I felt that KTC was a flexible and fast-paced company. There are many people from different nationalities and backgrounds, so I learn a lot just from casual conversations. What’s the atmosphere like on the team? There’s a strong sense of continuous improvement. It really feels like something gets upgraded every week, which keeps my curiosity sparked. We often focus on how to do things more efficiently, so I feel like I'm constantly sharpening my own skills as well. How did you feel about writing a blog post? I just hope I don’t make any typos... Question from Chen-san: What exactly do you mean by "solo activities”? I often go drinking alone, watch movies alone, or go solo camping. Recently, I even went to a Christmas market by myself. The illuminations were beautiful. MK Self-Introduction I’m a front-end engineer in the Digital Transformation Development Group of the Mobility Product Development Division. I develop products that support the digital transformation of dealership operations. My career path so far has been: sales → admin → front-end engineer. Also... I love prosciutto. How is your team structured? We’re a team of nine, working on multiple products. All of our engineers are skilled in a wide range of technologies, so we switch between coding and planning depending on the project, without being limited to any specific domain. What was your first impression of KTC when you joined it? Were there any surprises? To be honest, I thought it might be a bit strict before I joined... But once I got here, I found that it’s actually a very flexible company. It feels like the best of both worlds — the stability of Toyota with the agility of a young company. What’s the atmosphere like on the team? There’s a real passion for technology. There’s a real passion for the product, too. Communication is lively, and there’s great energy all around. How did you feel about writing a blog post? I thought it would be a great way for people outside the company to hear directly from those of us actually working on development. I'm also excited to read what everyone else thinks about the company! Question from T.A.-san: Were there any superstitions or lies you believed (or were fooled by) as a child? I used to believe the purple part of a pigeon's neck was poisonous. Finally Thank you to everyone for sharing your impressions after joining the company! At KINTO Technologies, new members are joining the company almost every day! We'll be posting more new-joiner stories from across divisions, so stay tuned! And yes — we're still hiring! KINTO Technologies is looking for new teammates to join us across a variety of divisions and roles. For more details, check it out here !
アバター
こんにちは こんにちは、2025年2月入社の hayashi-d1125 です! 本記事では、2025年2月入社のみなさまに、入社直後の感想をお伺いし、まとめてみました。 KINTOテクノロジーズ(以下、KTC)に興味のある方、そして、今回参加下さったメンバーへの振り返りとして有益なコンテンツになればいいなと思います! 佐竹 康晴 自己紹介 新サービス開発部 プロジェクト推進Gの佐竹です。 社内で新たに企画するプロダクトやプロジェクトのPdM/PMを担当しています。 所属チームの体制は? プロジェクト推進G全体で15名、私が所属するPMのチームは6名の体制になります。 KTCへ入社したときの第一印象?ギャップはあった? トヨタグループの内製会社として、社内組織や体制が高度に組み上げられており、想像以上の内製組織でびっくりしました。 現場の雰囲気はどんな感じ? 不明なことに対して情報やアドバイスをもらえるなど、チーム内での相互フォロー関係ができており、出社時にはランチ、業務後や週末には飲み会や一緒に出かけるなど、部署の垣根を越えた交流も盛んで、活気があります。 ブログを書くことになってどう思った? 入社前に読んでいたテックブログにこんな早々にブログ投稿することになるとは思ってもみませんでした。 大変光栄ですし、色々なことを発信していくことは好きですので、今後も機会があれば積極的に投稿させていただきたいと思います。 工藤 啓さん → 佐竹 康晴さんへの質問 他部署のメンバーとの関わりなどどのようにされていますか? Bear BashやKTC内の部活など他部署メンバーと交流できる機会に積極参加して繋がりを広げています。 特にBear Bashでは会場BGMとしてDJを披露したおかげで、多数の方と交流することができました! 脇坂 友里絵 自己紹介 開発支援部 企画管理Gで請求や予算など、KTCのお金に携わるバックオフィス業務を主に行っています。 所属チームの体制は? 6名体制で分担しながら業務を行っています。 KTCへ入社したときの第一印象?ギャップはあった? 思っていたよりも意思決定から行動までのスピードが早く驚きました! 現場の雰囲気はどんな感じ? 現場の雰囲気としてはとても協力的だと思います。 各拠点にチームメンバーがいるのでリモートでのやり取りが多いのですが、定期ミーティングを行うなど業務がスムーズに進むようにコミュニケーションを増やしています。 ブログを書くことになってどう思った? 文章を書くことに対して苦手意識はあるのですが、いい機会だな!と前向きに捉えています。 佐竹 康晴さん → 脇坂 友里絵さんへの質問 入社してみて、今まで勤務されていた会社とは異なっていたのはどんなところでしょうか? 会社として勉強会やセミナーなど、学ぶことに対しての投資は惜しみなくされているのかなと思っています。 楊 小龍 自己紹介 業務システム開発部Salesforce開発Gの楊です。 Kinto Factory保守開発を担当しています。 所属チームの体制は? 自分を含めて全 6 名のグループです。 KTCへ入社したときの第一印象?ギャップはあった? 「自由」だと感じます。 服装も、出社時間も 現場の雰囲気はどんな感じ? チーム全員が優しく、わからないことがあったら聞きやすいです。 ブログを書くことになってどう思った? 感想類の文書を書くことが苦手と思います。。。 脇坂 友里絵さん → 楊 小龍さんへの質問 入社後、一番困ったことを教えてください! MTG、しゃべりで、時々わからない言葉があります。 今も日本語を頑張って勉強しています! 林田 洋平 自己紹介 プラットフォームグループ/プラットフォームエンジニアリングチームの林田です。 KTC の開発チームのために各種ツールの開発・提供・メンテナンス等を行っております。 普段は Osaka Tech Lab で働いております。 所属チームの体制は? Osaka Tech Lab に3名。 神保町オフィスに6名の体制で仕事をしております。 拠点が離れているのでやりとりは Slack や Teams 等のコミュニケーションツールを使って行っております。 KTCへ入社したときの第一印象?ギャップはあった? 創業して僅か約4年の会社とは思えないほどに色んな制度やフローが整っている会社だと思いました。 一方で自チームに関しては、まだ未整備な部分も多くこれからチームビルディングに関われる機会も多そうで楽しみに思いました。 現場の雰囲気はどんな感じ? 私が勤務している Osaka Tech Lab はもともと1名だったのですが、私が入社した時点でやっと3名になりました。 雰囲気としては拠点が離れているぶん、まだ神保町オフィスのトレンドに付いて行けていない印象があるので、コミュニケーション面で課題を感じました。 ブログを書くことになってどう思った? 前職でも書いていたので特に苦手意識や違和感はありませんでした。 しかしネタ探しは会社が変わっても変わらず大変なので(笑)日頃から新しい技術に積極的に触れるようにしてネタに困らないようにしなければと思っております。 楊 小龍さん → 林田 洋平さんへの質問 休みの日どう過ごしますか? 妻と子の5人家族なのでもっぱら家族サービスに精を出しております。 先週は家族5人で車で愛知県の中部国際空港セントレアに遊びに行って来ました。 兒玉 桜 自己紹介 データ分析部 分析プロデュースG でデータ分析をしています。 所属チームの体制は? 上長+先輩4名+自分 KTCへ入社したときの第一印象?ギャップはあった? 入社オリエンテーションが手厚くて驚きました。 それ以外は事前にお聞きしていた通り適度(?) に自由な印象を受けているので、ギャップはありませんでした。 現場の雰囲気はどんな感じ? みんな穏やかで優しい。 しかし仕事はプロフェッショナルという謎のギャップにやられています。 (プロフェッショナル=怖いという先入観あり) ブログを書くことになってどう思った? 話をお聞きしたときは、正直「めんどうだな」と思いました。 が、実際に記事を書いていると自分の現在地の再確認にもなりやって良かったなと感じました。 何事も挑戦する事が大事だなと思いました。 林田 洋平さん → 兒玉 桜さんへの質問 データ分析のお仕事をしようと思ったきっかけは? アウトソーシング業界にいたある時、急遽欠員が出たクライアント先の穴埋めとしてたまたま配属されたのがアクセス解析チームでした。 そんな仕事がある事すら知らなかった未経験状態で始まったのですが、業務にあたるうちに深めたくなってしまい現在に至ります。 小川 就也 自己紹介 業務システム開発部 Salesforce開発G 小川です。 Factory BOシステムの保守を担当しています。 所属チームの体制は? マネージャー1名メンバー5名でSalesforceの運用保守、データ連携、Salesforceが関連するプロジェクト対応を行っています。 KTCへ入社したときの第一印象?ギャップはあった? 技術者集団=ある程度の技術力や知識が無いと質問や相談しにくいのでは?と思っていましたが、気軽に質問/相談できる雰囲気でした。 レスポンスもとても早く、親身に対応してくださる方が多いです。 現場の雰囲気はどんな感じ? 入社したときの第一印象、ギャップにも書きましたが、とても気軽に質問/相談ができる雰囲気です。 ブログを書くことになってどう思った? 今までブログを書くことをやったことが無かったので、機会をいただけたことに感謝しています。 兒玉 桜さん → 小川 就也さんへの質問 仕事の合間や休憩時間、どのようにリフレッシュしていますか? 在宅勤務時は昼休憩に30分程ランニングしてます。 ランニング中は考えている余裕が無くなるので強制的に無心になれます。 出社時はまだ模索中です。 安田 早希 自己紹介 プラットフォーム開発部 Cloud InfrastructureGに所属となりました、やっさんです。 部署名の通り、サービス基盤のクラウドインフラの部分を担当しております。 所属チームの体制は? クラウドインフラGとしては9名体制ですが、さらに細かくチームが分かれております。 KTCへ入社したときの第一印象?ギャップはあった? ルールとか非常に硬いイメージを持って入社したのですが、実際は上下関係なく接しやすく、チャットでもスタンプが飛び交うような和気あいあいとしていたことが、ギャップでしたね。 現場の雰囲気はどんな感じ? 前職では、「静かに、音を立てない」といった雰囲気だったこともあり、なかなか業務のことを相談しずらかったのですが、今はすぐに相談できる状況ですし、チーム仲がよいので出社メンバーで必ず、ランチを食べに行っています♪ ブログを書くことになってどう思った? 入社前に見ていたので、自分も書くことになったのか~と、感慨深いです 小川 就也さん → 安田 早希さんへの質問 神保町オフィス周辺でおすすめの飲食店はありますか? 先日行った、「森のブッチャーズ」というお店がおすすめです。 ランチメニューで、ビーフやポークのステーキが食べ応えあってよかったです。 11時半ごろに行って30分待ちましたが、並ぶ価値がありました! 工藤 啓 自己紹介 モビリティプロダクト開発部エンゲージG配属になりました工藤です。 販売店様内の業務DX化支援を行います。 所属チームの体制は? チームはMgr含め3名ですが、部内の開発担当チームやKINTO営業部とも協業しながら販売店様に入り込みDXニーズを聞き出していきます。 KTCへ入社したときの第一印象?ギャップはあった? エンジニアが周りにたくさんいるなーという印象。 これまでエンジニアとがっつり仕事をしたことがなかったので皆さんのモニター画面がコードばかりなのが新鮮でした。 現場の雰囲気はどんな感じ? 現場に訪問することが多く、社内にいないことが多いのですが、全員販売店様ファーストで提案を考えていることに刺激を受けます。 ブログを書くことになってどう思った? 会社のブログに携わることがこれまでなかったのでこの内容が発信されると思うと、本当に大丈夫かなと心配になります。 安田 早希さん → 工藤 啓さんへの質問 エンゲージメントを高めるために生成AIを使うとしたら、どのようなものがあると思いますか? お客様への代替車種提案業務など既に、生成AIを活用したプロダクトがあります。 他にも社内問合せ業務の効率化に活用するなど、販売店様への業務DXにおいて活用のシーンはかなり多いと思います。 さいごに みなさま、入社後の感想を教えてくださり、ありがとうございました! KINTO テクノロジーズでは日々、新たなメンバーが増えています! 今後もいろんな部署のいろんな方々の入社エントリが増えていきますので、楽しみにしていただけましたら幸いです。 そして、KINTO テクノロジーズでは、まだまださまざまな部署・職種で一緒に働ける仲間を募集しています! 詳しくは こちら からご確認ください!
アバター
Introduction Hello, I'm kh, and I came on board this September! In this article, we asked those who joined the company in August and September 2024 about their impressions immediately after joining the company, and summarized them. I hope this content will be useful for those who are interested in KINTO Technologies, and serve as a reflection for the members who participated in the interview. Naito Self-introduction I work in the Engineering Office. I'm involved in improving processes across different product teams. What is the structure of your team? The Engineering Office was just established in January and consists of two people. What was your first impression of KTC (KINTO Technologies) when you joined? Were there any surprises? Thanks to the interviews and chats I had before joining, there weren't any major surprises. The company has offices in Tokyo, Nagoya, and Osaka, with people frequently coming and going between them. On my very first day, I met several colleagues from the Nagoya office and thought, 'Wow, Nagoya’s actually pretty close! As I started chatting with more people in the company, I realized how embedded "kaizen" is in everyday work. Everyone knows about the Toyota Production System (TPS), which impressed me. What is the atmosphere like on-site? I've been reaching out to various development teams for chats and advice, and everyone has been genuinely kind. I really appreciate how they loop me in and make me feel part of things! How did you feel about writing a blog post? I had been reading tech blogs before I joined the company. So being on the writing side now feels pretty exciting. Question from Mari: Why did you choose this company? Cars are a familiar part of my daily life, so the domain naturally caught my interest. On top of that, I felt like KTC is a company that's going to keep evolving—and I wanted to be part of that journey and enjoy the changes firsthand. R.Y. Self-introduction I'm originally from Hong Kong and moved to Japan in 2023. After graduating, I joined KTC this August, and now I'm part of the Security & Privacy Group. What is the structure of your team? In the Security & Privacy Group, we're divided into teams based on our responsibilities. I'm on the Defense Team, where I mainly handle vulnerability assessments and respond to security consultation tickets. What was your first impression of KTC (KINTO Technologies) when you joined? Were there any surprises? The office is really spacious, with lots of open areas that everyone can use freely. There are also plenty of study sessions and social events, so you get the chance to pick up knowledge beyond your daily work. What is the atmosphere like on-site? Everyone is friendly and easy to talk to. In addition to work, there are all kinds of Slack channels for hobbies and local topics, so it's easy to connect with others who share your interests. How did you feel about writing a blog post? Looking back on everything I've experienced over the past three months—and getting to share it with future team members—makes me genuinely happy. Question from Naito: I'd love to travel to your hometown, Hong Kong. Please let me know if you have any recommendations for sightseeing or food! If you're a Disney fan, Hong Kong Disneyland is a must. The park is compact, so it's easy to explore the whole park in one day. When it comes to food, Hong Kong has tons of delicious local comfort food. Some examples of must-tries: chewy and bouncy curry fish balls, fish-meat shumai, and rich, bold-flavored Hong Kong-style milk tea. Eating on the go is common in Hong Kong, so dive in and enjoy the experience of this culture. (By the way, you can try some popular Hong Kong eats right here in Japan too—check out the Tam Jai Sam Goh Official Website if you're curious.) tHyt Self-introduction Hi, I'm tHyt from the Mobility Product Development Division. While I take on some engineering lead responsibilities, I mainly work as a front-end engineer. What is the structure of your team? Our team has nine members, with specialists across front-end, back-end, and infrastructure. It's a well-rounded crew. What was your first impression of KTC (KINTO Technologies) when you joined? Were there any surprises? Since the company is still relatively young, I expected some areas might be underdeveloped in terms of systems and structure—but to my surprise, everything was impressively well organized. What is the atmosphere like on-site? I'm based at the Osaka Tech Lab, and since the members aren't many, there's always chatter happening across teams. It keeps things interesting. All of my team members except for myself work in the Muromachi office, but we enjoy working together through daily meetings and business trips. How did you feel about writing a blog post? I knew about these new joiner blog posts even before I joined the company, and the day has finally come for me to write one...! That's how I feel. I'm looking forward to using the tech blog to share more than just intros! Question from R.Y.: After joining the company, was there anything you struggled to get used to? How did you overcome it? Hands down, business trips. Since I'm the only one in my team based in Osaka, I travel to Tokyo about once a month to help keep communication flowing. (Huge thanks to the company for supporting that!) Before joining KTC, I had only ever been on one business trip, and I rarely took the Shinkansen—so at first, I was pretty anxious about it all. But now, I've gotten used to it and have no trouble traveling. Remote communication works well, but face-to-face interaction is different. I'd definitely like to keep that going. kh ![](/assets/blog/authors/kh/kh.png =250x) Self-introduction I'm part of the Analysis Group. My work mainly involves building the data infrastructure and collecting the data needed for analysis. What is the structure of your team? There are 10 people including the leader, myself, and folks from partner companies and temporary staff. What was your first impression of KTC (KINTO Technologies) when you joined? Were there any surprises? Since KTC is still a relatively new company, I was expecting a fast-paced, startup-like vibe. But it actually felt more relaxed—in a good way. What is the atmosphere like on-site? We are a group of people with a variety of backgrounds, and everyone brings something different to the table in a friendly vibe. How did you feel about writing a blog post? I’d known KTC was active with tech blog posts, so writing this felt like taking that first step into being part of that culture. Question from tHyt: Got any tips for data analysis? Well, I actually focus more on building the data infrastructure rather than doing the analysis itself, so this might not be the exact answer you were expecting. But no matter how great your data analysis is, it won't be helpful if the data quality is poor. Ensuring data quality at the platform level is, in my view, the essential first step in any successful data analysis. woshahua Self-introduction Hi, my name is Gao. I work in the Woven Payment Solution Development Group! I'm a Chinese-born engineer with a solid Kansai dialect—it's stuck with me completely. My hobbies are basketball, sauna and poker. Recently, I've been working on a personal app that analyzes poker win rates—just for fun! What is the structure of your team? Our team is primarily made up of engineers, and we also work together with engineers from Woven. What I really like is that, no matter which organization we’re part of, everyone's aligned and moving together toward the same goals. What was your first impression of KTC (KINTO Technologies) when you joined? Were there any surprises? Even though KTC's attempt is still relatively new in the automotive field, it struck me as a company actively taking on a wide range of services and development projects. No big surprises, but I was honestly impressed by how much the company encourages technical sharing—and how there are study sessions going on nearly every week. What is the atmosphere like on-site? It's an environment where you're encouraged to explore all sorts of technologies, regardless of your past experience. Whenever I run into a roadblock, someone on the team is always quick to jump in and help. I really appreciate how supportive everyone is. How did you feel about writing a blog post? Both the company and the team are big on promoting tech knowledge, so I'm excited to contribute and share more going forward! Question from kh: I heard that you have a pet. Does living with a pet affect your daily life or work? Yes! I have a guinea pig at home, and just watching it after work is incredibly soothing. Being able to work remotely means I can spend more time with my pet, which I love. I truly think having emotional breathing room at work makes a difference in performance. My guinea pig helps ease the stress and gives me a nice mental reset! Mari Self-introduction I'm a team member of the Development Support Division, Human Resources Group, Talent Acquisition Team. We are recruiting mainly engineers. What is the structure of your team? There are six of us, including myself—and starting in January, we'll all be working from the Muromachi office! What was your first impression of KTC (KINTO Technologies) when you joined? Were there any surprises? The office is lovely! All the engineers are easy to talk to—cheerful, approachable, and just fun to be around. What is the atmosphere like on-site? The atmosphere is joyful and open—everyone's kind, and honest. It's full of people who are not only hardworking but also genuinely considerate of those around them. How did you feel about writing a blog post? I wasn't sure what to write at first, but I ended up going with an honest take on how I’m feeling right now! I also got inspiration from reading everyone's blog posts! Question from woshahua: How do you refresh yourself during work or on your days off? During work, I like to go for short walks to clear my head. On my days off, I try to stay active—going out or hitting the gym whenever I can. C4 ![](/assets/blog/authors/kh/20250123/c4.jpg =250x) Self-introduction I'm am part of KTC, but currently seconded to the KINTO Administration Department, where I mainly handle general office operations. My MBTI type is ISFJ-T, so I think I'm naturally suited for administrative work, though that might just be wishful thinking. What is the structure of your team? There are eight of us working at the Nagoya office, including myself. What was your first impression of KTC (KINTO Technologies) when you joined? Were there any surprises? My first thought was, "Oh, this office is really stylish." It was my first time working in an office, and I imagined it to be more formal, but the atmosphere in the team is relaxed and friendly, and we often go out to eat outside of work, so I think there is a lot of communication. What is the atmosphere like on-site? Not just my team, but everyone around me has been incredibly kind. Even when I ask questions during busy times, no one has ever reacted negatively or made me feel like a bother. We have weekly 1-on-1s and team meetings, which help me stay in the loop about what others are working on—even if I'm not directly involved—and I'm really grateful to have regular chances to talk through any challenges in my own work. How did you feel about writing a blog post? To be honest, I wasn't sure if a story from a non-engineer like me—doing admin and general affairs—would even be useful on a tech blog (laughs). But here I am, giving it a shot. Question from Mari: My MBTI is ESFP! The results were eerily accurate, especially the part about struggling with details. What about you? Was ISFJ-T accurate for you? What parts hit home? Oh, yes. Some parts hit a little too close to home, like "resistant to change," "perfectionist," and "self-critical" (ouch, right? lol). And that mindset of "If it makes someone else happy, I'll put myself second"—yep, that one definitely checks out. So yeah, I'd say the result was pretty spot-on. MBTI is great for self-reflection. I definitely recommend giving it a try!! Mari Self-introduction I'm a UI/UX designer in the Retailer Digital Transformation Planning Team, part of the Mobility Product Development Division's DX Planning Promotion Group. I design products that support the digital transformation of dealership operations. What is the structure of your team? We've got one team lead, three directors, and four designers (including me). What was your first impression of KTC (KINTO Technologies) when you joined? Were there any surprises? Since the parent company is big, I expected a lot of structure—and that's definitely true. But at the same time, the atmosphere is surprisingly free and relaxed. No real surprises after joining. What is the atmosphere like on-site? It's busy and we've got a lot on our plates. But that just makes the work more rewarding. The team's full of energy, and everyone gets along great. Very positive and easygoing environment. How did you feel about writing a blog post? I wasn't sure what to write at first, but ended up just sharing how I genuinely feel! I'm also looking forward to reading everyone else's posts! Question from C4: I heard you have a cat at home! I live with five myself. What's one product your cat absolutely loved? (Snacks, toys—anything!) Five!! Amazing! 🥰 My cat's a bit of a diva—most things get the “how dare you present me this peasant toy” treatment. That said, Churu treats is her one true weakness—especially the premium ones with fancy ingredients. Total game-changer 😂 Also, not sure how she feels about it, but I got a Miruto automatic litter box—makes my life way easier and has been super helpful! Oh, and the cat tower I bought? She's never touched it. After a month of rejection, it sadly became oversized trash… Finally Thanks to everyone who shared their first impressions after joining! There are more and more new members at KINTO Technologies every day! We'll be posting more new-joiner stories from across divisions, so stay tuned! And yes — we're still hiring! KINTO Technologies is looking for new teammates to join us across a variety of departments and roles. For more details, check it out here !
アバター
はじめに こんにちは! KINTOテクノロジーズでWebエンジニアをしている亀山です。 現在はマーケティングプロダクト開発グループという部署に所属しています。 今回はサーバレス構築についてお話しします。 ECSなどのコンテナが常時起動しているアプリケーションは、稼働している間、たとえリクエストが来なくても起動している時間分のリソース(CPUやメモリ)に対して課金が発生します。そのため、PoC開発や極端にリクエストが少ないプロダクトにおいては特に「 使っていないのにお金がかかる 」状態になりがちです。 そのようなプロダクトに対しては、使っている間だけサーバーが立ち上がり、一定時間処理が行われないと自動で停止するような従量課金型のサーバレスアーキテクチャによってランニングコストを大幅に抑えることが可能になります。 そこで私たちは下記の要点でLambdaアプリケーションを構築しました。 AWSのAPI Gateway + Lambdaでサーバレス開発 TypeScript + Expressでシンプルかつ汎用的なAPI開発 サーバレスについて AWSのサーバレス構成として広く用いられているLambdaを採用しましたLambdaはサーバレスアーキテクチャであるため、先にも述べましたが、サーバーの起動・停止やスケーリングを自動で行ってくれ、使った分だけ課金される従量課金制でコストを最小限に抑えられます。 一方でこのようなサーバレスAPIのデメリットとしては、 コールドスタートによる応答遅延 が発生する点があります。特にリクエスト数の少ない環境や、一定時間アクセスがないときにLambdaがスリープ状態になり、再度リクエストが来た際にコンテナの起動時間(実測値として応答時間約1秒)がかかるという特性があります。 まとめると、 とにかくサクッとプロトタイプを構築したいであったり、応答遅延を許容できるようなユーザー(例えば社内メンバー)向けのツールを構築したいという方には特におすすめな インフラ構成になります。 Lambdaでどれくらい費用が安くなるのか? 常時実行コンテナのFargateと今回使用するサーバレス型のLambdaで料金比較をしてみます。 Fargate AWS Fargateの料金について 0.5 vCPU でメモリ2GBを想定して1時間あたりの1タスク稼働費用は vCPU料金: 0.5 vCPU * $0.04048 / vCPU-時間 = $0.02024 / 時間 メモリ料金: 2GB * $0.004445 / GB-時間 = $0.00889 / 時間 という計算から1時間あたり合計費用は $0.02024 + $0.00889 = $0.02913 となり、 そのため1ヶ月720時間稼働するとすると$0.02913 * 720時間 = $20.9736 が1タスク月当たりかかります。(ただし、夜間停止やvCPUスペックダウンによって節約すること可能) これは1環境あたりの費用なので本番環境、開発環境など複数の環境が必要であればその数だけ掛け算されます。 Lambda AWS Lambdaの料金について 一方でLambdaはリクエスト件数とリクエストによって一時的に起動するコンテナの計算時間(コンピューティング時間)によって計算されます。 GB-秒あたり0.00001667 USD 1,000,000 件のリクエストあたり0.20 USD Fargateと同様の2GBで、1リクエストあたり0.5秒の計算時間、さらに1ヶ月あたり10万件のリクエストであると想定すると月当たりの合計費用は$0.02 (リクエスト費用) + $1.6667 (計算費用) = 約 $1.69 が月当たりかかります。 さらに良いことに、環境を増やしたり、1環境あたりのLambda数を増やしたとしても、合計リクエスト数が同じであれば上記と同じ金額になります。 これらの計算シミュレーションからLambdaのコスト面での優位性がわかると思います。 特に売上の出ないかつトラフィックの少ない社内向けツールであったり、PoCのプロダクトであればこのような費用削減は特にメリットが大きくコスト面でのハードルを下げてくれることが期待できます。 Expressについて サーバサイドJSのフレームワークとしてExpressを採用しました。 ルーティングやミドルウェアの概念が直感的に理解できるように設計されており、初めて Node.js でサーバサイド開発を行う開発者にとっても扱いやすい構成となっています。小規模なAPIから中〜大規模なアプリケーションまで、スムーズに拡張できる設計が可能です。また、ルーティングの記述も簡潔です。 app.get('/users/:id', (req, res) => { res.send(`User: ${req.params.id}`); }); ログ出力には morgan、認証処理には passport、入力バリデーションには express-validator など、用途に応じて豊富なミドルウェアのライブラリを簡単に組み込むことができます。これにより、アプリケーションの機能追加や保守が容易になります。 AWS公式で配布されているLambdaライブラリを用いてエンドポイントを構築することも可能ですが、汎用ライブラリであるExpressを用いて構築しておけばアプリケーションの規模が拡大したタイミングでECSやApp Runnerに転用する際にエンドポイント以降のコードを転用することもLamda特化のライブラリを使用するより容易になります。 開発方針 本記事では、 1つのLambda関数に複数の API エンドポイントをまとめて搭載する構成 を採用しています。 これは、Lambdaの特性である「ホットスタート」を活用するためです。 Lambda関数は一度起動されると、一定時間はメモリ上に残り続ける「ホットスタート」の状態になります。そのため、1つのAPIがリクエストされて Lambdaが起動されたあとは、同じ関数内の他のAPIに対するリクエストも高速に処理できるようになります。 この性質を活かすことで、操作時のパフォーマンスの向上が期待できます。 ただし、Lambdaにはデプロイ可能なパッケージサイズに制限(zip圧縮時で50MB以内かつ展開後で250MB以内)があるため、アプリケーション内すべてのAPIを1つの関数に詰め込むと最終的にこの上限に到達するため、現実的ではありません。 そのため、 画面単位や機能単位で関連のあるAPIを同一の Lambda関数にまとめる構成 とし、最終的には1つのリポジトリで複数の Lambda関数を管理していくmonorepo構成を前提で進めていきます。 また本記事ではSAMによるローカル実行できるようにするまでをゴールとし、AWSコンソールの設定やデプロイ以降のお話は割愛させていただきます。 環境構築(コーディングまでの準備) 本記事では複数の Lambda関数や共有コードを管理しやすいpnpmにAWS SAM を組み合わせた環境構築方法を説明します。 プロジェクト全体を pnpm のワークスペースとして管理し、各 Lambda関数や共通ライブラリを独立したワークスペースとして扱います。デプロイツールにはAWS SAM(Serverless Application Model)を利用します。 主に以下のツールが必要になります。 Node.js pnpm AWS CLI AWS SAM CLI Git (バージョン管理) Gitのインストールは割愛します。 必要なツールのインストール Node.js これまでと同様に Node.js が必要です。公式サイトから LTS 版をインストールしてください。 Node.js公式サイト インストール後、以下のコマンドでバージョンが表示されることを確認します。 node -v npm -v # pnpmをインストールするために使用する pnpm 依存ライブラリの管理には pnpm を使用します。pnpm は特に複数のモジュール(Lambda function)を1つのリポジトリで管理するようなmonorepo構成での依存解決やディスク使用効率に優れています。 以下の方法でインストールします。 npm install -g pnpm または、curl などを使用する方法は pnpm の公式サイトを参照してください。 pnpm インストールガイド インストール後、以下のコマンドでバージョンを確認します。 pnpm -v AWS CLI これまでと同様に AWS との連携に必要です。インストールおよび aws configure による認証情報の設定を行ってください。 AWS CLIインストールガイド AWS SAM CLI 今回はデプロイツールとして AWS SAM (Serverless Application Model) を使用します。AWS SAM はサーバーレスアプリケーションのための IaC (Infrastructure as Code) フレームワークであり、SAM CLI はローカルでのビルド、テスト、デプロイをサポートします。 以下の公式サイトを参考に、お使いのOSに合わせた方法でインストールしてください。 AWS SAM CLIインストールガイド インストール後、以下のコマンドでバージョンを確認します。 sam --version プロジェクト構造とワークスペース設定 プロジェクトのルートディレクトリには、monorepo全体の設定ファイルや、開発時に共通で使うツール(例: esbuild)の依存関係を定義する package.json を置きます。各 Lambda関数や共通ライブラリは、例えば functions ディレクトリの中にそれぞれ独立したサブディレクトリとして作成し、これらをpnpmのワークスペースとして定義します。 提供いただいた構造を参考に、基本的な構造と設定ファイルを説明します。 sample-app/ # (ルートディレクトリ) ├── functions/ │ ├── common/ # 共通コード用ワークスペース │ │ ├── package.json │ │ ├── src/ │ │ └── tsconfig.json │ ├── function-1/ # Lambda関数1用ワークスペース │ │ ├── package.json │ │ ├── src/ # Expressアプリやハンドラコード │ │ └── tsconfig.json │ └── function-2/ # Lambda関数2用ワークスペース │ ├── package.json │ ├── src/ │ └── tsconfig.json ├── node_modules/ # pnpmによって管理される依存ライブラリ ├── package.json # ルートのpackage.json ├── pnpm-lock.yaml # ルートのロックファイル ├── pnpm-workspace.yaml # ワークスペース定義ファイル ├── samconfig.toml # SAM デプロイ設定ファイル (初回デプロイで生成) └── template.yaml # AWS SAM テンプレートファイル ルートのpackage.json リポジトリ全体で共有するスクリプトや開発ツール(esbuild など)を定義します。 package.json { "name": "sample-lambda-app-root", // プロジェクト全体を表す名前 "version": "1.0.0", "description": "Serverless Express Monorepo with SAM and pnpm", "main": "index.js", "private": true, // ルートパッケージは公開しない設定 "workspaces": [ "functions/*" // ワークスペースとなるディレクトリを指定 ], "scripts": { "build": "pnpm -r build", // 全ワークスペースの build スクリプトを実行 "sam:build": "sam build", // SAMでのビルド (後述) "sam:local": "sam local start-api", // SAMでのローカル実行 (後述) "sam:deploy": "sam deploy" // SAMでのデプロイ (後述) }, "devDependencies": { "esbuild": "^0.25.3" // 各ワークスペースのビルドで使う esbuild をルートで管理 // 他、monorepo全体で使う開発ツールがあればここに追加 }, "keywords": [], "author": "", "license": "ISC" } pnpm-workspace.yaml どのディレクトリをワークスペースとして扱うかを定義します。 pnpm-workspace.yaml packages: - 'functions/*' # `functions` ディレクトリ内の全てのサブディレクトリをワークスペースとする # - 'packages/*' # 別のワークスペースグループがあれば追加 依存ライブラリ管理 (pnpm ワークスペース) 各Lambda関数や共通ライブラリに必要な依存ライブラリは、それぞれのワークスペース内の package.json に記述します。 例: functions/function-1/package.json { "name": "function-1", // ワークスペースの名前 "version": "1.0.0", "description": "Lambda Function 1 with Express", "scripts": { "build": "esbuild src/app.ts --bundle --minify --sourcemap --platform=node --outfile=dist/app.js", // esbuildでビルド "start:dev": "nodemon --watch src -e ts --exec \"node dist/app.js\"", // ローカルテスト用のスクリプト (SAM Localとは別に用意しても良い) "tsc": "tsc" // 型チェック用 }, "dependencies": { "@codegenie/serverless-express": "^4.16.0", // Lambdaアダプター "express": "^5.1.0", "@sample-lambda-app/common": "workspace:*" // 共通ライブラリへの依存 }, "devDependencies": { "@types/aws-lambda": "^8.10.138", // Lambdaの型定義 "@types/express": "^4.17.21", "nodemon": "^3.1.0", "typescript": "^5.4.5" // esbuild はルートの devDependencies にあるのでここでは不要 }, "keywords": [], "author": "", "license": "ISC" } @sample-lambda-app/common : functions/common ワークスペースを指します。 "workspace:*" とすることで、ローカルの common ワークスペースを参照するようになります。 common ワークスペース側の package.json で "name": "@sample-lambda-app/common" , と定義している必要があります。 scripts.build : esbuild を使用して、TypeScript コードと依存ライブラリをまとめて1つの JavaScript ファイル (dist/app.js) にバンドルする例です。Lambdaにデプロイするパッケージサイズを削減するために重要なステップです。 依存ライブラリのインストールは、プロジェクトのルートディレクトリで 一度だけ pnpm install を実行します。pnpmが pnpm-workspace.yaml を見て、各ワークスペースの package.json に記述された依存関係を解決し、効率的に node_modules を構成します。 pnpm install 特定のワークスペースにライブラリを追加したい場合は、ルートから以下のコマンドを実行します。 pnpm add <package-name> -w <workspace-name> # 例: pnpm add axios -w functions/function-1 pnpm add -D <dev-package-name> -w <workspace-name> # 開発依存の場合 実際にサンプルコードを書いてみる 先ほど説明したディレクトリ構成は、複数function構成になるように function-1 と function-2 の2つのfunctionモジュールを用意し、それらのfunctionが共用部品として利用できるために common というモジュールを用意しています。 具体的にコードを書いていきます。 commonのコード まず共通部品であるcommonにサンプルとしてミドルウェア関数を1つ書いてみます。 functions/common/src/middlewares/hello.ts import { Request, Response, NextFunction } from 'express'; /** * サンプル共通ミドルウェア * リクエストログを出力し、カスタムヘッダーを追加します。 */ export const helloMiddleware = (req: Request, res: Response, next: NextFunction) => { console.log(`[Common Middleware] Received request: ${req.method} ${req.path}`); // レスポンスにカスタムヘッダーを追加 res.setHeader('X-Sample-Common-Middleware', 'Applied'); // 次のミドルウェアまたはルートハンドラに進む next(); }; 続いて、middlewares/内のエクスポートを追加します。 functions/common/src/middlewares/index.ts export * from './hello'; // middlewares内に他のミドルウェアがあればここに追加していく さらにワークスペースのトップレベルのsrc/でもエクスポートしてあげる必要があります。 functions/common/src/index.ts export * from './middlewares'; // middlewaresのような共通処理が他にあればここに追加していく(utilsとか) funciton-1側のコード 次にfunction-1側のコードを書いていきます。 functions/function-1/src/app.ts import express from 'express'; import serverlessExpress from '@codegenie/serverless-express'; import { helloMiddleware, errorHandler } from '@sample-lambda-app/common'; // 共通ミドルウェア、エラーハンドラをインポート // apiRouter のインポートは不要になりました // import apiRouter from './routes/api'; // import cookieParser from 'cookie-parser'; // 必要に応じてインストール・インポート const app = express(); // express標準ミドルウェアの適用 app.use(express.json()); // JSONボディのパースを有効化 // app.use(cookieParser()); // クッキーパースが必要な場合このように追加する // 共通ミドルウェアの適用 app.use(helloMiddleware); app.get('/hello', (req, res) => { console.log('[Function 1 App] Handling GET /hello'); res.json({ message: 'Hello from Function 1 /hello (Simplified)!' }); }); app.post('/users', (req, res) => { console.log('[Function 1 App] Handling POST /users'); console.log('Request Body:', req.body); // JSONボディをログ出力 res.status(201).json({ received: req.body, status: 'User created (sample)' }); }); // common等にエラーハンドラミドルウェアを作成し、使用する場合は全てのミドルウェアとルート定義の後に配置する。 // app.use(errorHandler); // 本記事では作成していない // ハンドラのエクスポート export const handler = serverlessExpress({ app }); 補足:このあと行うtemplate.yamlでのAPI Gatewayの設定で、/function1 を取り除いたパスが渡されるようになるので、ここに定義するルートは、API Gateway のベースパスからの相対パスになります。 例えば、API Gatewayへのリクエストが /function1/hello なら、ここに定義する /hello にマッチします。 function-2側のコード functions/function-2/src/app.ts import express from 'express'; import serverlessExpress from '@codegenie/serverless-express'; // ★アダプターをインポート★ import { helloMiddleware, errorHandler } from '@sample-lambda-app/common'; // 共通ミドルウェア、エラーハンドラをインポート // ルーターファイルは使用しないためインポート不要 // import apiRouter from './routes/api'; // import cookieParser from 'cookie-parser'; // 必要に応じてインストール・インポート const app = express(); // express標準ミドルウェアの適用 app.use(express.json()); // JSONボディのパースを有効化 // app.use(cookieParser()); // クッキーパースが必要な場合このように追加する // 共通ミドルウェアの適用 app.use(helloMiddleware); // ルートをごとに処理を定義 app.get('/bye', (req, res) => { console.log('[Function 2 App] Handling GET /bye'); res.json({ message: 'Goodbye from Function 2 /bye!' }); }); app.post('/items', (req, res) => { console.log('[Function 2 App] Handling POST /items'); console.log('Request Body:', req.body); // JSONボディをログ出力 res.status(201).json({ received: req.body, status: 'Item created (sample)' }); }); app.get('/status', (req, res) => { console.log('[Function 2 App] Handling GET /status'); res.json({ status: 'OK', function: 'Function 2 is running (Simplified)' }); }); // common等にエラーハンドラミドルウェアを作成し、使用する場合は全てのミドルウェアとルート定義の後に配置する。 // app.use(errorHandler); // 本記事では作成していない // ハンドラのエクスポート export const handler = serverlessExpress({ app }); 今回サンプルなのでルート内の処理を全てアロー関数で書いていますが、実際の開発では処理が複雑になったら別のtsファイルに処理をまとめた方が良いと思います。 また、開発していく中でルートごとに使用するミドルウェアを使い分けたい場面などが出てくると思います。その際はexpressのRouterのライブラリを用いてAPIルーターを作成するとより柔軟に作成できますので調べて試してみてください。(参考: https://expressjs.com/ja/guide/routing.html ) SAMローカル実行するための準備 AWS SAM テンプレート (template.yaml) プロジェクトのルートに template.yaml ファイルを作成し、デプロイするAWSリソースを定義します。Lambda関数、API Gateway、必要な IAMロールなどを記述します。 template.yaml AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: Sample Serverless Application Globals: # Functions 全体に適用する共通設定 (メモリサイズやタイムアウトなど) Function: Timeout: 30 MemorySize: 256 # 適宜調整する Runtime: nodejs20.x Architectures: - x86_64 Environment: Variables: NODE_ENV: production Resources: # function-1 ワークスペースに対応するLambda関数リソース定義 Function1: Type: AWS::Serverless::Function # AWS SAMで定義するサーバーレス関数 Properties: FunctionName: sample-express-function-1 # AWSコンソールに表示されるLambda関数名 (任意) Description: Express App for Function 1 (Simplified) # CodeUri は SAM がコードをパッケージングする際のソースディレクトリを指す。 # ここには、sam build 前のソースコードがあるディレクトリを指定。 CodeUri: functions/function-1/ # Handler は、sam build によって生成された成果物の中でのエントリーポイントを指す。 # esbuild が src/app.ts を dist/handler.js にバンドルし、 # その中で 'export const handler = ...' を CommonJS の 'exports.handler = ...' に変換するため、 # 'ファイル名(拡張子なし).エクスポート名' と記述する。 Handler: handler.handler Events: # API Gateway からのトリガー設定 Function1Api: Type: Api # API Gateway REST APIをトリガーとする Properties: Path: /function1/{proxy+} # 許可するHTTPメソッド (ANYは全てのメソッドを許可) Method: ANY # function-2 ワークスペースに対応するLambda関数リソース定義 Function2: Type: AWS::Serverless::Function Properties: FunctionName: sample-express-function-2 # AWSコンソールに表示されるLambda関数名 (任意) Description: Express App for Function 2 (Simplified) # CodeUri は function-2 ワークスペースのソースディレクトリを指す CodeUri: functions/function-2/ # Handler は function-2 のビルド成果物の中でのエントリーポイントを指す Handler: handler.handler Events: # API Gateway からのトリガー設定 (function-2用) Function2Api: Type: Api Properties: # Function 2 が処理するAPI Gatewayパス Path: /function2/{proxy+} Method: ANY Transform: AWS::Serverless-2016-10-31 : SAM テンプレートであることを示します。 Resources : デプロイする AWS リソースを定義します。 Type:AWS::Serverless::Function : Lambda関数リソースです。 CodeUri : Lambda関数としてデプロイするコードがあるディレクトリを指定します。 functions/function-1/dist のように、各ワークスペースのビルド成果物の場所を指定します。 Handler : Lambda関数が実行されるときに最初に呼び出されるコード内の関数名を指定します。バンドル後のファイル ( dist/app.js ) の中でエクスポートされる関数名になります。 Events : その Lambda関数をトリガーするイベントを設定します。 Type: Api は API Gateway からのHTTPリクエストをトリガーとする設定です。 Path と Method で特定のエンドポイントに紐づけます。 /{proxy+} は、そのパス以下の全てのリクエストをキャッチするための記法です。 ローカルでの開発とテスト (AWS SAM CLI) AWS SAM CLI を使うと、ローカル環境で Lambda関数と API Gateway をエミュレートしてテストできます。 各ワークスペースのビルド : まず、各ワークスペースのソースコードを JavaScript にビルドします。ルートディレクトリで定義したスクリプトを利用できます。 pnpm run build # functions/* 以下のそれぞれの build スクリプトが実行される これにより、例えば functions/function-1/dist/app.js のようなビルド成果物が生成されます。 SAMビルド : 次に、AWS SAM がデプロイ用のパッケージを作成するためのビルドを実行します。 sam build このコマンドは template.yaml を読み込み、 CodeUri: で指定された場所にあるビルド成果物を ( .aws-sam/build ディレクトリ以下に) コピーし、Lambdaが必要とする形式に整えます。 ローカルAPI起動 : SAM CLI が提供するローカル API 機能を使って、API Gatewayをエミュレートし、ローカルで Lambdaコードを実行できるようにします。 sam local start-api コマンド実行後、 http://127.0.0.1:3000 のようなURLでローカルサーバーが起動します。ブラウザやPostman/curl などで、 template.yaml で定義したパス(例: /function1/hello )にアクセスすると、ローカルで Lambda関数が実行されます。 ローカル開発中は、ソースコードを変更したら pnpm run build → sam build → sam local start-api を再実行するか、sam local start-api --watch オプションを使ってコード変更を監視させるなどの方法があります。(--watch オプションはビルドやエミュレーションの再起動を自動で行ってくれますが、実際の環境構成によっては少し工夫が必要な場合もあります) 終わりに 今回はTypeScriptのサーバレスをLambdaとExpressを用いて、ローカル実行するまでの方法ご紹介しました。実際にプロダクトをリリースするにあたり、AWSインフラを構築し、適切な設定をするなどの作業が必要になります。 特にExpressであったりmonorepo構成については初めての試みであったため躓くことがあり、備忘録も兼ねて細かくご説明したため、少々長くなってしまったかもしれません。 同じように困っている人にとって少しでもお役に立てていただければ幸いです。
アバター
📱 Appium Meetup Tokyo #2 開催決定!大好評のモバイルテスト自動化イベントがさらに進化して帰ってくる! 技術広報Gの中西です。前回大きな盛り上がりを見せた「Appium Meetup Tokyo」の第2回目が、2025年5月28日(水)にKINTOテクノロジーズの室町オフィスで開催されます。前回はAppiumの実践的な活用事例やパフォーマンス改善の劇的な成功例が紹介され、多くの参加者から高い評価をいただきました。 🎯 今回の注目ポイント 今回のイベントでは、モバイルアプリのE2Eテストや自動化を一段階引き上げるためのノウハウや最先端技術を、現場で活躍するエンジニアたちが余すことなくお伝えします。 Appiumテストの失敗原因調査のコツと実践 (MagicPod 脇坂 雅幸 氏) モバイルE2Eテストにおける失敗原因を迅速に特定・解決するためのデバッグ手法を具体的に解説!Appium Inspectorの活用法やWebDriverAgentに関連するトラブルシューティングの実例を共有します。 モバイルアプリのVRT環境構築に向けた取り組み (カシオ計算機 髙橋 秀徳 氏) Flutter製アプリ「CASIO WATCHES」でのAppiumを活用したビジュアルリグレッションテスト(VRT)自動化事例を紹介!スクラム開発の現場での課題解決と効率化への実践的なアプローチを詳しく解説します。 手動リンクチェック撲滅!Appiumで実現するネイティブアプリURL完全自動化 (KINTOテクノロジーズ 岡 郁弥、パンヌウェイ) Webでは簡単にできるリンク先チェックの自動化ですが、ネイティブアプリでは技術的な制約から実現が難しいとされてきました。その課題をクリアし、ネイティブアプリでもリンクチェックを完全自動化するための具体的なノウハウと工夫を共有します。 Appiumで安定したスクロール量を実現するちょっとした小技 (Autify 武藤 大樹 氏) 実務で即活用できるノウハウ満載!小さな工夫で大きな改善をもたらすテクニックをご紹介します。 🕒 タイムスケジュール 時間 セッション内容 18:30 開場 19:00 イベント開始 19:05 Appiumテストの失敗原因調査のコツと実践 19:45 モバイルアプリのVRT環境構築に向けた取り組み 20:05 休憩 20:15 手動リンクチェック撲滅!Appiumで実現するネイティブアプリURL完全自動化 20:35 Appiumで安定したスクロール量を実現するちょっとした小技 20:55 懇親会(現地参加のみ) 21:30 撤収 🏢 開催概要 日時 :2025年5月28日(水)19:00~21:30(18:30開場) 会場 :KINTOテクノロジーズ 室町オフィス(東京都中央区日本橋室町2-3-1 室町古河三井ビルディング16階) 参加費 :無料 定員 :現地参加20名、オンライン参加50名(Zoomウェビナー) 🌟 お申し込み方法 参加希望の方は、 イベントページ よりお早めにお申し込みください。ご登録はお早めに! 💬 こんな方に特におすすめです モバイルアプリのテスト自動化を次のレベルに引き上げたい方 Appiumの導入・活用に興味があり、具体的な成功事例を知りたい方 最新の自動化技術を学び、QA業務の負担を劇的に軽減したい方 🚀 モバイルテストの未来を一緒に創ろう! 前回の参加者アンケートでもAppiumの実践的な活用方法やノウハウに関する関心が非常に高く、コミュニティの交流も活発でした。今回も充実した内容とともに、新たな交流の機会をご用意しております。皆さんとお会いできるのを楽しみにしています! 参加を検討している方へ モバイルアプリの自動テストをこれから本格的に導入したい方 Appiumに興味があるが具体的な事例やノウハウが欲しい方 CI/CDと組み合わせた運用に関心があるエンジニアやQA担当の方 他社事例を参考に自社のテスト文化を改善したい方 上記に当てはまる方は、ぜひAppium Meetup Tokyoで最新の知見を共有し合いましょう。今後の告知や詳細情報は @AutifyJapan や @KintoTech_Dev でさせて頂きます。ご質問やご要望などがございましたら、お気軽にお寄せください。 Appium Meetup Tokyoでお会いできることを心より楽しみにしています。
アバター
Hello! I am Wada ( @cognac_n ), a Generative AI Evangelist at KINTO Technologies (KTC), part of the Generative AI Development Project. Trying DeepSeek R1 Using Azure AI Foundry 1. Introduction Recently, large language models (LLMs) have seen significant progress, with numerous companies announcing their own versions. One standout gaining attention is DeepSeek R1 , developed by the Chinese AI company DeepSeek. On January 30, 2025, Microsoft made the DeepSeek R1 model available on Azure AI Foundry and GitHub. In this article, I’ll share a summary of the process I followed to try out DeepSeek R1 using Azure AI Foundry, along with my impressions. 2. What is Azure AI Foundry? Azure AI Foundry is Microsoft's comprehensive platform for AI development . It offers a unified set of tools and services for developers to build, evaluate, and deploy generative AI solutions and custom copilots. Main features Utilizing various AI models: Supports a wide range of cutting-edge and open-source models provided by partner companies, including Microsoft, OpenAI, Hugging Face, Meta, and Mistral. DeepSeek R1 was also provided as part of this initiative. Integrated AI toolchain: An SDK, API, and portal are provided to accelerate the entire development lifecycle, offering a seamless experience from data preprocessing to model inference and continuous monitoring. Responsible AI practices: It has incorporated evaluation features, safety filters, and security controls to provide mechanisms to enhance the reliability and transparency of AI. Scalability for enterprises: It ensures high availability and scalability on Azure's managed infrastructure, supporting enterprise-level monitoring and governance. @ card The Azure AI Foundry portal states that when using models through the model catalog, prompts and outputs are not shared with Microsoft or the model provider. This allows for secure use of a variety of models. Microsoft provides and manages the hosting infrastructure and API endpoints. Models hosted in this "Model as a Service" (MaaS) scenario are subject to Azure data, privacy, and security commitment. Check the details of the Azure compliance certifications applicable to Azure AI Foundry. Microsoft functions as a data processor for prompts and outputs sent and generated by models (MaaS) deployed for pay-as-you-go billing system inference. Microsoft does not share these prompts and outputs with the model provider. Additionally, Microsoft does not use these prompts and outputs to train or improve Microsoft, model provider, or third-party models. @ card 3. Building a DeepSeek R1 Environment on Azure AI Foundry From this point forward, I’ll walk through the steps to actually use DeepSeek R1 on Azure AI Foundry. Please note that the detailed screen transitions and settings are based on the specifications as of January 31, 2025. Since changes to the UI and operations occur frequently, I will quote the official documentation as much as possible. Prerequisite preparations and account settings Preparation of an Azure account Access to Azure AI Foundry @ card Steps for installing DeepSeek R1 Creating a Project: Create a new project on the Azure AI Foundry portal. DeepSeek-R1 is available in the following regions: [eastus2, westus3, northcentralus, eastus, southcentralus, westus]. (As of January 31, 2025) @ card Selecting DeepSeek R1 model: Search for DeepSeek R1 in the "Model Catalog" and transition to the model page. Set deployment name and check the price: Set a deployment name of your choice. Set the content filter to ON/OFF. As of January 31, 2025, DeepSeek-R1 is provided free of charge. The price is expected to change in the future, so be sure to check back regularly for the latest information. DeepSeek R1 is currently available at no cost, though usage is subject to rate limits that may change at any time. Pricing may be updated in the future, and continued use will be subject to the new rates. As the model is in preview, a new deployment may be required to maintain access. 4. Deployment and endpoint creation: An endpoint is automatically generated in the Azure AI Foundry workspace, and a URI and API key for calling the model are issued. 4. A simple demo using DeepSeek R1 Here, I will introduce an example code to try out inference with DeepSeek R1. Install necessary libraries. pip install azure-ai-inference Below is an example code for using the API. Azure AI Foundry also provides code samples, making it very easy to try out. from azure.ai.inference import ChatCompletionsClient from azure.ai.inference.models import SystemMessage, UserMessage from azure.core.credentials import AzureKeyCredential client = ChatCompletionsClient( endpoint="<YOUR_TARGET_URI>", credential=AzureKeyCredential("<YOUR_KEY>"), ) deploy_name = "<YOUR_DEPLOY_NAME>" response = client.complete( messages=[ SystemMessage(content="You are a helpful assistant."), UserMessage( content="Please think about ways to promote the use of generative AI in companies. Answer in Japanese." Switch the legend to Japanese, ), ], max_tokens=2048, model=deploy_name, ) print(response.choices[0].message.content) Example of response <think> The first step is to clearly understand what the problem is. You need to think about how to promote the use of generative AI in the company. Generative AI has a wide range of potential applications, so it's important to first assess and understand your company’s current situation. It's essential to identify which departments could benefit from AI adoption and what potential challenges they may face. For example, marketing, customer support, and business process automation are some potential areas. Next, education and training are important. If employees are not provided with opportunities to learn how to use AI, it will be difficult to actually utilize it. Especially, to alleviate concerns and lack of understanding about AI, it might be a good idea to conduct workshops and training programs. Selecting the right tools is also necessary. It is important to select a generative AI platform or tools that suit your company's needs Depending on the situation, customization may be necessary, and addressing security and data privacy issues is also required. Support from the management is also essential. Without support from management, it will be challenging to secure the necessary budget and resources. Clearly communicating the benefits of AI implementation is essential to gaining management’s understanding and support. Furthermore, making successful cases is effective. If certain departments successfully pilot AI and demonstrate tangible results, it becomes easier to scale adoption across other departments. Sharing the results company-wide and expanding on them can be an effective strategy. It is also important to develop ethical guidelines and policies. Clear rules will need to be established to prevent the misuse of AI and encourage its responsible use. Continuous evaluation and improvement also should not be overlooked. Even after implementing AI, it's crucial to evaluate its effectiveness and make improvements based on feedback to ensure ongoing progress. It seems important to consolidate these points and consider concrete steps to move forward. </think> To promote the utilization of generative AI within a company, it is effective to systematically follow the steps below: --- ### **1. Current situation analysis and goal setting** - **Identifying needs**: Identify the business challenges of each department (planning, sales, development, support, etc.) and clarify the areas where generative AI can provide solutions (document creation, data analysis, customer support, etc.). - **Prioritization**: Prioritize the implementation of use cases with high impact and feasibility (e.g., automatic response to inquiries and automated report generation). --- ### **2. Building a system and changing awareness** - **Launching a promotion team**: Establish a promotion team consisting of representatives from management, the IT department, and each department to collaborate to secure the budget and resources. - **Implementation of educational programs**: - **Basic understanding**: Share the mechanisms, benefits, and ethical risks (e.g., data leakage and bias) of generative AI through training. - **Hands-on training**: Provide hands-on training to promote learning of prompt design and output verification methods. --- ### **3. Tool selection and test operation** - **Choosing the right AI for your company**: - Compare open sources (e.g., Llama 2) and cloud services (ChatGPT Enterprise, Google Vertex AI, etc.). - Select based on security standards (e.g., data encryption and whether the pre-trained model can be customized). - **PoC (Proof of Concept)**: Conduct test operations in a limited scope to verify accuracy and business efficiency improvement. --- ### **4. Establishment of governance** - **Development of usage guidelines**: - Set clear rules to prevent the input of confidential information and implement a system for double-checking output content. - Address legal risks regarding copyright and privacy. - **Monitoring System**: Regularly monitor the output quality and ethical aspects of AI and continuously improve them. --- ### **5. Cultivating a company culture** - **Sharing successful cases**: Boost motivation by sharing success stories from departments that have achieved positive results, through internal presentations or reports. - **Incentive design**: Recognize and reward teams that have improved business efficiency through the use of AI. --- ### **6. Collaboration with external entities and adaptation to evolution** - **Collaboration with vendors and experts:**: Seek support for staying up to date with the latest technological trends and for implementing necessary customizations. - **Continuous AI Updates**: Regularly review AI usage methods in response to advancements in model accuracy and changes in regulations. --- ### **Key points** - **Management commitment**: Demonstrating return on investment (ROI) and securing management support with a long-term perspective is crucial. - **Improvement driven by the field:**: Utilize feedback from employees (i.e., users) to optimize tools and processes. Generative AI is a "tool," and the success or failure of its utilization depends on "how humans use it." In addition to introducing technology, improving digital literacy throughout the organization and ensuring psychological safety are keys. 5. Impressions from actual use Response: It took about 4 minutes for the response this time. It appears that the latency was caused by both the LLM's own inference time and the increased processing time resulting from heavy usage. Output precision: Since it's an inference model designed for "thinking," it provides responses that convey a sense of deep insight, even when handling highly abstract or complex prompts. In API usage, the thinking process is output in a format enclosed by the tag. This is easy to use. Looking at the contents inside the tag reveals a thinking process as if a discussion were taking place among multiple people. Conclusion: Azure AI Foundry provides a convenient way to experiment with the latest models developed by third parties. In the generative AI space, where "trying it out first" is key, this ease of experimentation is extremely valuable. We Are Hiring! KINTO Technologies is looking for passionate individuals to help drive AI adoption in our business. We’re happy to start with a casual interview. If you’re even slightly interested, feel free to reach out via the link below or through X DMs . We look forward to hearing from you! Great place to stay! https://hrmos.co/pages/kinto-technologies/jobs/1955878275904303115 Thank you for reading this far!
アバター
はじめに こんにちは、2025年1月入社の こっしー です! 本記事では、2025年1月入社のみなさまに、入社直後の感想をお伺いし、まとめてみました。 KINTOテクノロジーズ(以下、KTC)に興味のある方、そして、今回参加下さったメンバーへの振り返りとして有益なコンテンツになればいいなと思います! S.H 自己紹介 2025年1月入社のS.Hです。モビリティプロダクト開発部、DX開発GでPjMを担当しています。 これまでは数社のIT会社、制作会社でマーケやPdM、ディレクター、設計開発やPjM等を経験してきました。 所属チームの体制は? 十数名のチームとなり、複数のプロダクトや案件を対応しています。 KTCへ入社したときの第一印象?ギャップはあった? 高い技術力を持ち、社内外の勉強会も多数開催、参加者も多く、大変向上心が高いと感じました。ギャップは第一印象よりさらに想像以上に勉強熱心な方が多いところです。勉強会にオンラインで100名以上集まっているケースもあり圧巻です。 現場の雰囲気はどんな感じ? 気軽に質問したり、相談が出来る雰囲気だと思います。メンターさんだけでなく、困っていたら色々な方がフォローしてくださり働きやすい環境かと思います。 ブログを書くことになってどう思った? 想像もしていなかったので驚きました。 youさん→S.Hさんへの質問 KTCのDX推進に当たって感じる感想を教えていただけますか? グループ会社全体で見ますと、DX推進分野はとてもやれる事が多いと感じています。現場で働く方やその先にいるお客様にとってよい環境やシステムを提供できるよう尽力していきたいと思っております。 呂 文佳(wenjia lu) 自己紹介 プラットフォームのQAを担当しております。 所属チームの体制は? QAが9名、チームメンバーが4名います。 KTCへ入社したときの第一印象?ギャップはあった? 暖かいチームです。 仕事のやりがいがあります。 現場の雰囲気はどんな感じ? みんなコミュニケーションを取り合って仕事を進めている感じです。 ブログを書くことになってどう思った? 何を書けばよいか迷っています。 S.Hさん→呂さんへの質問 KTCで変わってるなーと感じた会社の文化や出来事はありますか? 変わっていると感じたことはありませんよ。 I 自己紹介 2025年1月入社のIです。モビリティプロダクト開発部 DXソリューションGでディレクターを担当しています。これまでは、マーケやPdM、ディレクターを経験してきました。 所属チームの体制は? ディレクターとデザイナーが在籍し、複数のプロダクトを担当しています。 KTCへ入社したときの第一印象?ギャップはあった? 新しい技術もキャッチアップできる環境で、学びが多い環境だと思います。 現場の雰囲気はどんな感じ? 業務のことはもちろん、心理面も気軽に相談できるフォローがあり、働きやすいです。 ブログを書くことになってどう思った? 入社ブログは初めて書くので驚きました。 呂さん→Iさんへの質問 KTCで一番やりたいことを教えていただけますか? ユーザーの課題解決をでき、自社の収益性も高いプロダクトを作れるようになりたいです。 KS 自己紹介 新車サブスク開発G コンテンツ開発TのKSです。 主にKINTO ONE の静的コンテンツのフロントエンドを担当しています。 所属チームの体制は? アシスタントマネージャー1名、リーダー1名、メンバー8名の10名体制です。 KINTO ONEサイトやコーポレートサイトなど複数サイトの開発、保守運用を行っています。 KTCへ入社したときの第一印象?ギャップはあった? 面接時にご説明いただいていましたので、特にキャップはなかったです。 社内でたくさん勉強会が開催されていて、会社全体が技術的モチベーションが高い印象を受けました。 現場の雰囲気はどんな感じ? チーム内はもちろん、他部署のディレクターやデザイナーの方ともコミュニケーションとりやすく、楽しく開発できる環境です。 ブログを書くことになってどう思った? 何度か拝見させていただいたことはありましたが、書く側になるとは思っていませんでした。 Iさん→KSさんへの質問 所属しているチームで一番HOTなプロジェクトはなんですか? KINTO ONEサイトのマイグレーションプロジェクト(Vue.jsからNext.jsへ)です。 自分はデザインシステムやコンポーネントの設計や開発を担当しています。 李 俊起(Joonki Lee) 自己紹介 李俊起(イジュンギ)です。 ”リ”ではなくて”イ”ですので、間違わないでください! プラットフォーム開発部プラットフォームグループで、開発者のための環境構築やツール開発などを行っています。 所属チームの体制は? スクラッチチームとマネージドプラットフォームチームに分かれていて、スクラッチチームは主にスクラッチからツールの開発を行い、マネージドプラットフォームチームはSaaSやManaged Serviceを使って環境構築を行っています。 KTCへ入社したときの第一印象?ギャップはあった? マネージャー層との距離感が近いと思いました。ギャップをそこまでなかったです。 現場の雰囲気はどんな感じ? 普段は静かで各自黙々と自分のタスクをこなしている感じですが、何か議論するときは皆熱くなり盛り上がります。 ブログを書くことになってどう思った? 普段の業務についてもテックブログで公開してみたいと思いました。 KSさん→李さんへの質問 まだ神保町オフィスに行ったことないのですが、オフィスはどんな雰囲気ですかー? 最近のリニューアル工事で開放感があって少しおしゃれになりました。 こっしー ![プロフィール画像 こっしー](/assets/blog/authors/kossy/profile-img.png =250x) 自己紹介 古代(こしろ)です 🙌 プラットフォーム開発部で KINTOサービス やその他のサービス の基盤となるクラウドインフラの構築や保守運用を担当しています! 所属チームの体制は? 部の配下に Platform 、 DBRE 、Cloud Infrastructure 、 QA の4つのグループがあり、サービスの非機能に責務を持つ組織としてさまざまな取り組みをしています。 KTCへ入社したときの第一印象?ギャップはあった? 設立から4年にも関わらず、オンボーディングの仕組みが整っていると感じました。また、運営しているサービスが想像以上に多く、技術的な挑戦も思っていた以上に積極的に行われており、そういった部分が良い意味でギャップとして感じました。 現場の雰囲気はどんな感じ? とても仲が良くて、出社のたびにチームメンバーとご飯に行っています。雑談も多く、なんでも会話できる環境に助けられています。 ブログを書くことになってどう思った? はやくテックブログを書きたいと思っていたので、キッカケ作りにはとても良いなと思いました! 李さん →こっしーさんへの質問 いま一番興味のある技術ワードを教えて下さい! 「プラットフォームデザインパターン」です!Platform Engineeringの文脈において、ユーザーに応じて提供するプラットフォームの特性(Dev Teamに任せる責任範囲の違い)を意識したプラットフォームプロダクトの設計パターンに興味があります! TY 自己紹介 IT/IS部、コーポレートITG所属の山田です。主に従業員マスタ構築や業務効率化・改善に向けたシステム構築に携わってます。 所属チームの体制は? チームはInnovation Drive チームで、メンバーは9名います 自社内だけでなくグループへの支援も行っているのが特徴です。 KTCへ入社したときの第一印象?ギャップはあった? 面接で見聞きした情報とギャップがないよう、オフィス見学もさせていただいたこともあり、ほぼなかったです。 オフィス見学の際には、名古屋にいるマネージャーの方々がわざわざ出張して対面で対応していただけたことも入社の決め手でした。とても嬉しかったです。 現場の雰囲気はどんな感じ? 皆さん建設的な議論ができる方々で、困っていれば手を差し伸べてくれる、とても働きやすい環境だと思います。 ブログを書くことになってどう思った? 期限ギリギリに書き上げている自分を責めつつ、これを見て少しでも興味を持って入社してくれる方がいると嬉しいです! こっしーさん→TYさんへの質問 KTCでチャレンジしてみたい技術やプロジェクトがあれば教えて下さい! 技術的なところだと、データスペースは触ってみたい技術です。あとはプロジェクト化までいかない細かい領域での問題解決が今のところ多いですが、ユーザー(社員)の利便性向上に関してトコトンこだわって取り組んでいきたいです。 瀧川 直樹(Naoki Takigawa) 自己紹介 瀧川です。プラットフォーム開発部スクラッチ開発チームでエンジニアが使うツールの検証や開発をしています。フロントエンド開発をメインで担当しています! 所属チームの体制は? こっしーさんの説明がまとまっていたので、そちらを参考にしてもらえると↓ 部の配下に Platform 、 DBRE 、Cloud Infrastructure 、 QA の4つのグループがあり、サービスの非機能に責務を持つ組織としてさまざまな取り組みをしています。 KTCへ入社したときの第一印象?ギャップはあった? 入社時の面接でできたばかりのチームなので教育体制があまり整っていないかもと聞いていましたが、オンボーディング資料やOJT研修が準備されていて全然そんな事ないやんって思いました。 現場の雰囲気はどんな感じ? なんでも質問しやすい雰囲気です。プラットフォーム開発部のメンバーが東京勤務が多く、月1くらいでお互いの拠点を行き来しています〜。 ブログを書くことになってどう思った? 何こうかな…て思いました。 TYさん→瀧川さんへの質問 今一番興味がある・ハマっている技術領域があれば教えてください! 技術領域はAI…?AIを使った開発の効率化に興味があって、Devin、OpenHands、GithubCopilt✖️MCPなど色んなツールを並行で稼働させて、AI開発部隊を作って開発の効率化を模索しています。レビューが大変…(笑) 喬 禹(Yu Qiao) 自己紹介 喬 a.k.a Alexです!IT/IS部、AIファーストグループで、生成AIエンジニアとして生成AIの事業推進支援やPoCを担当しています! 所属チームの体制は? チームメンバー6名、それぞれ異なる専門スキルを持ち、自身の小分けされた領域で活躍しています。 KTCへ入社したときの第一印象?ギャップはあった? 面接官から感じた風土とほぼ一致していると感じたので、ギャップはありませんでした。瀧川さんの言ったように、教育体制があまり整っていないかもと入社前に聞きましたが思ったより充実で良い意味で裏切られました。 現場の雰囲気はどんな感じ? チャンレンジしたいことを自由にチャレンジできるし、一人で解決できないことがあればいつでも助けを求めることができる環境です。 ブログを書くことになってどう思った? またテックブログを書きたくなってきました! 瀧川さん→Alexさんへの質問 いつも使っている会議の時に付けているヘッドフォンは何というやつですか?おすすめのポイントとかあれば教えて欲しいです! これは前々職でもらったものです。コロナの初期に会社がフルリモートに切り替わったタイミングで、チーム全員にノイズキャンセリング機能が優れたヘッドフォンを購入する必要がありました。その時、上司と一緒にヨドバシカメラに行って選びました。 you ![プロフィール画像 you](/assets/blog/authors/you/tanuki.jpeg =250x) 自己紹介 プラットフォーム開発部・Cloud Infrastructure Gの 劉(you)です!主にAWSを中心に社内のインフラの構築・運用・改善など様々な業務に触り合っています。 所属チームの体制は? Cloud Infrastructure Gは現在、9人体制でマネージャー・各リーダーともフラットに会話して業務をする事ができる環境です。Gの皆さんが意識高く仕事を取り組んでいますので、モチベーションが上がる毎日を過ごしてます。 KTCへ入社したときの第一印象?ギャップはあった? 会社の進化が早すぎると感じました。内部の体制とか業務の進め方とか、私が思った以上に整えていて感心しました。ギャップがあるとしたら、コミュニケーションも取りやすくて技術的なチャレンジが会社全体で起きてる、すごくいい方向でした。 現場の雰囲気はどんな感じ? リスクテイクがすごく忠実していて、業務に関して自由に意見交換ができる素晴らしい環境です! ブログを書くことになってどう思った? 次のテクブログのネタを考えています! Alexさん→youさんへの質問 今後KTCでどんなことに挑戦してみたいですか? KTCの技術と文化を進化して行きたいです。一人で成し遂げられることは本当に少ないと思いますので、私ができることの最大を発揮して影響を与えられるように頑張ります!今は新技術の習得・発信を中心にやりたい所です。 さいごに みなさま、入社後の感想を教えてくださり、ありがとうございました! KINTO テクノロジーズでは日々、新たなメンバーが増えています! 今後もいろんな部署のいろんな方々の入社エントリが増えていきますので、楽しみにしていただけましたら幸いです。 そして、KINTO テクノロジーズでは、まだまださまざまな部署・職種で一緒に働ける仲間を募集しています! 詳しくは こちら からご確認ください!
アバター
Introduction The combination of VSCode and Copilot is an absolute blast. It's so much fun that I almost forget I have a day job. I’m writing this article because I simply have to share how incredibly enjoyable this development experience has been. This article is the entry for day 25 in the KINTO Technologies Advent Calendar 2024 🎅🎄 What I'll Talk About today The AI world has been on fire since last year, and this year was no exception: there's been no shortage of buzz! At KTC, we've been diving headfirst into AI, looking for smart ways to boost our development productivity. In this post, I'll shine a spotlight on what you can actually do when you pair VSCode with Copilot. Now, maybe you're thinking, “AI? Meh. It just spits out vague code and I can write better stuff faster myself.” I get it. That was my take too, until I saw the new Copilot Chat and Edits features unveiled at GitHub Universe. Suddenly, coding with AI started to look… kind of fun? So today, I'll share some tips that have been genuinely useful when teaming up with Copilot Chat/Edits in real-world dev work. https://reg.githubuniverse.com/flow/github/universe24/attendee-portal/page/livestream?tab.day=20241029 Why Flutter? When doing mobile development, it's common to use the standard IDE for each OS, whether it’s iOS or Android. However, since this article focuses on programming with GitHub Copilot, we'll be working under the assumption that development is done using VSCode. With that in mind, Flutter stands out as a major mobile framework that officially supports VSCode. I also got a lot out of attending FlutterKaigi recently, so for this project, I decided to use Flutter for collaborating with AI. I even contributed to the FlutterKaigi app. Just a tiny issue, but still 😀 What can it actually do? Many of the features announced at GitHub Universe are still in preview, so what's available is limited. But even just using the already released Copilot Chat and Edits has made working with AI more enjoyable and clearly improved the developer experience. When you hear “coding with AI,” you might picture building apps without writing any code, or having code generated automatically. And sure, auto-generating code is possible, but that's really just one small part of what AI can do. Also, generating complex, fully functional code with a single prompt? Not exactly easy. Writing the right prompt is half the battle. In this article, we'll share tips for using Copilot Chat/Edits to do everyday coding tasks (like writing test code, formatting and breaking up code, and refactoring) all in collaboration with AI to help improve code quality. Now, here are some tips. Code Summary Copilot Chat makes it easy to generate code summaries. This can speed up code comprehension during onboarding. Add comments BEFORE AFTER If you want to add comments to your code, Copilot Edits can insert them directly into your file. This helps deepen your understanding of the code. Copilot can also update existing comments, making sure they stay accurate. For example, if you add validation to the add method in the class above, you can give an instruction like the one below, and Copilot will update the comment accordingly. BEFORE AFTER Creating Test Code You can add files to reference (besides the current one) above the text input field in Copilot Edits. So, when asking it to write test code, just create a test file, keep it open, and add the target file to the reference list. Copilot will then generate the test code for you. Code Formatting & Splitting When building UIs with declarative languages like Flutter, deeply nested code tends to become a common issue. ::: details Code before formatting class SomethingPage extends StatelessWidget { const SomethingPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Something Page'), ), body: Center( child: Container( padding: const EdgeInsets.all(16.0), color: Colors.blueAccent, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( padding: const EdgeInsets.all(8.0), color: Colors.redAccent, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( padding: const EdgeInsets.all(4.0), color: Colors.greenAccent, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( padding: const EdgeInsets.all(2.0), color: Colors.yellowAccent, child: const Text('Deeply Nested Widget 1'), ), Container( padding: const EdgeInsets.all(2.0), color: Colors.purpleAccent, child: const Text('Deeply Nested Widget 2'), ), ], ), ), ], ), ), ], ), ), ), ); } } ::: Copilot Edits can help with this too. It splits and formats the code into cleaner, more readable chunks. :::details Formatted code class SomethingPage extends StatelessWidget { const SomethingPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Something Page'), ), body: Center( child: Container( padding: const EdgeInsets.all(16.0), color: Colors.blueAccent, child: const NestedContainer(), ), ), ); } } class NestedContainer extends StatelessWidget { const NestedContainer({super.key}); @override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: const [ InnerContainer(), ], ); } } class InnerContainer extends StatelessWidget { const InnerContainer({super.key}); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(8.0), color: Colors.redAccent, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: const [ DeeplyNestedContainer(), ], ), ); } } class DeeplyNestedContainer extends StatelessWidget { const DeeplyNestedContainer({super.key}); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(4.0), color: Colors.greenAccent, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: const [ DeeplyNestedWidget1(), DeeplyNestedWidget2(), ], ), ); } } class DeeplyNestedWidget1 extends StatelessWidget { const DeeplyNestedWidget1({super.key}); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(2.0), color: Colors.yellowAccent, child: const Text('Deeply Nested Widget 1'), ); } } class DeeplyNestedWidget2 extends StatelessWidget { const DeeplyNestedWidget2({super.key}); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(2.0), color: Colors.purpleAccent, child: const Text('Deeply Nested Widget 2'), ); } } ::: Refactor Even those legacy methods tangled up with complex dependencies, something that you often see in older code, can be refactored using Copilot Edits based on SOLID principles. :::details Classes with methods with complex dependencies class SomethingLogic { Future<void> performComplexOperation() async { // Fetch data from remote server final response = await http.get(Uri.parse('https://example.com/data')); if (response.statusCode != 200) { throw Exception('Failed to load data'); } final data = jsonDecode(response.body); // Save data to local database final database = openDatabase( join(await getDatabasesPath(), 'app_database.db'), onCreate: (db, version) { return db.execute( 'CREATE TABLE data(id INTEGER PRIMARY KEY, value TEXT)', ); }, version: 1, ); final db = await database; await db.insert( 'data', {'id': data['id'], 'value': data['value']}, conflictAlgorithm: ConflictAlgorithm.replace, ); // Save data to shared preferences final prefs = await SharedPreferences.getInstance(); await prefs.setString('data', jsonEncode(data)); // Perform some complex logic if (data['value'] == 'special') { // ...existing code... print('Special value found!'); // ...existing code... } else { // ...existing code... print('Regular value found.'); // ...existing code... } } } :::: :::details Code refactored using SOLID principles class DataFetcher { final http.Client client; DataFetcher(this.client); Future<Map<String, dynamic>> fetchData(String url) async { final response = await client.get(Uri.parse(url)); if (response.statusCode != 200) { throw Exception('Failed to load data'); } return jsonDecode(response.body); } } class DatabaseHelper { Future<Database> getDatabase() async { return openDatabase( join(await getDatabasesPath(), 'app_database.db'), onCreate: (db, version) { return db.execute( 'CREATE TABLE data(id INTEGER PRIMARY KEY, value TEXT)', ); }, version: 1, ); } Future<void> saveData(Database db, Map<String, dynamic> data) async { await db.insert( 'data', {'id': data['id'], 'value': data['value']}, conflictAlgorithm: ConflictAlgorithm.replace, ); } } class SharedPreferencesHelper { Future<void> saveData(Map<String, dynamic> data) async { final prefs = await SharedPreferences.getInstance(); await prefs.setString('data', jsonEncode(data)); } } class SomethingLogic { final DataFetcher dataFetcher; final DatabaseHelper databaseHelper; final SharedPreferencesHelper sharedPreferencesHelper; SomethingLogic(this.dataFetcher, this.databaseHelper, this.sharedPreferencesHelper); Future<void> performComplexOperation() async { final data = await dataFetcher.fetchData('https://example.com/data'); final db = await databaseHelper.getDatabase(); await databaseHelper.saveData(db, data); await sharedPreferencesHelper.saveData(data); if (data['value'] == 'special') { // ...existing code... print('Special value found!'); // ...existing code... } else { // ...existing code... print('Regular value found.'); // ...existing code... } } } :::: Doing this level of refactor manually would take quite a bit of time, but with Copilot Edits, you can get it done much faster. The code is now much easier to read, so you can build on that and refactor it further based on your own experience. Others Besides that, the basic Suggestions feature is surprisingly powerful. Normally, when I run into implementation issues, I end up switching back and forth between the browser and the IDE, but now, most problems can be solved just by consulting Copilot. That means fewer distractions and better focus during development. This might seem minor, but it makes a big difference. Tips for Giving Instructions Working with AI has led to a lot of new discoveries, but I've come to realize that giving clear instructions is one of the most important parts. Many engineers I know still find AI hard to use,but once you get used to giving it specific instructions, collaborating with AI can actually be pretty fun. Here are a few instruction tips I've picked up: Keep it simple Be specific Mention which file Say what to do Say how to do it Don't give multiple instructions at once I especially feel that it's important for the person giving instructions to have a solid grasp of programming principles and design concepts. Summary In this post, I introduced some of the things you can do by combining VSCode and Copilot. With Copilot Chat and Edits, tasks like summarizing code, writing comments, generating test code, formatting, splitting, and refactoring become significantly easier; all through a few simple prompts. I hope that at least some of that came across. In the engineering world, opinions on AI are still divided, and many of the engineers around me are still hesitant to embrace it. But it's clear that the world is steadily moving toward AI, and it's only going to keep evolving and expanding what it can do. Feels like we've entered an era where engineers need to seriously think about how we'll use AI going forward. If this article got you even a little curious about collaborating with AI, I'd be glad.
アバター
Hello, I'm Xu Huang from the KINTO ID Platform team. For the past few years now, we have been providing user authentication and authorization systems (known internally as UserPool) across multiple countries. To support this, we adopted a broker model that connects Userpools across multiple regions, building and operating an architecture that allows them to share authentication and authorization information with each other. Last year, as part of our cost optimization efforts, we redesigned and migrated this architecture. In this post, I’ll walk you through what changed and why. In our initial deployment, we used AWS Aurora Global Database (referred to as Global DB) as part of our global deployment strategy. To minimize access load and latency, we deployed Slave DBs in close proximity to each UserPool and placed Broker servers in the same regions as the corresponding Slave DBs. (Due to Global DB limitations, only one Master DB is allowed, and it supports up to five Slave DBs.) As shown in the diagram above, we gradually rolled out the UserPool service to the regions outlined in blue. To enable centralized user management, we designed the system so that unique IDs would be issued from a central aggregation point and synchronized this information to each region’s sub-DB for local management. Phase 1: Migrating from Global DB to a Normal DB and Removing Write-Only Applications The original architecture prioritized minimizing access load by deploying servers across multiple regions. However, in reality, the system had not yet reached a scale that required such complexity, leading to unnecessary operational costs. To optimize the setup, we conducted a thorough evaluation and concluded that a Global DB setup was not essential for our current usage. We then redesigned the system to allow direct R&W access from the Broker to a shared common DB. The diagram below illustrates the updated architecture: Phase 2: Consolidating the Broker While Phase 1 significantly delivered cost savings, we looked for further optimization opportunities. This led us to consider whether we could consolidate the system into a single Broker instance. However, there was one challenge: as an identity provider, we also offer redirect URLs to external third party services. If those URLs were to change, it would require the third parties to update their configurations as well. So we started thinking about how we might migrate without changing the domain. With support from our infrastructure team, we realized that by updating DNS settings in Route53 and routing traffic through CloudFront to the new unified server, we could avoid changing the domain altogether and transition to a unified Broker. When implementing the design as shown above, we were concerned about the impact on latency caused by the increased physical distance between servers, particularly from the UserPool to the now-centralized Broker. So, we measured it. The results showed that communication between the UserPool and the Broker became about 10% slower, but since the Broker was now located in the same region as the database, DB communication became faster. Overall, there was no significant impact in end-to-end performance before and after the architecture change, so we proceeded with planning for the Phase 2 migration. Results Through these two phases, we optimized the system architecture to better align with the actual usage patterns of our business operations. Going forward, we will continue reviewing system functionality and regularly working on cost-efficiency efforts.
アバター