TECH PLAY

KINTOテクノロジーズ

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

936

はじめに こんにちは、KINTOテクノロジーズCSIRTの森野です。 2023年7月12日(水)~ 14日(金)の3日間、日本シーサート協議会が主催するTRANSITS Workshop 2023 Summerに参加してきました。 TRANSITS とは、CSIRTの設立や運用に関するヨーロッパ発のトレーニングコンテンツです。 今回のワークショップでは、組織、オペレーション、技術、法律の4つのモジュールを学びました。 CSIRTはComputer Security Incident Response Teamの略で、コンピュータセキュリティの事故対応を行うチームを指します。 コンピュータセキュリティの事故とは機密情報の流出、コンピュータシステムへの不正侵入、マルウエア感染などを指します。 組織モジュール 組織モジュールでは、CSIRTの役割や提供するサービス、チームの構成などについて学びました。 また、チームごとにCSIRTメンバや攻撃者などの人格を演じるインシデントシナリオ演習もありました。 この演習では、インシデント対応の流れやコミュニケーションの重要性を体感しました。 オペレーションモジュール オペレーションモジュールでは、インシデントレスポンスやインシデントハンドリングについて学びました。 インシデントレスポンスはインシデントの解析や封じ込めなどの対処を指し、 インシデントハンドリングはインシデント全体の対応を指します。 また、チームごとにインシデントハンドリングのプロセスについて検討する演習がありました。 この演習では、あらかじめインシデントを想定した対応手順を整えておくことの重要性を学びました。 技術モジュール 技術モジュールでは攻撃者の攻撃手法などについて学びました。 講義の中で、とあるセキュリティベンダで様々な組織で発生したインシデントの解析を携わっている方からお話がありました。 携わったほぼすべてのインシデントは、適切な監視が行われていれば攻撃を検知できたとのことでした。 また、セキュリティの基本として挙げられた下記の言葉も印象に残りました。 空けたら閉める 使ったら片づける 動かしたら管理する 法律モジュール 法律モジュールでは、サイバーセキュリティ関連の法律や規制について学びました。 特に、ログの取得や保存に関する法的な要件や注意点について詳しく説明されました。 また、警察との連携方法やeディスカバリーという制度についても紹介されました。 まとめ TRANSITS Workshop 2023 Summerは非常に有意義な経験でした。 講義でCSIRT関連の知識やスキルを深められるのはもちろんのこと、演習などを通して他の参加者と交流できた点が特に良かったです。 CSIRTを設立したり運用したりする方にはぜひおすすめしたいワークショップです。
アバター
Introduction Hello. I am Yamada, and I develop and operate in-house tools in the Platform Engineering Team of KINTO Technologies' (KTC) Platform Group. In this article, I will talk about the CMDB developed by the Platform Engineering team, its functions, the technology used, and how we made it in-house. What is a CMDB? A CMDB (Configuration Management Database) centrally manages the assets and configurations that are critical to delivering IT services. The primary role of a CMDB is to manage the lifecycles and information of assets (e.g., infrastructure required to deliver IT services, product information, product managers and other human resources). Why We Made the CMDB In-House Before we implemented a CMDB, as the number of products we had was increasing, everyone was working in silos with their asset information. Whenever there was an incident, it was difficult to determine who was in charge of a product or the extent of the impact. As a solution to these issues, we considered implementing a CMDB to centrally manage asset information in the company. There are several off-the-shelf CMDB software, but after considering installation and operation costs and customizability, we decided to make one in-house. The Features of Our CMDB Our company's CMDB includes fundamental functions like product and team management, and it's designed to seamlessly integrate with tools developed by other teams within the Platform Group. Some functionalities are still in development, but we are adding more every day so that anyone can view it and find the information they want. Product Management It manages basic information such as product names, affiliated departments, and management team. If a product malfunctions, you can easily find and contact the person responsible for it. For products that consist of multiple microservices, it can also manage which teams develop which functions, so you can accurately determine the right person in the event of a malfunction. Below is the product details screen, where you can check the team and domain information associated with a product. We plan to add more information such as which environment the product is in. There is also an item called "SID", which I will discuss later. Domain Management This manages domains associated with products. Team Management This manages team information associated with products. Manager Management This manages permissions for each user and group. DB Management This provides a mechanism to easily view all RDS information managed by KTC in the CMDB by linking with tools developed by the DBRE Team, which is also part of the Platform Group. In addition to basic RDS information, you check ER diagrams and DB designs according to the policy set by the DBRE team. Security Management Security management lets you manage the repository and its vulnerability information on the ECR. If a vulnerability is found in the weekly ECR repository scan, the MSP Team, which provides operational support, will work with the team that manages the repository. In that situation, it outputs an Excel file of the scan results and a CVS file that creates a Jira ticket for a response request to the person in charge. Scheduling Management This provides a scheduling management function that stops EC2, ECS, and RDS in the development environment for a certain period of time for the purpose of reducing AWS costs. By stopping services during late weekday nights and weekends when they are not required, it contributes to cost reduction. External Linking With external linking, you can link the AutoProvisioning system to the sandbox environment on AWS and manage the history. For more information, please read the article below! https://blog.kinto-technologies.com/posts/2023-05-30-AutoProvisioning/ SIDs To connect the data in the functions I have talked about up to now, KTC has the concept of SID . SID stands for Service ID and is a unique identifier for each product managed by KTC. For example, the SID of CMDB is set to kakazan . The name "Kakazan" comes from the mountain where the Monkey King was born in the novel Journey to the West. In fact, the name KINTO also comes from the Monkey King's story; it’s the name of his flying nimbus “Kinto'un”. So in the same way, it’s fun to see how a lot of the SIDs for KTC products are referencing Journey to the West. SIDs are used as product names and makes clear who is the owner of each product. This concept is spreading throughout KTC. In particular, AWS resource management uses ECS, RDS, S3, API Gateway, and many other AWS services for each product. The Tag setting is effective when determining which resources belong to which product. The resources are then linked to the products by attaching a SID tag to the resource. The CMDB uses this SID tag setting to link various information together. Technology Used I will briefly go over some technical elements used to develop the CMDB. The frontend is developed using React, while the backend is built with Spring Boot. Both utilize a shared framework for authentication, authorization, and utility classes. Additionally, there are three services—for the main service, DB management, and external linking—that are all dependent on the common framework. Batch processing was also developed with Spring Batch. I would like to write more about the system configuration another time. Future Plans We have more technologies to explore, and we plan to continually update features. Some are still in development, while others are on our agenda for future work. For example, we can try using EKS since KTC uses ECS as its container execution environment, or we can try using microfrontends (which are not necessary in terms of development scale), or we can implement PWAs (Progressive Web Apps) so the CMDB dashboard can be viewed from company smartphones, and so on. I think there are opportunities to explore only because the system was made in-house, so we will make good use of this system by trying out technologies that could be deployed in-house in the future. We also want to add functions to the common framework used to develop the CMDB, create a group of React components to suit the KINTO brand image, and implement them as a library to be used throughout the company. Conclusion In this article, I talked about the CMDB we developed at KTC, its background and functions, and our vision for the future. KTC s actively involved in the development of various systems alongside managing the services handled by KINTO I hope that this article has raised interest in KTC activities.
アバター
はじめに クリエイティブ室の杉本です。 今回は、オリジナルマスコットキャラクターができるまでの第二弾をお届けします。 第一弾は、キャラクター欲しいよねーという声を受けて形になるまででした。 1.全社員を巻き込みながら進めてきた道筋と、2.人気を集めたものを単純に開発するのではなく、ある程度、マスコットキャラクタープロジェクト(以下PJ)のメンバーが、KINTOのビジョンやブランドパーソナリティから選択の軸を決め、今後の展開とブランディングを含めて方向性を決めていったこと 3.社員の有志から集まったキャラクターアイデアから全社員にアンケートをとり、KINTOの社名の由来でもある“雲”をモチーフにしたアイデアに人気が集まったことをお話させていただきました。 具体的には、下記のキャラクターに人気が集まりました。左は、形を自由自在に変えられるという点に人気が集まり、右は雲をクルマ化?!させたところがチャームポイント。ちなみに、両方ともクリエイティブ室から選抜されたことは、マネージャーとして、ほっとひと安心。 こちらの2案に人気が集まりました。 雲モチーフに命を吹き込んでいく 1. インハウスでも、つくるべきではない制作物もある! 上記の2案を元に、次はイラスト化です。 時々、デザイナーは写真も撮影できて、動画制作もでき、イラストまで描けちゃうと思っていらっしゃる方がいます。 「外注費がないので、内製でできないですかね。」「AIでちゃちゃっと作れないですかね?」など、など色々と聞こえてきますが。。 社内デザイナーの中でも、もちろん、イラストが上手なメンバーはいます。ただ、餅は餅屋メソッド(「お餅はお餅屋さんでついたものがいちばん美味しいのだから、その分野のことはその道の専門家に任せたほうがうまくいく」という例え)が、ここは大事。キャラクターの命ですから! 上手に描くイラストと、命を吹き込むイラストは違います。やはり、イラストレーターやキャラクター制作に特化したクリエイターにお願いするのが、同じクリエイター同士へのリスペクトだと考えます。内製でできない、するべきではない制作物の例であるといえるでしょう。 2. ならどうする?イラストを外注 制作予算がある中でしたが、幸い、PJに入っているビジネス側の担当者は、「デザイナーだからイラストも描けるだろう」といった考えではなく、クリエイティブを尊重してくれるメンバーが揃っていたので、制作費をつくるべく尽力してくれました。外注先は、企業や商品、または地域などのブランディング及び企画デザインなどを得意とするクリエイティブカンパニー「 Steve* inc. 」さんに依頼することに。 PJが大切にしたいキャラクターへの想いに寄り添いながら、キャラクターにどんどん命を吹き込んでくれる物語をいっしょにつくっていってくれました。 私たちクリエイティブ室が「 Steve* inc. 」さんに注文させていただいたのは、例えばグッズをつくった際にも、大人でも持ちたくなるようなキャラクター。かわいい、愛くるしい、それだけではない大人が納得できるトーンにこだわり依頼しました。 そのこだわりをもとに、雲のモチーフキャラクターの案を3案つくってもらいました。A案「謎の生物K」B案「はぐれぐも」C案「くもりす」。彼らは全て、どこか俯瞰してるようでいて、少しかまってちゃんを感じる表情は、さすが「 Steve* inc. 」さん!PJメンバー全員、プレゼンをわくわくしながら聞かせてもらいました。次に、全社員にそれぞれの案の良いと思う点と懸念点を挙げてもらうアンケートを実施。アンケートを行うことで、多角的な視点で審査することで、かわいい!好き!それだけではないキャラクターの課題感が見えてきました。 そして、アンケートの結果、A案「謎の生き物K」に決定! 「謎の生き物K」って笑 これが名前?! このインパクトのあるネーミングを活かし、このまま名前や存在に「謎」感を残したプロモーションで進めていくのが面白いのでは?!ということで、マーケティングやSNS担当者とのミーティングも盛り上がりました。 さあ、フォルムが決まったので、次はブラッシュアップしてもらいます。さらに、「謎の生き物K」は、読みやすさと身近さを感じてもらえるよう、生き物をひらがなにということでこちらも地味に改名し「謎のいきものK」となりました。 「謎のいきものK」の形がどんどんできあがっていく! なんとなくとぼけた表情がグッドな「謎のいきものK」。ですが、長く愛されるようフォルムや顔立ちをブラッシュアップしていきました。 具体例: アルファベットの「K」感をもう少し出したい(ぱっと見て「K」を想起できないのではないかという意見が出ました。) もう若干、雲感を出したい(現状、ハンドソープの泡、マシュマロみたいで) 雲がモチーフなので、目とカラダのバランスを若干調整したい。(もう少し、雲が大きく見える初期のスティーブさんのイラストくらいのバランス感。) 3DのKの目の「白眼」と「雲」の違いをもう少し出したい(現状黒い部分のみが見えるので、ふちの線なのか、シャドウなのかを調整しもう少し2DのKの目のような可愛さを残したい。かつもうちょいマットな質感の方が良いかもと思いました) 3DのKのカラーをもう少しブランドカラーを入れたい(黒目部分と体の影など) 2Dイラストだけでなく、クルマの画像といっしょになったときにも、違和感がないように3Dイラストも制作することにしました。 さらに、形のモコモコはどうするか?イラストで描くぶんにはいいが、着ぐるみになったときにどう表すか、目の色はどうするか、口はないままで、かつセールストークはもちろん、何も話さないキャラクターにするか、性格や性質などを詰めていきました。 そして、現在のフォルムと表情に! ネーミングは2023年7月からお名前募集キャンペーンを行い、全部で932投稿をいただきました。 そのなかから、PJでキャラクターを決める際の軸( ブログ1を参照 )をもとに、ネーミング候補を選択。 雲のキントン くもびぃ 謎のいきものK K お客様(サブスクKINTOの契約者)の人気投票では、「雲のキントン」と「くもびぃ」がともに人気があったものの、年代別にみるとターゲット世代の10代〜30代に「くもびぃ」がダントツ人気になったことと、社内の投票結果が1位になったことで、 「くもびぃ」 に決定しました。 名前の由来として、雲=くもとモビリティが合体しているのもKINTOらしく、PJメンバーも納得。 こうして生まれた「くもびぃ」。これから会社のプロモーションに露出していく機会が増えると思います。どうぞよろしくお願いします。 ユニークな特徴の「くもびぃ」をチェックしてみてください! ▼ くもびぃストーリーはこちら ▼ @ card
アバター
Introduction Hello, my name is Numata, and I am part of the Project Promotion Group. I work hard every day as a backend engineer for KINTO FACTORY. In this article, I will talk about KINTO FACTORY services and the DX initiatives we did this summer. What is KINTO FACTORY? Many people in Japan think of KINTO as a subscription service, but KINTO FACTORY (hereinafter, FACTORY) offers various upgrade services so that you can ride your favorite vehicle over a longer period of time. To be more specific, you can customize your vehicle by updating its software, changing its interior and exterior such as seat replacement and wheel cap replacement; or improving the opening and closing speed of your doors. The range of available Toyota Group vehicle models (Toyota, Lexus, and GR), products, and areas where customizations are possible, is gradually expanding too. I always thought that once you buy a vehicle you do not really change any features until you switch to another vehicle, so I feel that the efforts of FACTORY and its approach to modularity are challenging and interesting. Modification Process FACTORY provides services not just through KINTO, but also in cooperation with Toyota and its dealer network throughout Japan. *The numbers in the image are for illustrative purposes and are not fixed. First, when a customer applies for a product on the FACTORY site, FACTORY orders the necessary parts from Toyota and shares the application details with the dealer of the customer's choice. After confirming the information in the application, the dealer sets up the arrival date with the customer. Once the delivery date is confirmed, the customer takes their vehicle to the dealer on the day of receipt, and the dealer carries out the modification with the delivered parts. As soon as the modification is completed, the dealer contacts the customer and delivers the vehicle to them. Specifics may vary depending on product and the desired modification, but that is the general process. DX of Modification Certificates Some of you may have never heard of modification certificates before (I learned about them after I joined the company). It is given in Japan to customers after a vehicle modification is completed, and written on it appears the details of what was modified, its date and time, the dealer where it was performed, along with other information. Before, the modification certificate was manually created by the dealer that delivered the vehicle to the customer, but since August, it has been possible to issue it on FACTORY. Process of Issuing a Modification Certificate Once the status of a purchased item changes to modification complete , you can issue a modification certificate from your purchase history on My Page (FACTORY refers to My Page as My Garage😃). When you click the modification certificate button, the certificate is displayed in a separate tab and can be downloaded as shown in the figure below. Currently, modification certificates can be issued for any products except for GR-related ones and event products. It also supports the invoice system that we implemented in October 2023, and payment statements can be issued from FACTORY. Architecture and Technology Stack FACTORY runs on AWS, and we use a microservice architecture like the one in the rough diagram above. The microservice that issues the modification certificate was developed using Go as programming language and uses the gopdf library to publish PDFs. The issued modification certificate is stored in S3. PDF Templates Since our company uses Office 365, we use Excel to manage PDF templates. We modify the Excel template and export it as a PDF whenever there is a change. Toyota Modification Certificate Lexus Modification Certificate We struggled with the fact that, not only the design of the modification certificate varies depending on the model, but the number of characters in the product name also varies, so it was difficult to decide on one layout that would not affect either of them. For convenience, we made it A5 just like the proofs of modification that were made manually. Side note: This was my first time handling PDFs with a program. I honestly did not think it was so straightforward. Beyond the Modification Certificate DX We can now provide a better experience for both customers and dealers by making it possible to easily generate modification certificates on FACTORY instead of having them made manually by dealers. Aside from modification certificates, there is still a lot of work that is done manually, and I think there is a lot of potential for DX in the automotive industry. FACTORY will keep working on various initiatives, to offer even better experiences in the future. Conclusion FACTORY is looking for new partners to liven up the company together. We do casual interviews, so feel free to apply! @ card
アバター
Introduction Hello, I am Aritome from the Development Support Division at KINTO Technologies Corporation. I am currently working mainly in the areas of organizational development, and education and training in order to address what is necessary for the company in a quick and agile manner. KTC holds a monthly Development and Organization Headquarters Meeting in which all employees (employees, contract employees, and temporary employees) participate. Today, I will talk about the twists and turns of the meeting. Some of you may be thinking, 'Hey, this is a Tech Blog, but this content isn't technical at all!' However, I want to assure you that I'm writing this article from our Osaka Tech Lab. So, even if the content might not seem technical, the place where I'm writing it is definitely tech-related! Also, I talk with various companies because of my work, and I feel that every company is worried about people and team building, including topics like building an organizational culture and retaining employees. I believe that making products means making people! I hope this will be a reference for those who are also struggling to build their organization. <What is a Development and Organization Headquarters Meeting?> KINTO Technologies Corporation's Development and Organization Headquarters Meetings started in July 2021, before I joined the company, with three departments announcing their respective initiatives in something similar to an in-house LT meeting. According to the minutes of the meeting at the time, there were about 160 participants... (We have grown considerably as a company and now have more than 330 employees.) The meeting has been held once a month since then. Each month, Kageyama, our Executive Vice President, gives a presentation, and two or three divisions talk about their activities in a LT (Lightning Talk) format. After that, one of the divisions gets a Kageyama Award. Kageyama gives a complimentary prize. <Why is the Development and Organization Headquarters Meeting Held in the First Place?> At first, we had a rigid culture in which the departments had a vertical structure and did not share information much, As we were in the business launch phase, we were very busy with practical work that we had to prioritize, and we put building a corporate culture on the back burner As the number of employees increased, so did the distance from Vice President Kageyama and the rest of employees. Due to the launch of the business during the COVID-19 pandemic, there were few chances to meet offline, and the company wanted everyone to communicate with each other at least once a month. Originally, the manager (Currently Mr. K, General Manager of the Development Support Division) was in charge of planning and managing, but when I joined the company, we started reviewing the meetings. We took over the operations of the Headquarters Meeting around April 2022, and have been improving it through trial and error for a year and a half. To prepare for the renovation, we identified the following three challenges and worked on them. (1) Improving communication We started entirely online using an LT meeting format, so at first, employees just listened to presentations one-sidedly instead of actively communicating with each other. I remember being surprised when a lot of employees attended halfheartedly, and I thought it felt like a management meeting. (2) Improving the Kageyama Award Also, I felt that it was a burden for employees in the workplace to make a 5-minute LT presentation even though they were busy. As the organization expanded, the number of managers other than Kageyama increased, so we thought, "We need to create a system that lets the board show the efforts of the members to more people." (3) Understanding other departments' work and sharing activities We received comments in the past such as “I don’t know what other departments are doing” in our questionnaires, so we wanted to use the Headquarters Meeting and other events to better understand what work and activities other departments were doing. (1) Improving communication We implemented a tool called Comment Screen , that displays emojis and comments on a screen in real time, and it encouraged more two-way communication. There were some who liked it because it was in real time, while some thought that it felt cheap, or that the presentations were hard to read. We kept experimenting, and now we communicate through Slack. All employees join the Headquarters Meeting Communication Channel when they join the company and use Slack to communicate in real time during the meeting every month. On each session, we added a friendly poll with questions such as, "What did you eat today for lunch?" By the way, there are a lot of restaurants with delicious food near our office, and a lot of members report going to lunch, but a there is also a handful who sadly say "Red Bull" or "I didn't eat..." lol But, just to be clear, our company is a place where everyone can take breaks easily! (Honestly, our company culture makes it easy to take breaks, and I think that is one of our company's good points) (2) Improving the Kageyama Award The purpose of the program was redefined as "managers should not miss the daily efforts of their members," and the style was changed so that managers recommend candidates, give the reason for their recommendation, and write an award speech. Before, Vice President Kageyama decided the winners, but they are now decided in a meeting with the managers in advance. With this system, team members no longer have to make tedious materials for the sake of being nominated and getting awards, and the managers were more motivated to pay attention to the members' daily efforts. I hope that the corporate culture changes so that people's daily efforts are assessed naturally. (3) Understanding other departments' work and sharing activities We made changes so that every month, the managers of each group take turns sharing information on projects that are being focused on and their activities. Kageyama also gives additional comments when necessary. Thanks to managers sharing information on activities and Kageyama's additional notes, the company's activities felt more concrete to employees, and they were more motivated to be informed. We also shake things up so that it’s not always the same announcements, and during the New Year period for example we introduce things such as the kanji of the year or the goals for next year. In addition, we post information on events from Twitter, announced activities related to the Tech Blog, and try to make the Headquarters Meeting an event where people can understand the company's activities. In addition to the above, the results of the previous month's questionnaire are announced at the start of each meeting, and we try to make communication during the meeting as open as possible. We are still making improvements, but the attendance rate of the Headquarters Meeting is gradually increasing. We have almost every employee (close to 300) attend every month, even as more employees join the company. The number of people participating online with their webcam on and making comments on Slack is also increasing gradually! We also get more happy comments through our questionnaires with each meeting. [Some Questionnaire Responses from our Employees (Examples)] It is really interesting to learn what each department is doing. It is also helpful to hear Mr. Kageyama's thoughts on each department! I like how the meeting is packed with information. Generally speaking, this kind of meeting tends to be light on content, or you can just read the materials afterward to get the information, but I think KTC's company-wide meetings have been different recently (in a good way). I can find out the status of departments that I normally don't have any connection with. I find that helpful. Conclusion What do you think? We will start taking on challenges such as announcing the 2024 kanji of the year and holding in-person events (holding the Headquarters Meeting offline). I think one of the good things about our company is that we are open to new initiatives and challenges. We can implement initiatives that are difficult for conventional large organizations and start them in a relatively quick and agile manner. Even if they fail, for better or for worse, they serve as precedents (and we don't get too mad?), and we can use the experience for our next actions. And of course, if you succeed, people will praise you (lol) Also, we have many employees who say, "I want to do it!" and lend us their strength. Please let us know about your company's initiatives when we meet at events! We will challenge ourselves so we won't lose!
アバター
はじめに KINTOテクノロジーズでmy routeのAndroid側を開発しているHand-Tomiと申します。 Android 14が2023年4月12日にリリースされてそろそろ1年になります。 しかし、新しく追加された「地域別の設定」についてまだ十分理解されていない方も多いと感じ、この記事を書くことにしました。 多言語対応のアプリケーション開発において「地域別の設定」を理解せずに進めると予期せぬバグが発生するリスクがあります。この記事を読んで、そうしたバグを予防できれば幸いです。 この記事で解説するもの Locale.getDefault() == Locale.JAPAN :::details コード解説 Locale : 言語、国、地域に基づく特定の文化的、地理的設定を表すクラス Locale.getDefault() : 現在のアプリケーションのデフォルトの Locale を返す Locale.JAPAN : 日本の言語( ja )と国( JP )の設定を表すLocaleのインスタンス ::: 上記のコードでは端末に「日本語(日本)」が設定されている場合、 true が出力されますか?それとも false が出力されますか? 正解は、Android 13以下では true であり、 Android 14以上の場合、これだけの情報では不明 です。 この記事では、 Android 14以上の場合、なぜ不明なのか を解説します! Androidでの Locale とは Locale は、言語、国、地域に基づいた文化的、地理的設定を表すクラスです。この情報を利用して、Androidアプリケーションは多様なユーザーに適応したアプリケーションを構成することができます。 Locale は主に言語や国を扱いますが、 LocalePreferences を使用することで、より多くのデータを抽出することが可能です。 val locale = Locale.getDefault() println("calendarType = ${LocalePreferences.getCalendarType(locale)}") println("firstDayOfWeek = ${LocalePreferences.getFirstDayOfWeek(locale)}") println("hourCycle = ${LocalePreferences.getHourCycle(locale)}") println("temperatureUnit = ${LocalePreferences.getTemperatureUnit(locale)}") 「日本語(日本)」の設定を持つ端末で上記のコードを実行すると、以下のようになります。 calendarType = gregorian : 暦法 = グレゴリオ暦 firstDayOfWeek = sun : 週最初の曜日 = 日曜日 hourCycle = h23 : 時間周期 = 0~23 temperatureUnit = celsius : 温度 = 摂氏 「地域別の設定」とは Android 14から導入される「地域別の設定」は、Locale(言語、国)で設定された「温度」や「週の最初の曜日」をカスタマイズできる機能です。 温度 デフォルトを使用 摂氏(℃) 華氏(°F) 週最初の曜日 デフォルトを使用 月曜日 ~ 日曜日 温度設定画面 週最初の曜日画面 :::details 設定画面に入る方法 「設定アプリ」内の「システム」→「言語」セクションから「地域別の設定」画面にアクセスできます。 ![setting](/assets/blog/authors/semyeong/2024-02-28-regional-preferences/setting.png =300x) ::: 「地域別の設定」がなぜ必要か? 「アメリカ🇺🇸」と「オランダ🇳🇱」では、共に英語を使用できますが、使用される「温度」の単位や「週の最初の曜日」が異なります。 アメリカ🇺🇸 オランダ🇳🇱 温度 華氏 摂氏 週最初の曜日 日曜日 月曜日 「アメリカ🇺🇸」に住んでいる「オランダ人🇳🇱」が摂氏に慣れており、 温度のみ を摂氏に変更したい場合は、「地域別の設定」を使用して、 温度のみ を変更することが可能です。 「地域別の設定」を設定すると、どのような変化があるのか Locale.getDefault().toString() 設定値を確認するために、上記のコードを使用しながら各設定を変更してみましょう。 言語 温度 週最初の曜日 結果 日本語(日本) デフォルト デフォルト ja_JP 日本語(日本) 華氏 デフォルト ja_JP_#u-mu-fahrenhe 日本語(日本) デフォルト 月曜日 ja_JP_#u-fw-sun 日本語(日本) 華氏 月曜日 ja_JP_#u-fw-sun-mu-fahrenhe 「温度」や「週の最初の曜日」を設定した結果、 #u や mu-fahrenhe 、 fw-sun など理解しにくいテキストが出力されましたが、これらは Locale のメンバー変数であり、 localeExtensions の値です。このように localeExtensions に値が設定された場合、 Locale の hashCode や equals() の結果も変わり、 Locale.JAPAN と比較しても true にはなりません。 では、どのようにして言語を確認するか? Locale.getDefault() == Locale.JAPAN // X Locale.getDefault().language == Locale.JAPANESE.language // O 言語を確認したい場合、 Locale に含まれる language プロパティで比較してください。 この方法を用いれば、「地域別の設定」を変更しても影響を受けず、求めている結果を得られると思います。 最後に Android 14からこっそり追加された「地域別の設定」機能によって、突然以前動いていたコードが動かなくなっても、この変更を検知することはかなり難しいですね。 ほとんどの方は問題ないと思いますが、もしLocaleインスタンスで言語を比較している場合は、確認してみてください。 一人でも多くの方がこのようなバグを早く発見し、解決できれば、この記事は大成功と言えるでしょう! また、myrouteのメンバーが執筆した他の記事もぜひご覧ください! Structured Concurrency with Kotlin coroutines myroute Android AppでのJetpack Compose Compose超初心者のPreview感動体験 ここまで読んでいただき、ありがとうございました。 ※Android ロボットは、Google が作成および提供している作品から複製または変更したものであり、 クリエイティブ・コモンズ 表示 3.0 ライセンスに記載された条件に従って使用しています。
アバター
Hey there! 👋 We're Az, Moji, and Ai—part of the UI/UX team in the Global Product Management Group at KINTO. Today, let's dive into the fascinating world of diversity and inclusivity in UI/UX design! What Does It Mean to Design for ‘Diversity and Inclusivity’? According to Nielson Norman Group , inclusive design describes methodologies to create products that understand and enable people of all backgrounds and abilities. Okay, let’s dive into some examples to get a better understanding of inclusive design. Clear examples can be seen in architecture – ramps for wheelchairs, tactile paving, even bicycle lanes, it’s all about making spaces welcoming for everyone. Examples of inclusive design in everyday life Examples in UI/UX Design Now that you (hopefully) have a clearer understanding of inclusive design, let's delve into specific examples within UI/UX design: (from left to right) Alt text, keyboard navigation, Apple's accessibility For those familiar with HTML/CSS, ever wondered the purpose of for images? It's not just a fallback for when images don't load; it's also the key to providing image descriptions for those visually impaired navigating websites with screen readers. Ensuring that your website is navigable using only a keyboard is crucial. Keyboard accessibility not only enhances the experience for keyboard-only users but also benefits other groups, including screen reader users, individuals with low vision, those with motor impairments or cognitive disabilities, and users who prefer keyboard shortcuts or alternative keyboards. Apple has excelled in incorporating accessibility into its design, with a user interface and experience that cater to individuals with diverse impairments. Notable features include the ability to easily adjust font sizes for improved legibility, the option to tap words for spoken feedback, voice control tailored for those with physical impairments, and a range of other inclusive design elements. You can explore all these features here . These examples represent just a few instances of inclusive design within UI/UX. The Web Content Accessibility Guidelines (WCAG) outline the principles and techniques for enhancing the accessibility of web content, ensuring it is more accommodating to individuals with disabilities. Now that we've explored the fundamentals of inclusive design, let's take a deeper dive into its application in mobility platforms, a core focus of our company. Moji, over to you. Ai has set the stage with the ins and outs of inclusivity, and now it's my turn to zoom in on how we make that happen in the world of moving around. Hi, I'm Moji , and and I'm all about making sure our designs help everyone get where they're going, no matter who they are. I believe as designers, we have the capability, and responsibility, to ensure the products and solutions we develop cater to a wide spectrum of users - in terms of ethnicity, language, age, gender, physical ability, and cultural background. Looking into how the big players nail this isn't just interesting, it helps us do our job better, and it helps us figure out better ways to design more inclusive tech products. Take Google Maps as an example. This app is a daily go-to for many of us for getting around. How Google Maps Sets the Standard for Accessible App Design Not only does Google Maps offer real-time GPS and transit info, it's also designed to cater to a wide-reaching audience. For those with sight impairments , Google Maps has a voice-guided navigation system . It'll tell you when you're about to make a turn, if there's heavy traffic ahead and any disruptions that might mess up your journey. This spoken assist feature makes life easier for anyone who needs audio cues. Google Maps' latest update brings some new features specifically aimed at making the app more accessible and inclusive. The Immersive View for Routes gives a detailed look at the route you’ll be travelling, whether that’s via car, foot or on a bike. Awesome for those with mobility challenges. And, because Google Maps is used all over the world, they’ve made sure it’s available in over 40 languages. This not only makes the app more accessible globally, but also boosts user satisfaction, since people prefer info in their native tongue. Challenges of Creating Globally Accessible App with RTL Language Support Transitioning to a more focused exploration of language and locale considerations in app design, I'll hand the reins over to our teammate Az. She's been at the forefront of tackling the ground-level challenges of designing a globally-accessible app, particularly when it comes to ensuring seamless compatibility for RTL (Right-to-Left) language speakers like those who speak Arabic. Over to you Az. Hi, now it’s my turn; I’m Az from the UI/UX team. While working on RTL (Right To Left) design for a project, I noticed something. And that is: To Promote Diversity, It's Crucial to Remain Mindful of Aspects One May Not Be Familiar With It is important to pick up on details of what one would ‘take for granted' rather than focusing on creating the unprecedented. I discovered many points that were previously unknown to me or learned about them for the first time in this project. The term RTL stands for “Right To Left”, referring to languages that are read from right to left. As the text direction is different from what we are used to in Japanese or even English, the way the eyes move also differs. The layout will also be adjusted to align from right to left. Nested components such as the position of icons and texts, action buttons’ direction, the badge position are also inverted. However, the icons for "the headset" and "the location" are not inverted, as they are physical items and a universal design concept. Not only the display but also the layout itself needs to be inverted. The order of the indicators changes according to the direction. There are some exceptions even in form-related elements. When a numerical sequence has a specific meaning, such as a phone number or a credit card number, it should not be inverted. A proper noun such as “KINTO” will not be inverted We have introduced you to examples in KTC, but you can find additional concrete examples in the Apple Human Interface Guideline and the Google Material Design . I think you noticed from this article that the members in our UIUX team come from diverse backgrounds. That’s why I can improve my knowledge, perspectives, and insights that one may not notice alone. Ai mentioned the necessity of “diversity” through comparison with real-world spaces based on her architectural knowledge. Moji, with her strong research skills and extensive knowledge, provided insights into what is happening in familiar services. Tim, who makes an appearance on another article, is also a reliable member capable of handling a wide range of tasks from project execution to frontend development. By building upon the "taken for granted" knowledge that each of us possess, we will continue to develop services that everyone can comfortably use in the future.
アバター
Flutter Webで単体テストしてますか? こんにちは。Woven Payment Solution開発グループの大杉です。 私たちのチームでは、 Woven by Toyota において Toyota Woven City で使われる決済システムの開発を行っており、普段はKotlin/Ktorでバックエンド開発とFlutterによるWeb/モバイルのフロントエンド開発をしています。 Flutter Webでは、Web固有のパッケージを使用しているとテスト実行でエラーになってしまうことがあります。 そのため、今回の記事ではFlutter Webのコードをテスタブルな状態に維持するために工夫していることを、特に単体テストにフォーカスしてまとめたいと思います。 なお、これまでのフロントエンド開発ストーリーについては過去の記事を参照していただけると幸いです。 KotlinエンジニアがFlutterに入門して1ヶ月でWebアプリケーションを作った話 バックエンドエンジニアたちが複数のFlutterアプリを並行開発していく中で見つけたベストプラクティス Flutter Webとは 初めに、Googleによって開発が進められているクロスプラットフォーム開発のフレームワークであるFlutterの内、 Webアプリ開発に特化したフレームワーク のことです。 Flutterの開発言語であるDartは、ソースコードを事前にJavaScriptに変換し、HTML、Canvas、CSSを使用して描画処理を行うことができるので、モバイルアプリで開発したコードをそのままWebアプリに移植することができます。 Flutter Webの実装方法 基本的な実装は、モバイルアプリ開発と同じ方法で実装できます。 一方で、DOM操作やブラウザAPIにアクセスしたい場合はどうすればいいでしょうか? これもDartの組み込みパッケージで dart:html などのWebプラットフォーム向けのパッケージが用意されています ^1 。例えば、ファイルダウンロード機能もJSによる一般的なWebアプリ開発と同じように実装することができます。 :::message 記事執筆時のSDKバージョンは、Flutter v3.16, Dart v3.2を対象としています。 ::: 下記のWidgetは、カウントアップした数値をテキストファイルとしてダウンロードするという何に使うかわからない機能を持ったサンプルアプリです。Floating Buttonをクリックするとテキストファイルのダウンロードが行われます。 import 'dart:html'; import 'package:flutter/material.dart'; class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ const Text( 'You have pushed the button this many times:', ), Text( '$_counter', style: Theme.of(context).textTheme.headlineMedium, ), IconButton( onPressed: _incrementCounter, icon: const Icon(Icons.add), ) ], ), ), floatingActionButton: FloatingActionButton( onPressed: () { AnchorElement(href: 'data:text/plain;charset=utf-8,$_counter') ..setAttribute('download', 'counter.txt') ..click(); }, tooltip: 'Download', child: const Icon(Icons.download), ), ); } } Flutter Webのコードを単体テストする 先ほどのサンプルコードのテストコードを以下のように用意しました(ほとんど flutter create して出力されたときのままです)。 import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:sample_web/main.dart'; void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async { await tester.pumpWidget(const MyApp()); expect(find.text('0'), findsOneWidget); expect(find.text('1'), findsNothing); await tester.tap(find.byIcon(Icons.add)); await tester.pump(); expect(find.text('0'), findsNothing); expect(find.text('1'), findsOneWidget); }); } 次のテストコマンドを実行するかVS CodeのTestingタブから上記のテストコードを実行してみましょう。 $ flutter test このままテストを実行すると、次のようなエラーが出るかと思います。 Error: Dart library 'dart:html' is not available on this platform. // 省略 lib/utils/src/html_util.dart:4:3: Error: Method not found: 'AnchorElement'. AnchorElement(href: 'data:text/plain;charset=utf-8,$data') どうやら dart:html のインポートに何か問題があるようです。 プラットフォームごとのDartコンパイラ 公式ドキュメント を確認すると、Dartコンパイラの実行には、 JITコンパイラを行うDart VMとマシンコードを生成するAOTコンパイラの Nativeプラットフォーム DartコードをJSにトランスパイルする Webプラットフォーム の2つがあることがわかります。また、それぞれのプラットフォームで利用できるパッケージが一部異なるようです。 プラットフォーム 利用できるパッケージ Native dart:ffi, dart:io, dart:isolate Web dart:html, dart:js, dart:js_interopなど つまり、前述のテストはVM上で実行されていたため、 dart:html を利用できなかったということがわかりました。 Webプラットフォームパッケージのインポートエラーを回避する方法として、テスト実行時にプラットフォームを指定する方法があります。 下記のオプションをつけてコマンド実行することで、テストをChrome上で(つまり、Webとして)実行することを指定できます ^2 。 $ flutter test --platform chrome :::message オプションなしテストがVM上であることは、 flutter test --help --verbose で確認できました。 --platform Selects the test backend. [chrome] (deprecated) Run tests using the Google Chrome web browser. This value is intended for testing the Flutter framework itself and may be removed at any time. [tester] (default) Run tests using the VM-based test environment. ::: Flutter WebのテストコードはChromeで実行すべきか? ブラウザAPIの利用はWebアプリを開発する上で避けられないことだと思いますが、Flutter WebのテストコードはChrome上で実行すべきなのでしょうか? 個人的な意見ですが、なるべくChromeを使わない方が良いというのが私の考えです。 理由としては、 テスト実行の際にバックグラウンドでChromeを起動する必要があるため、テストの起動時間が増大してしまう CI環境にChromeをインストールする必要があり、CI環境のコンテナサイズが大きくなる。または、コンテナのセットアップに時間がかかってしまう ことが想像でき、CI環境の金銭的コストがかなり増えてしまうことが考えられます(もちろん、ローカルでささっと確認する程度や富豪な方でしたら問題ないです)。 実際に、オプションでプラットフォームを指定しない標準ケース(Native)とChromeを指定したケース(Web)を比較したローカル環境の実行結果を載せました。 プラットフォーム プログラム実行時間(秒) トータルテスト実行時間(秒) Native 2.0 2.5 Web 2.5 9.0 上記表から、Webの方は実際にテストの起動に大幅に時間がかかるようになりました。さらに、テスト実行時間も25%ほど増大していることもわかるかと思います。 ![tester](/assets/blog/authors/osugi/20240301/annoying.png =400x) Webプラットフォーム依存のコードは分離しよう Webプラットフォームを指定しないで前述のエラーを回避するにはどうしたら良いでしょうか? 実は、Dartにはパッケージを条件でインポート・エクスポートする方法と、プラットフォームがWebかNativeかを判定するためのフラグも用意されています ^3 。 フラグ 説明 dart.library.html Webプラットフォームかどうか dart.library.io Nativeプラットフォームかどうか これらを駆使することでエラーを回避することができます。 まずは、以下のようにしてWeb用・Native用のダウンロード機能モジュールを用意し、前述のWebパッケージ使用箇所をテスト対象のコードから分離しましょう。 import 'dart:html'; void download(String fileName, String data) { AnchorElement(href: 'data:text/plain;charset=utf-8,$data') ..setAttribute('download', fileName) ..click(); } void download(String fileName, String data) => throw UnsupportedError('Not support this platform'); そして、上記モジュールのインポートをプラットフォームごとに切り替える方法は以下のようになります。 import 'package:flutter/material.dart'; - import 'dart:html' + import './utils/util_io.dart' + if (dart.library.html) './utils/util_html.dart'; class MyHomePage extends StatefulWidget { // 省略 } class _MyHomePageState extends State<MyHomePage> { // 省略 @override Widget build(BuildContext context) { return Scaffold( // 省略 floatingActionButton: FloatingActionButton( onPressed: () { - AnchorElement(href: 'data:text/plain;charset=utf-8,$_counter') - ..setAttribute('download', 'counter.txt') - ..click(); + download('counter.txt', _counter.toString()); }, tooltip: 'Download', child: const Icon(Icons.download), ), ); } } エクスポートをする場合は、別途 util.dart などの仲介ファイルを用意してWidget側からインポートすることになると思います(ここでは省略します)。 export './utils/util_io.dart' if (dart.library.html) './utils/util_html.dart'; 以上で、Web依存のコードによるエラーを回避してNativeプラットフォーム上でテストを実行することができるようになりました。 Webプラットフォーム依存の外部パッケージにはNativeプラットフォーム用のスタブも作ろう 私たちのシステムは認証基盤にKeycloakを採用しています。 Flutter Webアプリ上でKeycloakの認証をするために以下のパッケージを使用しています。 @ card リンクを開いてもらえるとわかると思いますが、このパッケージはWebのみをサポートしています。 このパッケージのおかげで楽に認証処理を実装することができたのですが、認証モジュールという特性上そのインターフェースは色々なところで利用されるため、APIコールなど認証情報を必要とするようなWidgetがすべてWebプラットフォーム依存となってしまい、CIでテストできなくなる状況になってしまったことがありました(この間はローカルで --platform chrome オプションでテストして全PassしたらOKという性善説運用をしていました)。 ちなみに、このパッケージをインポートすると以下のエラーがテスト実行時に発生します。 Error: Dart library 'dart:js_util' is not available on this platform. そこで、前述のインポート分離と同様な処置を外部パッケージにも行っていくのですが、ここではエクスポートを使ったパターンで実践していきたいと思います。手順は以下となります。 1. 仲介パッケージの作成 ここでは例として inter_lib というパッケージをサンプルコードのパッケージ内に作成しています。 flutter create inter_lib --template=package 実際のプロダクトコードでは、外部パッケージに準じたコードをプロダクトコード内に混入させないため、プロダクトとは別のパッケージを作成して外部パッケージを仲介させています。 Melos を使うと簡単にマルチパッケージ開発ができるのでおすすめです。 2. Nativeプラットフォーム用のスタブの作成 keycloak_flutter のスタブを作るため、Githubのリポジトリを参照してインターフェースを模擬します(ライセンスの確認は適宜お願いします)。 プロダクトコード上で使用しているクラスやメソッドはすべてが必要になります。 @ card 作成したファイルは以下のようになっています。 src ディレクトリ以下の stub_ のプレフィックスがついているものが外部パッケージのインターフェースを模擬したものです。 inter_lib ├── lib │ ├── keycloak.dart │ └── src │ ├── stub_keycloak.dart │ ├── stub_keycloak_flutter.dart │ └── entry_point.dart また、 entry_point.dart は実際の外部パッケージと同じものをエクスポートするように定義しました(実際にはプロダクトコード内で使用しているインターフェースだけで十分です)。 export './stub_keycloak.dart' show KeycloakConfig, KeycloakInitOptions, KeycloakLogoutOptions, KeycloakLoginOptions, KeycloakProfile; export './stub_keycloak_flutter.dart'; この inter_lib をパッケージとして内部公開するため、以下のようにエクスポートの設定をします。 library inter_lib; export './src/entry_point.dart' if (dart.library.html) 'package:keycloak_flutter/keycloak_flutter.dart'; 3. 仲介パッケージを pubspec.yaml の dependencies へ追加 pubspec.yaml に inter_lib への相対パスを追加します。 // 省略 dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.2 + inter_lib: + path: './inter_lib' // 省略 そして、元々外部パッケージを参照していたところを inter_lib に置き換えます。 - import 'package:keycloak_flutter/keycloak_flutter.dart'; + import 'package:inter_lib/keycloak.dart'; import 'package:flutter/material.dart'; import 'package:sample_web/my_home_page.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); final keycloakService = KeycloakService( KeycloakConfig( url: 'XXXXXXXXXXXXXXXXXXXXXX', realm: 'XXXXXXXXXXXXXXXXXXXXXX', clientId: 'XXXXXXXXXXXXXXXXXXXXXX', ), ); await keycloakService.init( initOptions: KeycloakInitOptions( onLoad: 'login-required', enableLogging: true, checkLoginIframe: false, ), ); runApp( const MyApp(), ); } 以上、Webプラットフォーム依存パッケージのNativeプラットフォーム用スタブの作成フローでした。これでテストをVM上で実行できるようになります。 この方法は今回の例として用いたkeycloak_flutter以外にももちろん適用できます。 ![successful people](/assets/blog/authors/osugi/20240301/success.png =480x) まとめ 今回の記事では、Flutter Webのコードをテスタブルな状態に維持するために単体テストで工夫していることをまとめました。 Dartの実行環境には、WebプラットフォームとNativeプラットフォームがある flutter test はNativeプラットフォーム実行であり、 dart:html などのWebプラットフォーム用パッケージを使っているとエラーとなってしまう dart.library.io , dart/library/html のフラグを活用して、プラットフォームごとに実パッケージとスタブを切り替える実装をすると幸せになれる
アバター
Hello, I am _awache ( @_awache ), and I do DBRE at KINTO Technologies (KTC from now onwards). KTC operates a large number of databases such as Amazon Aurora on Amazon Web Services (hereinafter abbreviated as AWS) as a foundation for providing mobility services. It established the Database Reliability Engineering (hereinafter abbreviated as DBRE) organization and is implementing initiatives to balance business agility and governance. In this article, I will talk about why KTC needs DBRE. About Database Reliability Engineering (DBRE) DBRE stands for Database Reliability Engineering. It is responsible for using an approach that combines the best practices of software engineering and database management. Our main jobs are: Defining and measuring SLO/SLI and making an approach to a development organization accordingly Increasing productivity through automation and autonomy Increasing the uptime of backup, restore, and other services Database security guarantee and governance control Cross-functional collaboration with specialists from other disciplines These roles can be summed up as ensuring the reliability of services by using specialized knowledge and decisions on databases. Do Companies Need DBRE? The term "DBRE" may seem very appealing to some people. However, it is difficult to achieve sustainable results without thinking the reasons why it is necessary in an organization. The rapid growth of AWS and other public cloud services, the evolution and widespread acceptance of DevOps and SRE principles, coupled with the progress in AI technology, have collectively established a robust foundation. This foundation empowers individuals to address problems up to a certain complexity level through Cloud utilization. Consequently, the demand for specialized knowledge in database engineering is diminishing. On the other hand, the basic approach to databases has not changed even now. Separate environment Manage configuration Measure performance Backup/Restore Security guarantee, etc. Simply put, it can be said that it's the environment surrounding databases that has changed . You might also want to consider introducing DBRE at your company if you decide it is necessary given the changes in the times. Why KTC Needs DBRE Here's an explanation of why KTC is adopting DBRE practices. The relationship between software engineers and database administrators had changed The roles of software engineers and database administrators are clearly separated in this age When the company still focused on on-premises configurations, software engineers and database administrators generally had distinct roles and worked in their respective areas of expertise. For example, I think there were classifications like these: Software Engineering Maintaining service uptime and accelerating its growth Extracting necessary data at users' requests Tuning that does not require changes to the database DDL such as query changes Adapting to application according to requests from database administrators Database Administration Maintaining database uptime The major difference between the two is the speed and expertise in responding to requests and users' needs. Because software engineers are closer to the service provider side, they need to respond as quickly as possible to meet needs. Since database administrators focus on the database rather than on services, they use their expertise to solve various issues at the latest even if they respond more slowly. It is like the following figure. ![Relationship1](/assets/blog/authors/_awache/20231211/関係性1.jpg =500x) In an organization like this, the database administrator finds issues throughout the organization and solves them. The rise of public cloud services has decreased work done by database administrator and expanded the area of software engineers The rise of public cloud services such as AWS has drastically changed the roles of both sides. It can be said that the role of the database administrator has been drastically reduced because public cloud services can maintain database uptime. On the other hand, some of the jobs that database administrators were responsible for are done by database administrators and software engineers, specifically: Separate environment Manage configuration Measure performance Backup/Restore Security and Governance Control Software engineers in the workplace are now required to do these things. Because of that, there are times when the database does not get enough attention. ![Relationship2](/assets/blog/authors/_awache/20231211/関係性2.jpg =500x) KTC started facing issues in this regard. In order to keep accelerating business growth, software engineers must be able to focus on business growth. In today's world of cloud utilization, DBRE must be a hub with public cloud services in order for software engineers to focus on business activities. The Key Roles Required of DBRE Maintaining service uptime using databases Making engineers in the workplace more productive Handling database security Protecting the database from internal and external factors By fulfilling these roles, DBRE accelerates the continued growth of the company. ![Relationship3](/assets/blog/authors/_awache/20231211/関係性3.jpg =500x) The following chapters provide more information on each role. The Roles of DBRE in the Cloud Era Maintaining service uptime using databases Generally, a properly functioning database is required for a service to run properly. In other words, database downtime directly leads to service downtime. In order to maintain service uptime, the database must be restored correctly, appropriately, and quickly. So what DBRE needs is the skills to keep the database running on the cloud. king engineers in the workplace more productive Promoting standardized operation of a database can significantly contribute to companies. Examples include using a platform that provides company guidelines, automatically generating database documents such as ER diagrams, and automating routine operations. DBRE also plays an important role in validating new features and applying them to the company, addressing application bottlenecks such as slow queries, and troubleshooting. These do not scale even if only DBRE does them. DBRE has to work with much less resources than software engineers. It is important to note that outputs from DBRE go back to the software engineers and can be handled by anyone. Handling database security The database becomes more important as the business grows. When the database becomes more valuable, it is constantly targeted. A data leak can cause financial losses and tarnish the company's reputation. It is necessary to protect the database from risks like that for the company to keep growing. For that reason, it is important that DBRE implements database security measures as a business unit. ![ChangeinTimeandsValue](/assets/blog/authors/_awache/20231211/時間と価値の変化.png =500x) Protecting the database from internal and external factors Data is easily influenced by changes in external factors. Because of that, database operation requirements become more strict over time. In particular, companies have to address changes in governments, regulations, public opinion, and other factor outside of the company's or people's control. For example, the Personal Information Protection Act and other laws get revised regularly, and the penalties tend to get more strict each time. If each service individually addresses influences by external factors, it presents financial risks, the risk of a leak, and other risks. DBRE is required to properly understand the risks of external factors and implement optimal governance control across all databases in the company. KTC DBRE's vision At KTC, DBRE is a cross-functional organization. It provides value by having our outputs reflected on the business. I think that having a cross-functional organization without knowing how to leverage it is the same as paying taxes and not understanding where your money goes. It is important to know how to positively affect the business. These days, businesses change too fast to be handled with just rules and reviews. It is important that DBRE uses its knowledge of databases to contribute to engineers in the workplace and maintain the reliability of KTC as a company. For that reason, we try to solve database issues through engineering to the best of our abilities. We implement governance control in services and positively impact the business by working together with engineers in the workplace and quickly solving issues without being restricted by rules. Conclusion The Roles of KTC DBRE Provide an environment in which engineers in the workplace can focus on growing the business. The Key Roles Required of KTC DBRE Maintaining service uptime using databases Making engineers in the workplace more productive Handling database security Protecting the database from internal and external factors By fulfilling these roles, DBRE accelerates the continued growth of KTC. It is required to positively influence the business by working together with engineers in the workplace and quickly solving issues by focusing on these roles without being bound by rules. Do you want to discuss DBRE with us? We have just starting doing DBRE. We are still doing trial and error to see why we are doing DBRE, what we want to accomplish, and we will do it. By having frank discussions on what we are doing and what we want to do, we can expand our horizons. We also want to talk about our efforts to receive a lot of input. If you are interested, please send us a DM on Twitter. We are Hiring I think recruiting DBRE team members is a huge challenge. If you are interested in our activities, do not hesitate to send your application through our recruitment page . We're also open to casual conversations with anyone who wants to chat with us. We're also planning to organize events such as DBRE meetups and collaborate with companies that follow DBRE practices. We look forward to you joining us when that happens!
アバター
はじめに 私は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!
アバター