KINTOテクノロゞヌズのブログ - TECH PLAY

TECH PLAY

KINTOテクノロゞヌズ

KINTOテクノロゞヌズ の技術ブログ

å…š1123ä»¶

My name is Ryomm and I work at KINTO Technologies. I am developing the app my route (iOS). Today I will explain how to create a reference image for Snapshot Testing in any directory. Conclusion verifySnapshot(of:as:named:record:snapshotDirectory:timeout:file:testName:line:) You can specify the directory if you use this method. Background Recently, I wrote an article about introducing Snapshot Testing. However, after running it for a while, the number of test files has increased significantly, making it very difficult to find the specific test file I need. ![Large number of SnapshotTesting files](/assets/blog/authors/ryomm/2024-04-26/01-yabatanien.png =150x) Large number of Snapshot Test files So I decided to organize the Snapshot Testing files into appropriate subdirectories, but the method assertSnapshots(of:as:record:timeout:file:testName:line:) in the Snapshot Testing library pointfreeco/swift-snapshot-testing does not allow specifying the location for creating reference images. The existing directory structure related to Snapshot Testing looks as follows: App/ └── AppTests/ └── Snapshot/ ├── TestVC1.swift ├── TestVC2.swift │ └── __Snapshots__/ ├── TestVC1/ │ └── Reference.png └── TestVC2/ └── Reference.png When test files are moved to a subdirectory, the method mentioned above creates a directry __Snapshots__ within that subdirectory. Inside this directory, it creates a directory with the same name as the test file which contains the reference images. App/ └── AppTests/ └── Snapshot/ ├── TestVC1/ │ ├── TestVC1.swift │ └── __Snapshots__/ │ └── Reference.png ← Created here 😕 │ └── TestVC2/ ├── TestVC2.swift └── __Snapshots__/ └── Reference.png ← Created here 😕 As part of the existing CI system, the entire directory App/AppTests/Snapshot/__Snapshots__/ is mirrored to S3, so I do not want to change the location of the reference images. The target directory structure is as follows: App/ └── AppTests/ └── Snapshot/ ├── TestVC1/ │ └── TestVC1.swift ├── TestVC2/ │ └── TestVC2.swift │ └── __Snapshots__/ ← I want to put reference images here 😣 ├── TestVC1/ │ └── Reference.png └── TestVC2/ └── Reference.png Specify the Directory for Reference Images and Run a Snapshot Test verifySnapshot(of:as:named:record:snapshotDirectory:timeout:file:testName:line:) By using the method, you can specify the directory. The three methods provided in Snapshot Testing have the following relationships: public func assertSnapshots<Value, Format>( Matching value: @autoclosure () throws -> Value, As strategies: [String: Snapshotting<Value, Format>], record recording: Bool = false, timeout: TimeInterval = 5, file: StaticString = #file, testName: String = #function, line: UInt = #line ) { ... } ↓Execute forEach on the comparison formats passed to as strategies public func assertSnapshot<Value, Format>( Matching value: @autoclosure () throws -> Value, As snapshotting: Snapshotting<Value, Format>, Named name: String? = nil, record recording: Bool = false, timeout: TimeInterval = 5, file: StaticString = #file, testName: String = #function, line: UInt = #line ) { ... } Run the following and use the returned values to perform the test. verifySnapshot(of:as:named:record:snapshotDirectory:timeout:file:testName:line:) You can check the actual code here . In other words, as long as the same thing is done internally, it is perfectly fine to use verifySnapshot(of:as:named:record:snapshotDirectory:timeout:file:testName:line:) directly! Boom! extension XCTestCase { var precision: Float { 0.985 } func testSnapshot(vc: UIViewController, record: Bool = false, file: StaticString, function: String, line: UInt) { assert(UIDevice.current.name == "iPhone 15", "Please run the test by iPhone 15") SnapshotConfig.allCases.forEach { let failure = verifySnapshot( Matching: vc, as: .image(on: $0.viewImageConfig, precision: precision), record: record, snapshotDirectory: "Any path", file: file, testName: function + $0.rawValue, line: line) guard let message = failure else { return } XCTFail(message, file: file, line: line) } } } For our app my route , I initially passed only a single value to strategies , so I omitted the looping process with strategies . Now, although I was able to specify the directory, to follow the existing Snapshot Testing pattern, I want to create a directory based on the test file name and place the reference images inside it. The path passed to verifySnapshot(of:as:named:record:snapshotDirectory:timeout:file:testName:line:) needs to be an absolute path, and since the development environment varies among team members, it is necessary to generate the path according to each environment. Although the code turned out to be quite straightforward and cute, I implemented it as follows. extension XCTestCase { var precision: Float { 0.985 } private func getDirectoryPath(from file: StaticString) -> String { let fileUrl = URL(fileURLWithPath: "\(file)", isDirectory: false) let fileName = fileUrl.deletingPathExtension().lastPathComponent var separatedPath = fileUrl.pathComponents.dropFirst() // Here it becomes a [String]? template // Delete the path after the Snapshot folder let targetIndex = separatedPath.firstIndex(where: { $0 == "Snapshot" })! separatedPath.removeSubrange(targetIndex+1...separatedPath.count) let snapshotPath = separatedPath.joined(separator: "/") // Since we pass it as a String to verifySnapshot, I will write it as a String without converting it back to a URL. return "/\(snapshotPath)/__Snapshots__/\(fileName)" } func testSnapshot(vc: UIViewController, record: Bool = false, file: StaticString, function: String, line: UInt) { assert(UIDevice.current.name == "iPhone 15", "Please run the test by iPhone 15") SnapshotConfig.allCases.forEach { let failure = verifySnapshot( matching: vc, as: .image(on: $0.viewImageConfig, precision: precision), record: record, snapshotDirectory: getDirectoryPath(from: file), file: file, testName: function + $0.rawValue, line: line) guard let message = failure else { return } XCTFail(message, file: file, line: line) } } } This way, we can keep the reference images in their original location, while organizing the Snapshot Testing into subdirectories. This resolves the inconvenience of not being able to find the files when you want to update a Snapshot Test. There is still room for improvement, so I aim to make our development experience even more enjoyable ♪
はじめに こんにちは。 KINTOテクノロゞヌズ モバむルアプリ開発グルヌプの䞭口です。 iOSチヌムのチヌムリヌダヌずしおこれたでにチヌムビルディングに関する蚘事を公開しおおりたすので、ご興味あればぜひご䞀読ください。 振り返り䌚がマンネリ化したのでプロファシリテヌタヌを呌んでみた 180床フィヌドバックずっおもおすすめです 先日、 【たぶん䞖界最速開催『アゞャむルチヌムによる目暙づくりガむドブック』ABD読曞䌚】 こちらのむベントに参加しおきたした。 このむベントの参加目的は、䞻に以䞋の3点です。 アクティブ・ブック・ダむアロヌグ®以䞋「ABD」ずいう。を䜓隓しおみたかった。 むベントで扱う本である 「アゞャむルチヌムによる目暙づくりガむドブック」 に興味があった。 著者である「小田䞭 育生おだなか いくお」さんにお䌚いしおみたかった。 その䞭でも、ABDずいう読曞法は初めおの経隓で非垞ためになるものでした。この読曞法をもっず倚くの方に知っおもらいたいず思ったので本蚘事ではABDに関する内容を䞭心に玹介させおいただきたす。 諞泚意 本蚘事で掲茉する人物や資料は、党お開催者様及びご本人様より掲茉蚱可をいただいおおりたす。 むベントに぀いお こちらのむベントは2024/07/10(æ°Ž)に開催されたむベントで、『アゞャむルチヌムによる目暙づくりガむドブック』を「刊行前に著者ず䌚えるABD読曞䌚」ずしお開催されたした。 募集ペヌゞが公開され、その日䞭に応募枠の15名を突砎しおしたう人気むベントでしお、参加できたこずが非垞に幞運だったず思いたす。 むベントのこずを玹介しおくれた匊瀟コヌポレヌトITグルヌプの きんちゃん にはずおも感謝です 本に぀いお 本の内容に぀いおは、実際に読んでもらえればず思いたすのでここでは倚くは語りたせんが、むベントのオヌプニングでいくおさんが玹介されおいた内容を共有させおいただきたす。 䞖の䞭的に目暙蚭定があたり奜たれおいない傟向があるように感じる。 しかし、みんなが真剣に目暙に向き合いそれを達成できるようになれば䞖界は良くなっおいくず思う。 だから、いい目暙を䜜れるこずはずおも倧事である。 䞀方で、目暙を䜜るこずも倧事だが、それをいかに達成しおいくかはもっず倧事である。 この本では、目暙䜜りに関しおは初めの2割皋床で、 残りは目暙を達成する方法をアゞャむルの芁玠を取り入れ぀぀玹介する本ずなっおいる。 たた、目暙ずセットで語られるこずの倚い人事評䟡に぀いおは曞いおいないが、 8名の方にコラムを曞いおいただいおおり、その䞭で評䟡の郚分も良い感じに補完されおいるので、 コラムもぜひ読んでほしい いくおさんによるオヌプニングの様子 いくおさんに぀いお いくおさんずは、これたで面識は無いのですが、䞋蚘のLTや蚘事を拝芋しお存じおおりたした。 『Keeper of the Seven Keys Four Keysずあず3぀ 』 こんな゚ンゞニアリングマネヌゞャだから仕事がしやすいんだなぁず思う10個のこず 誇り高き「マネヌゞャヌ」を党うするために。“理想のEM”小田䞭氏を支えた珠玉の5冊 開発生産性や゚ンゞニアリングマネヌゞャヌに関する考え方、及び読曞に察する向き合い方など、ずおも参考になる郚分が倚く、ぜひ䞀床お䌚いしおお話ししおみたいず思っおいたした。 しかし圓日は簡単な挚拶はさせおいただいたものの、しっかりずお話できる時間を䜜るこずができたせんでした。 非垞に残念でしたが、今埌の機䌚に期埅したいず思いたす。 ABDに぀いお こちら ABDの公匏サむト より匕甚させおいただきたす。 ABDずは䜕か 開発者竹ノ内 壮倪郎さんによる説明 ABDは、読曞が苊手な人も、本が倧奜きな人も、 短時間で読みたい本を読むこずができる党く新しい読曞手法です。 冊の本を分担しお読んでたずめる、発衚・共有化する、気づきを深める察話をするずいうプロセスを通しお、 著者の䌝えようずするこずを深く理解でき、胜動的な気づきや孊びが埗られたす。 たたグルヌプでの読曞ず察話によっお、䞀人䞀人の胜動的な読曞䜓隓を掛け合わせるこずで孊びはさらに深たり、 新たな関係性が育たれおくる可胜性も広がりたす。 ABDずいう、䞀人䞀人が内発的動機に基づいた読曞を通しお、 より良いステップを螏んでいくこずを切に願っおおりたす。 流れ コ・サマラむズ 本を持ちよるか冊の本を裁断し、担圓パヌトでわりふり、各自でパヌトごずに読み、芁玄を䜜りたす。 リレヌ・プレれン リレヌ圢匏で各自が芁玄文をプレれンしたす。 ダむアログ 問いを立おお、感想や疑問に぀いお話しあい、深めたす。 ABDの魅力 短時間で読曞が可胜 短時間で読曞ができお、著者の想いや内容を深く理解できるので、本を積ん読しおいる方にはピッタリです。 サマリヌが残る アクティブ・ブック・ダむアロヌグ®埌にサマリヌが残るので、芋盎しお埩習したり、本を読んでいない人にも芁点を䌝えやすくなりたす。 蚘憶の定着率の高さ 発衚を意識しおむンプットしおたずめた埌、すぐにアりトプットをしお意芋亀換をするので、深く蚘憶に定着したす。 深い気づきず創発 倚様な人どうし、それぞれの疑問や感想をもっお察話するこずで、深い孊びの創発が生たれたす。 個人の倚面的成長 集䞭力、芁玄力、発衚力、コミュニケヌション力、察話力など、今の時代に必芁なリヌダヌシップを同時に磚けたす。 共通蚀語が生たれる 同じメンバヌで行うこずで、同じレベルの知識を共有できるため、共通蚀語を䜜るこずができたす。 コミュニティ䜜り 本が冊あれば仲間ずの察話や堎を䜜れるので、気軜なコミュニティ䜜りに最適です。 䜕より楜しい 本を読んで感動したり孊んだ熱量をその堎ですぐに共有できるので、豊かな孊びが生たれ、䜕より読曞が楜しくなりたす。 個人的には「1. 短時間で読曞が可胜」、「6. 共通蚀語が生たれる」、「7. コミュニティ䜜り」、「8. 䜕より楜しい」が䟡倀が高いなず感じたした。 圓日の様子 本が裁断され15パヌト分に分かれおいたす。 こんな光景始めみたした笑 裁断された本 コ・サマラむズ(20分) 各自が担圓パヌトを読み、芁玄を䜜成したす。 20分で本を読みA4甹箙3枚にたずめるのですが、これがなかなか難しかったです。。。 時間に远われすぎおいお撮圱を忘れおしたいたした。 リレヌ・プレれン(1分30秒/人×1名) 各自が芁玄したものを、壁に貌り付けたす。 みなさんが芁玄した資料 そしお芁玄したものを1分30秒で発衚したす。 みなさん、芁玄もプレれンもずおも玠晎らしかったです。 写真は私のプレれンの様子です。1分30秒ずいうすごく短い時間だったこずず緊匵で、䜕を話したか党く芚えおいたせん。。。 私の発衚の様子 ダむアログ(25分) ここでは、プレれンの䞭から3぀のパヌトを参加者でピックアップし、各グルヌプに分かれお深掘りを行いたした。 私はその䞭で「助け合えるチヌムになろう」のグルヌプに参加させおいただきたした。 グルヌプによる深掘りの様子 グルヌプ内にはスクラムマスタヌや゚ンゞニアリングマネヌゞャヌをされおいる方もおり、様々な意芋亀換をさせおいただきたした。 その䞭でも、「奜きなこず」は、埗意(十八番)/苊手(成長機䌚)関わらず䌞ばしおいくべきなので、奜きなこずに挑戊できるチヌム䜜りをしたいね、ずいう話題が印象的でした。 ABDを通しお本から孊んだこず 私自身はこれたで、目暙管理ずしお「OKR」(Objectives and Key Results)を甚いたこずがなかったのですが、OKRに関する理解が進みたした。 たた、目暙づくりにおいおは、いかに内発的動機によっおチヌムずしお目暙を立おるこずが重芁かを孊びたした。 そのためにも、トップダりンによる目暙蚭定を行うのではなく、チヌム間で議論を行なった䞊での目暙づくりが鍵ずなるこずが印象的でした。 たた、重芁なのは「目暙の達成」であり、「タスクの消化」ではないずいうこずも印象に残っおおりたす。 そのため「時には優先順䜍が䜎いタスクを捚おる勇気が必芁である」ずいう考えは、これたでの自分には無い考え方でした。 そしお、目暙達成のために「時間が無い」ずいうこずがあるかず思いたすが、それを 本圓に時間が無い 時間をかけお良いか分からない 意欲が湧かない ずいうように分解されおいるのも初めお聞きたした。 「本圓に時間が無い」ずいうのはむメヌゞしやすいのですが、「時間をかけお良いか分からない」、「意欲が湧かない」ずいうのは初めお聞きたしたが、経隓的に玍埗感がありたした。 こちらに関しおは、本に解決法なども蚘茉されおいたのであたらめお本を読んで埩習したいです。 感想 初めおABDを䜓隓いたしたしたが、刺激的でずおも楜しかったです。 圓日参加されおいたメンバヌが、題材の本に興味がある方ばかりだったので、プレれンやダむアログにおいおも建蚭的な堎であり孊びも倚かったです。 匊瀟でもABDを実践しおみたいず思ったので、興味があるメンバヌを募っおやっおみたいな、ず考えおいたす。 䞀方で、䞋蚘に挙げるような理由から運甚の難易床はかなり高いのではないかず思いたした。 限られた時間内で進行する必芁があるためファシリテヌタヌのスキルが求められる。 コ・サマラむズが難しく、参加者により芁玄やプレれンのレベルに差が生じおしたいそう。 題材ずする本の遞定や、メンバヌ集めが難しそう。 私はこれたで䜕床か茪読䌚に参加したこずがあるのですが、「長期間の催しから生じる継続の負担」、「(茪読䌚の圢匏によりたすが)個人の䜜業負担」など、実際に行うには少々ハヌドルが高い読曞法だず感じおいたした。 䞀方でABDは、短時間で䞀気に終了できるので茪読䌚で感じおいたようなデメリットを解消できるずおも良い読曞法だず思いたす。 ただし、短時間が故に本の理解床が䞋がっおしたうずいう、トレヌドオフは生じおしたうかず思いたす。 「題材ずする本の遞定」や「参加メンバヌずの事前協議」をしっかり行なった䞊でどのような読曞法が良いのかは怜蚎の必芁があるず思いたした。
Sharing How Great Was Our Group Reading Session " Learning from GitLab: How to Create the World's Most Advanced Remote Organization ". Hello, I am Awache ( @_awache ). We were so fascinated by the book " {2 Learning from GitLab: How to Create the World's Most Advanced Remote Organization - How to use documents to achieve maximum results without an office ]( https://www.amazon.co.jp/dp/4798179426 ) " that we decided to hold a group reading session with both people from the company and from outside. In this article, I'd like to share our efforts with you. But first, let me announce our next get together: We will be hosting the ‘finale’ of the group reading session for " Learning from GitLab: How to Create the World's Most Advanced Remote Organization " A bit sudden maybe but it’s important. You can see the details below: Connpass: Grand Finale of the group reading session for " Learning from GitLab: How to Create the World's Most Advanced Remote Organization " Date and time: 18:00 - 21:00 (Opening at 17:40) Thursday, April 25, 2024 Event Type: Offline Venue: Muromachi Office, KINTO Technologies Corporation This event is intended for those who have read the book and participated in the previous group reading sessions of " Learning from GitLab: How to Create the World's Most Advanced Remote Organization - How to use documents to achieve maximum results without an office ", but it is also open to those who are currently reading it or plan to do so in the future. We will discuss how the group reading session was conducted in each of the companies, how was the reception, and gather insights from the book, aiming to create an open forum for all participants to engage in the discussions. There are still spots available, so if you are interested, please join us! We'd like to find ways for everyone to enjoy the session casually. (Though the irony is not lost on me that we will be meeting in person to discuss remote organizations lol) Common Challenges at Group Reading Sessions Ensuring continuous participation Regular gatherings are necessary to complete reading a book in a group setting. By dividing the book into reasonable portions and meeting once a week, it would take about 2 to 3 months. Dropping out in the middle It is always challenging to continue anything for long periods of time, so it’s natural that one by one the number of participants dwindle as the meetings progress. If we fail to keep the participants motivated, we may end up with a very lonely group reading session. Difficulty of joining in the middle Given the nature of book readings, the hurdle for participation typically rises in the middle stages. As a result, the number of participants is likely to decrease, with opportunities to increase the number of participants being very rare. Sustaining leadership Various burdens for the leader Pre-preparations Securing time for participants Facilitation These are not one-offs, but continues until the end of the book. It takes a lot of motivation to continue doing things alone Recognizing differences in reading speed and understanding among participants The speed and comprehension level of reading varies depending on the participant. Without recognizing this, the group reading session will end up with a lot of tedious time without much discussion. So taking all the above into account, it is quite challenging to finish a book in a group setting, isn't it? I myself have many times dropped out in the middle a book or couldn't read it until the end. However, this time, I really wanted to share the ideas of this book widely within the company and I was strongly motivated to finish it until the end . So, I was trying to figure out how to solve these issues. For example, I hypothesized that we could approach the issue effectively by creating an opportunity to conduct group reading sessions on the same subject in different ways at multiple locations beyond the boundaries of the company, not only by ourselves but involving others, and share our findings at the end of the session. However, there are limits to what I can do alone. I consulted with @soudai1025 -san, who is a technical advisor in our DBRE team, and with his cooperation, we decided to hold “A Sodai-Naru (Great) Group Reading Session.” Organizing The Reading Session Several companies: Using a kickoff meeting as a trigger Will set a time of about three months to hold a series of group reading sessions internally, After which findings will be shared together at the end We decided to divide our event in the above three-stages. You can check out our kickoff session on YouTube: https://www.youtube.com/watch?v=IBgmGtpW15Q How to Start a Group Reading Session I will briefly describe what I prepared for the group reading session after the kickoff was over. Gathering team members First of all, we gathered willing participants through internal open channels. We reached out to people interested in group reading sessions and waited for volunteers to raise their hands. As a result, we got 14 people interested! Transcription (Transcribing a book) I was determined to transcribe the book from the moment I decided to lead the group reading session. I think that the action of transcribing, which enables reading, writing, and reviewing simultaneously, is an excellent activity for quickly understanding the content of a book. However, this book is over 300 pages, so one needs determination! lol Purchasing books in bulk It is mentioned in our career website as well, but KINTO Technologies allows you to purchase the books you need. Since several of the 14 people did not have it yet, we used this program and purchased the books in bulk for those who didn’t. Thinking how to proceed with our in-house group reading session I seriously considered how we could ensure that everyone enjoys the session without feeling any pressure whenever they attend. I will introduce the specific actions later. While I was pondering this, I realized that time was passing by fast and our in-house group reading session was set to February. The In-house Group Reading Session Kickoff Working Agreement I shared with the participants a summary of what kind of atmosphere I would like to create. Here are the details: This session is designed with the aim of minimizing pressure on the participants: Follow up with each other even if someone did not read the book For the first 10 minutes, we'll have quiet reading time The main focus is on discussion , and the output is made public to create an atmosphere in which even those who are not actually participating can join in during the process. Summarize every output and make it available to everyone Record the session via Zoom and publish it (whenever possible) The same content can be read multiple times Do not interfere when other participants are speaking Be respectful and accepting of what participants say Stimulate free discussion Conduct discussions in breakout rooms of up to 4 people Conduct discussions in small groups reduces the psychological barrier to speaking up and allows each person to bring up what they want to discuss Do not refuse participation from ROMs (Read Only Members) When participating, communicate each ones’ situation to the rest of the participants to create an accepting atmosphere. Things like: I won’t be able to talk today Due to where I am working from today, I may not be able to talk much Everyone actively creates output Minutes of discussions are actively logged by those who are available (e.g., those who can’t speak that day) How we proceeded with the group reading session I still believe that a certain timeline is desirable for ongoing discussions. Even if you are a little late but want to join the group reading session, it may be psychologically difficult to do so if the session is in the middle of a heated discussion. On the other hand, if you have some idea of what you are doing, for example, you may be able to join in the middle of the session because it is now quiet reading time. That's why I decided to create a clear structure for us. Basic Format Quiet reading time (10 minutes) Discussion time (30 minutes) Content sharing (20 minutes) Content of the Discussions What I could relate to What I could not relate to What I want to put into practice at KINTO Technologies Perhaps the results of what was put into practice could be shared in the next session Discussion content output The agenda during the discussion is described in Google Slide After the discussion, everyone shares the topics that came up Selection of tools to use Gather Gather was chosen as the web meeting tool. Since our main focus was discussion, the idea was to engage with individuals who were comfortable talking with those attending. With Zoom, you have to make a breakout room every time, and it's hard to sort them out. Gather, a virtual office space perfectly suited our needs to gather everyone together and later move to small rooms for discussion. However, it is not suitable for sharing recordings, so we gave up on that. Instead, we made sure to keep logs so that we can review them later. Microsoft Loop Loop was chosen as our collaboration tool. KINTO Technologies has been using Confluence for the most part, but it has had some weaknesses when it came to collaborative editing, with several participants writing notes freely. We decided on Loop because the experience is not so different from Confluence, but it is less stressful. Setting Up Additional Meetings The time for our group reading session was set for every Tuesday from 18:00 to 19:00. It was a bit late, and it might overlap with prime time for those who have unexpected business schedules or for those with children. If you miss participation even once, the psychological hurdle to rejoining becomes higher. So, I decided to hold exactly the same content on the following Wednesday but from 12:00 to 13:00. This reduced the risk of missed participation, and the participants who attended the day before to have time to understand the content in more depth. Moreover, listening to other participants' perspectives provided them with new insights, making each session more enjoyable. Leveraging Generative AI As I mentioned in the Working Agreement above, I had a strong desire to create a place where people can still follow up each other without having to read the book. Although there is a quiet reading time in the first 10 minutes, it is rather challenging to read the required amount within 10 minutes. The strong allies that helped us were transcribing and ChatGPT. By summarizing the transcribed text by ChatGPT as much as needed, we realized even 10 minutes of quiet reading time can make a big difference in the quality of participants' input. For example, here is a summary of the first part. Don't you think that silent reading time would be effective when you can condense about 12 pages into this amount? ![AI Brief Summary](/assets/blog/authors/_awache/20240422/AIざっくり芁玄.png =750x) The original text is also available in Confluence, so if you find something you are interested in the summary, you can search for keywords to quickly find the point. Personally, this was such an important factor that I believe it was the main reason we were able to make it till the end. In-house Group Reading Session ![Group Reading Session](/assets/blog/authors/_awache/20240422/gather.png =750x) As a result, a total of 17 group reading sessions were held. I was able to make it through all 17 without being left alone until the end lol. Some people participated fully, while others came whenever they could. Despite variations in the number of participants per session due to some sessions being repeated, I found the number to be quite good in terms of participation per chapter. Part 1: Understanding the benefits of remote organizations / Part 2: Process to parallel the world's most advanced remote organization February 13, 2024 (6 participants) February 14, 2024 (9 participants) Chapter 5: Culture is fostered by value February 21, 2024 (8 participants) February 27, 2024 (4 participants) February 28, 2024 (4 participants) Chapter 6: Rules of communication March 5, 2024 (7 participants) March 6, 2024 (5 participants) Chapter 7: The importance of onboarding in remote organizations / Chapter 8: Fostering psychological safety March 13, 2024 (7 participants) March 19, 2024 (5 participants) Chapter 9: Bringing out individual performance / Chapter 10: Human resource system based on GitHub Value March 26, 2024 (7 participants) March 27, 2024 (5 participants) Chapter 11: Managerial roles and mechanisms to support management & Chapter 12: Achieving conditioning April 2, 2024 (6 participants) April 3, 2024 (7 participants) Chapter 13: Using L&D to improve performance and engagement & Conclusion April 9, 2024 (7 participants) April 10, 2024 (5 participants) Wrap up! April 16, 2024 (5 participants) April 17, 2024 (4 participants) To learn more about what was discussed, please join us for the Finale of the group reading session for " Learning from GitLab: How to Create the World's Most Advanced Remote Organization "! Ultimately, this book contains extensive information on what we should be aiming for, and there were intense discussions about how it may collide with reality, which is a little difficult to write about. So, please let me talk about this topic on another day. What we gained and produced through this group reading session Connections I was able to learn about the thoughts of those who participated through this group reading session, and I will continue to cherish these connections as I work to make KINTO Technologies a more exciting place to work. We have a channel called #thanks where we can openly express our gratitude towards each other. I was also very happy to receive warm messages from the participants on the final day of the group reading session. ! [thanks] (/assets/blog/authors/_awache/20240422/thanks.png = 750x) Transcription I feel that transcribing is an important process if I want to continue to lead group reading session in the future, as it allowed me to respond to the AI summary and various other topics that came up during the discussions. AI Summary Summaries output using generative AI are really powerful. You may forget where and what was written over time, but if you have a summary, a quick 10-minute look can recall your memory. Mandala Chart In my own way, I summarized the key points of this book in a mandala chart template. Of course, it is impossible to do everything, so I would like to set points and themes and increase what I can do little by little. Conclusion How was the group reading session for " " Learning from GitLab: How to Create the World's Most Advanced Remote Organization - How to use documents to achieve maximum results without an office "? I was personally more satisfied with this session than any other I have held before, which is why I felt compelled to share it on our Tech Blog. In truth, there is much more I would like to write, but it would be too long, so I will stop here for now. Reminder: We will be hosting the ‘finale’ of the group reading session for " Learning from GitLab: How to Create the World's Most Advanced Remote Organization " There are still spots available. We will do our best to make it enjoyable session as well, so if you are willing to come, please apply! Thank you very much. Cnnpass: Grand Finale of the group reading session for " Learning from GitLab: How to Create the World's Most Advanced Remote Organization " Date and time: 18:00 - 21:00 (Opening at 17:40) Thursday, April 25, 2024 Event Type: Offline Venue: Muromachi Office, KINTO Technologies Corporation This event is intended for those who have already read the book and participated in the previous group reading sessions of " Learning from GitLab: How to Create the World's Most Advanced Remote Organization - How to use documents to achieve maximum results without an office ", but it is also open to those who are currently reading it or plan to do so in the future. We look forward to seeing you at the event! See you!
Sharing How Great Was Our Group Reading Session " Learning from GitLab: How to Create the World's Most Advanced Remote Organization ". Hello, I am Awache ( @_awache ). We were so fascinated by the book " Learning from GitLab: How to Create the World's Most Advanced Remote Organization - How to use documents to achieve maximum results without an office " that we decided to hold a group reading session with both people from the company and from outside. In this article, I'd like to share our efforts with you. But first, let me announce our next get together: We will be hosting the ‘finale’ of the group reading session for " Learning from GitLab: How to Create the World's Most Advanced Remote Organization " A bit sudden maybe but it’s important. You can see the details below: Connpass: Grand Finale of the group reading session for "Learning from GitLab: How to Create the World's Most Advanced Remote Organization" Date and time: 18:00 - 21:00 (Opening at 17:40) Thursday, April 25, 2024 Event Type: Offline Venue: Muromachi Office, KINTO Technologies Corporation This event is intended for those who have read the book and participated in the previous group reading sessions of "Learning from GitLab: How to Create the World's Most Advanced Remote Organization - How to use documents to achieve maximum results without an office ", but it is also open to those who are currently reading it or plan to do so in the future. We will discuss how the group reading session was conducted in each of the companies, how was the reception, and gather insights from the book, aiming to create an open forum for all participants to engage in the discussions. There are still spots available, so if you are interested, please join us! We'd like to find ways for everyone to enjoy the session casually. (Though the irony is not lost on me that we will be meeting in person to discuss remote organizations lol) Common Challenges at Group Reading Sessions Ensuring continuous participation Regular gatherings are necessary to complete reading a book in a group setting. By dividing the book into reasonable portions and meeting once a week, it would take about 2 to 3 months. Dropping out in the middle It is always challenging to continue anything for long periods of time, so it’s natural that one by one the number of participants dwindle as the meetings progress. If we fail to keep the participants motivated, we may end up with a very lonely group reading session. Difficulty of joining in the middle Given the nature of book readings, the hurdle for participation typically rises in the middle stages. As a result, the number of participants is likely to decrease, with opportunities to increase the number of participants being very rare. Sustaining leadership Various burdens for the leader Pre-preparations Securing time for participants Facilitation These are not one-offs, but continues until the end of the book. It takes a lot of motivation to continue doing things alone Recognizing differences in reading speed and understanding among participants The speed and comprehension level of reading varies depending on the participant. Without recognizing this, the group reading session will end up with a lot of tedious time without much discussion. So taking all the above into account, it is quite challenging to finish a book in a group setting, isn't it? I myself have many times dropped out in the middle a book or couldn't read it until the end. However, this time, I really wanted to share the ideas of this book widely within the company and I was strongly motivated to finish it until the end . So, I was trying to figure out how to solve these issues. For example, I hypothesized that we could approach the issue effectively by creating an opportunity to conduct group reading sessions on the same subject in different ways at multiple locations beyond the boundaries of the company, not only by ourselves but involving others, and share our findings at the end of the session. However, there are limits to what I can do alone. I consulted with @soudai1025 -san, who is a technical advisor in our DBRE team, and with his cooperation, we decided to hold “A Sodai-Naru (Great) Group Reading Session.” Organizing The Reading Session Several companies: Using a kickoff meeting as a trigger Will set a time of about three months to hold a series of group reading sessions internally, After which findings will be shared together at the end We decided to divide our event in the above three-stages. You can check out our kickoff session on YouTube: https://www.youtube.com/watch?v=IBgmGtpW15Q How to Start a Group Reading Session I will briefly describe what I prepared for the group reading session after the kickoff was over. Gathering team members First of all, we gathered willing participants through internal open channels. We reached out to people interested in group reading sessions and waited for volunteers to raise their hands. As a result, we got 14 people interested! Transcription (Transcribing a book) I was determined to transcribe the book from the moment I decided to lead the group reading session. I think that the action of transcribing, which enables reading, writing, and reviewing simultaneously, is an excellent activity for quickly understanding the content of a book. However, this book is over 300 pages, so one needs determination! lol Purchasing books in bulk It is mentioned in our career website as well, but KINTO Technologies allows you to purchase the books you need. Since several of the 14 people did not have it yet, we used this program and purchased the books in bulk for those who didn’t. Thinking how to proceed with our in-house group reading session I seriously considered how we could ensure that everyone enjoys the session without feeling any pressure whenever they attend. I will introduce the specific actions later. While I was pondering this, I realized that time was passing by fast and our in-house group reading session was set to February. The In-house Group Reading Session Kickoff Working Agreement I shared with the participants a summary of what kind of atmosphere I would like to create. Here are the details: This session is designed with the aim of minimizing pressure on the participants: Follow up with each other even if someone did not read the book For the first 10 minutes, we'll have quiet reading time The main focus is on discussion , and the output is made public to create an atmosphere in which even those who are not actually participating can join in during the process. Summarize every output and make it available to everyone Record the session via Zoom and publish it (whenever possible) The same content can be read multiple times Do not interfere when other participants are speaking Be respectful and accepting of what participants say Stimulate free discussion Conduct discussions in breakout rooms of up to 4 people Conduct discussions in small groups reduces the psychological barrier to speaking up and allows each person to bring up what they want to discuss Do not refuse participation from ROMs (Read Only Members) When participating, communicate each ones’ situation to the rest of the participants to create an accepting atmosphere. Things like: I won’t be able to talk today Due to where I am working from today, I may not be able to talk much Everyone actively creates output Minutes of discussions are actively logged by those who are available (e.g., those who can’t speak that day) How we proceeded with the group reading session I still believe that a certain timeline is desirable for ongoing discussions. Even if you are a little late but want to join the group reading session, it may be psychologically difficult to do so if the session is in the middle of a heated discussion. On the other hand, if you have some idea of what you are doing, for example, you may be able to join in the middle of the session because it is now quiet reading time. That's why I decided to create a clear structure for us. Basic Format Quiet reading time (10 minutes) Discussion time (30 minutes) Content sharing (20 minutes) Content of the Discussions What I could relate to What I could not relate to What I want to put into practice at KINTO Technologies Perhaps the results of what was put into practice could be shared in the next session Discussion content output The agenda during the discussion is described in Google Slide After the discussion, everyone shares the topics that came up Selection of tools to use Gather Gather was chosen as the web meeting tool. Since our main focus was discussion, the idea was to engage with individuals who were comfortable talking with those attending. With Zoom, you have to make a breakout room every time, and it's hard to sort them out. Gather, a virtual office space perfectly suited our needs to gather everyone together and later move to small rooms for discussion. However, it is not suitable for sharing recordings, so we gave up on that. Instead, we made sure to keep logs so that we can review them later. Microsoft Loop Loop was chosen as our collaboration tool. KINTO Technologies has been using Confluence for the most part, but it has had some weaknesses when it came to collaborative editing, with several participants writing notes freely. We decided on Loop because the experience is not so different from Confluence, but it is less stressful. Setting Up Additional Meetings The time for our group reading session was set for every Tuesday from 18:00 to 19:00. It was a bit late, and it might overlap with prime time for those who have unexpected business schedules or for those with children. If you miss participation even once, the psychological hurdle to rejoining becomes higher. So, I decided to hold exactly the same content on the following Wednesday but from 12:00 to 13:00. This reduced the risk of missed participation, and the participants who attended the day before to have time to understand the content in more depth. Moreover, listening to other participants' perspectives provided them with new insights, making each session more enjoyable. Leveraging Generative AI As I mentioned in the Working Agreement above, I had a strong desire to create a place where people can still follow up each other without having to read the book. Although there is a quiet reading time in the first 10 minutes, it is rather challenging to read the required amount within 10 minutes. The strong allies that helped us were transcribing and ChatGPT. By summarizing the transcribed text by ChatGPT as much as needed, we realized even 10 minutes of quiet reading time can make a big difference in the quality of participants' input. For example, here is a summary of the first part. Don't you think that silent reading time would be effective when you can condense about 12 pages into this amount? ![AI Brief Summary](/assets/blog/authors/_awache/20240422/AIざっくり芁玄.png =750x) The original text is also available in Confluence, so if you find something you are interested in the summary, you can search for keywords to quickly find the point. Personally, this was such an important factor that I believe it was the main reason we were able to make it till the end. In-house Group Reading Session ![Group Reading Session](/assets/blog/authors/_awache/20240422/gather.png =750x) As a result, a total of 17 group reading sessions were held. I was able to make it through all 17 without being left alone until the end lol. Some people participated fully, while others came whenever they could. Despite variations in the number of participants per session due to some sessions being repeated, I found the number to be quite good in terms of participation per chapter. Part 1: Understanding the benefits of remote organizations / Part 2: Process to parallel the world's most advanced remote organization February 13, 2024 (6 participants) February 14, 2024 (9 participants) Chapter 5: Culture is fostered by value February 21, 2024 (8 participants) February 27, 2024 (4 participants) February 28, 2024 (4 participants) Chapter 6: Rules of communication March 5, 2024 (7 participants) March 6, 2024 (5 participants) Chapter 7: The importance of onboarding in remote organizations / Chapter 8: Fostering psychological safety March 13, 2024 (7 participants) March 19, 2024 (5 participants) Chapter 9: Bringing out individual performance / Chapter 10: Human resource system based on GitHub Value March 26, 2024 (7 participants) March 27, 2024 (5 participants) Chapter 11: Managerial roles and mechanisms to support management & Chapter 12: Achieving conditioning April 2, 2024 (6 participants) April 3, 2024 (7 participants) Chapter 13: Using L&D to improve performance and engagement & Conclusion April 9, 2024 (7 participants) April 10, 2024 (5 participants) Wrap up! April 16, 2024 (5 participants) April 17, 2024 (4 participants) To learn more about what was discussed, please join us for the Finale of the group reading session for "Learning from GitLab: How to Create the World's Most Advanced Remote Organization"! Ultimately, this book contains extensive information on what we should be aiming for, and there were intense discussions about how it may collide with reality, which is a little difficult to write about. So, please let me talk about this topic on another day. What we gained and produced through this group reading session Connections I was able to learn about the thoughts of those who participated through this group reading session, and I will continue to cherish these connections as I work to make KINTO Technologies a more exciting place to work. We have a channel called #thanks where we can openly express our gratitude towards each other. I was also very happy to receive warm messages from the participants on the final day of the group reading session. ![thanks](/assets/blog/authors/_awache/20240422/thanks.png =750x) Transcription I feel that transcribing is an important process if I want to continue to lead group reading session in the future, as it allowed me to respond to the AI summary and various other topics that came up during the discussions. AI Summary Summaries output using generative AI are really powerful. You may forget where and what was written over time, but if you have a summary, a quick 10-minute look can recall your memory. Mandala Chart In my own way, I summarized the key points of this book in a mandala chart template. Of course, it is impossible to do everything, so I would like to set points and themes and increase what I can do little by little. Conclusion How was the group reading session for Learning from GitLab: How to Create the World's Most Advanced Remote Organization - How to use documents to achieve maximum results without an office ? I was personally more satisfied with this session than any other I have held before, which is why I felt compelled to share it on our Tech Blog. In truth, there is much more I would like to write, but it would be too long, so I will stop here for now. Reminder: We will be hosting the ‘finale’ of the group reading session for "Learning from GitLab: How to Create the World's Most Advanced Remote Organization" There are still spots available. We will do our best to make it enjoyable session as well, so if you are willing to come, please apply! Thank you very much. Cnnpass: Grand Finale of the group reading session for "Learning from GitLab: How to Create the World's Most Advanced Remote Organization" Date and time: 18:00 - 21:00 (Opening at 17:40) Thursday, April 25, 2024 Event Type: Offline Venue: Muromachi Office, KINTO Technologies Corporation This event is intended for those who have already read the book and participated in the previous group reading sessions of Learning from GitLab: How to Create the World's Most Advanced Remote Organization - How to use documents to achieve maximum results without an office , but it is also open to those who are currently reading it or plan to do so in the future. We look forward to seeing you at the event! See you!
Hi! I’m Ryomm, developing the iOS app my route at KINTO Technologies. My fellow developers, Hosaka-san and Chang-san, along with another business partner and I, successfully implemented and integrated our Snapshot Testing. Introduction Currently, the my route app team is moving towards transitioning to SwiftUI, so we have decided to implement Snapshot Testing as a foundational step. We began this transition by initially replacing only the content, while keeping UIViewController as the base. This approach ensures that the implemented Snapshot Testing will be directly applicable. Let me introduce the techniques and trial-and-error methods we used to apply Snapshot Testing to an app built with UIKit. What is Snapshot Testing? It is a type of testing that verifies whether there are any differences between screenshots taken before and after code modifications. We use the Point-Free library for modifications https://github.com/pointfreeco/swift-snapshot-testing . While developing my route , we extend XCTestCase to create a method that wraps assertSnapshots as follows: We determined the threshold to be at 98.5% after various trials to ensure that very fine tolerance variances were accommodated successfully. extension XCTestCase { var precision: Float { 0.985 } func testSnapshot(vc: UIViewController, record: Bool = false, file: StaticString, function: String, line: UInt) { assert(UIDevice.current.name == "iPhone 15", "Please run the test by iPhone 15") // SnapshotConfig is an enum that specifies the list of devices to be tested SnapshotConfig.allCases.forEach { assertSnapshots(matching: vc, as: [.image(on: $0.viewImageConfig, precision: precision)], record: record, file: file, testName: function + $0.rawValue, line: line) } } } The Snapshot Testing for each screen is written as follows. final class SampleVCTests: XCTestCase { // snapshot test whether it is in recording mode or not var record = false func testViewController() throws { let SampleVC = SampleVC(coder: coder) let navi = UINavigationController(rootViewController: SampleVC) navi.modalPresentationStyle = .fullScreen // This is where the lifecycle methods are called UIApplication.shared.rootViewController = navi // The lifecycle methods starting from viewDidLoad are invoked for each test device testSnapshot(vc: navi, record: record, file: #file, function: #function, line: #line) } } Tips We need to wait for the data fetched by the API to be reflected in the View after the viewWillAppear method and subsequent methods. To ensure the Snapshot Testing run after the API data is reflected in View, we have encountered issues where the tests execute too early, causing problems like the indicator still being visible. Since it is difficult to determine if the data from the API call has been reflected in the view, we will implement a delegate to handle this verification. protocol BaseViewControllerDelegate: AnyObject { func viewDidDraw() } In the ViewController class, create a delegate property that conforms to the previously prepared delegate. If no delegate is specified during initialization, this property defaults to nil. class SampleVC: BaseViewController { // ... weak var baseDelegate: BaseViewControllerDelegate? // .... init(baseDelegate: BaseViewControllerDelegate? = nil) { self.baseDelegate = baseDelegate super.init(nibName: nil, bundle: nil) } // ... } When calling the API and updating the view, for example, after receiving the results with Combine and reflecting them on the screen, call baseDelegate.viewDidDraw() . This notifies the Snapshot Testing that the view has been successfully updated with the data. someAPIResult.receive(on: DispatchQueue.main) .sink(receiveValue: { [weak self] result in guard let self else { return } switch result { case .success(let item): self.hideIndicator() self.updateView(with: item) // Timing of data reflection completion self.baseDelegate?.viewDidDraw() case .failure(let error): self.hideIndicator() self.showError(error: error) } }) .store(in: &cancellables) As we want to wait for baseDelegate.viewDidDraw() to be executed, we add XCTestExpectation to the Snapshot Testing. final class SampleVCTests: XCTestCase { var record = false var expectation: XCTestExpectation! func testViewController() throws { let SampleVC = SampleVC(coder: coder, baseDelegate: self) let navi = UINavigationController(rootViewController: SampleVC) navi.modalPresentationStyle = .fullScreen UIApplication.shared.rootViewController = navi expectation = expectation(description: "callSomeAPI finished") wait(for: [expectation], timeout: 5.0) viewController.baseViewControllerDelegate = nil testSnapshot(vc: navi, record: record, file: #file, function: #function, line: #line) } func viewDidDraw() { expectation.fulfill() } } When there are multiple sets of data to be retrieved from the API that need to be reflected (when calling baseDelegate.viewDidDraw() in multiple places), you can specify expectedFulfillmentCount or assertForOverFulfill . final class SampleVCTests: XCTestCase { var record = false var expectation: XCTestExpectation! func testViewController() throws { let SampleVC = SampleVC(coder: coder, baseDelegate: self) let navi = UINavigationController(rootViewController: SampleVC) navi.modalPresentationStyle = .fullScreen UIApplication.shared.rootViewController = navi expectation = expectation(description: "callSomeAPI finished") // When viewDidDraw() is called twice expectation.expectedFulfillmentCount = 2 // When viewDidDraw() is called more times than specified, any additional calls should be ignored expectation.assertForOverFulfill = false wait(for: [expectation], timeout: 5.0) viewController.baseViewControllerDelegate = nil testSnapshot(vc: navi, record: record, file: #file, function: #function, line: #line) } func viewDidDraw() { expectation.fulfill() } } If the baseViewControllerDelegate from the previous screen remains active, running the Snapshot Testing across all screens will call viewDidLoad and subsequent lifecycle methods for each test device every time testSnapshot() is invoked. This causes the API to be called multiple times and viewDidDraw() to be executed repeatedly, resulting in multiple calls error. Therefore, we clear the baseViewControllerDelegate after calling wait() . Frame misalignment on devices While Snapshot Testing can generate snapshots for multiple devices, we encountered issues where the layout and size of elements were misaligned on some devices. Misaligned This issue is caused by the lifecycle of the Snapshot Testing execution. In a Snapshot Testing, it starts loading on one device, and then other devices are rendered by changing the size without reloading. This means that viewDidLoad() is executed only once at the beginning, and for the other devices, it starts from viewWillAppear() . As a solution, create a MockViewController that wraps the viewcontroller you want to test. Override viewWillAppear() to call the methods that are originally called in viewDidLoad() . import XCTest @testable import App final class SampleVCTests: XCTestCase { // snapshot test whether it is in recording mode or not var record = false func testViewController() throws { // Write it the same way as when calling the screen let storyboard = UIStoryboard(name: "Sample", bundle: nil) let SampleVC = storyboard.instantiateViewController(identifier: "Sample") { coder in // VC wrapped for Snapshot Test MockSampleVC(coder: coder, completeHander: nil) } let navi = UINavigationController(rootViewController: SampleVC) navi.modalPresentationStyle = .fullScreen UIApplication.shared.rootViewController = navi testSnapshot(vc: navi, record: record, file: #file, function: #function, line: #line) } } class MockSampleVC: SampleVC { required init?(coder: NSCoder) { fatalError("init(coder: \\(coder) has not been implemented") } override init?(coder: NSCoder, completeHander: ((_ readString: String?) -> Void)? = nil) { super.init(coder: coder, completeHander: completeHander) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // The following methods are originally called in viewDidLoad() super.setNavigationBar() super.setCameraPreviewMask() super.cameraPreview() super.stopCamera() } } Still not fixed・・・ If the rendering is still misaligned, calling the layoutIfNeeded() method to update the frames often resolves the issue. import XCTest @testable import App final class SampleVCTests: XCTestCase { var record = false func testViewController() throws { let storyboard = UIStoryboard(name: "Sample", bundle: nil) let SampleVC = storyboard.instantiateViewController(identifier: "Sample") { coder in MockSampleVC(coder: coder, completeHander: nil) } let navi = UINavigationController(rootViewController: SampleVC) navi.modalPresentationStyle = .fullScreen UIApplication.shared.rootViewController = navi testSnapshot(vc: navi, record: record, file: #file, function: #function, line: #line) } } fileprivate class MockSampleVC: SampleVC { required init?(coder: NSCoder) { fatalError("init(coder: \\(coder) has not been implemented") } override init?(coder: NSCoder, completeHander: ((_ readString: String?) -> Void)? = nil) { super.init(coder: coder, completeHander: completeHander) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // Update the frame before calling rendering methods self.videoView.layoutIfNeeded() self.targetView.layoutIfNeeded() super.setNavigationBar() super.setCameraPreviewMask() super.cameraPreview() super.stopCamera() } } Looks good Snapshot for WebView screens There are situations where you may want to apply Snapshot Testing to toolbars to other elements, but not the content displayed in a Webview. In such cases, it is good to separate the part that loads the WebView content from the WebView’s configuration and mock the loading part during tests. For the implementation, we separate the method that calls self.WebView.load(urlRequest) etc. to display the Webview content from the method that configures the WebView itself. // Implementation in the VC class SampleWebviewVC: BaseViewController { // ... override func viewDidLoad() { super.viewDidLoad() self.setNavigationBar() **self.setWebView()** self.setToolBar() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) **self.setWebViewContent()** } // ... /** * Separate the method for configuring the WebView from the method for setting its content */ /// Configure the WebView func setWebView() { self.webView.uiDelegate = self self.webView.navigationDelegate = self // Monitor the loading state of the web page webViewObservers.append(self.webView.observe(\\.estimatedProgress, options: .new) { [weak self] _, change in guard let self = self else { return } if let newValue = change.newValue { self.loadingProgress.setProgress(Float(newValue), animated: true) } }) } /// Set content for the WebView private func setWebViewContent() { let request = URLRequest(url: self.url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 60) self.webView.load(request) } // ... } Then, in the mock that wraps the VC under test, we make it so that the method that loads the WebView content is not called. import XCTest @testable import App final class SampleWebviewVCTests: XCTestCase { private let record = false func testViewController() throws { let storyboard = UIStoryboard(name: "SampleWebview", bundle: .main) let SampleWebviewVC = storyboard.instantiateViewController(identifier: "SampleWebview") { coder in MockSampleWebviewVC(coder: coder, url: URL(string: "<https://top.myroute.fun/>")!, linkType: .Foobar) } let navi = UINavigationController(rootViewController: SampleWebviewVC) navi.modalPresentationStyle = .fullScreen UIApplication.shared.rootViewController = navi testSnapshot(vc: navi, record: record, file: #file, function: #function, line: #line) } } fileprivate class MockSampleWebviewVC: SampleWebviewVC { override init?(coder: NSCoder, url: URL, linkType: LinkNamesItem?) { super.init(coder: coder, url: url, linkType: linkType) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewWillAppear(_ animated: Bool) { // Change the method that was called in viewDidLoad to be called in viewWillAppear self.setNavigationBar() self.setWebView() self.setToolBar() super.viewWillAppear(animated) } override func viewDidAppear(_ animated: Bool) { // Do nothing // Override to avoid calling the method that sets the WebView content } } Snapshot of the screen that is calling the camera Call the camera and also take the snapshot of the screen which displays a customized view. However, since the camera does not work on the simulator, it is necessary to find a way to disable the camera part while still being able to test the overlay. There was also a suggestion to insert a dummy image to make the camera work on the simulator, but it seems too costly to implement this just for the Snapshot Testing of a non-primary screen. In myroute’s Snapshot Testing, we used mocks to override the parts that handle the camera input and the parts that set up the capture to be displayed in AVCaptureVideoPreviewLayer, so they are not called. This way, the AVCaptureVideoPreviewLayer displays as a blank screen without any input, allowing the customized View to be shown on top. In the actual implementation, it is written as follows: class UseCameraVC: BaseViewController { // ... override func viewDidLoad() { super.viewDidLoad() self.videoView.layoutIfNeeded() setNavigationBar() setCameraPreviewMask() do { guard let videoDevice = AVCaptureDevice.default(for: AVMediaType.video) else { return } let videoInput = try AVCaptureDeviceInput(device: videoDevice) as AVCaptureDeviceInput if captureSession.canAddInput(videoInput) { captureSession.addInput(videoInput) let videoOutput = AVCaptureVideoDataOutput() if captureSession.canAddOutput(videoOutput) { captureSession.addOutput(videoOutput) videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main) } } } catch { return } cameraPreview() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // Since the camera cannot be used in the simulator, disable it #if targetEnvironment(simulator) stopCamera() dismiss(animated: true) #else captureSession.startRunning() #endif } } Override them with mocks as follows: Due to the reasons described regarding the frame misalignment issue, we call the methods from viewWillAppear() that were originally called in viewDidLoad() . class MockUseCameraVC: UseCameraVC { // ... override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.videoView.layoutIfNeeded() super.setNavigationBar() super.setCameraPreviewMask() super.cameraPreview() super.stopCamera() } } The cameraPreview() method uses AVCaptureVideoPreviewLayer to display the camera image from the captureSession , but since we override it to have no input, it renders as a white view. CI Strategy At the initial stage of introducing Snapshot Testing, we uploaded reference images to a single S3 bucket. During reviews, we downloaded the reference images each time and ran the tests. However, when a view was modified and the reference images were updated simultaneously, there was an issue where tests for other PRs would fail until the PR with the updated reference images was merged. To address the issue, we created two directories within the bucket hosting the reference images. One directory hosts the images during PR reviews, and once a PR is merged, the images are copied to the other directory. By doing so, we ensure that updates to the reference images do not interfere with the tests of other PRs. Useful shells my route provides four shells for snapshots. The first one downloads all the reference images for the current screen. This allows the tests to pass locally. Used when switching from the # develop branch # Example: Sh setup_snapshot.sh # Clean up the old files from the reference images directory rm -r AppTests/Snapshot/__Snapshots__/ # Download reference images from S3 aws s3 cp $awspath/AppTests/Snapshot/__Snapshots__ --recursive --profile user The second shell uploads modified reference images to the PR review S3 bucket when creating a Pull Request. # When creating a PR, upload the modified tests as arguments. # Example: Sh upload_snapshot.sh ×××Tests path="./SpotTests/Snapshot/__Snapshots__" awspath="s3://strl-mrt-web-s3b-mat-001-jjkn32-e/mobile-app-test/ios/feature/__Snapshots__" if [ $# = 0 ]; then echo "No arguments provided" else for testName in "${@}"; do if [[ $testName == *"Tests"* ]]; then echo "$path/$testName" aws s3 cp "$path/$testName" "$awspath/$testName" --exclude ".DS_Store" --recursive --profile user else echo "($0testName) No tests found" fi done fi The third shell individually downloads the reference images for the modified screens. It is used when reviewing a Pull Requests that includes screen changes. # When reviewing tests, download the reference images for the specific tests # Example: Sh download_snapshot.sh ×××Tests if [ $# = 0 ]; then echo "No arguments provided" else rm -r AppTests/Snapshot/__Snapshots__/ for testName in "${@}"; do if [[ $testName == *"Tests"* ]]; then echo "$localpath/$testName" aws s3 cp "$awspath/$testName" "$localpath/$testName" --recursive --profile user else echo "($0testName) No tests found" fi done fi The fourth shell forcibly updates the reference images. Although it is basically unnecessary because the reference images for screens with modified test files are automatically copied, it is useful when changes to reference images occur without modifying the test files, such as when common components are updated. # If changes affect reference images other than the modified test files, (for example, when common components are updated), # Please upload manually # Please use it after merging # Example: Sh force_upload_snapshot.sh × × × Tests if [ $# = 0 ]; then echo "No arguments provided" else echo "Do you want to forcibly upload to the AWS S3 develop folder? 【yes/no】" read question if [ $question = "yes" ]; then for testName in "${@}"; do if [[ $testName == *"Tests"* ]]; then echo "$localpath/$testName" aws s3 cp "$localpath/$testName" "$awsFeaturePath/$testName" --exclude ".DS_Store" --recursive --profile user aws s3 cp "$localpath/$testName" "$awsDevelopPath/$testName" --exclude ".DS_Store" --recursive --profile user else echo "($testName) No tests found" fi done else echo "Termination" fi fi Since having four shells can be confusing regarding when and who should use them, we have defined them in the Taskfile and made the explanations easily accessible. When executing, we have to use -- when passing arguments such as specifying file names, making the command bit longer. As a result, we often call the shells directly. However, having this setup is valuable just for the sake of clear explanations. % task task: [default] task -l --sort none task: Available tasks for this project: * default: show commands * setup_snapshot: [For Assignee] [After branch switch] Used when making changes to Snapshot Testing after switching from the develop branch. (Example) task setup_snapshot or sh setup_snapshot.sh * upload_snapshot: [For Assignee] [During PR creation] Upload the snapshot images to the S3 bucket for PR review by passing the modified tests as arguments (Example) task upload_snapshot -- ×××Tests or sh upload_snapshot.sh ×××Tests * Download_snapshot: [For Reviewer] [During review] Download the reference images by passing the relevant tests as arguments (Example) task download_snapshot -- ×××Tests or sh download_snapshot.sh ×××Tests * force_upload_snapshot: [For Assignee] [After merging] If changes affect reference images other than the modified test files, (for example, when common components are updated), manually upload the changes by passing the modified tests as arguments. (Example) task force_upload_snapshot -- ×××Tests or sh force_upload_snapshot.sh ×××Tests Additionally, this is something I have set up personally, but I find it convenient to have an alias that changes the hardcoded profile name in the shell to the profile configured in your environment. (For those who prefer their own profile names) In this case, the profile hardcoded as user is changed to myroute-user . alias sett="gsed -i 's/user/myroute-user/' setup_snapshot.sh && gsed -i 's/user/myroute-user/' upload_snapshot.sh && gsed -i 's/user/myroute-user/' download_snapshot.sh && gsed -i 's/user/myroute-user/' force_upload_snapshot.sh" Bitrise In my route , we use Bitrise for CI. When a PR that includes changes to Snapshot Testing is merged, Bitrise automatically detects these changes and copies the reference images from the feature folder to the develop folder. This ensures that the snapshot tests always run correctly in all situations. Detecting subtle differences in reference images Sometimes, differences are too subtle to see with the naked eye, but snapshot tests will still detect them and report errors. Can’t see anything (3_3)? In such cases, using ImageMagick to overlay the images can help you spot the differences more easily. By running the following command: convert Snapshot/refarence.png -color-matrix "6x3: 1 0 0 0 0 0.4 0 1 0 0 0 0 0 0 1 0 0 0" ~/changeColor.png \ && magick Snapshot/failure.png ~/changeColor.png -compose dissolve -define compose:args='60,100' -composite ~/Desktop/blend.png \ && rm ~/changeColor.png You can see the overlaid images. Changing the hue of the reference image to a reddish tint before overlaying can make it easier to spot differences. For added convenience, I recommend adding this command to your bashrc. compare() { convert $1 -color-matrix "6x3: 1 0 0 0 0 0.4 0 1 0 0 0 0 0 0 1 0 0 0" ~/Desktop/changeColor.png; magick $1 ~/Desktop/changeColor.png -compose dissolve -define compose:args='60,100' -composite ~/Desktop/blend.png; rm ~/Desktop/changeColor.png } If the files are generally placed in the same location, you may only need to pass the test name as an argument instead of the entire path. Additionally, since images hosted online can also be processed, this method can be useful during reviews. To wrap things up, I bring Surprise Interviews! I interviewed my colleagues to get feedback on the implementation of Snapshot Test! Chang-san said: "Thanks to Hosaka-san’s initial research, we are now able to handle snapshots in a more convenient way. With the help of Ryomm-san, various implementation methods were organized into documents to ensure we didn’t forget anything. It has been really great, and I am very greatful🙇‍♂. Hosaka-san said: “The biggest bottleneck is the time it takes to run full tests, so I would like to work on reducing that in the future." As for myself, I’ve noticed the frustration of having to fix Snapshot Tests when the logic changes but the screen remains unaffected. However, it’s been helpful to confirm that there were no differences when transitioning to SwiftUI, which I think was good!
はじめに こんにちは。 KINTOテクノロゞヌズ モバむルアプリ開発グルヌプの䞭口です。 KINTOかんたん申し蟌みアプリのiOSチヌムでチヌムリヌダヌをしおおり、チヌムビルディングの䞀環ずしお180床フィヌドバックを実斜したしたのでその内容を共有したす。 こちらのチヌム振り返り䌚の蚘事 も同じチヌムで行った取り組みですので、ご興味あればご芧ください。 実斜背景 先日、瀟内の有志メンバヌで 「GitLabに孊ぶ 䞖界最先端のリモヌト組織の぀くりかた ドキュメントの掻甚でオフィスなしでも最倧の成果を出すグロヌバル䌁業のしくみ」 の茪読䌚を行いたした。 この茪読䌚に぀いおは こちらの蚘事 で詳しくご玹介されおいたす。 この茪読䌚は私にずっお非垞に刺激的で、ここでの孊びを䜕かチヌムに持ち垰りたいず考えたした。 その䞭でたず初めに興味を持ったものが360床フィヌドバックでした。 360床フィヌドバックずは、1人の埓業員に察しお同僚や䞊叞、郚䞋など耇数人の芖点からフィヌドバックをもらう評䟡手法です。 䞀般的にフィヌドバックず聞くず、䞊叞が郚䞋ぞフィヌドバックを行うこずが倚いかず思いたす。䞀方で私はメンバヌ同士、あるいは郚䞋から䞊叞ぞフィヌドバックを行うこずも重芁ではないかず垞々考えおいたため、この360床フィヌドバックを実斜しおみようず思いたした。 ただし、茪読䌚の䞭で360床フィヌドバックは調査察象が広すぎたり、業務ず盎接関係のない人からの評䟡を受けたりなどデメリットもあるずいうお話があったので、調査察象を自チヌムのみに限定した180床フィヌドバックずいう手法を教えおもらい、そちらを行うこずにしたした。 狙い 私はこの180床フィヌドバックを通じお、以䞋のような狙いがありたした。 チヌムが求める圹割ず、自身が認識しおいる圹割のギャップを知る 自身の匷み、匱みを再認識し今埌の成長に掻かす チヌムメンバヌが普段どんなこずを思っおいるのか、本音を知る機䌚を䜜る アンケヌトに回答する過皋で、メンバヌのこずを改めお考えるこずによりチヌムの䞀䜓感を高める この180床フィヌドバックは、関係の質を向䞊させるために、メンバヌ同士がお互いのこずを理解し合う非垞に良い機䌚になるのではないかず考えたした。 実斜方法 察象メンバヌ チヌムリヌダヌ:1名 ゚ンゞニア:6名 調査方法 Microsoft Formsを䜿甚し、匿名アンケヌトを実斜 䞋蚘蚭問に぀いお自身を陀く6名分を回答 定量評䟡(5段階評䟡) 積極的な姿勢に関する質問 盞手を受け入れる姿勢に関する質問 意思決定における姿勢に関する質問 やりきる姿勢に関する質問 未知からの習埗に関する質問 自䞻性に関する質問 定性評䟡(フリヌテキストによる評䟡) 匷みに関する質問 改善ポむントに関する質問 察象者ぞ感謝の蚀葉を送る 進める䞊で工倫したこず メンバヌに前向きに取り組んでもらうため、事前に1on1の䞭で実斜する背景や目的を共有する。 完党に匿名であるこずを認識しおもらうため、事前にテストアンケヌトを実斜しお、その結果を共有する。 アンケヌト回答時間が無い、などの理由でアンケヌトの回収率が䞋がるこずを避けるため、あらかじめアンケヌト回答のための時間を甚意する。 フィヌドバックをする以䞊、厳しい蚀葉やネガティブに感じる蚀葉をコメントする可胜性がありたす。少しでも前向きな気持ちでアンケヌトを終了しおもらいたいので、アンケヌトの最埌に日頃の感謝を䌝える項目を甚意する。(たた、フィヌドバック結果を芋る際も、感謝のコメントが綎られおいるこずで前向きにフィヌドバックを受け取っおもらいやすくなる) チヌムリヌダヌずしおオヌプンな姿勢を瀺したかったので、私のフィヌドバック結果はチヌムメンバヌに開瀺し、今埌の改善ポむントなどを共有する。(ただしメンバヌぞは自身のフィヌドバック結果の開瀺を匷芁しない) 私のフィヌドバック結果の芁玄 私のフィヌドバック結果を、芁玄しおみたので䞋蚘に蚘茉いたしたす。 匷み コミュニケヌション力が高く、気さくに話せる。䟋えば、ミヌティングでは積極的に発蚀し、分かりやすく説明するよう心がけおいる。 積極的に孊び、他のメンバヌず情報を共有。新しい技術動向を垞に把握し、Slackやミヌティングなどで共有しおいる。 チヌムワヌク向䞊のため努力。定期的にチヌムむベントを䌁画し、メンバヌ同士の芪睊を深めおいる。 情報収集力やスピヌド感のある察応力。問題発生時には迅速に察応し、関係者に正確な情報を䌝えおいる。 思いやりが匷く、頌りになる。メンバヌの悩みに耳を傟け、適切なアドバむスをしおいる。 改善点 プロダクトに察する仕様理解。機胜の仕様を十分に理解せずに開発を進めおしたうこずがある。 タスクチケットの敎理をもう少し頻床を䞊げお行う。チケットの優先順䜍付けが䞍十分なため、重芁なタスクが埌回しになるこずがある。 斜策を行う際に背景や目的をしっかりず説明する。斜策の意図が䌝わっおいないため、メンバヌの理解が䞍足するこずがある。 リスクをずった行動が少ない。新しい取り組みに察しお慎重になりすぎ、チャンスを逃すこずがある。 匷みの郚分では、日頃意識しお取り組んでいる郚分が評䟡されおいるず思ったので非垞に嬉しかったです。 䞀方で改善点に関しおは、自分自身が自芚しおいるこずだけでなく、自芚できおいなかった郚分に぀いおも気づくこずができ、今埌の成長に掻かすこずができるず感じたした。 たた最埌にメンバヌからの感謝の蚀葉もいただき、ずおもモチベヌションが䞊がりたした。 今埌もより䞀局チヌムに貢献できるよう努めおいきたいず思いたす。 180床フィヌドバックを通しお気付いたチヌムの匷みず改善点 チヌム党䜓に぀いおも芁玄しおみたした。 チヌム党䜓の匷み 倚様な技術力ずリヌダヌシップ  メンバヌ各自が高い技術力ずリヌダヌシップを持ち合わせおいる。 コミュニケヌション胜力  チヌム内のコミュニケヌションが掻発で、情報共有が効果的に行われおいる。 問題解決胜力  技術的な課題や難易床の高いタスクに察する積極的な取り組み。 孊習意欲  新しい知識や技術ぞの取り組みが積極的で、垞に成長を続けおいる。 チヌム党䜓の改善点 情報共有の効率化  新しい技術やプロゞェクトの情報をより効率的に共有する方法の改善。 圹割分担の明確化  メンバヌの胜力を最倧限に掻甚するための圹割分担ず責任のさらなる明確化。 倧局的芖点の逊成  プロゞェクト党䜓の芖点を持ち、タスクの目的ず過皋をチヌム党䜓で共有するこずを重芖。 技術共有ずナレッゞマネゞメント  技術やナレッゞのチヌム内暪展開を促進し、党メンバヌのスキルアップを図る。 たた、各チヌムメンバヌの匷みや圹割を䞋蚘図のようにたずめおみたした。 実斜埌アンケヌト 180床フィヌドバックを実斜した埌に、調査を行っおみおどうだったかアンケヌトを実斜したした。 (回答数は7名です) 期埅倀の倉化 実斜前:7.29→実斜埌:9.19 NPS (NPSずは?) 57 定期的(半幎毎など)に180床調査を実斜したいず思いたすか 86%が「Yes」ず回答 「”参加した埌”の満足床に぀いお、その理由を教えおください(フリヌテキスト)」のAI芁玄 アンケヌトの結果から、回答者は自己認識を深め、自分の課題を芋぀けるこずができたず感じおいたす。 たた、他者の芖点からのフィヌドバックを通じお、普段気づかない芳点を埗るこずができ、 具䜓的な評䟡や改善点を知るこずで、今埌の行動指針が明確になったず述べおいたす。 これらの結果は、アンケヌトが有効な自己反省のツヌルであるこずを瀺しおいたす。 たずめ 今回実斜した180床フィヌドバックに関しお、運営面での䞋蚘のような課題がありたした。 回答党䜓の平均点が高く、差が぀きにくかった。 メンバヌの入れ替えのタむミングず重なっおしたい、䞀郚のメンバヌに適切なフィヌドバックずならなかった。 ただ、党䜓的には私も含めおメンバヌの満足床の高いフィヌドバックができたず感じおいたす。 アンケヌト結果からもわかる通り、メンバヌの定期的な実斜意向も高いため今埌も匕き続き取り組んでいきたいず思いたす。 今回のフィヌドバック結果を受け、私自身やチヌム党䜓ずしおの課題を再認識できたしたので、今埌の成長に掻かしおいきたいず思いたす。 たた、メンバヌも同様にそれぞれの課題を芋぀けお成長の機䌚ずしおいただければずおも嬉しいです。
Introduction (Overview of Activities) We started the "Manabi-no-Michi-no-Eki” at KINTO Technologies! So you'd ask, what is "Manabi (learning) + Michi-no-Eki (roadside station)" about? At our company, we do our best to foster a culture of output by hosting different activities including this Tech Blog, by presenting at events, or promoting various other initiatives. So, what drives our focus on output? We believe that input, or what we have learned, is a crucial prerequisite for output. That is why we created a team dedicated to strengthening our internal learning capabilities, initiated by volunteers within our company. The name "Michi-no-Eki (roadside station)" incorporates various ideas as well. Have you ever been to roadside stations in Japan? It gathers products from local communities, provides rest for travelers, and serve as hubs where you can encounter unique experiences found nowhere else. That's where our idea of Manabi-no-Michi-no-Eki (Roadside Station of Learning) comes from: a desire to create a unique place where everyone on the journey of learning can drop by, be thrilled by new encounters , and come together to be uplifted . What Does the Manabi-no-Michi-no-Eki Do? As a "roadside station" where study groups and workshops intersect, we aim to support internal activities centered around study sessions: Engaging in internal communications Letting everyone know what study groups are being held. Sharing what the current study groups are like. Supporting study groups For those who say, 'I want to start a study group', but I don’t know how to. For those who are organizing study groups but want to improve them. Offering advice on other concerns. Asking the Organizers: What Ideas Led to the Creation of 'Manabi-no-Michi-no-Eki'? Nakanishi: I have always believed that life is about learning. People constantly seek knowledge to find meaning in life, to find a place of solace in their hearts, and to energize their lives. The most fascinating people I have met so far who impressed me the most are those who are constantly learning new things; they shine the most. We believe that creating a company-wide space for colleagues to gather would enhance our daily work output. However, we began receiving feedback about the scattered information on internal study groups and a desire to understand the available learning environments. This prompted the launch of this project. HOKA: Working in human resources, I often hear during employee interviews a common desire for increased communication across different groups. This sparked a feeling that I wanted to do something about it. At the same time, through my work I have observed that successful people in KINTO Technologies often participate in study groups. These two points intersected, sparking the idea of creating a system where people could interact with each other while learning. When I discussed this idea with my boss, he introduced me to Kinchan and Nakanishi-san, and that is how the "Manabi-no-Michi-no-Eki" project was born. Kinchan: I have been involved with the culture of study groups on various occasions over the past 15 years. When I joined KINTO Technologies, I found that the company already had a good culture where learning is an integral part of everyday work. I wanted to expand this positive culture even further and contribute to the growth of people, our organization, and our business. That is why we've decided to take action by gathering information about study groups across the company. Establishment Step 1: Compile information on internal study groups! KINTO Technologies is an organization where voluntary learning activities led by employees such as study groups and reading circles are very active. Various study groups are held within the company, but questions often arise, such as 'where and when are they held?'. Some employees want to learn more about what's available. Having heard many voices, I wanted to give them more visibility. This was the starting point of our activities. We quickly gathered information and discovered that there were about 40 study groups. We were also aware of the existence of other hidden study groups, so we estimated that there were probably more than 60 groups in the company, including smaller ones. The three of us who found amazing that there were so many active study groups, started discussions at the end of November 2023. Step 2: What shall we do? In our first meeting, we listed what we wanted to do. Should we just storm into these study groups? Should we post about them on the Tech Blog more often? Many ideas came up, but we settled on the premise that it would be important to let people know about us internally first. So, we decided to participate in an in-house LT (Lightning Talk) event, which was to be held three weeks later on December 21. Without mentioning the "Manabi-no-Michi-no-Eki" yet, each of us three took the stage at it, and Kinchan won (yay!). First, we took action to make ourselves known to people within the company. Note: For more information, please see our Tech Blog article about the LT Event. ↓↓ We Held an In-House-Only LT (Lightning Talk) Event! Step 3: Make an inception deck! At our December 27, 2023 meeting, we realized the need for guidelines because we have so many things we wanted to do. We decided to create an "inception deck" from the beginning of the year. Inception deck is a software development tool to ensure that all team members have a common understanding of and goals for the development of a project. In ours, we clarified the following four points: Why We Are Here Elevator Pitch Not-To-Do List Our A Team By talking through the above, the name "Manabi-no-Michi-no-Eki (Roadside Station of Learning)" naturally came to mind, and we were able to decide on it without hesitation. In the process of creating our inception deck, we each shared our thoughts on learning with discussions of cooperative learning and about Peter Koenig’s Source Principle. It was a moment when I felt that the process of creating the inception deck itself was also a learning experience for us. And now: Let's Start the Engines! The inception deck was completed in late January 2024. When it was finished, we were a little impatient. We had a clear idea of our goals and tasks, and we were eager to get started right away. Kinchan, who proposed the inception deck, was probably secretly pleased, saying, 'just as expected.' As a first step to get things moving, we announced the birth of "Manabi-no-Michi-no-Eki" at the monthly All-Hands meeting with all KINTO Technologies members! At the same time, we also started the "Joining the next door study group" series. On February 22, we gathered everyone running study groups in a meeting room to interview them. Without having prepared any interview questions beforehand, we just pulled out our phones and recorded on the spot. Both the interviewers and the interviewees were very surprised. Although there was some confusion, they cooperated with us. (Thank you all!) We later edited unnecessary segments so that it could be played as a podcast, and we were able to successfully launch it to all employees via Slack on March 13. Our Next Steps We then run three study groups, published two podcasts, and published two blog articles, while reflecting and discussing our future! What do people want to know? Are they interested in the study groups? What do the organizers want people to know? As a result of the discussion, we came to the conclusion that "the purpose and needs of each study group are different. It would be better to individually assemble a story tailored to each of their characteristics." Moreover, What would be the role of our podcasts? Content as an advertisement for the study group? Content as internal newsletters? After considering these points, we came to the conclusion that "KINTO Technologies holds so many study groups," that to sum it up, "our goal will be achieved if we can give visibility to how rooted our study culture is." As for the future, we have decided to proceed with the activity of creating podcasts, running study groups, learning from any failures, and expanding wherever possible! In fact, I was a bit nervous about this agile approach—iterating, correcting, and steering things in a better direction. Before joining KINTO Technologies, I worked for a company with rigid rules and flows for handling information. As one of the organizers of 'Manabi-no-Michi-no-Eki,' this is an opportunity for me to learn about KINTO Technologies' development style of 'Make Small, Grow Big' while working in HR. The "Manabi-no-Michi-no-Eki" has just begun. We look forward to keeping you updated about it on the KINTO Tech Blog from time to time. Thank you very much for your support!
Introduction (Overview of Activities) We started the "Manabi-no-Michi-no-Eki” at KINTO Technologies! So you'd ask, what is "Manabi (learning) + Michi-no-Eki (roadside station)" about? At our company, we do our best to foster a culture of output by hosting different activities including this Tech Blog, by presenting at events, or promoting various other initiatives. So, what drives our focus on output? We believe that input, or what we have learned, is a crucial prerequisite for output. That is why we created a team dedicated to strengthening our internal learning capabilities, initiated by volunteers within our company. The name "Michi-no-Eki (roadside station)" incorporates various ideas as well. Have you ever been to roadside stations in Japan? It gathers products from local communities, provides rest for travelers, and serve as hubs where you can encounter unique experiences found nowhere else. That's where our idea of Manabi-no-Michi-no-Eki (Roadside Station of Learning) comes from: a desire to create a unique place where everyone on the journey of learning can drop by, be thrilled by new encounters , and come together to be uplifted . What Does the Manabi-no-Michi-no-Eki Do? As a "roadside station" where study groups and workshops intersect, we aim to support internal activities centered around study sessions: Engaging in internal communications Letting everyone know what study groups are being held. Sharing what the current study groups are like. Supporting study groups For those who say, 'I want to start a study group', but I don’t know how to. For those who are organizing study groups but want to improve them. Offering advice on other concerns. Asking the Organizers: What Ideas Led to the Creation of 'Manabi-no-Michi-no-Eki'? Nakanishi: I have always believed that life is about learning. People constantly seek knowledge to find meaning in life, to find a place of solace in their hearts, and to energize their lives. The most fascinating people I have met so far who impressed me the most are those who are constantly learning new things; they shine the most. We believe that creating a company-wide space for colleagues to gather would enhance our daily work output. However, we began receiving feedback about the scattered information on internal study groups and a desire to understand the available learning environments. This prompted the launch of this project. HOKA: Working in human resources, I often hear during employee interviews a common desire for increased communication across different groups. This sparked a feeling that I wanted to do something about it. At the same time, through my work I have observed that successful people in KINTO Technologies often participate in study groups. These two points intersected, sparking the idea of creating a system where people could interact with each other while learning. When I discussed this idea with my boss, he introduced me to Kinchan and Nakanishi-san, and that is how the "Manabi-no-Michi-no-Eki" project was born. Kinchan: I have been involved with the culture of study groups on various occasions over the past 15 years. When I joined KINTO Technologies, I found that the company already had a good culture where learning is an integral part of everyday work. I wanted to expand this positive culture even further and contribute to the growth of people, our organization, and our business. That is why we've decided to take action by gathering information about study groups across the company. Establishment Step 1: Compile information on internal study groups! KINTO Technologies is an organization where voluntary learning activities led by employees such as study groups and reading circles are very active. Various study groups are held within the company, but questions often arise, such as 'where and when are they held?'. Some employees want to learn more about what's available. Having heard many voices, I wanted to give them more visibility. This was the starting point of our activities. We quickly gathered information and discovered that there were about 40 study groups. We were also aware of the existence of other hidden study groups, so we estimated that there were probably more than 60 groups in the company, including smaller ones. The three of us who found amazing that there were so many active study groups, started discussions at the end of November 2023. Step 2: What shall we do? In our first meeting, we listed what we wanted to do. Should we just storm into these study groups? Should we post about them on the Tech Blog more often? Many ideas came up, but we settled on the premise that it would be important to let people know about us internally first. So, we decided to participate in an in-house LT (Lightning Talk) event, which was to be held three weeks later on December 21. Without mentioning the "Manabi-no-Michi-no-Eki" yet, each of us three took the stage at it, and Kinchan won (yay!). First, we took action to make ourselves known to people within the company. Note: For more information, please see our Tech Blog article about the LT Event. ↓↓ We Held an In-House-Only LT (Lightning Talk) Event! Step 3: Make an inception deck! At our December 27, 2023 meeting, we realized the need for guidelines because we have so many things we wanted to do. We decided to create an "inception deck" from the beginning of the year. Inception deck is a software development tool to ensure that all team members have a common understanding of and goals for the development of a project. In ours, we clarified the following four points: Why We Are Here Elevator Pitch Not-To-Do List Our A Team By talking through the above, the name "Manabi-no-Michi-no-Eki (Roadside Station of Learning)" naturally came to mind, and we were able to decide on it without hesitation. In the process of creating our inception deck, we each shared our thoughts on learning with discussions of cooperative learning and about Peter Koenig’s Source Principle. It was a moment when I felt that the process of creating the inception deck itself was also a learning experience for us. And now: Let's Start the Engines! The inception deck was completed in late January 2024. When it was finished, we were a little impatient. We had a clear idea of our goals and tasks, and we were eager to get started right away. Kinchan, who proposed the inception deck, was probably secretly pleased, saying, 'just as expected.' As a first step to get things moving, we announced the birth of "Manabi-no-Michi-no-Eki" at the monthly All-Hands meeting with all KINTO Technologies members! At the same time, we also started the "Joining the next door study group" series. On February 22, we gathered everyone running study groups in a meeting room to interview them. Without having prepared any interview questions beforehand, we just pulled out our phones and recorded on the spot. Both the interviewers and the interviewees were very surprised. Although there was some confusion, they cooperated with us. (Thank you all!) We later edited unnecessary segments so that it could be played as a podcast, and we were able to successfully launch it to all employees via Slack on March 13. Our Next Steps We then run three study groups, published two podcasts, and published two blog articles, while reflecting and discussing our future! What do people want to know? Are they interested in the study groups? What do the organizers want people to know? As a result of the discussion, we came to the conclusion that "the purpose and needs of each study group are different. It would be better to individually assemble a story tailored to each of their characteristics." Moreover, What would be the role of our podcasts? Content as an advertisement for the study group? Content as internal newsletters? After considering these points, we came to the conclusion that "KINTO Technologies holds so many study groups," that to sum it up, "our goal will be achieved if we can give visibility to how rooted our study culture is." As for the future, we have decided to proceed with the activity of creating podcasts, running study groups, learning from any failures, and expanding wherever possible! In fact, I was a bit nervous about this agile approach—iterating, correcting, and steering things in a better direction. Before joining KINTO Technologies, I worked for a company with rigid rules and flows for handling information. As one of the organizers of 'Manabi-no-Michi-no-Eki,' this is an opportunity for me to learn about KINTO Technologies' development style of 'Make Small, Grow Big' while working in HR. The "Manabi-no-Michi-no-Eki" has just begun. We look forward to keeping you updated about it on the KINTO Tech Blog from time to time. Thank you very much for your support!
An Issue We Encountered During Testing With Spring Batch using DBUnit Introduction Hello. I am Takehana from the Payment Platform Team, Common Service Development Group[^1][^2][^3][^4][^5][^6] at the Platform Development Division. This time, I would like to write about an issue that we encountered while testing with Spring Batch + DBUnit. Environment Libraries, etc. Version Java 17 MySQL 8.0.23 Spring Boot 3.1.5 Spring Boot Batch 3.1.5 JUnit 5.10.0 Spring Test DBUnit 1.3.0 Encountered Issues We are using DB unit for testing Spring Boot 3 with Spring Batch. The Batch process follows the Chunk model, where ItemReader performs DB searches, and ItemWriter updates the DB. Given this setup, when running tests with data volumes exceeding the Chunk size, the tests did not complete... Investigations and Attempts Observations Code new StepBuilder("step", jobRepository) .<InputDto, OutputDto>chunk( CHUNK_SIZE, transactionManager) .reader(reader) .processor(processor) .writer(writer) .build(); I was testing a batch with the steps mentioned above as follows. @SpringBatchTest @SpringBootTest @TestPropertySource( properties = { "spring.batch.job.names: Foobar-batch", "targetDate: 2023-01-01", }) @Transactional(isolation = Isolation.SERIALIZABLE) @TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, TransactionDbUnitTestExecutionListener.class }) @DbUnitConfiguration(dataSetLoader = XlsDataSetLoader.class) class FoobarBatchJobTest { @Autowired private JobLauncherTestUtils jobLauncherTestUtils; @BeforeEach void setUp() { } @Test @DatabaseSetup("classpath:dbunit/test_data_import.xlsx") @ExpectedDatabase( value = "classpath:dbunit/data_expected.xlsx", assertionMode = DatabaseAssertionMode.NON_STRICT_UNORDERED) void launchJob() throws Exception { val jobExecution = jobLauncherTestUtils.launchJob(); assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus()); } } When I set the test data to be less than the chunk size, the test passed without any issues. However, when the test data exceeded the chunk size, the test froze and never completed. (This occurred even with a chunk size of 1 and a data count of 1) Suspecting the issue might be on DB connections, I noted that Spring Batch treats each chunk as a single transaction. If processing in parallel, it would require more DB connections than the number of concurrent executions. So I adjusted the pool size to test this hypothesis. spring: datasource: hikari: maximum-pool-size: I changed 10 to 100 among other adjustments, but the issue was still not resolved
 Start debugging I set up debug logs and ran the application to observe the behavior. The execution seemed to stop at the log output on line 88 of org.springframework.batch.core.step.item.ChunkOrientedTasklet . So, I set a breakpoint to verify. I then reached line 408 of org.springframework.batch.core.step.tasklet.TaskletStep . It appeared that the semaphore couldn’t acquire a lock (= waiting for the lock to be released), causing the execution to halt there. Delving deeper into Spring Batch Continuing my investigation, I traced the flow of execution in the step processing. The rough outline of the relevant parts is as follows. Execute doExecute of TaskletStep Create a semaphore Pass the semaphore to ChunkTransactionCallback , which is an implementation of TransactionSynchronization , link it with the transaction execution, and configure it in RepeatTemplate Step processing begins for the chunk The semaphore is locked in doInTransaction of TaskletStep Execute the main step processing The commit is executed by TransactionSynchronizationUtils` The AbstractPlatformTransactionManager ’s triggerAfterCompletion method is called, and the in-process invokeAfterCompletion` is executed. The semaphore is released in the afterCompletion method of the ChunkTransctionCallback by the invokeAfterCompletion. If data remains, return to 4 During this test run, the semaphore of 9 was not released, and it passed through 4 again and ended up freezing at 5 . Why was the semaphore not released...? During the review mentioned above, at Step semaphore release , I found the following condition in the relevant code. status.isNewSynchronization() did not become true , so invokeAfterCompletion was not executed. org.springframework.transaction.support.DefaultTransactionStatus#isNewSynchronization is as follows: /** * Return if a new transaction synchronization has been opened * for this transaction. */ public boolean isNewSynchronization() { return this.newSynchronization; } It returns whether a new transaction synchronization has been opened for this transaction. Considerations The current situation is that we haven’t fully traced yet why isNewSynchronization doesn’t become true . However, I thought I might be able to find some clues in the logs from our various trial and error attempts. If @Transactional is not applied to the test class 2024-03-27T08:57:14.527+0000 [Test worker] TRACE o.s.t.i.TransactionInterceptor - Completing transaction for [org.springframework.batch.core.repository.support.SimpleJobRepository.update] Foobar-batch 19 2024-03-27T08:57:14.527+0000 [Test worker] DEBUG o.s.orm.jpa.JpaTransactionManager - Initiating transaction commit Foobar-batch 19 2024-03-27T08:57:14.527+0000 [Test worker] DEBUG o.s.orm.jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [SessionImpl(1075727694<open>)] Foobar-batch 19 2024-03-27T08:57:14.534+0000 [Test worker] DEBUG o.s.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [SessionImpl(1075727694<open>)] after transaction Foobar-batch 19 2024-03-27T08:57:14.536+0000 [Test worker] DEBUG o.s.b.repeat.support.RepeatTemplate - Repeat operation about to start at count=2 Foobar-batch 19 If @Transactional is applied to the test class 2024-03-27T09:04:04.600+0000 [Test worker] TRACE o.s.t.i.TransactionInterceptor - Completing transaction for [org.springframework.batch.core.repository.support.SimpleJobRepository.update] Foobar-batch 20 2024-03-27T09:04:04.601+0000 [Test worker] DEBUG o.s.b.repeat.support.RepeatTemplate - Repeat operation about to start at count=2 Foobar-batch 20 When @Transactional is applied, "Initiating transaction commit..." from JpaTransactionManager with @Transactionalis not being logged. The test class uses TransactionalTestExecutionListener and executes within the same transaction using @Transactional . This ensures that the test data registered with DBUnit is accessible to code under test and is rolled back after the test is completed. However, I concluded that isNewSynchronization does not become true because existing transactions are being reused (a new transaction is not started) when the same step is executed. Workaround As a brute-force workaround to avoid using TransactionalTestExecutionListener , I performed the cleanup manually after each test, which successfully prevented the freeze. class FoobarTestExecutionListenerChain extends TestExecutionListenerChain { private static final Class<?>[] CHAIN = { FoobarTransactionalTestExecutionListener.class, DbUnitTestExecutionListener.class }; @Override protected Class<?>[] getChain() { return CHAIN; } } class HogeTransactionalTestExecutionListener implements TestExecutionListener { private static final String CREATE_BACKUP_TABLE_SQL = "CREATE TEMPORARY TABLE backup_%s AS SELECT * FROM %s"; private static final String TRUNCATE_TABLE_SQL = "TRUNCATE TABLE %s"; private static final String BACKUP_INSERT_SQL = "INSERT INTO %s SELECT * FROM backup_%s"; private static final List<String> TARGET_TABLE_NAMES = List.of( "Foobar", "fuga", "dadada"); /** * Create a test working table * * @param testContext * @throws Exception */ @Override public void beforeTestMethod(TestContext testContext) throws Exception { val dataSource = (DataSource) testContext.getApplicationContext().getBean("dataSource"); val jdbcTemp = new JdbcTemplate(dataSource); // Backup existing data to a temporary table before testing TARGET_TABLE_NAMES.forEach( tableName -> jdbcTemp.execute(String.format(CREATE_BACKUP_TABLE_SQL, tableName, tableName))); // Table initialization TARGET_TABLE_NAMES.forEach( tableName -> jdbcTemp.execute(String.format(TRUNCATE_TABLE_SQL, tableName))); } /** * Drop the test working table * * @param testContext * @throws Exception */ @Override public void afterTestMethod(TestContext testContext) throws Exception { val dataSource = (DataSource) testContext.getApplicationContext().getBean("dataSource"); val jdbcTemp = new JdbcTemplate(dataSource); // Restore the table TARGET_TABLE_NAMES.forEach( tableName -> jdbcTemp.execute(String.format(TRUNCATE_TABLE_SQL, tableName, tableName))); TARGET_TABLE_NAMES.forEach( tableName -> jdbcTemp.execute(String.format(BACKUP_INSERT_SQL, tableName, tableName))); } } Remove TransactionDbUnitTestExecutionListener and avoid using TransactionalTestExecutionListener. (Use DbUnitTestExecutionListener to lode the test data from Excel) Create a custom TestExecutionListener and move data from the target table to a temporary table during pre-processing, then restore it after the test. beforeTestMethod is executed before the test method, and afterTestMethod is executed after the test method. This approach made it possible to run tests while preserving Spring’s transaction management. Impressions Despite extensive searches, I couldn’t find satisfactory information, leaving the issue in a state of uncertainty. However, by looking further into the Spring Boot source code, I made various discoveries and it turned out to be a valuable learning experience through code reading. (Although I haven’t fully grasped everything yet
) I was wondering if I was fundamentally misunderstanding how to use Spring and the test libraries, questioning whether I was implementing them correctly based on the library creators’ assumptions and if there were more suitable classes available. This has highlighted that I still have much to learn. I would like to continue to approach exploration and improvement with the same curiosity, asking, “How does this work?” Thank you for reading this article. I hope this will be helpful to others facing similar issues. [^1]: Post 1 by a member of the Common Service Development Group [ Domain-Driven Design (DDD) incorporated in a payment platform intended to allow global expansion ] [^2]: Post 2 by a member of the Common Service Development Group [ Remote Mob Programming: How a Team of New Hires Achieved Success Developing a New System Within a Year ] [^3]: Post 3 by a member of the Common Service Development Group [ Efforts to Improve Deploy Traceability to Multiple Environments Utilizing GitHub and JIRA ] [^4]: Post 4 by a member of the Common Service Development Group [ Creating a Development Environment Using VS Code's Dev Container ] [^5]: Post 5 by a member of the Common Service Development Group [ Spring Boot 2 to 3 Upgrade: Procedure, Challenges, and Solutions ] [^6]: Post 6 by a member of the Common Service Development Group [ Guide to Building an S3 Local Development Environment Using MinIO (RELEASE.2023-10) ]
An Issue We Encountered During Testing With Spring Batch using DBUnit Introduction Hello. I am Takehana from the Payment Platform Team, Common Service Development Group[^1][^2][^3][^4][^5][^6] at the Platform Development Division. This time, I would like to write about an issue that we encountered while testing with Spring Batch + DBUnit. Environment Libraries, etc. Version Java 17 MySQL 8.0.23 Spring Boot 3.1.5 Spring Boot Batch 3.1.5 JUnit 5.10.0 Spring Test DBUnit 1.3.0 Encountered Issues We are using DB unit for testing Spring Boot 3 with Spring Batch. The Batch process follows the Chunk model, where ItemReader performs DB searches, and ItemWriter updates the DB. Given this setup, when running tests with data volumes exceeding the Chunk size, the tests did not complete... Investigations and Attempts Observations Code new StepBuilder("step", jobRepository) .<InputDto, OutputDto>chunk( CHUNK_SIZE, transactionManager) .reader(reader) .processor(processor) .writer(writer) .build(); I was testing a batch with the steps mentioned above as follows. @SpringBatchTest @SpringBootTest @TestPropertySource( properties = { "spring.batch.job.names: Foobar-batch", "targetDate: 2023-01-01", }) @Transactional(isolation = Isolation.SERIALIZABLE) @TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, TransactionDbUnitTestExecutionListener.class }) @DbUnitConfiguration(dataSetLoader = XlsDataSetLoader.class) class FoobarBatchJobTest { @Autowired private JobLauncherTestUtils jobLauncherTestUtils; @BeforeEach void setUp() { } @Test @DatabaseSetup("classpath:dbunit/test_data_import.xlsx") @ExpectedDatabase( value = "classpath:dbunit/data_expected.xlsx", assertionMode = DatabaseAssertionMode.NON_STRICT_UNORDERED) void launchJob() throws Exception { val jobExecution = jobLauncherTestUtils.launchJob(); assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus()); } } When I set the test data to be less than the chunk size, the test passed without any issues. However, when the test data exceeded the chunk size, the test froze and never completed. (This occurred even with a chunk size of 1 and a data count of 1) Suspecting the issue might be on DB connections, I noted that Spring Batch treats each chunk as a single transaction. If processing in parallel, it would require more DB connections than the number of concurrent executions. So I adjusted the pool size to test this hypothesis. spring: datasource: hikari: maximum-pool-size: I changed 10 to 100 among other adjustments, but the issue was still not resolved
 Start debugging I set up debug logs and ran the application to observe the behavior. The execution seemed to stop at the log output on line 88 of org.springframework.batch.core.step.item.ChunkOrientedTasklet . So, I set a breakpoint to verify. I then reached line 408 of org.springframework.batch.core.step.tasklet.TaskletStep . It appeared that the semaphore couldn’t acquire a lock (= waiting for the lock to be released), causing the execution to halt there. Delving deeper into Spring Batch Continuing my investigation, I traced the flow of execution in the step processing. The rough outline of the relevant parts is as follows. Execute doExecute of TaskletStep Create a semaphore Pass the semaphore to ChunkTransactionCallback , which is an implementation of TransactionSynchronization , link it with the transaction execution, and configure it in RepeatTemplate Step processing begins for the chunk The semaphore is locked in doInTransaction of TaskletStep Execute the main step processing The commit is executed by TransactionSynchronizationUtils` The AbstractPlatformTransactionManager ’s triggerAfterCompletion method is called, and the in-process invokeAfterCompletion` is executed. The semaphore is released in the afterCompletion method of the ChunkTransctionCallback by the invokeAfterCompletion. If data remains, return to 4 During this test run, the semaphore of 9 was not released, and it passed through 4 again and ended up freezing at 5 . Why was the semaphore not released...? During the review mentioned above, at Step semaphore release , I found the following condition in the relevant code. status.isNewSynchronization() did not become true , so invokeAfterCompletion was not executed. org.springframework.transaction.support.DefaultTransactionStatus#isNewSynchronization is as follows: /** * Return if a new transaction synchronization has been opened * for this transaction. */ public boolean isNewSynchronization() { return this.newSynchronization; } It returns whether a new transaction synchronization has been opened for this transaction. Considerations The current situation is that we haven’t fully traced yet why isNewSynchronization doesn’t become true . However, I thought I might be able to find some clues in the logs from our various trial and error attempts. If @Transactional is not applied to the test class 2024-03-27T08:57:14.527+0000 [Test worker] TRACE o.s.t.i.TransactionInterceptor - Completing transaction for [org.springframework.batch.core.repository.support.SimpleJobRepository.update] Foobar-batch 19 2024-03-27T08:57:14.527+0000 [Test worker] DEBUG o.s.orm.jpa.JpaTransactionManager - Initiating transaction commit Foobar-batch 19 2024-03-27T08:57:14.527+0000 [Test worker] DEBUG o.s.orm.jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [SessionImpl(1075727694<open>)] Foobar-batch 19 2024-03-27T08:57:14.534+0000 [Test worker] DEBUG o.s.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [SessionImpl(1075727694<open>)] after transaction Foobar-batch 19 2024-03-27T08:57:14.536+0000 [Test worker] DEBUG o.s.b.repeat.support.RepeatTemplate - Repeat operation about to start at count=2 Foobar-batch 19 If @Transactional is applied to the test class 2024-03-27T09:04:04.600+0000 [Test worker] TRACE o.s.t.i.TransactionInterceptor - Completing transaction for [org.springframework.batch.core.repository.support.SimpleJobRepository.update] Foobar-batch 20 2024-03-27T09:04:04.601+0000 [Test worker] DEBUG o.s.b.repeat.support.RepeatTemplate - Repeat operation about to start at count=2 Foobar-batch 20 When @Transactional is applied, "Initiating transaction commit..." from JpaTransactionManager with @Transactionalis not being logged. The test class uses TransactionalTestExecutionListener and executes within the same transaction using @Transactional . This ensures that the test data registered with DBUnit is accessible to code under test and is rolled back after the test is completed. However, I concluded that isNewSynchronization does not become true because existing transactions are being reused (a new transaction is not started) when the same step is executed. Workaround As a brute-force workaround to avoid using TransactionalTestExecutionListener , I performed the cleanup manually after each test, which successfully prevented the freeze. class FoobarTestExecutionListenerChain extends TestExecutionListenerChain { private static final Class<?>[] CHAIN = { FoobarTransactionalTestExecutionListener.class, DbUnitTestExecutionListener.class }; @Override protected Class<?>[] getChain() { return CHAIN; } } class HogeTransactionalTestExecutionListener implements TestExecutionListener { private static final String CREATE_BACKUP_TABLE_SQL = "CREATE TEMPORARY TABLE backup_%s AS SELECT * FROM %s"; private static final String TRUNCATE_TABLE_SQL = "TRUNCATE TABLE %s"; private static final String BACKUP_INSERT_SQL = "INSERT INTO %s SELECT * FROM backup_%s"; private static final List<String> TARGET_TABLE_NAMES = List.of( "Foobar", "fuga", "dadada"); /** * Create a test working table * * @param testContext * @throws Exception */ @Override public void beforeTestMethod(TestContext testContext) throws Exception { val dataSource = (DataSource) testContext.getApplicationContext().getBean("dataSource"); val jdbcTemp = new JdbcTemplate(dataSource); // Backup existing data to a temporary table before testing TARGET_TABLE_NAMES.forEach( tableName -> jdbcTemp.execute(String.format(CREATE_BACKUP_TABLE_SQL, tableName, tableName))); // Table initialization TARGET_TABLE_NAMES.forEach( tableName -> jdbcTemp.execute(String.format(TRUNCATE_TABLE_SQL, tableName))); } /** * Drop the test working table * * @param testContext * @throws Exception */ @Override public void afterTestMethod(TestContext testContext) throws Exception { val dataSource = (DataSource) testContext.getApplicationContext().getBean("dataSource"); val jdbcTemp = new JdbcTemplate(dataSource); // Restore the table TARGET_TABLE_NAMES.forEach( tableName -> jdbcTemp.execute(String.format(TRUNCATE_TABLE_SQL, tableName, tableName))); TARGET_TABLE_NAMES.forEach( tableName -> jdbcTemp.execute(String.format(BACKUP_INSERT_SQL, tableName, tableName))); } } Remove TransactionDbUnitTestExecutionListener and avoid using TransactionalTestExecutionListener. (Use DbUnitTestExecutionListener to lode the test data from Excel) Create a custom TestExecutionListener and move data from the target table to a temporary table during pre-processing, then restore it after the test. beforeTestMethod is executed before the test method, and afterTestMethod is executed after the test method. This approach made it possible to run tests while preserving Spring’s transaction management. Impressions Despite extensive searches, I couldn’t find satisfactory information, leaving the issue in a state of uncertainty. However, by looking further into the Spring Boot source code, I made various discoveries and it turned out to be a valuable learning experience through code reading. (Although I haven’t fully grasped everything yet
) I was wondering if I was fundamentally misunderstanding how to use Spring and the test libraries, questioning whether I was implementing them correctly based on the library creators’ assumptions and if there were more suitable classes available. This has highlighted that I still have much to learn. I would like to continue to approach exploration and improvement with the same curiosity, asking, “How does this work?” Thank you for reading this article. I hope this will be helpful to others facing similar issues. [^1]: Post 1 by a member of the Common Service Development Group [ Domain-Driven Design (DDD) incorporated in a payment platform intended to allow global expansion ] [^2]: Post 2 by a member of the Common Service Development Group [ Remote Mob Programming: How a Team of New Hires Achieved Success Developing a New System Within a Year ] [^3]: Post 3 by a member of the Common Service Development Group [ Efforts to Improve Deploy Traceability to Multiple Environments Utilizing GitHub and JIRA ] [^4]: Post 4 by a member of the Common Service Development Group [ Creating a Development Environment Using VS Code's Dev Container ] [^5]: Post 5 by a member of the Common Service Development Group [ Spring Boot 2 to 3 Upgrade: Procedure, Challenges, and Solutions ] [^6]: Post 6 by a member of the Common Service Development Group [ Guide to Building an S3 Local Development Environment Using MinIO (RELEASE.2023-10) ]
Introduction Hello. I am Nakaguchi from KINTO Technologies' Mobile App Development Group. I lead the iOS team for the KINTO Easy Application app which I will refer to as “the iOS team” in this article for convenience. We hold Retrospectives irregularly, but I find that they can be rather challenging. Am I succeeding in bringing out everyone's true feelings?? What are the team's real challenges?? Is my facilitation effective?? etc. I recently watched a webinar by Classmethod, Inc. and was so impressed by their session on "How to Build a Self-Managed Team" that I decided to apply for another training session they introduced in it about Retrospectives. In this article, I'll share my experience attending that session. Pre-Alignment Session Before the Retrospective, we had a meeting with Mr. Abe and Mr. Takayanagi from Classmethod. In order to hold Retrospectives that were best suited to our team’s situation, we discussed the current status of the iOS team with them for nearly an hour. Overview of the Retrospective On the day of the Retrospective, Mr. Takayanagi and Mr. Ito came to the company to facilitate the meeting. The meeting lasted for about two hours and followed this general flow: Self-introductions Aligning the purpose of our Retrospectives Individual exercise on “How to make the team a little bit better” Same content as above but in pairs Sharing the findings with the whole team Thinking about specific action plans in pairs Sharing the findings with the whole team Closing First Half Out of the almost two-hours meeting, it is worth noting that about half of the time was spent on "1. Self-introductions" and "2. Aligning the purpose of our Retrospectives". During the segment "1. Self-introductions", the facilitators asked us questions such as our names or nicknames, our roles in the team, or the extent of our interactions with other team members. They looked not only at the atmosphere of the team and the personality of each of us, but also at the relationships and compatibility between team members. During "2. Aligning the purpose of our Retrospectives", I got everyone to agree on what can be done to make the current team a little better , which was a topic I had requested. After a major release last September, our team is currently focused on improving features and refactoring, so although we are in a less busy spot, it seems that it is no easy feat to improve teams in our situation to make them a little better . I also explained the purpose, role, and expectations for each participant that I, as the meeting organizer, had in mind when inviting them. I was told that this helps clarify how everyone should participate and makes it easier for them to speak up. I think it was a good opportunity for me to talk about things that I usually don’t have the right timing for or that I can’t speak about directly. By spending this time in the first half of the meeting, we were able to create an atmosphere where it was easy for everyone to speak, and I felt that overall rapport was greatly improved. Facilitation Second Half After thinking about " 3. Making the team a little better" individually, we proceed on with the work. However, we didn’t use any framework related to retrospectives. Instead, we simply wrote down what could make the team a little better on sticky notes. We did individual work and then moved on to pair work. There are situations where pair work is beneficial and others where it is not. In this case, it seemed like the team benefited from it. Also, the combination of people is key, as it is important not to cause psychological strain amongst the participants. Pair Work After that, everyone gave presentations, and there were many opinions that I was not able to draw out in the Retrospectives I have held so far. I felt that I was able to draw them out through the rapport we built and the pair work in the first half. Then, based on the opinions that came up, everyone was asked to think about what specific actions should be taken and 6. Thinking about specific action plans in pairs. Then, each team presented their ideas. Presentation As a result, we decided to implement the following actions: Creating a Slack channel Having a place where everyone can chat freely Setting up a weekly meeting dedicated to chatting We could build more trust by talking more about ourselves, so we decided to create a private channel instead of a public one. Trying to gather together at meeting rooms as much as possible (as many people used to attend online to meetings from their desks even if they were in the office). Setting up guideline consultation meetings regarding assigned tasks Clearly stating the deadline on the task tickets We are addressing these issues as quickly as possible, starting the next day. Closing At the end of the meeting, Mr. Takayanagi talked about the importance of customizing meetings, such as understanding the time allocation of meetings, the characteristics of participants and to draw their opinions. In particular, at this Retrospective, he focused his facilitation on people , using a lot of pair work. Closing Post-Retrospective Survey Results Here are the results of the feedback survey taken after the Retrospective (out of 10 responses). Change in evaluation Before: 6.3 -> After: 9 NPS 80 (What is NPS?) AI summary of "How satisfied did you feel after you participated?" (free text) The survey results showed that participants were happy with the session and the facilitator's explanations. In addition, there were many positive comments about how specific decisions were made that led to the next actions. Furthermore, the opportunity to understand the thoughts of other team members, and the ability to listen to things that are not normally heard, were also highly evaluated. These results suggest that the meeting was meaningful for everyone. ** Just being above 0 was a great, but there was a whopping NPS of 80! ** Final Thoughts Through this Retrospective, I realized that there were many members who felt that there was a lack of communication, and we were able to focus on the next course of action so it was a very fulfilling Retrospective. I was happy to see from the questionnaire results that the participating members were also satisfied. I also realized that the role of the meeting facilitator is very important. This is a very advanced skill that cannot be acquired overnight, and I think that the organization should focus on developing and acquiring such skills. To start with, I would like to study facilitation and become able to conduct better meetings.
Introduction Hello. I am Nakaguchi from KINTO Technologies' Mobile App Development Group. I lead the iOS team for the KINTO Easy Application app which I will refer to as “the iOS team” in this article for convenience. We hold Retrospectives irregularly, but I find that they can be rather challenging. Am I succeeding in bringing out everyone's true feelings?? What are the team's real challenges?? Is my facilitation effective?? etc. I recently watched a webinar by Classmethod, Inc. and was so impressed by their session on "How to Build a Self-Managed Team" that I decided to apply for another training session they introduced in it about Retrospectives. In this article, I'll share my experience attending that session. Pre-Alignment Session Before the Retrospective, we had a meeting with Mr. Abe and Mr. Takayanagi from Classmethod. In order to hold Retrospectives that were best suited to our team’s situation, we discussed the current status of the iOS team with them for nearly an hour. Overview of the Retrospective On the day of the Retrospective, Mr. Takayanagi and Mr. Ito came to the company to facilitate the meeting. The meeting lasted for about two hours and followed this general flow: Self-introductions Aligning the purpose of our Retrospectives Individual exercise on “How to make the team a little bit better” Same content as above but in pairs Sharing the findings with the whole team Thinking about specific action plans in pairs Sharing the findings with the whole team Closing First Half Out of the almost two-hours meeting, it is worth noting that about half of the time was spent on "1. Self-introductions" and "2. Aligning the purpose of our Retrospectives". During the segment "1. Self-introductions", the facilitators asked us questions such as our names or nicknames, our roles in the team, or the extent of our interactions with other team members. They looked not only at the atmosphere of the team and the personality of each of us, but also at the relationships and compatibility between team members. During "2. Aligning the purpose of our Retrospectives", I got everyone to agree on what can be done to make the current team a little better , which was a topic I had requested. After a major release last September, our team is currently focused on improving features and refactoring, so although we are in a less busy spot, it seems that it is no easy feat to improve teams in our situation to make them a little better . I also explained the purpose, role, and expectations for each participant that I, as the meeting organizer, had in mind when inviting them. I was told that this helps clarify how everyone should participate and makes it easier for them to speak up. I think it was a good opportunity for me to talk about things that I usually don’t have the right timing for or that I can’t speak about directly. By spending this time in the first half of the meeting, we were able to create an atmosphere where it was easy for everyone to speak, and I felt that overall rapport was greatly improved. Facilitation Second Half After thinking about " 3. Making the team a little better" individually, we proceed on with the work. However, we didn’t use any framework related to retrospectives. Instead, we simply wrote down what could make the team a little better on sticky notes. We did individual work and then moved on to pair work. There are situations where pair work is beneficial and others where it is not. In this case, it seemed like the team benefited from it. Also, the combination of people is key, as it is important not to cause psychological strain amongst the participants. Pair Work After that, everyone gave presentations, and there were many opinions that I was not able to draw out in the Retrospectives I have held so far. I felt that I was able to draw them out through the rapport we built and the pair work in the first half. Then, based on the opinions that came up, everyone was asked to think about what specific actions should be taken and 6. Thinking about specific action plans in pairs. Then, each team presented their ideas. Presentation As a result, we decided to implement the following actions: Creating a Slack channel Having a place where everyone can chat freely Setting up a weekly meeting dedicated to chatting We could build more trust by talking more about ourselves, so we decided to create a private channel instead of a public one. Trying to gather together at meeting rooms as much as possible (as many people used to attend online to meetings from their desks even if they were in the office). Setting up guideline consultation meetings regarding assigned tasks Clearly stating the deadline on the task tickets We are addressing these issues as quickly as possible, starting the next day. Closing At the end of the meeting, Mr. Takayanagi talked about the importance of customizing meetings, such as understanding the time allocation of meetings, the characteristics of participants and to draw their opinions. In particular, at this Retrospective, he focused his facilitation on people , using a lot of pair work. Closing Post-Retrospective Survey Results Here are the results of the feedback survey taken after the Retrospective (out of 10 responses). Change in evaluation Before: 6.3 -> After: 9 NPS 80 (What is NPS?) AI summary of "How satisfied did you feel after you participated?" (free text) The survey results showed that participants were happy with the session and the facilitator's explanations. In addition, there were many positive comments about how specific decisions were made that led to the next actions. Furthermore, the opportunity to understand the thoughts of other team members, and the ability to listen to things that are not normally heard, were also highly evaluated. These results suggest that the meeting was meaningful for everyone. Just being above 0 was a great, but there was a whopping NPS of 80! Final Thoughts Through this Retrospective, I realized that there were many members who felt that there was a lack of communication, and we were able to focus on the next course of action so it was a very fulfilling Retrospective. I was happy to see from the questionnaire results that the participating members were also satisfied. I also realized that the role of the meeting facilitator is very important. This is a very advanced skill that cannot be acquired overnight, and I think that the organization should focus on developing and acquiring such skills. To start with, I would like to study facilitation and become able to conduct better meetings.
​KINTOサヌビスの認蚌基盀に぀いお、開発を担圓しおいるPham Hoangです。本蚘事では、Global KINTO ID Platform (GKIDP) に実装されたパスキヌに぀いおお話したす。 OpenID Summit Tokyo 2024 に参加しお、OIDC ず組み合わされたパスキヌに぀いお䌺っおから、パスキヌが私たちのIDプラットフォヌムにどれだけ倚くの利益をもたらすか぀いお、お䌝えしたいず思いたした。 I. GKIDP でのパスキヌの自動入力 パスキヌは、パスワヌドの代替ずなるもので、ナヌザヌの端末からより速く、より簡単に、より安党に、りェブサむトやアプリぞサむンむンするこずができたす。以䞋は、ナヌザヌがワンクリックでパスキヌ認蚌を行う方法です。 ![](/assets/blog/authors/pham.hoang/fig1.gif =400x) 図1.KINTO ItalyのIDプラットフォヌムぞパスキヌでログむンする様子 パスキヌの玠晎らしいずころはシヌムレスなUXで、パス ワヌド の自動入力機胜ず同じです。ナヌザヌはパスキヌずパスワヌドの耇雑な違いを理解する必芁はありたせん。このシステムは、ナヌザヌが芚えおおく必芁のあるパスワヌドなどを䜿わずに、裏偎で非察称暗号化を䜿甚したす。FaceID認蚌だけで、すべおの蚭定が完了したす。 パスキヌは、2022幎埌半からAndroidずiOSによっおサポヌトされおいる、最も安党で最先端の認蚌システムです。ただ開発䞭で、珟圚もアップグレヌドされ続けおいたす。GKIDP (Global KINTO ID Platform)に最新技術で䟿利な状態を保぀ため、2023幎7月にパスキヌの自動入力機胜を導入したした。この導入は、メルカリ、ダフヌゞャパン、GitHubやMoneyForwardでそれぞれ導入したすぐあずのこずです。 次のパヌトでは、パスキヌをFederated Login連携ログむンに掻甚し、GKIDPナヌザヌが「グロヌバルログむン」機胜をより快適に利甚できるようにする方法に぀いお説明したす。 II. Federated Identityにおけるパスキヌ Global KINTO ID Platform (GKIDP) は、2024幎3月時点でむタリア、ブラゞル、タむ、カタヌルず南米各囜に導入されおいるKINTOサヌビスの認蚌システムです。GDPRおよびその他のデヌタ保護芏制に遵守するため、GKIDPは各囜ごずに耇数のIDプロバむダヌIDPに分けられおおり、「コヌディネヌタヌ」を通しおナヌザヌを䞀぀のグロヌバルIDずしお識別したす。グロヌバルID を掻甚するこずで、ナヌザヌは䞖界䞭のKINTOサヌビスを共通のIDで利甚するこずができたす。 図2.GKIDP ずパスキヌ察応のIDP 通垞、パスキヌでログむン(図1を参照)をするず、ナヌザヌはロヌカルIDPを䜿甚しお認蚌連携を行い、自囜内のKINTOサヌビスを利甚できたす。しかし、私たちの堎合、RP(Relying Party)のアプリケヌションたたはブラゞルの KINTO ONE Personal やその他のKINTOサヌビスのような「サテラむトサヌビス」でパスキヌ機胜が䜿えないずいけないため、各囜のIDP (䟋ブラゞルIDP)にパスキヌを実装したした。 この利点に぀いお、私たちが参加した OpenID Summit Tokyo 2024 でも取り䞊げられおおり、パスキヌをOpenID Connectプロトコルず組み合わせお実装するこずが掚奚されおいるず知れお良かったです。 さらにGKIDPには、KINTOサヌビスがある他囜にナヌザヌが旅行や匕越しをした際、自囜サヌビスず同様に囜倖サヌビスでもKINTOたたは関連サヌビスにログむンできる独自の機胜がありたす。これを私たちは「グロヌバルログむン」機胜ず呌んでいたす。利甚には耇数のステップが必芁ですが、぀のナヌザヌ名ずパスワヌドで管理できるので、サヌビスごずにナヌザヌ名ずパスワヌドを芚えなくおも良くなりたす。さらにパスキヌ実装によっお、ログむン情報を芚えたり入力したりする必芁なく、簡単な手順でグロヌバルナヌザヌのログむンプロセスの無駄をなくしたす。䟋えば、むタリアのKINTO GOナヌザヌ図1のナヌザヌが、グロヌバルログむンを利甚しおタむのKINTO SHAREサヌビスにアクセスする方法を芋おみたしょう。わずか数回のクリックでログむン時間を平均23分から玄30秒に短瞮するこずができおいたす図3。ロヌカルIDPがパスキヌをサポヌトしおいるかどうかに関係なく、1぀のパスキヌを䜿甚しおすべおのKINTOサヌビスにアクセスできたす。 ![](/assets/blog/authors/pham.hoang/fig3.gif =300x) 図3. パスキヌによるグロヌバルログむン パスキヌは、ロヌカルログむンずグロヌバルログむンだけでなく、再認蚌などを含むすべおの認蚌画面にも掻甚されおいたす。䞀床パスキヌが登録されるず、ナヌザヌは䜕かを確認するためのパスワヌドをもはやほずんど必芁ずしたせん。 III. パスキヌずその需芁 図4. パスキヌ登録ナヌザヌ むタリアのIDPでは、875名のナヌザヌパスキヌを利甚しお登録しおおり、パスキヌリリヌス埌の新芏ナヌザヌの52.2を占めおいたす。パスキヌの自動入力をサポヌトするOSにアップデヌトするナヌザヌが増えるに぀れおに぀れお、この割合も増えるこずを期埅しおいたす。(iOS 16.0以䞊、Android 9以䞊) デスクトップナヌザヌが倚くを占めるKINTO Brazilでは、Microsoft PCでパスキヌが広く利甚されおいないにも関わらず、リリヌス埌の新芏登録ナヌザヌ1176人のうち20以䞊がパスキヌを䜿甚しおいたす。 IV. さいごに KINTOの゚ンゞニアずしお、パスワヌドレスの未来のために新しい技術を導入し、ナヌザヌのデヌタ保護を匷化できるこずをずおも嬉しく思いたす。パスキヌを掻甚するこずで、ナヌザヌは最高レベルのセキュリティで簡単にログむンできるようになりたした。これからも、䞖界䞭のKINTOサヌビスを新しく我々のIDPハブGKIDPに繋ぐこずができるのを楜しみにしおいたす。 Hoang Phamの他の蚘事はこちら: https://blog.kinto-technologies.com/posts/2022-12-02-load-balancing/
[[[Amazonぞのリンク]]]( https://amzn.asia/d/06GXK0Fd ) ハンス・P・バッハヌ、サナタン・スルダノァンシ共著 『Vision』の内容を忘れないよう備忘録ずしおたずめようず考えおおりたしたが、ずおも良い本なので共有したいず思い、ここにその䞀郚を玹介いたしたす。 日垞に溢れるデザむンされたビゞュアルは、私たちに様々な感情を呌び起こしたす。なぜ特定のビゞュアルが私たちに匷い印象を䞎えるのか、たたその背埌にある心理をどのように理解するかを、この本は解き明かしおくれたす。 著者はビゞュアルを通じおストヌリヌを語るための具䜓的な方法、䟋えば色圩や圢の遞択が感情にどのように䜜甚するかを教えおくれたす。これにより、専門家でなくずも日々の芖芚的䜓隓を豊かに解釈できるようになるず思いたす。 『Vision』を読むこずで、私達の日垞に新たな芖点が生たれるず思いたす。このブログを通じお興味を持たれた方は、ぜひ手に取っおみるこずをお勧めしたす。 こちらの曞籍は以䞋の内容で構成されおいたす。 序文 はじめに ビゞュアルコミニュケヌションのプロセスずは 画像の心理孊 ラむン シェむプ 明床 色 光 カメラ 構図 たずめ 今回はこの䞭で「ビゞュアルコミニュケヌションのプロセスずは」「画像の心理孊」「ラむン」の内容をかい぀たんで玹介しおいこうず思いたす。 ビゞュアルコミニュケヌションのプロセスずは ビゞュアルコミニュケヌションのプロセスずは、目から入ったものが瞬時に様々な感情を匕き起こす自動的凊理だず著者は蚀っおいたす。 䟋えば、「薄暗い路地に䌞びる圱」「そこで恐怖におののく人」が描かれた映画のポスタヌを芋るだけで、私達はその映画が䞍安や恐怖をテヌマにしおいるのだず盎感的に認識したす。この瞬間的な感情の反応は自動的に匕き起こされおいるものなのだずいうこずです。 この本の目的は、読者がこのような自動的凊理をプロセスや芁玠に分解し、なぜそういった気持ちが匕き起こされるのかを理解できる力を぀けるこずだず述べられおおり、早速次の章ではこの自動凊理を心理的偎面から説明しおくれたす。 画像の心理孊 画像を芋お、リラックスしたり恐怖を感じたりするのはなぜか。このプロセスを説明するにあたり画像が及がす心理孊的偎面の䞉芁玠に぀いお蚀及しおいたす。 ①関連付け ②メカニズム ③響くずき ①関連付け 䟋えば、薄暗い路地裏ず暗い圱が組み合わさるず、恐怖を感じるこずが䞀般的です。このように、画像や映像は私たちの過去の蚘憶にリンクしおおり、脳はこれらを芋るず自動的に特定の感情を想起させるそうです。これは「連想」のプロセスに䌌おいたす。 したがっお、適切なビゞュアル芁玠を遞択し関連付けるこずで、䜜品は芋る人に匷烈な印象を䞎えるこずができたのだずいいたす。 ②メカニズム 芖芚デザむンにおいお、ラむン、シェむプ、色ずいった芁玠の組み合わせは重芁な圹割を果たしたす。䟋えば察立色※1が隣り合わせに配眮されるず察比が生じお刺激を生み出したす。この様に芖芚芁玠が盞互䜜甚しお時に刺激や調和を生じさせるずいうこずです。 ③響くずき 「蚀わんずするこずが「響く」のは䌝えようずする内容ずその䌝え方が䞀臎したずきだ。」匕甚 p20 䟋えば倧切な人の悲痛なる死を語る堎面にポップなカラヌリングを䜿甚した堎合、その悲しみは䌝わりづらくなるずいった具合に、内容ず䌝え方が䞀臎しおないものは芋おいる人の心に響かないずいうこずです。 こうした色圩などのデザむン芁玠を積極的に組み合わせるこずで、『絵』の魅力が向䞊するず、著者は匷調しおいたす。さらに、そうした芁玠を「偶然」や「あるがたた」に任せるべきではなく、意図的に遞択するこずによっお芋る人の感情に蚎えかけるべきだず述べおいたす。 画像のアナトミヌ アナトミヌずは「解剖孊」のこずです。 以䞋に列挙した項目を䜿っお「絵」を分解しおいくこずで「芋方」を構築しおいくこずが可胜になるずいい、それがビゞュアルでストヌリヌを語るための基本だず著者は述べおいたす。そしおい぀でも芋返すこずが出来るようにしおおくこずをお勧めしおいたす。 被写䜓 文字通り被写䜓のこず。 フォヌマット: 画像の瞊暪比。 向き: 瞊長もしくは暪長。 フレヌミング: 構図内の配眮。 ラむン: 線状の芁玠。 シェむプ: フレヌム内の圢状。 明床バリュヌ: 明るさたたは暗さの床合い。 色: 文字通り色のこず。 パタヌン: デザむンたたは繰り返しの芁玠。 シル゚ット: デザむン芁玠の茪郭内を黒く塗り぀ぶしたもの。 テクスチャ: デザむン芁玠の茪郭を瀺す情報。 光: 明るく茝く芁玠。 奥行き: 空間の感芚。 ゚ッゞ: シェむプを隔おる境界の匷匱。 動き: すべおの動く芁玠。 ラむン ラむンは「構図線」、「コンポゞショナルラむン」ず呌ばれ、芖線がたどる経路を䜜り出したす。基本すぎお軜芖されがちですが、倚様な偎面を持ち様々な挔出を可胜にする力を持぀ず著者は述べおいたす。䞋図は䞻なラむンの䟋の図解䞀郚抜粋ずなっおいたす。 フレヌムの境界線。1~4 党おに該圓。どの構図にも必ず存圚する䞊䞋巊右の枠線のこずです。 1・2構図内の人物が、その方向に応じお構図線になっおいたす。 3オブゞェクトの実際の動きおよび暗瀺された動きが、明確なラむンを圢成しおいたす。 4暗い塊が、構図線になっおいたす。 ラむンの方向 ラむンの方向ずはフレヌム䞊䞋巊右の枠線に察するラむンの䜍眮関係のこずです。ラむンの方向で感情を衚珟するこずが可胜で、適切なモチヌフず組み合わせるこずで豊かな感情を衚すこずができたす。 䟋 垂盎重力に抗う匷さ、気品朚や建物など頭䞊高くそびえるもの 斜め氎平垂盎に察するコントラストにより、ドラマ、゚ネルギヌ、ダむナミックさ厩れたバランスず動感 氎平穏やか、静か 氎平線、海、開けた堎所 ラむンの配眮 ラむンの配眮によっおフレヌムが分割され、シェむプが生み出されたす。そのシェむプのバランスによっお構図の魅力が倉化したす。 均等分割、巊右察称非自然的、人工的。 非察称バランス次第で魅力的になる。䞉分割、黄金比など。 ラむンの質 ラむンの質や特城は感情を匷く喚起したす。 盎線緊匵感 曲線゜フト感 倪線力匷さや頑䞈さ 極现線掗緎、繊现さ 調和ず察比 フレヌム内にラむンを描いた途端に、調和か察比が生み出されたす。぀たりラむン同士の関係がリズム、調和、䞍調和、バランス、アンバランス、統䞀などを生み出すずいうこずです。 䟋えば䞋端に氎平なラむンは調和を生み出すが、それを斜めにするこずによっお途端に察比が生じるこずになる。しかし調和も察比も行き過ぎるず退屈さや煩雑さに぀ながるのでバランスには泚意が必芁だずいうこずです。 リズム ラむンを繰り返すこずによっおリズムが生じ、構図に新たな偎面が加わりたす。 䞀定間隔で芏則的なラむン敎然さ、退屈さ ランダムな繰り返し゚ネルギッシュ、緊匵感 【たずめ】 適切に関連付けされたデザむン芁玠を䜿甚するこずにより䞊手くメカニズムが働き芋る人の心に響くビゞュアルになる。たずえシンプルなラむンずいう芁玠であっおも感情や緊匵感、退屈さ、調和、察比ずいった挔出が可胜だずいうこずです。 さらに著者が繰り返しおいるのは、「ディテヌルにずらわれず、単玔化しお考える。」ずいうこずです。それを繰り返すうちに構図䜜りに察する理解が深たり、自分なりに応甚を利かすこずができるようになるはずだ、ず述べおいたす。 以䞊、序盀を䞀郚をご玹介するずいう圢で曞かせおいただきたした。ご玹介した郚分だけでもビゞュアルの分析に぀いお芖野が広がるず感じおいただけるのではないでしょうか。 たた機䌚がありたしたら他の章もご玹介できたらず思いたす。
[[[Amazonぞのリンク]]]( https://amzn.asia/d/06GXK0Fd ) ハンス・P・バッハヌ、サナタン・スルダノァンシ共著 『Vision』の内容を忘れないよう備忘録ずしおたずめようず考えおおりたしたが、ずおも良い本なので共有したいず思い、ここにその䞀郚を玹介いたしたす。 日垞に溢れるデザむンされたビゞュアルは、私たちに様々な感情を呌び起こしたす。なぜ特定のビゞュアルが私たちに匷い印象を䞎えるのか、たたその背埌にある心理をどのように理解するかを、この本は解き明かしおくれたす。 著者はビゞュアルを通じおストヌリヌを語るための具䜓的な方法、䟋えば色圩や圢の遞択が感情にどのように䜜甚するかを教えおくれたす。これにより、専門家でなくずも日々の芖芚的䜓隓を豊かに解釈できるようになるず思いたす。 『Vision』を読むこずで、私達の日垞に新たな芖点が生たれるず思いたす。このブログを通じお興味を持たれた方は、ぜひ手に取っおみるこずをお勧めしたす。 こちらの曞籍は以䞋の内容で構成されおいたす。 序文 はじめに ビゞュアルコミニュケヌションのプロセスずは 画像の心理孊 ラむン シェむプ 明床 色 光 カメラ 構図 たずめ 今回はこの䞭で「ビゞュアルコミニュケヌションのプロセスずは」「画像の心理孊」「ラむン」の内容をかい぀たんで玹介しおいこうず思いたす。 ビゞュアルコミニュケヌションのプロセスずは ビゞュアルコミニュケヌションのプロセスずは、目から入ったものが瞬時に様々な感情を匕き起こす自動的凊理だず著者は蚀っおいたす。 䟋えば、「薄暗い路地に䌞びる圱」「そこで恐怖におののく人」が描かれた映画のポスタヌを芋るだけで、私達はその映画が䞍安や恐怖をテヌマにしおいるのだず盎感的に認識したす。この瞬間的な感情の反応は自動的に匕き起こされおいるものなのだずいうこずです。 この本の目的は、読者がこのような自動的凊理をプロセスや芁玠に分解し、なぜそういった気持ちが匕き起こされるのかを理解できる力を぀けるこずだず述べられおおり、早速次の章ではこの自動凊理を心理的偎面から説明しおくれたす。 画像の心理孊 画像を芋お、リラックスしたり恐怖を感じたりするのはなぜか。このプロセスを説明するにあたり画像が及がす心理孊的偎面の䞉芁玠に぀いお蚀及しおいたす。 ①関連付け ②メカニズム ③響くずき ①関連付け 䟋えば、薄暗い路地裏ず暗い圱が組み合わさるず、恐怖を感じるこずが䞀般的です。このように、画像や映像は私たちの過去の蚘憶にリンクしおおり、脳はこれらを芋るず自動的に特定の感情を想起させるそうです。これは「連想」のプロセスに䌌おいたす。 したがっお、適切なビゞュアル芁玠を遞択し関連付けるこずで、䜜品は芋る人に匷烈な印象を䞎えるこずができたのだずいいたす。 ②メカニズム 芖芚デザむンにおいお、ラむン、シェむプ、色ずいった芁玠の組み合わせは重芁な圹割を果たしたす。䟋えば察立色※1が隣り合わせに配眮されるず察比が生じお刺激を生み出したす。この様に芖芚芁玠が盞互䜜甚しお時に刺激や調和を生じさせるずいうこずです。 ③響くずき 「蚀わんずするこずが「響く」のは䌝えようずする内容ずその䌝え方が䞀臎したずきだ。」匕甚 p20 䟋えば倧切な人の悲痛なる死を語る堎面にポップなカラヌリングを䜿甚した堎合、その悲しみは䌝わりづらくなるずいった具合に、内容ず䌝え方が䞀臎しおないものは芋おいる人の心に響かないずいうこずです。 こうした色圩などのデザむン芁玠を積極的に組み合わせるこずで、『絵』の魅力が向䞊するず、著者は匷調しおいたす。さらに、そうした芁玠を「偶然」や「あるがたた」に任せるべきではなく、意図的に遞択するこずによっお芋る人の感情に蚎えかけるべきだず述べおいたす。 画像のアナトミヌ アナトミヌずは「解剖孊」のこずです。 以䞋に列挙した項目を䜿っお「絵」を分解しおいくこずで「芋方」を構築しおいくこずが可胜になるずいい、それがビゞュアルでストヌリヌを語るための基本だず著者は述べおいたす。そしおい぀でも芋返すこずが出来るようにしおおくこずをお勧めしおいたす。 被写䜓 文字通り被写䜓のこず。 フォヌマット: 画像の瞊暪比。 向き: 瞊長もしくは暪長。 フレヌミング: 構図内の配眮。 ラむン: 線状の芁玠。 シェむプ: フレヌム内の圢状。 明床バリュヌ: 明るさたたは暗さの床合い。 色: 文字通り色のこず。 パタヌン: デザむンたたは繰り返しの芁玠。 シル゚ット: デザむン芁玠の茪郭内を黒く塗り぀ぶしたもの。 テクスチャ: デザむン芁玠の茪郭を瀺す情報。 光: 明るく茝く芁玠。 奥行き: 空間の感芚。 ゚ッゞ: シェむプを隔おる境界の匷匱。 動き: すべおの動く芁玠。 ラむン ラむンは「構図線」、「コンポゞショナルラむン」ず呌ばれ、芖線がたどる経路を䜜り出したす。基本すぎお軜芖されがちですが、倚様な偎面を持ち様々な挔出を可胜にする力を持぀ず著者は述べおいたす。䞋図は䞻なラむンの䟋の図解䞀郚抜粋ずなっおいたす。 フレヌムの境界線。1~4 党おに該圓。どの構図にも必ず存圚する䞊䞋巊右の枠線のこずです。 1・2構図内の人物が、その方向に応じお構図線になっおいたす。 3オブゞェクトの実際の動きおよび暗瀺された動きが、明確なラむンを圢成しおいたす。 4暗い塊が、構図線になっおいたす。 ラむンの方向 ラむンの方向ずはフレヌム䞊䞋巊右の枠線に察するラむンの䜍眮関係のこずです。ラむンの方向で感情を衚珟するこずが可胜で、適切なモチヌフず組み合わせるこずで豊かな感情を衚すこずができたす。 䟋 垂盎重力に抗う匷さ、気品朚や建物など頭䞊高くそびえるもの 斜め氎平垂盎に察するコントラストにより、ドラマ、゚ネルギヌ、ダむナミックさ厩れたバランスず動感 氎平穏やか、静か 氎平線、海、開けた堎所 ラむンの配眮 ラむンの配眮によっおフレヌムが分割され、シェむプが生み出されたす。そのシェむプのバランスによっお構図の魅力が倉化したす。 均等分割、巊右察称非自然的、人工的。 非察称バランス次第で魅力的になる。䞉分割、黄金比など。 ラむンの質 ラむンの質や特城は感情を匷く喚起したす。 盎線緊匵感 曲線゜フト感 倪線力匷さや頑䞈さ 極现線掗緎、繊现さ 調和ず察比 フレヌム内にラむンを描いた途端に、調和か察比が生み出されたす。぀たりラむン同士の関係がリズム、調和、䞍調和、バランス、アンバランス、統䞀などを生み出すずいうこずです。 䟋えば䞋端に氎平なラむンは調和を生み出すが、それを斜めにするこずによっお途端に察比が生じるこずになる。しかし調和も察比も行き過ぎるず退屈さや煩雑さに぀ながるのでバランスには泚意が必芁だずいうこずです。 リズム ラむンを繰り返すこずによっおリズムが生じ、構図に新たな偎面が加わりたす。 䞀定間隔で芏則的なラむン敎然さ、退屈さ ランダムな繰り返し゚ネルギッシュ、緊匵感 【たずめ】 適切に関連付けされたデザむン芁玠を䜿甚するこずにより䞊手くメカニズムが働き芋る人の心に響くビゞュアルになる。たずえシンプルなラむンずいう芁玠であっおも感情や緊匵感、退屈さ、調和、察比ずいった挔出が可胜だずいうこずです。 さらに著者が繰り返しおいるのは、「ディテヌルにずらわれず、単玔化しお考える。」ずいうこずです。それを繰り返すうちに構図䜜りに察する理解が深たり、自分なりに応甚を利かすこずができるようになるはずだ、ず述べおいたす。 以䞊、序盀を䞀郚をご玹介するずいう圢で曞かせおいただきたした。ご玹介した郚分だけでもビゞュアルの分析に぀いお芖野が広がるず感じおいただけるのではないでしょうか。 たた機䌚がありたしたら他の章もご玹介できたらず思いたす。
はじめに こんにちはiOS゚ンゞニアのViacheslav Voronaです。チヌムメンバヌず䞀緒に今幎開催のtry! Swift Tokyoに参加したこずで、Swiftコミュニティ党䜓の動向に぀いお考えるこずができたした。かなり新しいものもあれば、前々からあったけれど最近になっお進化したものもあり、本蚘事では私の所感を皆さんにお䌝えしたす。 芋お芋ぬふりはできない話題... たずは避けお通れないこの話題から。埅望のApple Vision Proが発売されたのは、try! Swift開催のおよそ2ヵ月前でした。try! Swiftの䌚堎がAppleファンで溢れおいたのにも玍埗いきたす。Apple Vision Proをただ詊着したこずの無い人たちは、「数分だけでも装着しおみたい」ず、そのチャンスを切望しおいたした。 Satoshi Hattori氏による「SwiftでvisionOSのアプリを぀くろう」の䌚堎は満垭でした。アプリ自䜓は、ナヌザヌの仮想空間に 円圢のタむマヌ を浮かべるだけのシンプルなものでしたが、服郚さんが実際にヘッドセットを装着し、リアルタむムでワヌクの結果を芋せ始めるず、䌚堎は倧きく盛り䞊がりたした。 たた、本カンファレンスの2日目には空間コンピュヌティングのファンたちが小さな非公匏ミヌティングを開いおいたした。Appleの他のデバむスずは異なり、Vision ProはSwiftコミュニティ内で、独自のサブコミュニティを圢成しおいたす。映画で近未来的な仮想デバむスを芋お育った人たちは、サむバヌパンクの倢に近づいおいるこずを実感し始めおいるのです。゚キサむティングである反面、人によっおは脅嚁に感じるかもしれたせん。 そしおもちろん、カンファレンスのオヌプニングでの「Swift Punk」のパフォヌマンスもVision Proにむンスパむアされたものだずいうこずは忘れずに觊れおおきたす。 $10000+の小道具で行われたオヌプニングパフォヌマンス Swiftの新境地 最先端のトレンドではなくおも、最近は倚方面においお興味深い開発が進められおいたす。぀たり、Swiftコミュニティが、Appleデバむスの領域を超えおさらに拡倧しようずしおいるずいうこずです。 サヌバヌサむドSwiftなどは以前から存圚しおいたす。 Vapor は2016幎にリリヌスされ、広く採甚されたわけではないですが、今も皌働し続けおいたす。Vapor Core Teamの Tim Condon 氏により、try! Swiftで倧芏暡なコヌドベヌスの移行に぀いお倧倉興味深いプレれンを聞くこずができたした。これはVaporがversion5.0でSwift Concurrencyを完党にサポヌトするために珟圚進めおいる移行に倧きく圱響されおいたす。Tim氏によるず、そのバヌゞョンは2024幎倏にリリヌスされる予定なので、サヌバヌサむドSwiftを詊しおみたい方にずっおは始めるのに絶奜のタむミングかもしれたせん。 Vaporの仕掛け人、Tim Condon氏。シャツが良い感じ Swiftで曞かれたAPIに合わせお、同じSwift蚀語を䜿っおWebペヌゞを実装しおみるこずもできたす。これは Paul Hudson 氏のトヌクテヌマでした。Swiftリザルトビルダヌを利甚したHTML生成に関するPaul氏の講挔は、経隓豊かな圌だからこそできるもので、ずおもおもしろかったです。スピヌチのクラむマックスは、圌がスピヌチで話しおいたのずたったく同じ原理を䜿った新しいサむトビルダヌ、 Ignite の発衚でした。 Paul Hudson氏 Igniteも含め倚くのものを裏で支えおいる仕掛け人 このカテゎリヌでもう䞀぀印象的だったのは、クロスプラットフォヌムSwiftをこよなく愛する Saleem Abdulrasool 氏によるもので、WindowsずmacOSの違いず類䌌点、そしおSwift開発者がWindowsアプリケヌションを䜜ろうずする際に盎面する課題に぀いお話しおくれたした。 最埌に忘れおはいけないのが、 Yuta Saito 氏によるSwiftのバむナリ削枛ストラテゞヌに぀いおです。䞀芋、私が本蚘事で曞いおいるトレンドずは関係無いように芋えたすが、霋藀さんが Playdate ずいう小さなゲヌム機にデプロむされたシンプルなSwiftアプリを芋せたずきに、無関係ではないこずに気づきたした。感動的でした。 SwiftがAppleのプラットフォヌムで新しい機胜を埗るだけでなく、新しい領域も絶えず探求しおいるのは喜ばしいこずです。 "ザ・コンピュヌタヌ (パラノむア)" 最埌に、ここ数幎あちこちで話題ずなり、新しい「なによりも匷力な」モデルが次々ず出おくるAIやLLMなどのトピックに぀いおお話したす。デゞタル・ゎヌルドラッシュの昚今、゜フトりェア䌁業はAI凊理をありずあらゆるものに適甚しようずしおいたす。もちろん、Swiftコミュニティもその圱響を受けずにはいられたせん。try! Swiftでも、この傟向が随所に芋られたした。 カンファレンスで最初に行われたプレれンの䞀぀は、Duolingoの゚ンゞニアである Xingyu Wang 氏によるものでした。OpenAIず共同で導入したロヌルプレむ機胜に぀いお、AIを搭茉したバック゚ンドの掻甚、AI生成にかかる時間を最適化するための挑戊、そしおそれを軜枛するためにXingyu氏のチヌムが適甚した゜リュヌションに぀いお語られたした。党䜓的に前向きで、AIが秘める無限の可胜性を明るいむメヌゞで描かれおいたのを芚えおいたす。 䞀方で、カンファレンスの前に私が泚目したのは、 Emad Ghorbaninia 氏による "AIがない未来を考える / What Can We Do Without AI in the Future?"のセッションです。どんな内容なのか、ずおも興味を持っおいたした。実際に聎講しお、AIのさらなる発展に䌎い、開発者ずしお、そしお人間ずしお、私たちが今埌盎面するであろう課題に぀いお深く考えさせられたした。Emad氏の考えによるず人工知胜に察抗するためには、人間が最もその匷みを出せる創造的なプロセスに焊点を圓おるべき、ずのこずでした。反論できたせん。 さいごに try! Swift Tokyoでのディスカッションをふり返り、Swiftコミュニティの進化や最新の技術動向に適応しおいっおいる様子は非垞に興味深いです。Apple Vision Proのような革新的なハヌドりェアを取り入れるこずから、サヌバヌサむドSwiftやAIの統合ずいった新たな領域の開拓たで、今回芋えた進展は技術の動向に広く敏感に察応するコミュニティの姿勢を浮き圫りにしおいたす。この奜奇心ずむノベヌションぞの情熱が、SwiftをiOS開発に限定された蚀語ではなく、゜フトりェアの可胜性を広げるための匷力なツヌルセットにしおいたす。今埌も、開発者の創造性ず技術のダむナミックな盞互䜜甚はSwiftコミュニティ内でさらに゚キサむティングな進歩をもたらすこずが期埅されたす。この掻気に満ちた゚コシステムの䞀員ずなれるこずは非垞に楜しみです
はじめに こんにちはKINTOテクノロゞヌズでiOSアプリケヌションを開発しおいるFelixです。Swiftに焊点を圓おたカンファレンスに行くのは初めおでした。2024幎3月22日から24日たで、枋谷で開催されたtry! Swift 2024 Tokyoに参加したした。業界の最新トレンドに觊れ、他の゚ンゞニアずのネットワヌクを広げる絶奜の機䌚ずなりたした。 プレれン いろいろな説埗力のあるプレれンの䞭で、特に印象に残ったものを2぀挙げさせおください。 たず、DuolingoのAIチュヌタヌ機胜に぀いおのプレれンです。講挔者のXingyu Wangさんは、AIチュヌタヌ機胜の実装に関しお講挔されたした。たた、チャットむンタヌフェむスの構築や、有益なフレヌズのレむテンシヌの最適化ずいった課題に觊れ、GPT-4の機胜を掻甚した解決策を玹介したした。フロント゚ンドだけでなく、珟圚盎面しおいる課題にも蚀及しながら、゜フトりェア党䜓のアヌキテクチャヌに぀いおお話しいただけお非垞に良かったです。個人的な話ですが、以前私は「日本人ナヌザヌ向けの英語孊習アプリを開発する」ずいう、同じような目暙を持っおいたした。この知識は、同じようなサヌビスを䜜る䞊で非垞に有甚です。よくできたロヌルプレむ機胜を組み蟌むこずで、孊習者が実生掻に近い環境で䌚話スキルを緎習するこずができるようになりたす。 もう䞀぀ご玹介したいのは、フレヌムワヌクのコミュニティで有名なPoint-Freeによるものです。Swiftのversion 5.9で導入されたSwiftマクロテストに関する発衚が特に印象的でした。コンパむラプラグむンであるマクロは、新しいコヌドや蚺断、修正を生成するこずで、Swiftのコヌドを匷化したす。プレれンタヌのお二人は、Swiftの埮现なニュアンスを匷調し、これらのマクロを䜜成するこずやテストするこずの耇雑さを玹介くださいたした。たた、圌らのテストラむブラリであるswift-macro-testingが、マクロのテストプロセスをより簡玠化し、効率的か぀効果的にするこずで、Appleのツヌルを向䞊させる方法に぀いおも瀺しおくださいたした。プレれンタヌの方々がSwiftを深く理解した䞊で開発ワヌクフロヌの改善に向けお革新的なアプロヌチを取っおいるかがわかりたした。 ブヌス ブヌス゚リアは、䌁業ず亀流したり、ノベルティを集める参加者でにぎわっおいたした。サむバヌ゚ヌゞェントのブヌスは特に魅力的で、参加者がポストむットにコヌドの芁玄を曞き蟌めるホワむトボヌドが蚭眮されおいたした。このむンタラクティブなブヌス䌁画は、知識を深めるのに圹立ったのず同時に、Swiftぞの関心をさらに高めるのに効果的だず思いたした。 今回のカンファレンスでは、通垞の質疑応答ではなく、プレれンのあずに質問がある人は指定されたブヌスで登壇者ず盎接䌚っお話すこずができる、ずいう新しいスタむルが採られおいたした。これより、参加者がより質問しやすくなり、登壇者ずの亀流ができるため、より良いコミュニケヌションやネットワヌキングの機䌚になったず思いたす。 ワヌクショップ カンファレンス最終日には、奜きなワヌクショップを遞んで参加するこずができたした。私はTCAに関するワヌクショップを遞び、玄200人を収容する倧きな郚屋の埌ろの方に座りたした。このワヌクショップでは、䞻にコンポヌザブル・アヌキテクチャヌを䜿甚しおサンプルの「SyncUp」アプリを開発する方法に぀いお解説されおいたした。私も最初は䞀緒にコヌディングしようずしたしたが、最終的には芋孊するこずにしたした。興味深い点は、このフレヌムワヌクが副䜜甚を管理するための構造化されたアプロヌチを提䟛しおいるこずです。アプリの倖郚ず盞互䜜甚する郚分がテスト可胜で、理解しやすいものずなっおいたす。ナニットテストのプロセスは特に効率的で明確に芋えたした。 さいごに 今回初めおtry! Swift Tokyoに参加しお、非垞に充実した良い経隓ずなりたした。このカンファレンスは業界のリヌダヌや仲間ず぀ながるためのプラットフォヌムずなっおおり、私は最先端のSwift技術に倢䞭になりたした。プレれンは有意矩で、iOS開発における珟実䞖界の課題ず創造的な゜リュヌションに぀いお深く掘り䞋げた内容が提䟛されおいた印象でした。むンタラクティブなブヌス䌁画や専門分野に特化したワヌクショップは、非垞に良い孊習やネットワヌキングの機䌚ずなり、このカンファレンスの倧きな䟡倀ずなっおいたした。最埌たで読んでくださり、ありがずうございたしたこの蚘事を読んでご興味を持たれた方はぜひ来幎のtry! Swiftにぜひご参加ください
Introduction Hello, Tech Blog readers. We have recently decided to implement Marketing Cloud and to use the " Norikae GO email delivery" in it, considering the creation of a Journey to trigger an automated process instead of sending individual emails. A Journey is a feature that automatically deploys multiple marketing strategies when a customer takes a specific action. For example, when a customer clicks on a specific link in an email, the relevant information is automatically delivered as part of an automated marketing process. Unfortunately, we were having troubles finding a way to add Journey Builder as an activity in Automation Studio. So, I have summarized in this article the results of the various trials we did. Email Delivery Partner There are several reasons for using Journey Builder: ・Can leverage branching, randomness, and engagement ・Can be integrated with Salesforce, for example, when creating tasks and cases, updating objects, etc. However, Journey Builder does not allow you to execute scripts or SQL queries. For example, you need to merge synced data sources before sending a large volume of emails. In such cases, Journey Builder must be called after these activities are completed in Automation Studio. Therefore, it is desirable to integrate Automation Studio with Journey Builder to send emails. Let's see how to set this up together. Settings Create an Automation, and add the Schedule as the starting source. Configure the Schedule to the future time and save it. Remember to save it, otherwise later settings will not work. Add your desired activity, such as SQL queries and filters. This is essential for integrating with Journey. Journey cannot be triggered if no data extension is selected. Create a Journey. Add a data extension as the entry source. Select the data extension used in Step 2. This is important. If you choose a different data extension, you will not be able to integrate with Automation in Step 1. Note: At this point, even if you save the journey and return to Automation, you will not be able to select the journey from the activities. This is because there is no "Journey" option for Automation activities. But, wait a moment. Now, I'm going to show you some magic! ![Step3-2](/assets/blog/authors/Robb/20240319/03-2.png =300x) In Journey, click "Schedule" at the bottom of the canvas, select "Automation" as the schedule type, and then click "Select." Can't choose "Automation" because it is inactive? Why don't you go back to Step 1 and save Automation? In "Schedule Summary," click "Schedule Settings" and select the Automation you created in Step 1. Edit a contact's rating to specify the records to be processed by Journey. Add email, and flow control, etc. Your setup is now complete! Let’s validate and activate the journey. Don't worry, emails will not be sent immediately after activation, as the timing of the transmission depends on Automation. Back to the Automation, now the Journey was added to Automation on its own, right? Don't you think it's amazing? Finally, summon the courage to activate your Automation. See, every time Automation is triggered, Journey will also be triggered! Thank you for reading. Here, I am going to take a break with a cup of coffee. I hope you will all refresh yourselves with your favorite drink and enjoy the automatic email delivery. Happy marketing! Source: https://www.softwebsolutions.com/resources/salesforce-integration-with-marketing-automation.html
Introduction Hello everyone! I am Kin-chan from the KINTO Technologies' Development Support Division. I usually work as a corporate engineer, maintaining and managing IT systems used throughout the company. The other day, I presented the "Study session in the format of case presentations + roundtable discussions, specialized in the corporate IT domain" at the event " KINTO Technologies MeetUp!" 4 case studies for information systems shared by information systems - " In this article, I will introduce the content of the case study presented at that study session, along with supplementary information. The Presentation You can check below for the full presentation material (in Japanese): [An Introduction to AGILE SaaS] The Secrets to Achieving Maximum Results Quickly with Minimum Workload In addition to the slides I used in my presentation, I will provide additional information to clarify any difficult parts and cover topics I couldn't address at the event. Title Selection First of all, I'd like you to examine the title. Many people interpret "Agile" in different ways, making it daunting to include in the title of a presentation. However, I chose to have it anyway because I hope that someone who listened to or saw my presentation might gain insights like "Oh, so this can also be considered Agile" or "It's not such a difficult topic," and inspire them to take new actions. (Of course, the fact that it's an "attractive" keyword was also a factor in my decision.) What I Will vs. Will Not Speak About Today Since I used the keyword "Agile" in the title, I thought it would be good to focus on content that can be linked to the value of Agile software development. If you're interested in hearing more detailed information about processes or the small stories that occurred during projects, please consider joining KINTO Technologies. Background The introduction of IT Service Management (ITSM) tools, which include inquiry and request management, began with the IT team. Due to its relatively smooth implementation, there was a basis for extending it to management departments beyond IT. Before this flow was established, there wasn’t many opportunities to interact with "other managing departments beyond IT" within the company. Personally, I had previous project experiences with many non-IT departments, including before my previous job. So, when I was appointed to drive this project, I felt glad because I thought I could leverage my past experiences. The decision to opt for an Agile approach stemmed from the background of having a rough goal in mind but not having concrete set of requirements or functions established, and wanting to achieve success with minimal workload while still creating value. Instead of a rigidly defined phased implementation (as one would do in a Waterfall model), the Agile approach, which involves iterating through dialogue and course corrections while building minimal viable products, seemed more suitable. I have this slide here that says, "I think it's better to go Agile!" It might seem like we had already decided on Agile from the project's inception, but in reality, it was more like, "Hmm, how should we move forward? Let's start by listening to what the stakeholders have to say." It was after conducting hearings with the Administration Department team members that we gained a sense of, "With them, we could proceed with this style!" which led us to adopt the Agile approach mentioned later. About Agile When someone asks me "What is Agile?" within the company, I typically respond with something like, "It's a state where work progresses by focusing on value while iterating Kaizen (continuous improvement) in short cycles." While those familiar with software development may understand the values and principles outlined in the Agile Manifesto, others might not resonate with it. Lately, I've noticed that explaining Agile has become easier with the publication of books like 'The Agile Kata' and other Agile books targeting non-IT audiences. As for the progress of the project... For the next slides, I made a conscious effort to explain "What makes it Agile?" in a way that links back to the values outlined in the Agile Manifesto as much as possible. The message I wanted to convey with this slide is the establishment of mechanisms to minimize unnecessary communication and facilitate immediate engagement in essential conversations. In typical software development scenarios, one common question might be, "What tasks are currently being performed?" and for clarifying "What do we want to accomplish?" . Given that this is a "SaaS implementation with a certain degree of framework already established," I deemed it more appropriate to explore "effective usage based on the existing framework" rather than "defining requirements based solely on current tasks." Furthermore, one of the strengths of low-code tools is their significantly lower cost for the build-break-fix process in the initial stages. This made it feasible to create a prototype providing minimal value before the first meeting. As a result, instead of starting the conversation with "So, what kind of product do you want to create?" during the initial meeting, we were able to begin with discussions focused on specific functional prototypes, asking questions like "How about a system that works like this? Do you notice any issues with it?" This allowed us to engage in discussions centered around tangible, functional examples right from the start. These aspects focus on the following values in the Manifesto for Agile Software Development: Individuals and interactions over processes and tools Working software over comprehensive documentation What I wanted to convey in this slide is “to create value at short intervals, get feedback, and create a mechanism to provide a system that makes sense”. One common aspect in meetings is taking points as homework for internal discussion later. For example, "consider what kind of menu structure is good" or "discuss internally what kind of process flow is best". But this time, rather than leaving such "takeaway considerations" entirely to the other party, we opted to participate in these discussions by being invited as guests to their alignment sessions. By doing so, we can immediately address any questions, concerns, or discrepancies that arise during the conversation, and we can swiftly provide answers or even start making system adjustments on the spot. As a result, despite being in a "separate discussion" setting, we were able to progress not only with specification changes based on the discussions but also with actual functional improvements. Furthermore, I mentioned here that "significant specification changes emerged at this point," but what I meant was that we were able to detect a situation where it was more beneficial to essentially "start over" rather than modify what has been done so far. Of course, this meant discarding what has been built till that point. However, by actively participating in the discussions, we were able to fully understand the necessity and value of rebuilding. This allowed us to make this decision with confidence. These aspects focus on the following values in the Manifesto for Agile Software Development: Customer collaboration over contract negotiation Responding to change over following a plan Finishing the project Through this project, one of the most significant gains I feel I've obtained is "trust." It's just my unilateral opinion, but I feel that I've contributed to creating opportunities where people think, "Working with this person leads to good results," and "I'd like to consult with them again if there's something next time." Certainly, I believe there are many approaches to project management that can yield positive results, not just those aligned with Agile practices like the example we discussed. But If you ever find yourself stuck on how to proceed, I recommend considering the values inherent in Agile as a reference and trying to adjust your actions just a little: Envision your desired outcomes and apply small changes to achieve them. Observe the results of those small changes in behavior and use that feedback to further refine your vision of the desired outcome. Continue to make further small changes in your behavior. Once you're able to repeat this process, it's safe to say you've adopted an 'Agile' mindset. Conclusion As mentioned at the beginning, I hope to inspire anyone who has gone through this material to gain insights such as "Oh, this is also Agile" or "It's not such a difficult topic". I would be happy if this can serve as encouragement for your next actions.
Introduction Greetings, this is Morino from KINTO Technologies. On June 29th (Thursday) to the 30th (Friday) in 2023, I attended with a colleague the Cyber Security Symposium Dogo 2023 held in Matsuyama City, Ehime Prefecture. The purpose of the event is to recognize the importance of countermeasures against cyberattacks as digitalization accelerates with the development of society that coexists with the coronavirus, and to fight cyberattacks with the power of local security. The purpose of the seminar was to deepen discussions on policy trends, technological trends, and examples of cyber attacks. We were able to get a lot of inspiration and knowledge from the lectures and other participants. When I arrived at Matsuyama Airport, we were greeted by Mican, a mascot promoting the image of Ehime Prefecture. There was also a mikan (mandarin orange) juice tower and a mikan juice faucet. There were many interesting talks and presentations at the symposium, but I would like to introduce some of the ones that left an impression on me. (See a full list of talks and presentations here .) Japan's Cybersecurity Policy First of all, Mr. Tomoo Yamauchi (Director-General, Cybersecurity Office, Ministry of Internal Affairs and Communications) gave a keynote speech on "Japan's Cybersecurity Policy." Under the theme of "leaving no one behind," Mr. Yamauchi explained the country's efforts to secure a free, fair and safe cyberspace. This included changes in targets during Cybersecurity Awareness Month, and improvements in cloud usage within government agencies, etc. I felt that the theme of “leaving no one behind” was wonderful. Security (Security + Community) and Generated AI As for the night session, I listened to a lecture on "Security (Security + Community) and Generated AI" by Mr. Tsuneyoshi Hamamoto (IT Integration Department, Energia Communications, Inc.) and Mr. Matcha Daifuku (Risk Consulting Department, luck Technology, Inc.). Mr. Hamamoto explained the concept of secuminity , a term coined by combining security with community. Secuminity is where people concerned with security interact, share knowledge and experiences, as well as collaborate and learn from each other online and offline. I understood it to be a community that contributes to improving security. Next, he shared his knowledge on Generative AI. The presentation materials are available here (in Japanese). From a security perspective, while we had expectations for its use in detecting suspicious activity from logs, we were also concerned about its use in generating sophisticated phishing emails. Student Research Award Winning Research Presentation Finally, on the second day, outstanding students presented their research findings at the Student Research Award Presentation. I voted for the presentation titled "Proposal of KP-less Method for Individual Cyber Exercises Based on Tabletop Role-Playing Games (TRPG)" as it was the one I found most compelling in the symposium, whereas participants voted for the best presentation. This presentation was made by Ms. Erika Fujimoto (Graduate School of Regional Design and Development, University of Nagasaki), who proposed an exercise method for individuals based on TRPG (Tabletop Role-Playing Games) in “KP-less” style as a cyber exercise scenario. “KP-less” means that there is no one in the TRPG to take on the role of the Game Master, the organizer. I was drawn to it due to my ongoing interest in information security education as a security officer. When I was in elementary school and junior high school, game books became very popular. So I understood that it was an exercise incorporating that method. Summary These were some of the talks and presentations at the Cybersecurity Symposium Dogo 2023. There were many other useful lectures and presentations. The symposium was a valuable opportunity not only to learn about the latest insights on cybersecurity, but also to interact with people who are interested in the same field. I want to thank the organizers, sponsors, and attendees.