TECH PLAY

KINTOテクノロジーズ

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

969

はじめに 私は2020年11月にKINTOテクノロジーズに入社し、KINTO WebのフロントエンドとAPIの開発に携わった後、現在はモバイルAndroidアプリチームの開発者を務めています👋🏾 IT業界で女性であることについての思いや経験を書いてほしいとの依頼でしたが、正直なところ、性別による違いはないと思いますし、あるべきでもないと思っています。本記事は、KINTOテクノロジーズにおけるさまざまな働き方や視点を掘り下げてダイバーシティを探求する全5回のシリーズの1つですので、ここでは私がKINTOテクノロジーズで担当する開発チームでのリーダーシップについて、私の思いと個人的な成長についてお話ししたいと思います。 簡単な自己紹介 : 😊 経歴: 💡 豆知識:高校生の時に始めた個人事業に10年間従事 🌱 ゲームプログラミングを学ぶために来日し、15年の開発経験あり 💼 前職:モバイルアプリエンジニア、ソフトウェア(SmartTV)エンジニア、Webエンジニア(フルスタック)、デジタルサイネージスタートアップ。 📫 2020年にKINTOテクノロジーズに入社。 優れたリーダーとは? 開発者から初めてチームリーダーになったとき、最初に自問したのは「優れたリーダーとはなにか」ということでした。 初めてリーダーを任せてくれた上司が、リーダーと上司の違いを説明してくれて、「こんなリーダーになりたい」と思ったのはその時でした。 リーダーとは、メンバーの力を結集し、優れた成果を生み出し、それを共有する人です。 そのためには、自分が前に立ってチームを引っ張り、裏ではサポート役となってチームを良い方向に導いていくことが大切だと考えます。 開発チームの最終的な使命は、今あるリソースを活用して、必要なサービスをできるだけ早く、完璧に作り上げることです。さらに、開発チームの目的は優れた開発を行うだけでなく、開発を通じて最大の価値を生み出すことでもあります。最終的にはこれがチームの成果として表れます。こういったチームが優れたチームであり、これを支えるリーダーが優れたリーダーであると考えます。 「チームワーク」の重要性 では、結果を出す優れたチームを作るにはどうすれば良いのでしょうか。優れたチームに最も必要なものは何でしょうか。チームメンバーをひとつのゴールに集中させるにはどうすれば良いのでしょうか。その原動力はチームワークだと私は思っています。チームワークを高めるために、私がチームのメンバーと行ったことを以下にご紹介します。 チームの全員がリーダーになる 「Team Goal Task Content Sharing Meeting (ゴール・タスク情報共有会)」で現在のチームゴールを共有し、各自がタスクを選択できるようにしています。通常、リーダーシップが求められるのはチームリーダーやグループリーダーのみで、実際に組織で役職に就いていない限り、リーダーシップが自分の役割だと考える人はあまりいません。私は、チームのメンバーが自分の仕事に対してリーダーシップを発揮し、与えられた仕事に対して「リーダーとしての」責任感を持てるようにすることもリーダーの役割だと考えています。そして、これがチームにとって重要な役割を果たしていると感じます。自主性があると人はやる気になり、個人の能力を最大限に高めることにつながるのだと思います。 仕事は開発文化によって生み出される 開発チームが良い仕事をするのは、「仕事」のためではなく、チームの「文化」があるからだと思っています。 例えば、作業プロセスを作ること、文書を作成すること、仕様を明確に伝えること、これらは「仕事」の基本です。 成功する開発チームは、チームの「文化」が物事をうまく機能させると信じているのだと思います。 チームのメンバー同士がどのようにコミュニケーションを取っているか。どのようにまとまっているか。結論が出た後はどうするのか。反対意見を言うのか、支持するのか、陰で批判するのか。などなど。 これが開発文化であり、チーム文化です。 多様性を認め、受け入れる チームのメンバーにはそれぞれ強みがあります。一番大切なのは、その強みを最大限に生かし、最大限の価値を生み出すことだと思います。 では、私たちのチームではどうしているのでしょうか? デイリースクラムリーダー:チーム全員が日替わりでリーダーになる 私たちのチームでは毎朝11時にミーティングを開いて、チームメンバーが集まり、昨日やったこと、今日やること、そして仕事上の問題を簡単に共有します。通常のチームミーティングと異なるのは、上下関係の報告形式ではなく、横並びの雰囲気の中でメンバーが交代でファシリテーターを務める点です。ミーティングは「共有」の形式で進められます。チームメンバーが問題を抱えていてタスクを進められない場合は、デイリースクラムの終了後に「助け合いミーティング」を開いて解決を目指します。また、昨日行ったすべての作業を覚えていない場合があるので、Confluenceに書き留めておくと、チームメンバーはそれを見て、スケジュールを立て、やるべきことを計画することができます。 KINTO ONEサブスクチームのデイリースクラムのやり方をご紹介します。その日のファシリテーターがデイリースクラムのアジェンダを説明します。最初の週は、まずは今後2週間でチームが改善すべき点や試みるべきことを共有します。毎朝10~15分程度の短い時間ですが、このように全員が交代でリーダーを務めることで、日々の仕事の中でリーダーシップを鍛えることができ、チームメンバーが率先してチームの現在のタスクやゴールを共有し、タスクに貢献することができます。 その重要性を理解することで、「リーダーシップのマインドセット」を磨くことができ、やがてそれが_自身の中のモチベーター_となって、より良い結果につながると思っています。 コードレビュー:モチベーションと自律性 多くの開発者は、創造性によって高い「モチベーション」を得ています。自分の仕事や表現を認め、高く評価してくれる人たちと分かち合いたいと思っています。私自身も、人がやったことを見たり、コードに没頭して、人の発想に驚かされたりするのが好きです。コードレビューの時間を通して、私たちは互いの仕事を共有し、互いに学び合うことができます。現在の方法よりも良い方法があれば、それを共有し、大胆な変更も取り入れます。もちろん、どんな変更にもチーム全体の合意が必要です。こうして、優れたコードについて議論し、互いにコードレビューを行うことで、私たちは日々成長しています。素晴らしい仲間と充実した共同作業の経験が、チーム内の信頼関係をますます強化していると感じています。 ブレインストーミング:一つのゴールに集中しよう 私たちは、なぜこの仕事をする必要があるのか、なぜこのサービスをユーザーに提供する必要があるのか、考える時間を取っています。どう作るか、どう伝えるか、どう実現させるか、そして私たちの作るサービスがユーザーに与える価値の大きさについて、深く考えます。コードの寿命やコンポーネントのスケーラビリティ、ユーザーの視点に立った全体の設計を考慮することで、開発チームの各メンバーが、目的や機能ごとに開発リーダーとして独立して技術的な意思決定を行うことができます。 私たちのチームのブレインストーミングは、次のルールに則って進められます。 トピックに集中しよう アイデアを自由に表現しよう アイデアを組み合わせよう できるだけ多くのアイデアを出そう アイデアは批評しない イメージしてみよう アイデアを決定する 自分で決めた場合は、複雑なコミュニケーションプロセスを経ずに自律的に「プロトタイプ」を作り、それを企画チームに届けてプロダクトにすることがゴールです。 開発文化の成長のために柔軟であり続ける 私自身の成長、チームメンバーの成長、そして皆の成長のために小さな行動を積み重ねていく過程で、優れた開発文化が生まれ、結果として皆がともに成長していくのだと思っています。 私個人としては、素晴らしい仲間がいるチームの一員でいられることに常に感謝しています。開発文化は良いサービスを作るための手段であり、ツールであって、ゴールではありません。チームの文化は今後も変化し続け、良い方向に向かっていくものと信じています。 最後に、私が考える優れたリーダーの理念とは、チームメンバーの成長をコントロールするのではなく、後押しし、サポートすることであり、チーム内で互いに助け合える優れた開発文化を築くことです。優れたチームを作ることが必ずしも大きな成功を保証するものではないかもしれませんが、その可能性を高めることはできると私は信じています。
アバター
はじめに こんにちは!KTCでAndroidエンジニアをしている長谷川( @gotlinan )です! 普段はmyrouteというアプリの開発をしています。myrouteのメンバーが書いた他の記事も是非読んで見てください! myroute Android AppでのJetpack Compose Compose超初心者のPreview感動体験 本記事ではKotlin coroutinesを使用したStructured Concurrencyを解説します。 Structured Concurrencyは知っているけど、coroutineを使う方法はどんな感じ?って方は、 並行処理のための便利関数 をご確認ください。 Structured Concurrency? Structured Concurrencyって何でしょう?日本語にすると「構造化された並行処理」みたいな感じだと思います。イメージとしては、二つ以上の処理を並行しながら、それぞれでキャンセルやエラーが発生した場合も正しく管理されていること、だと思います。本記事を通じて、Structured Concurrencyについて詳しくなりましょう! 今回は二つのよくある例をもとに紹介してみます。 1. エラーを協調したい まずよくある例として処理1と処理2を実行後、その結果に応じて処理3を実行したい場合です。 図にすると、以下のようになります。 処理1と処理2を実行後、その結果に応じて処理3を実行する この場合、処理1でエラーが発生した場合、処理2を継続しても無駄ですね。 したがって処理1でエラーが発生した場合、処理2をキャンセルする必要があります。 同様に処理2でエラーが発生した場合も、処理1をキャンセルして、処理3に進む必要はありません。 2. エラーを協調したくない 次によくある例として、画面内に複数のエリアがあり、それぞれ独立して表示する場合です。 図にすると、以下のようになります。 画面内に複数のエリアがあり、それぞれ独立して表示する この場合、仮に処理1でエラーが発生しても、処理2や処理3の結果は表示したい場合があります。 したがって処理1でエラーが発生した場合でも処理2や処理3はキャンセルせずに継続する必要があります。 二つの例は理解できましたか?coroutineでは上記のような例を、Structured Concurrencyの考えをもとに簡単に実装することができます! ただし理解するためにはcoroutineの基礎を理解する必要があります。次のセクションからは実際にcoroutineを学びましょう! 基礎は知っているよっていう方は、[並行処理のための便利関数](#並行処理のための便利関数)までスキップしてください。 coroutineの基礎 詳しい解説の前にcoroutineの基礎的な話をしましょう。 coroutineでは CoroutineScope から launch 関数を呼ぶことで非同期の処理を開始できます。具体的には以下のような形です。 CoroutineScope.launch { // 実行したいコード } ところでなぜ CoroutineScope を使用する必要があるのでしょうか?それは非同期処理では、「どのスレッドで実行するか」、「キャンセルやエラーが発生した時にどう振る舞うか」がとても重要だからです。 CoroutineScope は CoroutineContext を持ちます。ある CoroutineScope で実行されるcoroutineは CoroutineContext をもとに制御されます。 具体的には CoroutineContext は以下の要素などから構成されます。 Dispatcher : どのスレッドで動くか Job : キャンセルの実行、キャンセルやエラーの伝搬 CoroutineExceptionHandler : エラーハンドリング CoroutineScope を作成する際は、それぞれの要素を+演算子で渡すことが可能です。 そして CoroutineContext はcoroutineの親子間で継承されます。例えば以下のようなコードがあったとします。 val handler = CoroutineExceptionHandler { _, _ -> } val scope = CoroutineScope(Dispatchers.Default + Job() + handler) scope.launch { // 親処理 launch { // 子処理1 launch {} // 子処理1-1 launch {}// 子処理1-2 } launch {} // 子処理2 } この場合は CoroutineContext が以下のように継承されます。 CoroutineContextの継承 おや、画像を見ると Job は継承されずに新しく作成されているようですね? これは間違いではないです。「 CoroutineContext はcoroutineの親子間で継承されます」と述べましたが、厳密には「 Job 以外の CoroutineContext はcoroutineの親子間で継承される」の方が正しいです。それなら Job はどうなるんだ?と思いますよね。 次のセクションでは Job について理解を深めてみましょう! Jobとは coroutineにおける Job とは何でしょうか?それは短くまとめるのであれば、「coroutineの実行を制御する」ものだと思います。 Job には cancel メソッドがあり、開発者は開始されたcoroutineをいつでもキャンセルすることが可能です。 val job = scope.launch { println("start") delay(10000) // Long Process println("end") } job.cancel() // start (printed out) // end (not printed out) Androidエンジニアがよく利用するであろう viewModelScope や lifecycleScope に紐づく Job はそれぞれのライフサイクルの終わりの時にキャンセルされています。これによりユーザーが画面外にでた場合に継続中の処理があっても、開発者が意識せずに正しくキャンセルされます。 そんな超重要な Job ですが、coroutineの親子間でのキャンセルやエラーの伝搬の役割も持ちます。前のセクションでは Job は継承されない話をしましたが、その例を使うと、以下の画像のように Job は階層関係を持ちます。 Jobの階層関係 実際に Job の定義を一部抜粋すると、以下のようになっています。 public interface Job : CoroutineContext.Element { public val parent: Job? public val children: Sequence<Job> } 親子関係を保持できるになっており、キャンセルやエラーが発生したときに親や子の Job を操作できそうですね。 次の章からは Job の階層関係を通じて、どのようにcoroutineがキャンセルやエラーを伝搬しているか確認してみましょう! cancelの伝搬 coroutineがキャンセルされた場合、以下のような挙動になります。 自身の子coroutineを全てキャンセルする 自身の親coroutineには影響しない ※ CoroutineContext を NonCancellable に変更することで親coroutineのキャンセルの影響を受けないcoroutineを実行することも可能です。Structured Concurrencyのテーマとは離れるため、今回は割愛します。 つまりキャンセルは Job の階層関係において下方向に影響します。 下記の例だと、 Job2 がキャンセルされた場合、 Job2 、 Job3 、 Job4 で動いているcoroutineがキャンセルされます。 Cancelの伝搬 エラーの伝搬 実は Job には大きく分けて、 Job と SupervisorJob があります。 この種類によって、エラーが発生した場合の挙動が変わります。 自身のJobでエラーが発生したときと、子 Job でエラーが発生したときの挙動を二つの表にまとめました。 Job 内でエラーが発生したとき 子Jobを 自身のJobを 親Jobに Job 全てキャンセルする エラー終了する エラーを伝搬する SupervisorJob 全てキャンセルする エラー終了する エラーを伝搬しない エラーが子 Job から伝搬してきたとき 他の子Jobを 自身のJobを 親Jobに Job 全てキャンセルする エラー終了する エラーを伝搬する SupervisorJob 何もしない 何もしない エラーを伝搬しない 二つの表を参考にしてエラー発生時の挙動を表したイメージは、 Job と SupervisorJob の場合でそれぞれ以下のようになります。 Jobの場合 通常のJobのJob2でエラーが発生した場合 子Jobである Job3 、 Job4 はキャンセルされる 自身のJobである Job2 はエラー終了する エラーを親Jobである Job1 に伝搬する Job1 の他の子Jobである Job5 をキャンセルする Job1 がエラー終了する SupervisorJobの場合 通常のJobのJob2でエラーが発生した場合 子Jobである Job3 、 Job4 はキャンセルされる 自身のJobである Job2 はエラー終了する エラーを親SupervisorJobである Job1 に伝搬する 意識してもらいたい点として、エラーが伝搬された SupervisorJob1 は、他の子Job( Job5 )をキャンセルせず、自身も通常終了します。 ちなみに Job が、通常終了したのか、エラーにより終了したか、キャンセルにより終了したのかを確認する方法として、 invokeOnCompletion を使用することができます。 val job = scope.launch {} // Some work job.invokeOnCompletion { cause -> when (cause) { is CancellationException -> {} // cancellation is Throwable -> {} // other exceptions null -> {} // normal completions } } catchされなかった例外 ところでcoroutineで捕捉されなかった例外はどうなるのでしょうか? 例えば TopLevelの Job でエラーが発生したり、伝搬してきた場合はどうなるの? SupervisorJob でエラーが発生したり、伝搬してきた場合どうなるの? などの疑問があると思います。 答えは CoroutineExceptionHandler が指定されていれば、呼ばれる CoroutineExceptionHandler が指定されていなければ、スレッドのデフォルトの UncaughtExceptionHandler が呼ばれる となります。 coroutineの基礎 で前述のように、 CoroutineExceptionHandler も CoroutineContext の仲間です。以下のように渡すことができます。 val handler = CoroutineExceptionHandler { coroutineContext, throwable -> // Handle Exception } val scope = CoroutineScope(Dispatchers.Default + handler) もし CoroutineExceptionHandler が指定されていない場合、スレッドのデフォルトの UncaughtExceptionHandler が呼ばれます。 開発者が指定したい場合は以下のように記述します。 Thread.setDefaultUncaughtExceptionHandler { thread, exception -> // Handle Uncaught Exception } 自分が本記事執筆まで誤解していたこととして、 SupervisorJob を使用すれば、エラーが伝搬しないのでアプリケーションは終了しないという認識がありました。 しかし SupervisorJob はあくまでcoroutineの Job の階層関係上でエラーを伝搬しないだけです。従って上記の二種類のHandlerのどちらかを適宜定義しておかないと、意図した通りに動かない可能性があります。 例えばAndroidアプリではスレッドのデフォルトの UncaughtExceptionHandler は、開発者が指定しない限りアプリケーションが終了(クラッシュ)するようになっています。一方で通常のKotlinコードを実行すると、ただエラーログを表示するだけとなります。 また、少し話は逸れますが、 try-catch と CoroutineExceptionHandler のどちらを使用すればいいのか、という疑問があるかもしれません。 CoroutineExceptionHandler でエラーを捕捉したとき、coroutineの Job は既に終了しており、復帰することはできません。基本的に復帰可能なエラーは try-catch を使用して、Structured Concurrencyの考えをもとに実装する際や、ログを出しておきたいときなどは、 CoroutineExceptionHandler を設定する方針が良さそうです。 並行処理のための便利関数 ここまでの説明が少し長くなってしまいましたが、coroutineではStructured Concurrencyを達成するために、 coroutineScope() や supervisorScope() のような関数があります。 coroutineScope() 1. エラーを協調したい を覚えていますか?このような例では coroutineScope() を使用することができます。 coroutineScope() は起動した子coroutineが全て終了するまで待ちます。また子coroutineでエラーが発生した場合、他の子coroutineはキャンセルします。 以下のようにコードを記述すると、 子処理1と子処理2は並行で実行 子処理3は子処理1と子処理2が終わった後に実行 どの子処理でエラーが発生しても、他の子処理はキャンセルされる などを達成することができます。 scope.launch { coroutineScope { launch { // 子処理1 } launch { // 子処理2 } } // 子処理3 } supervisorScope() 2. エラーを協調したくない を覚えていますか?このような例では supervisorScope() を使用することができます。 supervisorScope() も起動した子coroutineが全て終了するまで待ちます。また子coroutineでエラーが発生した場合でも、他の子coroutineはキャンセルしません。 以下のように記述すると、 子処理1と子処理2と子処理3は並行で実行 どの子処理でエラーが発生しても、他の子処理に影響しない などを達成することができます。 scope.launch { supervisorScope { launch { // 子処理1 } launch { // 子処理2 } launch { // 子処理3 } } } まとめ Structured Concurrencyは理解できましたか? 説明のための基礎的な内容が多かったかもしれませんが、基礎的な内容を理解しておくと、いざ複雑な実装に取り組む際の助けとなります。 そしてStructured Concurrencyをうまく記述できるようになると、比較的簡単にサービスの局所的なパフォーマンスの改善に繋げることができます。もし無駄に直列で実行しているようなボトルネックがあれば、Structured Concurrencyを考慮してみてはどうでしょうか? 以上です〜
アバター
こんにちは。KINTOテクノロジーズのグローバルプロダクト開発グループで働いているティムです。 以前の記事では、 弊社のデザインシステムの開発 と、このシステムに基づいてデザインに関する決定が行われていることについて書きました。 私自身は、2歳になる娘と2023年の8月に生まれた息子の2児の父でもあります。こちらの記事では私の「父親業と仕事の両立」についてお話したいと思います。 本記事は、KINTOテクノロジーズにおけるダイバーシティとさまざまなワークスタイルを探るアドベントカレンダーの全5本中4本目の記事となります。 日本における父親業 初めて父親となったとき、私はすでに日本に住み、今とは別の会社ですが日本で働いていました。 そのときは、 世界でもトップクラスの長期育児休暇制度 を利用して、6か月間の休暇を取得することにしました。生まれたばかりのわが子との絆を深める時間はかけがいのないもので、 ほとんどの国では得られない恩恵 を受けられたことはとても幸運でしたが、その一方で、もっと早く職場に復帰して関連プロジェクトに貢献し、プロフェッショナルとしてのアイデンティティを取り戻すことができたのではないか、とも感じました。 妻が第2子を妊娠したとき、私はKINTOテクノロジーズで正社員として働いていましたが、もう一度育児休暇を取るかどうか悩みました。 手厚い制度があったとしても、自身や周囲の仕事の状況を考えると、実際には 必ずしも簡単に休暇を取得できるわけではありません 。特にまだ入社して間もない身で、休暇を取ることがどう見られるか心配でした。 育休を取るか、取らないか そんな中、KINTOテクノロジーズの多様性のある職場環境やフレックスタイム制について知り、不安が解消されました。新型コロナの流行を受けて、当時会社では午前中は在宅勤務、午後は出社を奨励する臨時措置が導入されており、これが仕事と家庭を両立させる現実的な方法となったのです。 これは私自身だけでなく、家族にとっても画期的なことでした。オムツを替え、泣いている赤ん坊を寝かしつけ、療養中の妻をサポートすると同時に、仕事についてもこなせる範囲の業務量を維持することができました。そしてふと、休暇を取らなくてもどうにかなるのではないかと思い、妻との長い話し合いの結果、私たちはあえて育児休暇を取らず、代わりに会社の柔軟性とサポート体制を活用し、個人的にも仕事面でも成長を続けるという決断をしました。 この決断がワークライフバランスにどう影響したか 息子が生まれてから徐々に職場環境に慣れるにつれ、同僚やラインマネージャー、そして人事部が、キャリア形成と並行して家庭を優先させることを真摯にサポートしてくれるのを目の当たりにするようになりました。同じような経験をしてきた彼らとの率直な対話と励ましのおかげで、会社のワークライフインテグレーションの理念を信頼を持って受け入れることができました。 生まれたばかりの息子と同僚からのお祝いの品 おわりに 今思えば、KINTOテクノロジーズの風土があったからこそ、仕事か家庭かの選択を迫られることなく父親になることができたのだと思います。大変な道のりでしたが、職場のサポートと理解に感謝しています。 これから家庭を持とうと考えている人には、その一歩を踏み出すことを心からお勧めします。家庭を持つ社員に対して、とても暖かい職場風土であることを知っているからです。KINTOテクノロジーズの柔軟性を身をもって体験した者として、ここは自身のキャリアと親としての役割のどちらも尊重できる場所だと自信を持って言えます。居心地の良い雰囲気の中で、キャリアを磨きながら子育ての挑戦も乗り切ることができます。 Credit Cover Image by BiZkettE1 on Freepik
アバター
はじめに こんにちは!KINTOテクノロジーズ(以下、KTC)の開発支援部に所属するriomaです。 普段はコーポレートエンジニアとして「全社利用するITシステムの維持管理」を行っています。 先日、「 KINTOテクノロジーズ MeetUp!~情シスによる情シスのための事例シェア4選~ 」というタイトルで「コーポレートIT領域に特化した、事例発表+座談会形式の勉強会」を開催しました。 今回は、その勉強会で事例発表した内容について、補足を交えながらテックブログ上で紹介します。 登壇の背景 初の社外勉強会を開催しよう!と社内で企画が上がり、ちょうど直近で発表ネタにできそうなPJを経験していたので認証基盤切り替えを実施したというテーマでお話しさせていただきました。 切り替えたのは当社ではなく兄弟会社であるKINTOの環境のお話しですが、スケジュールや当時起きたことなどを交えつつざっくりですがKTCのコーポレートITとして実施していることの紹介ができたと思っています。 この記事では発表時の資料を用いて簡単な補足と、改めて内容のご紹介をいたします。 前提 「なぜ認証基盤切り替えが必要だったのか。」 KINTOでは認証基盤周りの細かい課題が山積みで、利便性とセキュリティの面にいくつか困っていました。 そこでMicrosoft Entra ID(旧Azure AD)を検討したところ最適解となりそうなことからEntra IDへの切り替えを進めることに決定しました。 他の理由としては、KINTOテクノロジーズの認証基盤がすでにEntra IDだったためゆくゆくはテナント統合などの連携強化を見据えて実施しておきたかったという点や、Microsoft E3ライセンスを持っているのに活用できていなかったからといった理由も相まってこの選択になりました。コストカットという面でも大きなメリットがありました。 切り替えにあたって 切り替えにあたって考慮した事項が2つありました。 1つ目は、これまで証明書を利用して制御していたアクセスポリシーを証明書を使わずに同じような条件で実装することです。 条件付きアクセスを利用した設定ですが、概要としては「MDMに登録済みのデバイス」を条件として設定していて、その属性値に当てはまらないものはブロックされるといった設定を組み合わせて既存よりも強化かつ柔軟なアクセスポリシーを実装することができました。 2つ目は、切り替え時に全アカウントのパスワードがリセットされてしまうという仕様があるという点です。 結構強烈なインパクトがある仕様だったのですが、これに対していかに社内のスタッフに影響を出さずに対応するということが求められました。 それにあたって実施したこととしては、システムからの強制リセット後にこちらで一定のルールに基づいて全てのアカウントへのパスワード変更を実施しました。変更ルールはあらかじめ周知しており、ログイン後の詳細手順を合わせて展開していたため当日、ログインできないといった事象は特に発生せず問い合わせ件数もほとんどありませんでした。 ※実はほとんどの方はパスワードではなくPINでのログインを利用して入っていたため「変更されたパスワードはこれです」といった周知はそこまで意味がなく逆に少し混乱させてしまうことになった 切り替え作業周辺のトラブル 手順書の展開においてはよくあるケースの一つですが、展開した手順書や作業概要の説明がわかりにくいという声を結構いただいていました。これは私がほぼ100%悪かったのですが、認証基盤切り替えといった大きなインパクトを与える作業のリスクや影響を超丁寧に説明しすぎて普段そのシステムに触らない/意識しない人たちから見るととてもわかりにくいような言葉選びや説明をしてしまったことが反省点です。 そして前述しましたが、切り替え後のPCログインパターンの一つに「PINを入力してログインする」というものがあることに直前まで気づいていませんでした。 事前に展開していた切り替え後のログイン手順書では、そこに全く触れておらず普段PINでログインしている方にとっては「???」となる事態を生んでしまいました。幸い、ギリギリ資料は前日〜当日に直すことができたのですが何度も展開しなおす手間となり混乱を与えてしまいました。。 また切り替え作業中に設計ミスに気づき、設計書と手順書を直しながら切り替え手順を実施するというちょっと無理のある対応もしました。。根幹に関わる部分ではなかったのでそこは助かりました。 他にもあるので添付のスライドをぜひご覧ください。 最後に 細かい問い合わせや指摘はあったものの、何十分も業務ができないといったクリティカルなことは起きなかったようで結論としては無事認証基盤切り替えを実施できました。 のちに「こんな大規模な切り替えなのにあまり問い合わせや業務影響がなかったのはすごい」といった社内のスタッフから声があったと教えていただき、とても嬉しかったです。 今後もシステム変更/切り替えなどは継続して実施していくのでこの経験を踏まえて、よりよい社内環境を構築していきたいです。
アバター
Introduction I am Hand-Tomi, and I am developing the "my route" app for Android at KINTO Technologies. Recently, our project needed an event trigger for when a RecyclerView item in the RecyclerView was fully visible. There are several ways to do this, but we found a solution that could work by adding a little code to the RecyclerView Adapter. I am writing this article to share and exchange ideas about this method and its implementation. :::details What is a RecyclerView? A RecyclerView is an extensible and flexible UI component for viewing and managing dynamic datasets efficiently in Android applications. ::: The Goal of This Article I will explain how to trigger an event when multiple RecyclerView items are fully visible. For example, when the image on the left (←) is visible, Card1 and Card2 in Title1 and Card1 and Card2 in Title2 should be triggered. I will explain how to trigger Card3 in Title2 when you scroll Title2 and change the visibility as shown in the image on the right (→). Left image (←) Right image (→) Terms Parent RecyclerView : A RecyclerView placed in an overall layout that allows vertical scrolling. Child RecyclerView : A RecyclerView that can be scrolled horizontally as an item in the Parent RecyclerView. Parent RecyclerView Child RecyclerView Receiving Scroll Events First of all, when an item's visibility changes, it is necessary to track the following two events in order to check the item's visibility status. When the parent RecyclerView is scrolled vertically When a child RecyclerView is scrolled horizontally To track these events, set viewTreeObserver.addOnScrollChangedListener for the child RecyclerView. recyclerView.viewTreeObserver.addOnScrollChangedListener { // TODO: Check the visibility status } viewTreeObserver is used to register listeners that watch for global changes to the ViewTree, such as global layout changes, start of drawing, and changes to touch mode. By registering addOnScrollChangedListener in viewTreeObserver , you can get the scroll change events included in the screen. To get an event when the child RecyclerView is placed in the layout, write code that sets the onAttachedToRecyclerView() method in the Adapter of the child RecyclerView and releases it with the onDetachedFromRecyclerView() method. private val globalOnScrollChangedListener = ViewTreeObserver.OnScrollChangedListener { checkImpression() } override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { super.onAttachedToRecyclerView(recyclerView) this.recyclerView = recyclerView recyclerView.viewTreeObserver.addOnScrollChangedListener(globalOnScrollChangedListener) } override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { super.onDetachedFromRecyclerView(recyclerView) recyclerView.viewTreeObserver.removeOnScrollChangedListener(globalOnScrollChangedListener) } private fun checkImpression() { // TODO Check } By implementing the above code, when the parent or child RecyclerView is scrolled or visible for the first time, the event is passed to the checkImpression() function. Checking That the Child RecyclerView Is Fully Visible If the child RecyclerView itself is not fully visible, the items in it are also considered not fully visible. Therefore, you first need to make sure that the child RecyclerView is fully visible. For that purpose, we created the following function. private fun RecyclerView.isRecyclerViewFullyVisible(): Boolean { if (!this.isAttachedToWindow) return false val rect = Rect() val isVisibleRecyclerView = getGlobalVisibleRect(rect) if (!isVisibleRecyclerView) return false return (rect.bottom - rect.top) >= height } View.getGlobalVisibleRect(rect: Rect): Boolean This method returns true if the view is at least partially visible on the screen, or false if it is not. rect stores the position and size of the view, with the origin at the top left of the screen. if (!this.isAttachedToWindow) return false The getGlobalVisibleRect method may return true if RecyclerView is not included in the layout layer. Therefore, it skips checking and returns `false<4>} if it is not in the layout layer. (rect.bottom - rect.top) >= height Check the height of the visible view and compare it with the height of the view to see if it is fully visible. With this function included in the checkImpression() method, the processing is skipped if the child RecyclerView is not fully visible. private fun checkImpression() { if (recyclerView?.isRecyclerViewFullyVisible() == false) { return } // TODO Check that the items in the Child RecyclerView are fully visible } Get the positions of the fully visible items in Child RecyclerView LinearLayoutManager provides a function that allows you to determine if the items in the RecyclerView are visible on the screen. findFirstCompletelyVisibleItemPosition() Returns the first position that is fully visible on the screen. findLastCompletelyVisibleItemPosition() Returns the first position that is fully visible on the screen. findFirstVisibleItemPosition() Returns the first Position that is at least partially visible on the screen. findLastVisibleItemPosition() Returns the first Position that is at least partially visible on the screen. In this article, we want to make sure that the items are fully visible . So, we used findFirstCompletelyVisibleItemPosition() and findLastCompletelyVisibleItemPosition() . private fun checkImpression() { if (recyclerView?.isRecyclerViewFullyVisible() == false) { return } val layoutManager = layoutManager as? LinearLayoutManager ?: return null val first = layoutManager.findFirstCompletelyVisibleItemPosition() val last = layoutManager.findLastCompletelyVisibleItemPosition() // TODO Trigger the event if there is a newly visible item } Event trigger for when a new item is fully visible When an event with the position obtained in the above session is triggered, it will trigger the event for each item that is currently fully visible. Since we don’t want to get duplicate information, let’s implement an event that triggers when a new item is fully visible. private var oldRange = IntRange.EMPTY private fun checkImpression() { if (recyclerView?.isRecyclerViewFullyVisible() != true) { oldRange = IntRange.EMPTY return } val layoutManager = recyclerView?.layoutManager as? LinearLayoutManager ?: return val newFirst = layoutManager.findFirstCompletelyVisibleItemPosition() val newLast = layoutManager.findLastCompletelyVisibleItemPosition() val newRange = newFirst..newLast for (position in newRange.minus(oldRange)) { // Sends the position of a new item that is fully visible. onImpression(position) } oldRange = newRange } fun onImpression(position: Int) { // Send the impression event here. } newRange contains the position of the item that is currently fully visible on the screen. To avoid triggering duplicate events, remove the previously triggered oldRange and then trigger a new event. This way, the position of the new item that is fully visible is passed to the onImpression() function. Then, by implementing the code that sends the event in this function, the process of sending the impression event is completed. Summary By using the above code, it is possible to monitor impression events on the Adapter side. This Project Manager created ImpressionTrackableAdapter , which has the impression function, to improve convenience, and decided that the required Adapter inherits ImpressionTrackableAdapter . I will attach the ImpressionTrackableAdapter code to the toggle below, so feel free to copy and paste it if you need it. :::details Complete code abstract class ImpressionTrackableAdapter<VH : RecyclerView.ViewHolder> : RecyclerView.Adapter<VH>() { private val globalOnScrollChangedListener = ViewTreeObserver.OnScrollChangedListener { checkImpression() } private var recyclerView: RecyclerView? = null private var oldRange = IntRange.EMPTY abstract fun onImpressionItem(position: Int) override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { super.onAttachedToRecyclerView(recyclerView) this.recyclerView = recyclerView recyclerView.viewTreeObserver.addOnScrollChangedListener(globalOnScrollChangedListener) } override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { super.onDetachedFromRecyclerView(recyclerView) this.recyclerView = null recyclerView.viewTreeObserver.removeOnScrollChangedListener(globalOnScrollChangedListener) } private fun checkImpression() { if (recyclerView?.isRecyclerViewFullyVisible() != true) { oldRange = IntRange.EMPTY return } val layoutManager = recyclerView?.layoutManager as? LinearLayoutManager ?: return val newFirst = layoutManager.findFirstCompletelyVisibleItemPosition() val newLast = layoutManager.findLastCompletelyVisibleItemPosition() val newRange = newFirst..newLast for (position in newRange.minus(oldRange)) { onImpressionItem(position) } oldRange = newRange } private fun RecyclerView.isRecyclerViewFullyVisible(): Boolean { if (!this.isAttachedToWindow) return false val rect = Rect() val isVisibleRecyclerView = getGlobalVisibleRect(rect) if (!isVisibleRecyclerView) return false return (rect.bottom - rect.top) >= height } } ::: End I hope this article will help you with triggering impression events when working with multiple RecyclerViews. If you have any questions or feedback, please feel free to contact us. Thank you for reading!
アバター
Introduction I am Okapi, from the Quality Assurance Group. In the previous article, titled " Increased Awareness of QA ," I described how the QA Group participates in projects and performs QA tasks. In this article, I would like to write about the key characteristics of QA testing for native apps, drawing from my recent experience working on several native app projects. About QA Testing for Native Apps In basic QA design, a test scenario is created that clarifies the scope of the testing (what is to be tested or excluded), and test cases (preconditions, procedures, and expectations) are then created from that perspective. However, in addition to the above, a native app design requires consideration of the following points: ・ iOS and Android ・ OS versions and smartphone devices to be tested ・ Native app functionality As a result, even native apps with less complex functions exhibit characteristics that tend to increase the scale of testing. Item Characteristics iOS and Android ・ iOS is an operating system developed by Apple ・ Android is an operating system developed by Google Due to the differences in the development environments, the amount of testing simply doubles. OS versions tested and smartphone devices to be tested There are many types of smartphone devices available to the public. Testing all of these and OS version combinations is practically impossible. Native app functionality Due to the unique functions and specifications of mobile devices affecting app functionality, it is necessary to verify the operation of installed native apps based on these characteristics. ・ Push Notification:  The function that enables apps to send notifications to the user ・ Touchscreen:  The feature that allows users to interact with the app by touching areas on the screen ・ Permission:  The feature that enables a pop-up dialogue requesting the user’s consent before the app attempts to access certain functionalities of the device. iOS and Android As the operating systems of iOS and Android are different, the amount of testing is doubled, so we want to reduce the man-hours. However, the development team is also divided into iOS, Android and BFF. Even if there are no bugs on the iOS version, bugs may be found on the Android version. Same may be true on reverse: no bugs on Android, but issues on the iOS version. Issues with the API may require testing on both Android and iOS. These patterns may occur with each function. Therefore, if we proceed in such a way as to omit testing on Android because it has been confirmed on iOS, or vice versa, there is a risk that 'bugs affecting quality' may persist. So we are proceeding with a basic policy of implementing the system for both operating systems. OS Versions and Smartphone Devices to be Tested Since testing all combinations of OS and devices is impossible, we always confirm the recommended environment for the target app (e.g., iOS 15.0 or higher / Android 9 or higher), taking into account the market share of each OS. And then assign: Main OS: All tests conducted Non-main OS: Display check and locations where OS-related bugs occurred As device-dependent bugs are rare, and even if they occur, they are unlikely to be fatal, testing is basically conducted on devices that comply with the above-mentioned OS. However, there is an exception: Functional tests involving camera activation will be conducted on all types of devices available to us. The reason for this is that during the initial QA testing of a native app, there was a relatively high frequency of issues where the app would crash when the camera was launched on certain devices. Native App Functionality In the process of QA of native apps, it is necessary to verify whether the app operates in accordance with specifications, considering the functionality of the mobile device. However, the specification sheet typically outlines only the app specifications and often does not describe the functions of the mobile device. Therefore, bugs can occur when device functions affect the behavior of the app. Test designs based on an understanding of device functions can effectively detect bugs from a usability perspective. Item App Specifications Device Functions Common Bugs from a Usability Perspective Push Notifications ・ Push notifications'  - timing  - content  - transition destination when tapped ・ In the app notification badge's  - display timing  - deletion timing ・ Notification badge of app icon  - display when multiple accumulations  - display timing  - deletion timing ・ Specification by change of condition  - login/logout  - App foreground/background/lock screen ・ The number of app icons does not match the number of notifications when receiving multiple notifications ・ The app notification badge  - is not displayed  - display timing is slow ・ The app notification badge  - does not disappear  - deletion timing is slow ・ When logging out, the target notification  - cannot be received  - error occurs when notification is pressed ・ No notifications when the app is in the foreground Touchscreen Behavior when a button or link is tapped ・ Double-tap  - tap twice quickly ・ Flick  - swipe left and right with a fingertip ・ Swipe  - slowly slide left and right ・ Pinch in  - touch the screen with two fingers simultaneously and move them closer together to zoom out ・ Pinch out  - touch the screen with two fingers simultaneously and move them apart to zoom in ・ Double-tap  - to open the same screen twice  - registration details are registered twice ・ Display error occurs when performing flick/swipe/pinch in/pinch out Permissions ー ・ Allow/disallow push notifications ・ Allow/disallow location information ・ Allow/disallow camera ・ Push notification permission setting is not linked to settings ・ Crash occurs with location permissions and camera permissions Next Challenges In QA testing scenarios for native apps, we check for specifications according to system requirements and app-specific functions. As I became more fully involved in QA for app development, I learned that the iOS screening process is very strict. For example, ・ Rejected unless it is in "non-login accessible" format ・ Rejected if it contains a link to GooglePlay and so on. I believe that by adding these insights into our knowledge, we can incorporate them into further ad-hoc testing scenarios as one perspective and lead to further quality improvements. Conclusion In this article, I introduced the characteristics of QA testing for native apps that have a tendency to increase the scale of testing. However, in native apps, QA reports numerous bugs from various perspectives, including iOS, Android, and API. This places a substantial burden on the development side to address modifications, resulting in higher costs for both sides compared to web apps, making the current situation less efficient. The latest app development languages I worked with include Kotlin for Android and Swift for iOS, respectively. Native development for each platform has the advantage of individual optimization that allows for fine-tuning. Although there are cross-platform technologies such as Kotlin Multiplatform Mobile (KMM) and Flutter that can be developed using the same source code, there are disadvantages, such as the need to learn separately the parts that depend on individual OS, such as device control.[^1] [^1]: Camera, GPS, sensor system, etc. In that regard, native languages are directly supported by the corresponding OS, providing a high degree of freedom in leveraging device functions. In the future, I expect and hope that the most suitable development method will be chosen based on the preferences of development engineers, as well as the purpose of app development. As a QA engineer, I also would like to exert effort in flexibly improving the efficiency of QA testing in alignment with the development method.
アバター
はじめに 初めまして、KINTOテクノロジーズ株式会社でmy routeのAndroid開発をしているソミです。my routeは'おでかけ情報'(お出かけ·交通情報)・'地図で探す' (地図検索)・'おでかけメモ' (メモ)などの様々な機能を提供して、移動の体験を豊かにしているアプリです。 現在、my routeのAndroidチームはUI/UXの改善を目指してJetpack Composeを積極的に活用しています。このUIツールキットはコードの可読性を高め、迅速かつ柔軟なUI開発を可能にします。さらに、宣言的UIアプローチにより開発プロセスを簡素化し、UIコンポーネントの再利用性を向上させます。この背景を踏まえて、my routeのAndroidアプリで使用されているJetpack Composeの機能について、いくつかの例を通じて紹介したいと思います。今回は4つの機能を紹介します。 機能紹介 1. drawRectとdrawRoundRect Jetpack Composeでは、Canvasを利用して特定の範囲での描画を可能にします。そして drawRectとdrawRoundRect はCanvasの内部で定義できる図形に関連する関数です。drawRectは、指定されたオフセットとサイズで長方形を描画します。一方、drawRoundRectは、drawRectのすべての機能を含むと同時に、cornerRadiusパラメーターを追加し、角の丸みを調整することができます。 my routeには、端末のカメラでテキスト形式のクーポンコードを読み取る機能があります。コードを正確に認識するためには、テキストを認識する部分のみを透明にし、残りの部分を暗くする必要がありました。そのため、drawRectとdrawRoundedRectでUIを実装しました。 @Composable fun TextScanCameraOverlayCanvas() { val overlayColor = MaterialTheme.colors.onSurfaceHighEmphasis.copy(alpha = 0.7f) ... Canvas( modifier = Modifier.fillMaxSize() ) { with(drawContext.canvas.nativeCanvas) { val checkPoint = saveLayer(null, null) drawRect(color = overlayColor) drawRoundRect( color = Color.Transparent, size = Size(width = layoutWidth.toPx(), height = 79.dp.toPx()), blendMode = BlendMode.Clear, cornerRadius = CornerRadius(7.dp.toPx()), topLeft = Offset(x = screenWidth.toPx(), y = rectHeight.toPx()) ) restoreToCount(checkPoint) } } } 上のコードは下記のUIで実装されます。 コードを説明すると、overlayColorで色が指定されたdrawRectを使用して画面全体を暗くします。さらに、drawRoundRectを利用して角の丸い透明な四角形を作成し、テキストを認識できる領域であることを明確にしました。 2. KeyboardActionsとKeyboardOptions KeyboardActionsとKeyboardOptions はTextFieldコンポーネントに属するクラスです。TextFieldは入力を処理するUI要素で、KeyboardOptionsを使用して入力フィールドに現れるキーボードの種類を設定することができます。そして、KeyboardActionsは、Enterキーを押した時の動作を定義できます。 my routeのアカウント画面には、支払いのためクレジットカードの情報を保存するところがあります。カード番号を入力する部分は端末キーボードと関わっているので、KeyboardActionsとKeyboardOptionsで実装しました。 @Composable fun CreditCardNumberInputField( value: String, onValueChange: (String) -> Unit, placeholderText: String, onNextClick: () -> Unit = {} ) { ThinOutlinedTextField( ... singleLine = true, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Number, imeAction = ImeAction.Next ), keyboardActions = KeyboardActions( onNext = { onNextClick() } ) ) } 上のコードは下記のUIで実装されます。 クレジットカード番号のみを入力するため、KeyboardActionsではKeyboardTypeをNumberに設定し、入力時に次に移動できるようにImeAction.Nextを設定しました。また、KeyboardOptionsでは、キーボードの「次へ」ボタンを押したときにonNextClick()メソッドが実行されるようにしています。ちなみに、onNextClick()はFragment内で以下のように設定されています。 CreditCardNumberInputField( ... onNextClick = { binding.creditCardHolderName.requestFocus() } ) この設定により、「次へ」ボタンを押すと、クレジットカード番号の入力から次のステップ、氏名を入力する部分に進みます。 3. LazyVerticalGrid LazyVerticalGrid は、アイテムをグリッド形式で表示します。このグリッドは縦スクロールが可能で、多数のアイテム(または長さが不明なリスト)を表示します。また、画面のサイズに応じて列の数が調整され、様々な画面で効果的にアイテムを表示することができます。 my routeのおでかけ情報の「今月のイベント」セクションは現在の位置が属するエリアで開催される多くのイベント情報を提供します。このように大量のイベント情報(タイトル、画像、開催期間)は、Columnで実装するには限界があるため、LazyVerticalGridを使って数列にわたって上下にスクロール可能なコンテナにイベントアイテムを表示しました。 private const val COLUMNS = 2 LazyVerticalGrid( columns = GridCells.Fixed(COLUMNS), modifier = Modifier .padding(start = 16.dp, end = 16.dp), horizontalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(20.dp) ) { items(eventList.size) { index -> val item = eventList[index] EventItem( event = item, modifier = Modifier.singleClickable { onItemClicked(item) } ) } } 上のコードは下記のUIで実装されます。著作権のため画像とタイトルは削除しました。 eventListに含まれるデータのサイズに基づいて、アイテムを一定の間隔でグリッドに表示し、絶えずイベント情報を見ることができるようになりました。 4. Drag And Drop draggable修飾子 は、画面のコンポーネント内部に何かをドラッグアンドドロップする機能です。ドラッグの流れ全体を制御する必要がある場合は、pointerInputを使います。 my routeには「myステーション」という、最大12個まで自分だけの駅またはバス停を登録する機能があります。カードリスト形式で表示されるため、一目で確認することができます。このカードリストは自由に順番を変更することができて、実装ためにはドラッグ&ドロップ操作が必要です。 itemsIndexed(stationList) { index, detail -> val isDragged = index == lazyColumnDragDropState.draggedItemIndex MyStationDraggableItem( detail = detail, draggableModifier = Modifier.pointerInput(Unit) { detectDragGestures( onDrag = { change, offset -> lazyColumnDragDropState.onDrag(scrollAmount = offset.y) lazyColumnDragDropState.scrollIfNeed() }, onDragStart = { lazyColumnDragDropState.onDragStart(index) }, onDragEnd = { lazyColumnDragDropState.onDragInterrupted() }, onDragCancel = { lazyColumnDragDropState.onDragInterrupted() } ) }, modifier = Modifier.graphicsLayer { val offsetOrNull = lazyColumnDragDropState.draggedItemY.takeIf { isDragged } translationY = offsetOrNull ?: 0f } .zIndex(if (isDragged) 1f else 0f) ) val isPinned = lazyColumnDragDropState.initialDraggedItem?.index == index if (isPinned) { val pinContainer = LocalPinnableContainer.current DisposableEffect(pinContainer) { val pinnedHandle = pinContainer?.pin() onDispose { pinnedHandle?.release() } } } } 上のコードは下記のUIで実装されます。 drag操作はpointerInputによって検出され、detectDragGestures関数はdragイベントを処理します。アイテムをdragする際、lazyColumnDragDropStateオブジェクトのonDrag、onDragStart、onDragEnd、onDragCancelメソッドを呼び出してドラッグ状態を管理し、drag中のアイテムのY軸位置を更新して視覚的に移動する効果を提供します。また、drag中のアイテムがスクロールによって画面外に出るのを防ぐために、このコードはisPinned変数とLocalPinnableContainerを活用しています。 まとめ 簡潔に書いたため、すぐに理解できない部分もあるかもしれませんが、my routeの活用方法をご紹介させて頂きました。最初、私はJetpack Composeに慣れていなかったため、my routeのUIをXMLレイアウトから書き換えるのがやや複雑に感じることもありましたが、Jetpack Composeで書かれたコードはすぐに理解することができ、可読性やメンテナンスの面で非常に効率的な方法だと感じています。今後もさまざまなJetpack Composeを基にしてmy routeのUX改善に努めたいです。最後までお読みいただき、ありがとうございました。
アバター
Introduction  Hello! I am mmm from the QA team.  I am mainly involved in the QA of KINTO web systems. The systems we handle include the frontend visible to customers, the back-office area used by dealerships, and several systems for internal operations. Between these systems, various types of data are linked.  Recently, we have adding been more apps such as " KINTO Unlimited " and " KINTO Easy Application ". As new features and requirements are added, organizing their relationship to and impact on existing systems is essential. Therefore, it is necessary to understand not only the specifications for each system unit, but also the series of operations in KINTO services to grasp the flow of data.  I personally consider organizing QA work challenging and crucial, especially as each new system or functional requirement increases the complexity and impact on QA as well.  In this article, I would like to focus on test design, discussing challenges from my past projects and considerations when interacting with the development team. Common Challenges Specifications for the same function exist in multiple documents  Since a project may involve multiple development teams, each team can have documentation for the same function. Therefore, the following are likely to occur. There are differences in content between documents, and the correct specifications are unknown. There are wording fluctuations between documents, leading to miscommunication. Specifications that should be considered on the development side are buried, leading to bugs. A specification for the status under review exists.  While reading documents, you may find specifications listed with expressions such as "under confirmation" or "?" as it had points not yet finalized. These have the following effects on test design and implementation. Test design: The number of test cases is tentative (may increase or decrease), as we proceed with a tentative testing perspective. Test implementation: Testing of undefined ranges cannot proceed, and when specifications change, case modification work will be required. No documentation that provides a bird's eye view of the status of each system.  While the actual front-end area that is visible to users may display status, on the back-office, level, behind the scenes may retain detailed status, but there is not always documentation that can be seen at a glance.  For example, when purchasing a product on an e-commerce site, a store's status is more (actually, probably more) detailed than the information seen on the customer's side  In the absence of documentation that provides a bird's eye view of both, the QA side needs to organize test design in terms of data linkage between systems. The specification of the calculation system is described in code.  If there is a test that requires the calculation of amounts or days, we check the development specifications, but they are sometimes written in code. In such cases, there are the following effects. Deciphering the code takes time. If specifications are not summarized so that a third party can understand its contents, by the time a test is implemented the QA work becomes a silo that depends on the knowledge of specific people. Considerations When Interacting with the Development Team Get an overview of the project  Given that the above-mentioned issues are inevitable due to the nature of the project. I believe that first inquiring about the background of the project's inception and understanding its purpose and history can help the QA side better comprehend the specifications. This, in turn, enables questions about potential excesses or deficiencies in the specifications. Request an outline of scenario operations.  Although the specifications for each system are available and you can understand if you read documentation, receiving explanations directly from the development side who understands the system has the following advantages. (The QA side often makes its own materials to understand the specifications and gain a bird's-eye view.) Easier to understand the operation of the intended actor/user Easier to visualize data flow Timely questioning promotes a deeper understanding Check the segregation of documents  We will simply check to see which documents contain the correct specifications for this functional requirement and screen design, and whether other documents exist but are outdated notes, as it cannot be determined.  As the content of the area in which each development team is in charge is often up-to-date and correct, we aim to minimize the burden on the developer side by asking closed questions. "Is it correct that Document A accurately reflects the specifications for ●●? May I confirm that Document B also contained the same information, but slightly differently? " Review the Restrictions  If there are currently known restrictions in QA work, asking for sharing in advance will make it easier for the QA side to consider how to respond. Request a separate briefing for complex specifications such as calculation systems.  Since various prices and plans exist, there are multiple formulas for calculating them. Even with similar formulas, the values obtained may differ slightly. To prevent mistakes in advance, we are conscious of clarifying the following when asking for explanations from developers. The original meaning of the amount The meaning of values used in the formula and where they are referenced How to count the number of days Considerations to keep in mind when testing Existence of calculation tools  For calculation systems, the QA side often creates its own calculation tools for efficient testing. Specifications are compiled and finally reflected in the tools through discussions with developers.  In addition, although I mentioned the calculation system this time, if a specification proves challenging to understand, direct consultation with the developer is often sought. Conclusion  When I was struggling with the content of this writing request, a member of the development team who is also in charge of this blog said, "It would be helpful to know what kind of information the QA team wants when requesting QA."  Despite not directly aligning with this content, I wrote it with the hope that it will be useful for awareness of QA work other than testing by sharing information on the challenges in test design, which is the starting point of QA work.  In addition, the development team has already given consideration to the challenges mentioned above, and I feel that the work environment is quite organized compared to when the QA team was first formed.  Nevertheless, I believe that one of QA work is to organize information that cannot be seen from documents alone, so I will continue to exert effort not only to read the specifications but also to seek and organize the impact on other specifications.
アバター
はじめに オリジナルマスコットキャラクターができるまでのお話を執筆します。 第一弾は、キャラクター欲しいよねーという声を受けて形になるまでです。 クリエイティブ室の杉本です。私が所属するクリエイティブ室は、超簡単にいうとクルマのサブスクKINTOのお客様とコミュニケーションをとるアウトプットを、企画・制作する担当をしています。少し、小難しくいうと、事業側が持つコミュニケーションの課題を理解し(内製だからできる!)解決方法を可視化して、ビジネス側から発するすべてのコミュニケーションメッセージをぶれずに一貫性をもって伝える(=ブランディング)、そんなことを担当しています。 そんな私たちが、KINTOのマスコットキャラクターを開発したので、どのように作っていったかをお伝えさせていただきます。かっこいいキャラクター制作のHow toというわけではもちろんないです。産み出した我が子の母子手帳の記録のような、いや小学生のときの夏休みの宿題の絵日記のような、そんな感じで読んでいただければと思います。 いよいよ始まるキャラクター誕生ストーリー 2021年11月、公式マスコットキャラクター開発についてキックオフ。マーケティング企画部広報・ブランディングチームのメンバーと、我々クリエイティブからはCDの役目をもつ私と、AD1名が参加。「マスコットキャラクタープロジェクト(以下PJ)」を結成しました。プロジェクトというと大々的な感じですが、企業CMやポスターデビューといった企業ブランディングという大きな枠ではなく、若者や女性のクルマ離れの一つの解決施策で、小さく生んで大きく育てようという立ち位置で始めました。とはいうものの、メンバー全員、誰からも愛される我が子を産み育てたいという気持ちでいっぱいでした。 実は、公式キャラクターではないですが、もともとサービスサイト内で使用していたイラストがありました。社内での通称はクロコくん。このクロコくんをどう活かすかを検討する会が発端でした。彼らは、「クルマの保有を迷っている人、運転に不安がある人」をひっそり応援するという設定。クロコくんに愛着を持ちながらも、この機会にKINTOのキャラクターについてをゼロから考えて新たに誕生させてもいいのではないかという意見が多く、一気にキャラクター誕生プロジェクトになりました。 クロコくんのいい仕事っぷり! なにからはじめた? まず、キャラクター開発の目的の明確化。 【目的:「生活者にKINTOのファンになってもらう」】。 クルマを購入したことのない方やクルマにまだ興味のない方をターゲットに、クルマライフの楽しさを知ってもらいたい。教えるという設定よりも「一緒に移動することを楽しんでくれる」キャラクターが最適なのではないかということになりました。 いきなりイラストレーターさんに依頼するのではなく、インナーブランディングも兼ねて、社員も巻き込みキャラクター案を自由に出してみましょうということになりました。 サービスをつくるビジネス人材と、技術者から構成される社内の視点から多彩なものが出てくるだろうと想定し、マスコットキャラクターPJとしてはワクワクどきどき。 募集期間中に、キャラクターを選定する際の軸をつくるために、チームでキャラクターのアイデアを出し合いました。集めたアイデアから以下3つのステップで、キャラクターの方向性を決めていきました。 1. 【アーキタイプに沿っているか確認】 ここからは、アウトプットに結びつくステップがはじまるので、クリエイティブ室がリードしていきました。 また別の機会にお話しさせていただきますが、KINTOにはブランドパーソナリティなるものが存在します。ブランドを人間に例えるとどんな要素、性格で構成されているかを示したものです(アーキタイプ)。KINTOブランドを構成するパーソナリティ要素=KINTOさんは、自由な移動のスタイルの実現を探し続ける「Explorer」、親しみやすく共感力のある「Every person」、ユーモアのある「Jester」、専門知識を提供する「Sage」。一見、バラバラのようですが、「好奇心が強く、周りの人を楽しませ、自分の持っている知識で役に立ちたいと思っている人」がKINTOさんのパーソナリティです。もちろん、キャラクターはブランドを表す大きな存在になるので、設定に関してこのパーソナリティにも沿う形にしましょうということになりました。 2. 【キャラクターの性質・モチーフ】 出し合ったキャラクターのアイデアを「役割・属性」「モチーフ」と整理し、性質を出していきました。 こちらはアイデアの一部 3. 【課題を解決できそうなキャラクターアイデアの発散】 2.で整理した性質とモチーフを4つの方向性のカテゴリーに分けました。 A: ドライブの楽しさや自由を表し、ブランドストーリーを語る「KINTOのDNAそのものを表すキャラクター」 B: 親近感のある「ドライバーに寄り添う姿勢を表すキャラクター」 C: 「自由、前進の移動要素を象徴するキャラクター」 D: 「先進性、知性を体現したキャラクター」 社内から集まった愛すべきキャラクターたち 社内に募集告知ポスターを貼りました。 PJメンバーでキャラクターの軸を先行して議論する中、募集していた22年10月から11月の一ヶ月間で、有志から24ものキャラクター案が集まりました。絞り込みを行う際、「KINTOに合っていて好きなキャラクターはどれですか?」と全社にアンケートをとっています。ちなみに、マスコットキャラクターを制作する経過途中、KINTO/KTC社員の希望や意向もなるべく吸い上げたいというPJの想いもあり、進捗がある度に全社にアンケートをとりました。これは、今になって思うと、社員一人ひとりに、キャラクターへの愛着の種を蒔いていた時期だったなと実感しています。 話は戻して、初回アンケートの結果、KINTOの社名の由来でもある“雲”をモチーフにしたアイデアに人気が集まったので、方向性として、「雲のキャラクター」という軸が決まりました。 ここから、審査員(プロジェクトメンバー)の意見と回答者の回答を比較し、共通項や違いを見つけ、キャラクターにどのような要素をプラスしていくかをまとめていきました。 どんな容姿で、どんな性質をもつ子に育つのか、核となる部分になります。 さあ、今回はここまでにさせてもらいます。次回のブログでは、どのように形になっていったかをお伝えさせていただきます!
アバター
こんにちは。KINTOテクノロジーズ(トヨタグループ)でサイバーセキュリティエキスパートとして働いているサジュ・マタラダンです。 このブログでは、文化の微妙な違いからプロフェッショナルとしての成長の機会まで、私が日本のIT企業で働いた経験についてお話しします。 本記事は「ダイバーシティ」をテーマにしたシリーズ記事の1つで、このシリーズではKINTOテクノロジーズにおけるさまざまなワークスタイルや考え方を掘り下げています。 日本での経験 日本企業の技術革新については、その魅力的な立地と最先端かつハイエンドなテクノロジー環境から、常に注目をしてきました。 26年間のキャリアのうち日本で暮らしたのは15年で、その間別の国に滞在したり、グローバルプロジェクトに関わったりしました。ありがたいことに、日本を代表する企業のIT環境の管理や最新のテクノロジーへの変革に関われました。KINTOテクノロジーズに入社する前は、世界第3位の日系アパレル企業で6年間ITセキュリティ部門に勤務し、それ以前は、アジア最大の日系製薬企業をはじめ、国内外の大企業のITアウトソーシング案件に携わってきました。 文化的なつながり 私の経験から見て、日本のテクノロジーは変革期にあります。日本企業は以前よりもさらにグローバルな視野で事業展開を進めており、多様なグローバル人材を採用する動きが活発です。中でもテックカンパニーでは世界に通用するレベルとなるため、グローバルな働き方とプロセスが採用され、チームワークや連携、組織の共通目標への貢献が重視されています。KINTOテクノロジーズも決して遅れを取っておらず、100%トヨタ所有の企業として、「トヨタウェイ文化」の中でうまく機能し、社員が地域を越えて連携できるようなグローバルな環境を提供しています。世界をより良いものにするため、モビリティの未来を創造しています。 求められる言語能力 グローバル人材が日本で働くために、言語は常に障壁です。テックカンパニーでは英語が広く使われるようになってきていますが、基本的な日本語が理解できることは武器となりえます。KINTOテクノロジーズでは、日々の業務で英語を使うことは特に大きな課題はありません。異なる国から多様なチームメンバーが集まっているため、日本語に加えて英語も共通言語として使えるようになりました。 チャレンジ 私の経験から、日本の文化として「悪いことは起きない」という考え方があり、「信頼」が非常に重要なものとして位置づけられるため、一般的にサイバーセキュリティに対する意識が低いと感じています。しかし、不正アクセスやデータハッキング、マネーロンダリングなどがインターネット上で蔓延している昨今、脅威に国境はありません。この点で、日本企業はあまりにも脆弱に見えます。サイバーセキュリティの専門家として、企業の重要なアプリケーション、インフラ、データ、およびサービスへのインターネットからの安全なアクセスを確実に保護するセキュリティコントロールとフレームワークを構築することは、大きな挑戦です。「Mobility as a Service(MaaS)」の新しい技術要件や関連するeコマース取引、顧客と社員によるオンラインサービスの利用が増えてくると、特にこれを実感します。 下図のようなセキュリティフレームワークを構築し、エンドツーエンドでデータとそのアクセスの安全に保護するためには、複雑であらゆる方面を考慮したアプローチが求められます。そのような難しい目標であっても、KINTOテクノロジーズではテックに精通した社員やサポートしてくれる経営陣がいるので、比較的スムーズに対応できています。それに加え、MaaSのIT環境にさまざまなレベルで携われることをとても嬉しく思っています。 テクノロジー環境 私自身の経験では、日本のIT企業では少し古くて時代遅れの技術を使い、アップグレードが遅れている印象がありました。一方で、KINTOテクノロジーズでは最新のクラウド技術やツールがすべて導入されています。KINTOテクノロジーズでは、AIからその他最先端のソフトウェア開発まで、幅広い分野で社員が持つ興味や情熱をキャリアと繋げるためのさまざまな機会を提供しています。また、懇親会などのネットワーキングイベントや、業界カンファレンスへの参加を通じて、同じ界隈の知見者と繋がり、最新のトレンドを把握する機会も多くあります。 職能開発 管理職であれ技術職であれ、日本のテックカンパニーではプロフェッショナルとしての成長の機会が十分に与えられています。ありがたいことに、私の経験上これまでの企業でもそのような素晴らしい機会を得られてきました。KINTOテクノロジーズでは、グローバルな業界水準と同じレベルにあります。マネジメント層は、社員がカンファレンスに出席してトップクラスの知見者と交流したり、学習曲線を最大化してスキルを向上させ、キャリアを積むことを奨励しています。 ワークライフバランス これまでの会社でも、現在のKINTOテクノロジーズでも、健全なワークライフバランスを維持することの大切さと、それが日本の倫理観の基礎であることについて、人事から説明がありました。近年ではさまざまな企業が社員の健康を重視するようになり、フレックスタイム制やリモートワーク、ウェルネスプログラムなどを提供するようになっています。仕事とプライベートのバランスを取ることは、奨励されるだけでなく、豊かで有能なチームメンバーの証とされます。 さいごに KINTOテクノロジーズをはじめとする日本のテックカンパニーで働くことは、プロフェッショナルとしての成長と技術革新に満ちたエキサイティングな旅になると思います。日本が製造業とハイエンドテクノロジーの世界的なテック大国である限り、日本のテックカンパニーで働くということは、日本文化の美しさと結びついたテクノロジーの未来へのチャンスに溢れたキャリアの転機となりえるでしょう。気になる方はぜひチャレンジしてみてください!
アバター
Hello I am HOKA from the Human Resources Group at KINTO Technologies. I am responsible for organizational human resources and recruitment PR. I also manage our X (formerly Twitter) account . As part of the annual Advent Calendar event, my focus on this Tech Blog article will be about how the Human Resources Group started. I hope you will stay with me until the end. The Establishment of KINTO Technologies, a Development Organization KINTO Technologies Corporation (hereinafter, "KINTO Technologies") was founded in April 2021 and is now in its third year. There are more than 320 employees as of December 2023. The company is growing rapidly. KINTO Technologies was originally the IT Development Group of KINTO Corporation (hereinafter, "KINTO") and mainly consisted of IT engineers. Before KINTO Technologies was founded, KINTO was in charge of recruiting IT engineers, but it was a seller's market where every company had a shortage of IT engineers. It was hypothesized that in order to recruit the best IT engineers, you had to change hiring methods to fit the IT industry. So, Iwamoto, who had experience in hiring engineers in the IT industry, started hiring IT engineers for KINTO Technologies. She was the first member of our team. Our Mission Was To Just Hire Engineers At first, Iwamoto's mission was to just hire engineers. When Iwamoto joined in November 2021, KINTO Technologies had about 130 employees. There was no talk of setting up a human resources department, and Iwamoto was the only person in charge of hiring. Iwamoto started with the secretary, Shida. IT Engineers Cannot Be Hired as Automotive Professionals First, Iwamoto set out to change the hiring style to match the IT industry. ● Replacing PDF job applications with an applicant tracking system (ATS) Due to the job application form being in PDF format, candidates were required to enlist with a recruitment agency in order to complete the application process. We renovated our corporate website and implemented an applicant tracking system (ATS) so that interested candidates could submit their applications easily. ● Engaging in dialog instead of scrutinizing during interviews Having job interviews with 6 interviewers per candidate was oppressive and unpopular. We trained interviewers and changed the interview style so they engaged in dialog and casually asked about the applicant's career. ● Switching to a flexible selection process that involves getting close to the candidate We listened to candidates' requests, did casual interviews with engineers in the workplace and offline interviews, and aimed to schedule interviews to accommodate the candidates. We switched to a more flexible selection process. ● Contacting successful job applicants five business days sooner After the final interview, a paper offer letter with the interviewer's comments was mailed to Nagoya, and it took five business days for the employment conditions to be approved. We reviewed the process and implemented an electronic approval system. Thanks to that, approval was done the day after the final interview. ● Holding company briefing sessions for recruitment agencies To better explain our prospects and position, we held an online briefing session that was about three hours long and had explanations by Mr. Kageyama, the Executive Vice President of KINTO Technologies, with other several managers. About 15 recruitment agencies participated in this event, and they are still supporting the recruitment of KINTO Technologies. Finally, Sheer Effort! Iwamoto held interviews from 9:00 to 21:00 while implementing the aforementioned Kaizen (improvement). Takeno, a talented recruitment assistant, joined the company in January 2022 and sped up the hiring process further. (She goes home around 18:30 these days, so don't worry lol) Establishing the Human Resources Group After Iwamoto joined, we hired 140 people in one year (from January 1, 2022, to December 31, 2022). On the other hand, as our organization expanded, organizational issues came to the surface. Then, Tsun-Tsun, our labor expert, joined the company in April 2022. We gradually started doing HR work other than hiring, such as consultations for new employees and retirees. We now play a role in delivering the voices of our employees to management. Tsun-Tsun also started making Kaizen projects in the office (link to his article). Then, Mr. Kageyama finally told us to make official our Human Resources organization. In August 2022, the President Said, “I Calmly Stand at a Staircase Landing” In July 2022, KINTO Technologies will hold its first "all-employee interviews." Of course, this will be the first time for the employees, so the company received many requests and concerns, and the Human Resources Group was wondering how to solve them. Looking at the situation, Kotera, the president and CEO of KINTO and KINTO Technologies, gave us this advice: "Stand calmly at a staircase landing. Build management functions appropriate for the size of the organization, then hire the required people." That was in August 2022. Since then, we hired less frequently but focused on training our management and improving our organizational capabilities. Managers gradually started cooperating more with each other. Reviewing the Hiring Requirements in October 2022 Since then, KINTO Technologies developed services other than for the KINTO brand and did more as a company as engineers had bigger roles. We thoroughly reviewed the hiring requirements and targeted people with experience in developing their own services to better fit our organization. Around that time, we were joined by Muranaka, who had experience in HRBP at a mega venture. By building the aforementioned management functions, hiring less frequently, and reviewing the hiring requirements, the Human Resources Group's leadership strengthened its organizational capabilities, but Muranaka was overwhelmed by how quickly KINTO Technologies grew. He smiled bitterly, saying, "I have no memory of anything from the moment I joined in October 2022 to March 2023." The Human Resources Group Enters Its Second Phase KINTO Technologies has 320 employees as of December 2023. As the organization has grown, we have added more layers in departments and increased the number of roles. We think about the kind of people we want to have in the company as the Human Resources Group started to receive more requests, and we conduct more personal interviews with managers and employees. We also train more employees to become interviewers and constantly get more employees to be involved in the recruitment process. The hiring activities that Iwamoto started alone is by now a series of activities conducted cross-functionally. There are currently ten people in the Human Resources Group, and it is divided into the Recruitment Team, the Labor Affairs and General Affairs team, and Organizational Human Resources team. The Human Resources Group intends to keep working together in 2024 so that we can keep growing and everyone can challenge themselves even further. Well... many of you may look back on your life, review your life plans, or consider changing jobs at the end of the year. KINTO Technologies is looking for new colleagues in various positions, so please feel free to apply if there is a job that you are interested in. We are also happy to conduct interviews. You can check job openings at KINTO Technologies here. That concludes my article "Let's Make a Human Resources Group." Since this is part of our Advent Calendar, let me finish by saying... Merry Christmas to you!
アバター
はじめに こんにちは、KINTO FACTORY のフロントエンド開発を担当しているきーゆのです。 今回は Visual Studio Code(以下 VS Code)で React プロジェクトをデバッグするための環境を構築した件について、まとめてみたいと思います。 これまで VS Code は優秀なメモ帳程度にしか使って来なかったので、結構苦戦しました(主に言語の壁)。 今まさに VS Code にデバッグの環境を構築しようとしている皆さん。 どうぞ私の屍を超えていってください。幸あれ。 環境情報 OS : macOS Sonoma 14.1.2 VS Code : ver1.85.1 Node.js : 18.15.0 terminal : zsh 構築手順 1. launch.json のセットアップ launch.json を追加して、デバッグ用の起動構成を構築していきます。 VS Code 左サイドメニューにある「実行とデバッグ」メニューを選択します。 選択後に表示される「launch.json ファイルを作成します」をクリックすると、 launch.json ファイルがプロジェクト内に作成されます。 :::message 初回作成時にデバッガーを選択することになりますが、今回は React なので Node.js を選択します。 ::: launch.json を作成します 作成直後の launch.json には、デフォルトの起動構成が追加されています。 自動生成直後はデフォルトの起動構成が追加されています 2. 新しい起動構成の追加 先ほど追加した launch.json に、デバッグ用の起動構成を追加します。 追加する起動構成は以下になります。 { "name": "[localhost]Chromeデバッグ", "type": "node-terminal", "request": "launch", "command": "npm run dev", "serverReadyAction": { "pattern": "started server on .+, url: (https?://.+)", "uriFormat": "%s", "action": "debugWithChrome" }, "sourceMaps":true, "trace": true, "sourceMapPathOverrides": { "webpack:///./*": "${webRoot}/src/*" } } 編集後の launch.json は以下画像のようになります。 私はデフォルトの起動構成を削除しましたが、残しておいても特に問題はありません。 また、起動時のコマンドを変えたい場合は command プロパティを編集したり、デバッグ時に複数のコマンドを実行したい場合は preLaunchTask プロパティでタスクを追加したりすることも可能です(この辺の話は今回は割愛します)。 name プロパティの値が起動構成の名前になります 3. デバッグ実行開始 あとは F5 キーを押すだけで、デバッガーが起動してくれます。 起動に成功すると中央上部にデバッグ用のボタンが表示されます 中央上部に表示されたデバッガーボタンや F キーを使って、ステップイン/ステップオーバー等を実行することができます。 困った時は 以下は私が実際に遭遇した"困った!"たちです。 運悪く遭遇してしまった方の一助になれば幸いです。 ◽ デバッグ時のターミナルが"sh-3.2$"で実行され、"npm command not found"になる VS Code を再起動することで解決します。 どうやら Microsoft によって自動的に VS Code が起動した場合に発生するようです。 私の環境の場合、PC 起動時 Microsoft365 にログインするのですが、ログイン成功時に VS Code も自動で起動するところでこの問題に遭遇しました。 ◽️ npm インストール済みにも関わらずデバッグを開始すると"npm command not found"になる .vscode/settings.json ファイルに以下を追記してください。 ファイル自体を作成していない場合は、作成しておきましょう。 { // npm scripts コマンドを実行するためのpath設定 "terminal.integrated.profiles.osx": { "zsh": { "path": "/bin/zsh", "args": ["-l", "-i"] } } } :::message ターミナルの実行環境が bash の場合は、プロパティ名と path を zsh → bash に変更してください ::: これによりデバッガーの実行ターミナルに path が通るようになり、npm コマンドを実行できるようになります。 まとめ 今回は VS Code で React プロジェクトをデバッグするための環境構築についてまとめてみました。 まだまだ VS Code で 遊べる 効率化できると思うので、次回は tasks.json でさらに効率化していければと思います。 これは私見ですが、開発時にデバッグできると QOL が爆上がりして開発生産性が向上します。 これによる副次的効果として、オフィス内での笑顔率向上や通勤時幸福度の向上が見込める...かもしれません。 皆さんのデバッグライフに幸あれ。 読んでいただき、ありがとうございました! 最後に、私の所属する KINTO FACTORY では一緒に働く仲間を募集しています。 ご興味があればぜひ下記の求人をチェックしてみてください! @ card @ card
アバター
自己紹介 はじめまして!モバイルアプリ開発Gにて my routeアプリ のAndroid側の開発を担当しておりますRomieです。 前職からAndroidの開発を始めて2年経ちましたが、個人開発も含めてレイアウトは全てxml形式で実装してきたためComposeにきちんと触れたのはお恥ずかしながら2023年12月にKINTOテクノロジーズ株式会社(以下KTC)に入社してからになります。 TechBlogに記事を書くのも初めてになります! こんな人に読んでほしい 本記事は以下が対象です。 Androidの開発超初心者の方 さまざまな事情でxml形式でしかレイアウトを書いたことがなくComposeを全くご存知ない方 実機で動作確認する際なかなか修正した箇所を表示できず困っている方 Previewとの出会い 入社して一番最初Composeのコの字も知らないということで、以下の画面をxml形式からComposeで実装し直す作業を行いました。 ![About my route画面](/assets/blog/authors/romie/2024-02-08-compose-preview-beginner/03.png =200x) About my route画面 早速コードリーディングを始めると、Previewを冠した謎の関数が。 @Preview @Composable private fun PreviewAccountCenter() { SampleAppTheme { AccountCenter() } } その関数はアカウントセンターのボタンのPreviewを表示するためのものでした。 ですがprivate関数にもかかわらず同じktファイル内のどの箇所でも呼び出されていなかったため「この関数は使用されていないのだろう」と考えPreview周辺のコードは触らずに実装を進めることにしました。 そして無事Compose化の作業を終え、pull requestを出したところcommentが来ました。 「Previewがないので作ってください!」 「呼び出されない関数を作って何の意味があるんだろう」と思いつつ他を真似して画面全体のPreviewを実装し、buildして実機が問題なく動いていることを確認しましたが、この時は実機ばかり見ていました。 Previewは何のためのものなのだとまだボンヤリしつつ何気なくAndroid StudioのSplit画面を見ると、そこには実機で表示されているのと全く同じ画面がAndroid Studioに表示されているではありませんか。 「Previewってそういうことか、関数を呼び出さなくてもSplit画面で表示するためのものなのか!」 公式ドキュメント ^1 にもきちんと書いてありました。 アプリをデバイスやエミュレータにデプロイする必要はありません。幅と高さの制限、フォントのスケーリング、テーマがそれぞれ異なる、特定のコンポーズ可能な関数を複数プレビューできます。アプリの開発を行うとプレビューが更新され、変更内容をすばやく確認できます。 Previewと動作確認 ある日、my routeアプリのルート詳細画面に駅出口からの進行方向セクション8方向の画像と文言を追加する作業を行いました。 実装自体はすぐにできましたが、問題は動作確認でした。8方向分の画像と文言が正しく追加できているかどうか確認するのに実際に動作させていると非常に時間がかかります。 再現手順は以下の通りです。 ![進行方向セクション表示の再現手順](/assets/blog/authors/romie/2024-02-08-compose-preview-beginner/01.gif =150x) 進行方向セクション表示の再現手順 では、効率的に8方向分全て確認するにはどうすればよいでしょうか。 更にUI表示が崩れていたり違った画像が表示されていたりして修正し最初から確認しようとすると、余計時間がかかります。 ここで活躍するのがPreviewです。 以下の通り実装します。 @Preview @Composable fun PreviewWalkRoute() { SampleAppTheme { Surface { WalkRoute( routeDetail = RouteDetail(), point = Point( pointNo = "0", distance = "200", direction = Point.Direction.FORWARD, ), ) } } } Buildを通しAndroid StudioでSplit画面を確認すると、ご覧の通り。 進行方向セクションのプレビュー画面 確認したい方向を入れるだけで正しい画像と文言が入っているか確認できるのです。 そして実際に表示が崩れているかは1パターンのみ確認できればOK!これで大幅に動作確認の時間を短縮できます。 まとめ これからもPreviewだけでなくComposeの諸々を体感することがもっと増えると思います。 とりあえず軽く触っただけでもこのような感動があったので共有しました! Compose超初心者の感動体験、これからもお付き合いのほどよろしくお願いいたします。
アバター
Introduction Nice to meet you! I am yama from the Quality Assurance Group. I joined KINTO Technologies in May 2023. I mainly do QA work for KINTO Unlimited . About Today's Theme Today, I will talk about the quality improvement initiative that I have been working on since I joined the company. The Quality Assurance Group and Its Future Prospects The figure above shows the future prospects of the Quality Assurance Group as given by our manager zume during a company announcement. It shows that QA was formed three years ago and the team is now stable, so what will we do next? I joined the company around that time. At the system development company where I previously worked, I worked in QA with the goal of contributing to quality improvement by providing high-quality tests, but as I gained experience, I encountered the difficulty of ensuring quality through testing. There is a limit to what you can do by just fixing bugs. You have to make sure that there are no bugs in the first place. I wanted to work somewhere I could do this, so I joined KINTO Technologies. Understanding the Current Situation After I joined the company, I first tried to understand the in-house development and QA processes and the current state of the project I was in charge of ( KINTO Unlimited ). I found out that waiting time in development was costly (My previous job also demanded speed, but not as much as KINTO Technologies). That was because KINTO and KINTO Technologies are businesses that create new services, and delays lead to lost business opportunities. It made sense. Therefore, when taking measures to improve quality, I felt that it was necessary to do something that did not slow down development. Also, I knew from my previous job that the manager could not handle everything for long, so I decided to do things as simply as possible. However, I realized that the current project lacked an objective indicator of current quality. If you can't see the quality of the products you’re making, you can't see what you need to improve so you don't make bugs, so we first made a system that would visually indicate quality. What We Did However, even though we went, "Let's do ___ to improve our quality!" it was hard to casually accept that. So, we first conducted a quality analysis in a slightly more in-depth manner through the development project, and fed the analysis results back to the project. At that time, the bug report did not have enough quality analysis items, so the QA team investigated the resolution history of each bug report, categorized them, and did a quality analysis. Analysis Materials (Excerpt) At the end of the project, we presented analysis results at a review session and said, "We can see the quality and current issues if we have these classification items in the bug report!" By narrowing down the classification items and simplifying the input methods, we also minimized the burden on the person in charge. Newly Added Classification Items Thankfully, this proposal was accepted, and we started using the bug report with the above quality classification items added. What I Want To Do in the Future Now that we have a starting point for quality improvement, we would like to give feedback regularly to the project of the information we get and consider quality issues that need to be solved together with development and QA. We also plan to continue these efforts to make the progress in quality (improvements) visible. We also aim to expand this trend horizontally to other projects and hope it will be widespread. We will continue with the belief that it will lead to the Quality Assurance Group's future prospects and overall quality improvement, which I mentioned at the beginning.
アバター
Introduction I am oshima from the Quality Assurance Group. I am an old man born in Kansai and a Hanshin Tigers fan. I feel like 38 years ago was not so long ago. Although I do not have any special skills or qualifications, I have been working in QA for more than 20 years. I am currently in charge of QA for page designs and functionality improvements of services that have been released such as KINTO ONE, KINTO ONE (Used Vehicles), KINTO FACTORY, and Mobility Market, as well as QA for static content, such as introductory pages for new vehicle models. Today, I will talk about the difference between the concepts of verification and validation, which are relatively old-fashioned in the QA area, explain the projects I am currently in charge of, and describe the focus points and issues (directions I want to go in) I think about personally. I bring up verification and validation because I was asked in a job interview to explain the difference between the two. I had not thought about the terms or the difference between them before. That happened almost ten years ago, but it left a deep impression on me. I believe we should remember these concepts in today's QA work, which is why I am bringing them up. A Brief Explanation of the Difference Between Verification and Validation So, what is the difference between verification and validation? If you look them up on Google Translate, they come up with the same result. They may seem the same, but strictly speaking, they check different things. Verification ・ Making sure the notations and actions match specifications ・ checking that they are executed correctly Validation ・ Making sure the notations and actions align with product requirements ・ checking that their correctness For example, suppose you are testing an event announcement page (leaving aside if its appropriate or not), and you find the description, "The application deadline is November 31". Checking the specifications, the documentation also states, "The application deadline is November 31". From a verification perspective, it is correct because the page being tested matches the specifications. However, from a validation point of view, there are only 30 days in November, and it is not possible to have 31st as the deadline, so it is not indicating an existing deadline. Therefore, it will fail the test. You should not miss a date that does not exist, but it is hard for QA to decide whether there is a spelling mistake or incorrect expression if it involves a legal term in a contract or a new conceptual term for a new service, so you have to be careful. Characteristics of an Actual Case As I said earlier, at KINTO Technologies I am mainly responsible for improving our existing services and doing final reviews of static content such as those presenting events or introducing new models. In this article, I will focus on the static content which is relatively frequent and large in volume. QA for static content-related projects is slightly different from general program testing, but I am working hard on it since KINTO customers see the results firsthand. The main job in testing is to check whether the layout is broken and whether the descriptions and numbers on the page are different from the price list given by the sales department or the vehicle images given by the design department. In terms of the way I described verification and validation, checking static content is mainly verification and has a few aspects of validation. Contributions and Challenges of Verification Checking static content is not hard if you check the design and writing specifications (it requires attentiveness). The downside is that if you cannot check the essential specifications, you cannot proceed to the verification stage. The problem is that it has to be passive, and you have to make gradual confirmations such as "The XX area can be checked, YY will be updated later." You have to be flexible and monitor the progress each step. I think verification helps improve what is being tested by pointing out things that are ambiguous and not determined by the specifications before the test stage, although that may sound like a paradox. In terms of test automation, if you simply check specifications and the expected values based on them, testing becomes a simple comparison between specifications and implemented results. For that reason, differences can be inspected automatically as it can be done more accurately than inspecting by sight, and it reduces workload. However, you cannot make comparisons if the specifications or expected values have not been determined, and if you cannot detect whether a change in specifications is reflected in the implemented results, there is no point in automating the test. You have to define what is correct before testing. Just like Akinobu Okada, a former Hanshin Tigers coach, I think this is an important part of a project's success. What You Can Do With the Contributions From Validation QA cannot say anything about static content because designs and other elements are up to each of the subject matter experts in their fields. However, an engineer with knowledge on topics such as UX and design elements may be able to point out things from upstream. You can do that without thinking too hard if you look at the explanations for the new service, become familiar with the explanations, and see whether it is easy for the customer to understand and the figures correctly reflect the content of the service. I think this is related to validation because you are not making a comparison with the specifications, but seeing whether the service being provided is accurately communicated to the customer. Here is a more common example of the difference between verification and validation. I once checked an information page for a vehicle type has a link to a related article. The URL matches the specifications, but the vehicle type was different from the one in the article. This is okay in terms of verification, but wrong in terms of validation. Whether it is really correct is questionable, but in terms of whether not there is a mistake, you have to keep the quality of the service you provide the customer high. Conclusion Although I talked big, I am aware that it is hard to reflect that in reality, and it’s closer to ideals than what we encounter. However, by doing the usual work again and again, you can gradually make that dream a reality. We are looking for skilled partners to conduct QA with us, especially superstars who can easily accomplish things we have not been able to do yet. People who are neither super nor a star but are willing to do their best with us are also welcome. See the recruitment page below for more information. Thank you for reading until the end.
アバター
Introduction Hello, I am Nishida, a backend engineer at KINTO FACTORY. It has been six months since the launch of KINTO FACTORY, and I would like to talk about the problems we encountered since we started operating the service, mainly involving its release and system monitoring, and what we have learned. About KINTO FACTORY I will give a brief overview of KINTO FACTORY's service. The service allows you to update functions and items such as hardware and software that are appropriate for your vehicle. With KINTO FACTORY, you add items that you could only pick before when ordering a new vehicle, such as manufacturer options, or vehicle updates that normally require you to go to a dealer. This update service extends to, not only the KINTO lineup but to Toyota, Lexus, and GR vehicles if they are compatible. Almost half a year has passed since it launched this summer. @ card Operations There is a release every two weeks, and we build CI/CD and deploy mainly with GitHub Actions. The service is monitored mainly by the development team members, who take turns to do so, as there is no established operation team or organization. We use PagerDuty's scheduling function for the rotation. Incident detection is set up as shown in the illustration. Application logs and service monitoring information are linked to OpenSearch to determine user impact and send notifications to PagerDuty. (The image shows the result of the transmission) After that, a notification is sent to Slack, and the person on duty to monitor responds. The person in charge responds. We try to get an expert involved when necessary. In addition, the details of the response are shared at the daily scrum the next day so that the team knows. Challenges and Responses I will talk about the problems we encountered since we started operations and how we dealt with them. Preparing for the release had a large burden It took us time as we had no templates, so we had to start preparing for the release from scratch. Additionally, the task granularity was uneven and the release procedure was managed based on Confluence, so checking and modifying said procedure was complicated. ⇒ Transferring the release procedure manual to code management let us do version control, create templates, confirm differences, and reduce the burden of preparing for the release. Incidents were detected frequently The number of incidents within a few days after launch was as follows: Because the error handling design on the application side was lenient, errors were detected and treated as critical even if they did not affect the user. After we started operations, there were incidents every day, and monitoring was a heavy burden. ⇒ Because there were too many incidents to handle all at once, we optimized by using exclusion settings so that each output was reviewed if it was not urgent, and if it could not be corrected immediately, it would not be notified. Slow initial response time when responding to incidents Because the response procedure and other procedures were not organized, members interpreted things differently, and there were times when they took time. There were also members who were not used to PagerDuty and forgot to confirm status updates. .. ⇒ We improved the environment so that members could define workflows in Slack, start responding to incidents by entering a command, and handle incidents according to procedures. We also made an incident VS team structure in which every team member gathered and handled incidents as a mob while comparing each other's interpretations. By doing so, we reduced the time from when an alert is made to when someone responds down to less than one tenth of the time before. Summary We were busy dealing with a variety of problems right after the launch, but it has improved continuously little by little. Looking back, members responded differently based on their experience and knowledge, and I feel that we had a smooth start because we planned in advance what kind of operations to do. We still have room for improvement, but we will continue operations so that we can provide better services for our users! Conclusion In this article, I talked about the problems we encountered while operating the service and how we dealt with them. We hope that our experience could be of some help to you. Also, KINTO FACTORY is looking for new members, so if you are interested, please check out the following job openings! @ card @ card
アバター
Introduction Hello. Thank you for reading this! I am Nakamoto, and I work in frontend development for the KINTO FACTORY service (hereinafter FACTORY). Since I decided to participate on the Advent Calendar series, I will talk about how we implemented vehicle inspection QR code reading, which we released this year. Motivations for Adoption At FACTORY, we are currently developing a service that allows customers to ride their cars for a long time from the perspectives of "Upgrade," "Renovation," and "Personalization." FACTORY's frontend functions like an e-commerce site, allowing customers to search for products that can be installed based on their vehicle information and make applications on the Internet. Information on the vehicle they are currently driving, such as the model, model year, and grade, is important. Based on that kind of information, the service determines which products can be installed and whether or not they can be combined. In order to accurately determine such combinations and possibilities, FACTORY uses something called a chassis number. Some of you may know this, but when you look at a vehicle inspection form, you can find a serial number that is a chassis number. (The third field from the top left in the figure below) *Source: Ministry of Land, Infrastructure, Transport and Tourism "Vehicle Inspection Certificate (Vehicle Inspection Certificate Sample)" ( https://wwwtb.mlit.go.jp/hokkaido/content/000176963.pdf ) With FACTORY, you can easily search for products that can be attached to your vehicle by entering its chassis number. Product listing page (Products have been searched by chassis number) Right after the release of FACTORY, the user had to enter the chassis number manually using the form in the figure below. Chassis number entry form We released the ability to search by entering a chassis number this June, but at first, I thought it would be difficult to enter unfamiliar alphanumeric characters directly into the input field. Most people access FACTORY on their smartphones, as is the case with many eCommerce websites nowadays. Typing a long string of alphanumeric characters using a smartphone can be troublesome on a small screen, and can lead to input mistakes. When this happens, it will show a message saying that the vehicle is not compatible with FACTORY, making the user unable to find the products they are looking for. I believed this could be a potential factor contributing to missed opportunities. Then I noticed the QR code in the bottom right of the vehicle inspection. Information That Can Be Read Using a Vehicle Inspection QR Code As indicated by the Ministry of Land, Infrastructure, Transport and Tourism's electronic vehicle inspection website , the chassis number used in the above search can be read using a vehicle inspection QR code. In addition, if you find a product you want to attach on FACTORY and want to buy it, you must first register your vehicle information. A chassis number and license plate information are needed to register. The vehicle inspection QR code basically contains the information written in the car inspection. We thought that by reading these, it would be easy to search for products and register a vehicle when buying. As you can see in the figure below, there are QR codes in groups or two or three, and it is necessary to have them read correctly in either case without failure. Each QR code has a separate piece of information, and they must be combined in correct order after all of the codes are read. We wanted it to give feedback on the screen so the user can see which code in each group is being read. *Source: Ministry of Land, Infrastructure, Transport and Tourism "About QR Codes" ( https://www.denshishakensho-portal.mlit.go.jp/assets/files/Two-dimensional_code_item_definition.pdf ) Implementing the Reading UI After the codes are read with a smartphone camera, they go through image processing and are analyzed and decoded with a JavaScript library. It was our first time using a camera to read and decode QR codes, so we tested it while gathering information on the Internet. We chose to use the getUserMedia() web API to read with the camera, and the js library qr-scanner to analyze QR codes. The code read by getUserMedia is copied to a canvas element, and transferred to qr-scanner , which analyzes the code and determines which code from the data was read. When testing the implementation, reading was a little difficult, and the QR code reading rate was slightly low for new vehicle inspections. We switched to electronic vehicle inspections in January. People who bought a vehicle or did a vehicle inspection already know this, but the form is considerably smaller (size B5) than the previous one (size A4). Because of this, the QR codes became a little denser and difficult to read. By looking at the qr-scanner source and adjusting the Grayscale settings, the new and old car inspection types can both be read with some accuracy. After the image data is copied to the canvas, it is converted to a black-and-white image using the above Grayscale settings and sent to the QR code analysis library. Depending on the values, the car inspection pattern was reflected as garbage, and that seemed to lead to a lower reading rate. https://github.com/nimiq/qr-scanner/blob/master/src/worker.ts#L73-L79 When implementing the UI, we wanted to show the positions of the readable QR codes by group while looking at the images captured by the camera in real time, so we arranged the necessary number of boxes at the top and displayed a check icon on the border of readable QR codes. The reading screen looked like the figure below. You can see that the positions of the codes are recognized correctly regardless of the order in which they are read. After all of the information is read, the screen transitions the same way as when you search for a chassis number manually. After Release We released the QR code search function in October. For a while after the release, it was used only for the product list page as shown in the example above, so it is hard to say that this function was used a lot, but it is now used for the home screen. By reading the QR code on the home screen, it is possible to check for compatible vehicles and product compatibility both at once, and we think it will be used more. As I mentioned in the "readable information" part, the QR codes also contain information needed for vehicle registration, so we will use this information for vehicle registration in the future and aim to make it more convenient and reduce input errors by reducing manual inputs as much as possible. Conclusion The rise of smartphones, enrichment of web content, and expansion of various web APIs have expanded the possibilities of websites. We will actively try new technologies with user convenience in mind, such as real-time OCR, NFC tags, and other contactless technologies. We will explore various ideas to make KINTO FACTORY easier and more fun to use! Lastly, KINTO FACTORY is looking for people to work with. If you are interested, check out the job openings below! @ card @ card
アバター
​ Introduction Hello! I am Aoshima from KINTO Technologies' Project Promotion Group. New variable functions have been added to Figma. Even though they are very convenient, I don't think there are many tutorials on them written in Japanese, so although it may be presumptuous, I am writing this article with the hope that it will be useful even for beginners. ​ Let's Make a Shopping Cart Mock-Up Using the Functions of Figma Variables! ![](/assets/blog/authors/aoshima/figma/image.webp =400x) Completed Shopping Cart I will explain in two parts how to create an interactive shopping cart function using Figma variables I want to start by explaining the variables in Part 1, and explain the count-up function that allows you to increase or decrease the number of products, and the ability to calculate the subtotal according to the number of products. In part 2, I will write about using functions when there are two products in the cart so you can calculate the subtotal, change free shipping settings, change total amount settings, and change settings so the wording is different when the shipping is free. ​ [Part 1] What Are Variables Part Creation First Is the Count-Up Function How To Create and Assign Variables Creating a Count-Up Function Subtotal Settings [Part 2] We Try Increasing the Number of Products to Two Subtotal Settings Free Shipping Settings Total Settings Changing the Wording for Free Shipping End [Part 1] ​ What Are Variables Variables are a new feature added to Figma in June 2023. Variables can be assigned to objects. Variables are called "hensuu" in Japanese. Variables are often described as a box that temporarily holds various information and values. Figma provides four types of variables (number, color, text, and boolean values), and these four types of information and values can be assigned to variables. However, since it seems that it is not possible to cross types, it seems that it is not possible to change a number variable to a text one partway through. Part Creation I will now start creating. I want to create these two functions. Count-up function: The number of products increases when the plus button is pressed, and decreases when the minus button is pressed Subtotal settings: The total amount changes according to the number of products First, I will teach you how to create parts and create and assign variables in order to make these functions. Create Base Parts To create the count-up function, I have created a design that resembles a coffee shop as the base of the shopping cart, and made it so that there are coffee beans in the cart. ![](/assets/blog/authors/aoshima/figma/base.png =400x) There is 1 base part product in the cart ​ Creating Button Parts Next, we want to include an action that changes the color of the button when the mouse hovers over it, so we will make a button component and create a variant. In the sample, its default state is light gray, and the mouseover state is dark gray. ![](/assets/blog/authors/aoshima/figma/button.png =400x) Create button variant ​ How to Create and Assign Variables Now that we have the necessary parts, I will explain how to create and assign variables. Variables are primarily assigned to objects that you want to change (by clicking or doing other actions). For example, you want to change the number of products when you press the plus or minus button, so you assign a variable to the number of items. ![](/assets/blog/authors/aoshima/figma/variable.png =400x) * Assign a variable to the number of items in the red rectangle* To create a variable, click Local Variables in the right column to open the window, then click the Create Variable button in the bottom left of the window. ​ ![](/assets/blog/authors/aoshima/figma/local_variable.png =400x) ![](/assets/blog/authors/aoshima/figma/all_variable.png =400x) Since we want to assign to a number, choose "number" as the type and named it "Kosu1." Since we assume that there is already one product in the cart, put 1 in the Mode 1 field. We have now created a variable. Next, we will assign this variable to an object. Select the number 1 on the design, and click the octagonal icon (above the three-dot leader) in the text information field in the right column. Select Kosu1 from the list of variables. We have now assigned a variable. ​ ![](/assets/blog/authors/aoshima/figma/kosu1.png =400x) A list of variables that can be assigned appears We assign the variable Kosu1 to the "1" between the plus and minus buttons and give it the value 1. If you change this value to 2, the number on the object will also change to 2. ​ Creating a Count-Up Function Now that we have a set of parts and variables, I will create a function that increases the number of products when the plus button is pressed. To do this, you need to assign an action to the plus button. Selecting the plus button and click "Prototype" at the top of the right column to change the mode. Then click the + sign to the right of "Interaction" and enable assigning mouse actions. ![](/assets/blog/authors/aoshima/figma/count_up1.png =400x) *Select a variable and enter a formula. * As for the type of action, I want to increase the number when I click the plus button, so I can keep the default settings for "click." Then select "Set Variable" and do the following. Select the variable you want to change when the object is clicked Enter the formula for what happens when the object is clicked When you are done, it should look like the figure. ![](/assets/blog/authors/aoshima/figma/kosu.png =400x) *Select the variable and fill in the formula. * This formula makes it so that when the plus button is clicked, Kosu1 becomes Kosu1+1. If the plus button is clicked while Kosu1 is 1, it will become 2. If you see a preview, you can see that each time you click the plus button, the number increases by one. Similarly, we will assign an action to the minus button, but we must be careful of one thing. Unlike the plus button, if you do not set any restrictions (conditions), the number will be negative. In this case, you need to set a conditional action (if statement) as shown in the figure below. ![](/assets/blog/authors/aoshima/figma/count_up3.png =400x) This formula makes it so that if ** Kosu1 is not 0, then Kosu1 becomes Kosu1-1**. For example, if you click the minus button while Kosu1 is 1, it will be 0. However, if you click the minus button while Kosu1 is 0, there will be no action, so it will remain 0. If you see a preview, you can see that the number increases when you click the plus button, and the number decreases when you click the minus button, but it does not go below zero. ​ ![](/assets/blog/authors/aoshima/figma/count_up.gif =400x) How the count-up function works The count-up function is now complete. ​ Subtotal Settings Finally, I will set up the subtotal. In Part 1, there is only one product, so we will treat the total amount as a subtotal. ​ Create and Assign a Variable The subtotal is also an object that changes according to the number of item, so you need to set a variables I made the variable the same way as before and named it Shoukei. Since we assume that the shopping cart starts with one product, the subtotal will be ¥100, and the value will be 100. We assign the variable to a number the same way as before. ​ ![](/assets/blog/authors/aoshima/figma/sum1.png =400x) Assign a variable to the amount in the red rectangle Give an Action to the Button When deriving the subtotal amount, you can also increase or decrease the price of the product by pressing the plus or minus buttons, just like with the quantity. You can also use the multiplication operator to calculate quantity x price. You can also use the same formula for both the plus and minus buttons, which makes it a little easier. When you are done, it should look like the figure. ![](/assets/blog/authors/aoshima/figma/sum2.png =400x) This formula makes it so that Shoukei is Kosu1 x 100 , so if Kosu1 is 1, the subtotal is 1x100, which is $100. If you see a preview, you can see that the number of products increases or decreases when you click the plus or minus button, and the price of the subtotal changes accordingly. ​ ![](/assets/blog/authors/aoshima/figma/sum.gif =400x) The subtotal changes Now the subtotal settings are complete. You can make a mock-up of a like button or simple cart function with just the information in Part 1, and I think it is useful for various applications. This concludes Part 1. In Part 2, we will put all this to practical use. I will explain how to make shipping free if there are two products and the amount exceeds a certain number. I hope this was helpful.
アバター
Introduction Nice to meet you. I am Shirai, working as a Cloud Infrastructure Engineer in the Cloud Infrastructure Team of the Platform Group at KINTO Technologies Corporation. I typically build and design the infrastructure for systems built on AWS. My hobby is playing table tennis and video games. Recently, I bought the remake of Super Mario RPG and played it while immersing myself in nostalgic memories. This time, I will introduce the deployment process in CloudFront Functions, which is being built in KINTO Technologies, and the story of the operational kaizen, including the background! KINTO Technologies' Cloud Infrastructure Team Prior to exploring the subject, I'd like to share a bit about our team. At KINTO Technologies, infrastructure construction is managed by IaC using Terraform. For a detailed historical background, etc., please refer to Mr. Shimakawa’s article from the same team. He has published a document on How to Abstract Terraform and Reduce the Man-hours Required to Build an Environment . Current Challenges KINTO Technologies currently uses CloudFront Functions (hereafter, CF2) for redirect processing in some systems. For more details, you can read the post from Mr. Iki, another team member, as he introduces CF2 under the title Edge Functions Available with CloudFront. While using CF2 at KINTO Technologies, the following three challenges have been raised: High communication costs between the Application Team and the Cloud Infrastructure Team The Application Team is not authorized to view logs output to CloudWatch Logs Logs output to CloudWatch Logs remain unexpired We will solve these three challenges. Digging Deeper Into Challenges 1. Challenges in high communication cost The process for CF2 to be applied so far is as follows. Deployment process to date Because the Deployment is reliant on the Cloud Infrastructure Team, in the event of an issue with CF2 source code, steps (2) to (4) in the above diagram must be re-executed by the Cloud Infrastructure Team. The problems with this flow include: The update of CF2 depends on the Cloud Infrastructure Team When CF2 is updated, the Cloud Infrastructure Team must also review the scope of impact and coordinate with the Application Team The above two points have resulted in high communication costs. 2. Challenges in Application Team not being able to view logs KTC has restricted the authority to hand over to the Application Team. As a result, they do not have permission to view CF2 logs. In this situation, the Application Team cannot investigate when a problem occurs in CF2. 3. Challenges with permanent CF2 logs At present, CF2 was built without a CloudWatch log group set up. According to the specification of CF2, a log group named /aws/cloudfront/function/${FunctionName} is automatically created in CloudWatchLogs in the us-east-1 region when CF2 are output. In this situation, the log group has no set expiration period, causing it to persist and resulting in high costs. Solutions The problems and solutions are summarized below. Issue Issue Solution 1 High communication cost Grant additional permissions to the Application Team to deploy at any time 2 Application Team not being able to view logs Add log view permission to the Application Team 3 CF2 logs remain permanent Create log group with expiration period first Now, I would like to dig deeper into each solution. Issue 1: High communication costs As mentioned above, establish a policy allowing the Application Team to deploy at any time. So, I decided to revamp the deployment process. First, I will show you an example of the configuration before CF2 was built and an example of the configuration after the process was revamped. Example of the configuration before CF2 was built Example of final configuration I would like to add more details about the DEVELOPMENT stage and LIVE stage of CF2. LIVE stage is actually CF2 running linked to CloudFront. Apart from that, the DEVELOPMENT stage is mainly used for development purposes and allows you to validate incoming requests in the LIVE stage. Next, I would like to briefly explain about the maintenance role and CICD user listed in red text. Maintenance role and CICD user Each role is as follows. Duty of the maintenance role Monitoring and updating various AWS services on the AWS Management Console. At KINTO Technologies, when logging into the AWS Management Console, SSO logins are made to an account provided for each environment. By switching to the properly authorized maintenance role after SSO login, you can view and update the necessary AWS services manually. Due to the presence of various products within the same account, we enforce restrictions on viewing and updating permissions to prevent misoperation. Duty of the CICD user Updating various AWS services using CICD tools such as Github Actions. Setting permissions to be used in deploying applications. The AWS resources used by each product determine the permissions to be granted. For example, a product that deploys Lambda and ECS has permission to deploy both, while a product that deploys ECS only has permission to deploy ECS only. Existing maintenance roles and CICD users were not granted CF2 permission, so the following permissions were added. { "Action": [ "cloudfront:UpdateFunction", "cloudfront:TestFunction", "cloudfront:PublishFunction", "cloudfront:ListFunctionTestEvent", "cloudfront:GetFunction", "cloudfront:DescribeFunction", "cloudfront:DeleteFunctionTestEvent", "cloudfront:CreateFunctionTestEvent" ], "Effect": "Allow", "Resource": "arn:aws:cloudfront::{AccountID}:function/${aws:PrincipalTag/environment}-${aws:PrincipalTag/sid}-*", "Sid": "" }, { "Action": [ "cloudfront:ListFunctions" ], "Effect": "Allow", "Resource": "*", "Sid": "" } As a side note, CF2 can submit test requests like Lambda at the DEVELOPMENT stage. Among them, *TestEvent permission was needed, but the action was not stated in the official document , so I added the necessary permissions by relying on CloudTrail. I found it to be a good example of realizing that official document isn't everything. Next, I'll talk about the division of responsibilities between the Cloud Infrastructure Team and the Application Team. The Roles of the Cloud Infrastructure Team and the Application Team Task Cloud Infrastructure Team Application Team CF2 permissions ○ - Create sample app and link to CloudFront ○ - Develop CloudFront Functions, publish to LIVE stage - ○ Operate and monitor CF2 - ○ Let's take a look at the process of actual deploying (Publishing) to the LIVE stage. Deployment process 1. The Application Team asks the Cloud Infrastructure Team to build You need to issue Jira tickets based on the following template. CF2 naming: hogehoge e.g.) redirect-cf2 List of environments to build: xxx CloudfFront ARN to associate: arn:aws:cloudfront::{AccoutID}:distribution/{DistributionID} e.g.) arn:aws:cloudfront::111111111111:distribution/EXXXXXXXXXXXXX Associate cache behaviors Viewer request Viewer response hogehoge ○ - 2. Built by the Cloud Infrastructure Team Link CF2 of the sample app (request through) created by the Cloud Infrastructure Team to CloudFront behavior. Grant the Application Team permissions for development and deployment to maintenance role and CICD user. function handler(event) { var request = event.request; return request; } *The Cloud Infrastructure Team updates and creates the necessary resources. The red frame is the target. * 3. The Application Team publishes the CF2 code to the DEVELOPMENT stage. How to update the source code to the DEVELOPMENT stage is as follows. 1. Manual execution from the AWS Management Console using maintenance role 2. Apply using CI/CD tools such as Github Actions, using CICD user credentials You can run tests on the AWS Management Console or with CI/CD tools. Development and testing 4. The Application Team publishes the CF2 code to the LIVE stage. Similar to applying to the DEVELOPMENT stage, publishing to the LIVE stage can be performed from the AWS Management Console or CI/CD tools such as Github Actions. Final Configuration Issue 2: The Application Team is not being able to view logs. Grant view permission to the log group. { "Action": [ "logs:StartQuery", "logs:GetLogGroupFields", "logs:GetLogEvents" ], "Effect": "Allow", "Resource": "arn:aws:logs:us-east-1:{AccountID}:log-group:/aws/cloudfront/function/${aws:PrincipalTag/environment}-${aws:PrincipalTag/sid}-*-cloudfront-function:log-stream:*", "Sid": "" } In the maintenance role, the logs are now visible because we have granted the log group view and log insight view permissions as described above. As a result, I believe the Application Team can now take the lead in addressing problems as they occur. Issue 3: CF2 logs remain unexpired. A CloudWatchLog group is created when CF2 is built. This was achieved by including it in a module that is referenced in the process of CF2 creation. resource "aws_cloudwatch_log_group" "this" { name = "/aws/cloudfront/function/${local.function_name}" retention_in_days = var.cwlogs_retention_in_days == null ? var.env.log_retention_in_days : var.cwlogs_retention_in_days } Summary/Conclusion Three improvement initiatives were implemented for CF2 at this time. Let me summarize it in bullet points. Issue 1: High communication costs Solution: Organize permissions and processes to enable the Application Team to deploy on their own Effect: The Application Team can now execute tasks at any time, allowing effective communication as required. Issue 2: The Application Team cannot view logs Solution: Grant the Application Team permission to view logs Effect: Even when problems occur, they can check the logs and respond by themselves Issue 3: CF2 logs remain permanent Solution: Create destination log group with expiration period first Effect: The log validity period was determined, which contributed to cost optimization. Thank you for reading my article all the way to the end!
アバター
Outline in 3 Lines I am a Scrum Master We use Atlassian products, including Jira in our company Here are some useful features of Jira Introduction Hello, everyone. This is Koyama from KINTO Technologies. I am an iOS (Swift) engineer. I've also been doing a bit of Scrum Master work lately. This time, I would like to introduce some recommended Jira practices. Scrum and Jira? As stated in the 2020 Scrum Guide , a Scrum Master has a key role to “help the Scrum team by coaching them self-management and cross-functionality”. I anticipate the creation of various mechanisms to fulfill this, but at this time, it's important to have a system that operates with minimal human (Scrum Master) intervention. … …No, I don't mean I just want to make things easier. …Okay, maybe a bit (We all want to work with less effort, though.) So, What Was Jira Again? Jira is a SaaS product developed by Atlassian primarily used for project management. For more information, please visit the official website . It has a very versatile task management function and is highly compatible with Confluence, a document management tool also made by Atlassian. Our company provides both Jira and Confluence, which are available to all employees. I wonder how widespread it is. Getting to the Point (Finally) Creating fields and setting required fields "The person in charge didn't write down the issue in detail!" "I thought I'd add the deadline later, but I forgot..." We hear voices like these. The amount of information that remains on each issue in project management using Jira will help you and the person in charge around you understand quickly, preventing the need to explain the same information over and over again. In addition to the fields provided in the template, Jira allows you to add and customize any field and even make it mandatory at will. I think this can be used to structure and resolve the above comments. "The person in charge didn't write down the issue in detail!" Let's include additional fields to provide more detailed information. "I thought I'd add the deadline later, but I forgot..." Let’s make sure that the deadline field is a mandatory requirement. Use cases Our team makes it mandatory to enter labels to clarify which team is responsible; such as "iOS", "Android", "Backend", etc. While simply incorporating suitable labels would meet the need for the required field, it would be adequate to prevent the person in charge from unintentionally omitting it during the ticket creation process We made the "label" field mandatory. To set up, simply click the "Required" checkbox. It's that simple. However, if you make all of them mandatory, creating an issue will be troublesome, so please set the usage guidelines after discussing with your team. Automation "It's frustrating to enter the same values every time I create an issue." "I want to regularly check that the issue is operating correctly." Next, let's address this kind of feedback. Jira has a function called Automation, which I avoided when I first started using it because I didn't know what it was. However, I found it to be really convenient when I gave it a try. This can solve most of the problems that can be done in Jira. Let's take a look at how to set them up in order. "It's frustrating to enter the same values every time I create an issue." Create an action with the trigger set to "Issue Created." In our project, we automatically flag "Issue Created" after determining whether there are any related issues. Here are the settings for your reference. Set "Issue Created" as the trigger for the rule. Determine if there are "story" or "bug" in linked issues Jira allows you to narrow down not only whether there are linked issues, but also the type of issues to which they are linked. We use these to support issue operation in line with the team's approach. "I want to regularly check that the issue is operating correctly." For this, how about setting the trigger to "every day at midnight" or "every Monday at 13:00"? In our project, a system has been created for regular checks to ensure no oversight of time-limited issues. Here are some examples. Set "9:00 a.m. on weekday morning" as a trigger for rule Check that the limit is expired. Send a message using Slack Webhook Since Jira can also send Slack notifications, we can leave it up to our now familiar Slack to notify us about important messages. "I didn't notice the Jira comment!" You can also avoid situations where you might miss comments. JQL? The term "JQL", which frequently appears in automation settings, is unfamiliar, right? If you are only using Jira as a task management tool, you may never use JQL, but from a management perspective, it allows detailed configuration. "JQL" stands for "Jira Query Language" and is a unique language for searching for specific issues in Jira. I myself had difficulty finding the information I needed on the web, so here I would like to introduce JQL and how I use it myself for automation. Narrow down projects and issue statuses All Jira projects are in scope by default in regular executions. If you set up an automation workflow without any scope, you may unintentionally manipulate the issues of other teams. It can happen. Our project has the following conditions for automation to be performed on a schedule. The project must be yours The status must be "Done" or "DROP" project = PP20 AND status not in (Done, "DROP") Note: In the PP20 part, enter the key set for the project. Insert the content of the issue into the message you send to Slack As mentioned in Automation, it is possible to connect to Slack, but without information on the issue, the person in charge who is contacted on Slack will be confused. In our project, we create Slack messages with the following settings. *There are overdue tickets. Please review the contents asap. * @channel > 【<https://hogehoge.atlassian.net/browse/{{issue.key}}|{{issue.key}}>】{{issue.summary}} The message changes to something like this. Actual Slack message Conclusion This was the introduction of Jira's useful settings. I hope this provides a bit of help for both current Jira users and those considering Jira as their management tool. In order to make Agile development easier and more progressive, I look forward to leveraging the useful features of Jira.
アバター