LINEヤフー Tech Blog

LINEヤフー株式会社のサービスを支える、技術・開発文化を発信しています。

AIコードレビュー企画によるブース運営(DroidKaigi 2025)

Group photo

2025年9月10日(水)〜9月12日(金)の3日間にわたって開催されたDroidKaigi 2025に、LINEヤフー株式会社はゴールドスポンサーとして参加しました。

イベント期間中は、たくさんの方にLINEヤフーのブースにお越しいただき、誠にありがとうございました。

本ブログでは、イベントのうち2日間に実施した「AI-Code Review Challenge」の概要とLINEヤフーのブースの様子をご紹介します。

AI-Code Review Challenge

LINEヤフーのブースでは、AI-Code Review Challengeを実施しました。

AIが当日その場で生成したコードから、バグやパフォーマンスの問題などを探し出し、来場者にレビューしてもらうという企画です。

コードは大きなディスプレイに表示し、レビューコメントは付箋に書いてボードに貼ってもらう形式で行いました。また、QRコードを読み込むことで、今までに出題された問題すべてが確認できるようにしました。

Booth

DroidKaigi 2024DroidKaigi 2023でも、LINEヤフーのブースではコードレビューの企画を開催していましたが、今年はAIの力を借りることで、2日間で12問もの問題を皆さんと一緒にレビューしました!

Android特有のバグやJetpack Composeで書かれたUI、Viewを利用したJavaの少し懐かしいコードまで、バリエーション豊かな問題をレビューしてもらいました。

ボードが埋まるほど多くのコメントを、付箋に書いて貼っていただきました。また、単に問題を見つけるだけでなく、どのように修正すべきかについても来場者と議論し、大盛況でした。

comments

実際に出題された問題

以下の問題は実際にブースで出題された問題の一つです。

// SPDX-License-Identifier: Unlicense
// SPDX-FileComment: Generated by ChatGPT Enterprise on 2025‑9‑11; human‑reviewed

class UserId(val raw: String) {
    override fun equals(other: Any?): Boolean {
        return other is UserId && raw.equals(other.raw, ignoreCase = true)
    }
    override fun hashCode(): Int = raw.hashCode()
    override fun toString(): String = raw
}

data class User(val id: String, val name: String)

interface Api {
    suspend fun fetchUsers(): List<User>
}

class FakeApi : Api {
    // ネットワークの代わり
    override suspend fun fetchUsers(): List<User> {
        Thread.sleep(300) // 擬似的な遅延
        return listOf(
            User("U1", "Alice"),
            User("U2", "Bob"),
            User("U3", "Carol"),
            User("U4", "Dave"),
            User("U5", "Eve")
        )
    }
}

class UserRepository(private val api: Api) {
    private val cache = mutableMapOf<UserId, User>()

    fun cachedUsers(): List<User> = cache.values.toList()

    fun usersFlow(): Flow<List<User>> = flow {
        emit(cachedUsers())
        val fresh = api.fetchUsers()
        for (u in fresh) cache[UserId(u.id)] = u
        emit(cachedUsers())
    }

    fun page(page: Int, size: Int): List<User> {
        val start = page * size
        return cachedUsers().drop(start).take(size - 1)
    }
}

class Presenter(
    private val repo: UserRepository,
    private val onUsers: (List<User>) -> Unit
) {
    private val started = AtomicBoolean(false)

    fun start() {
        if (!started.compareAndSet(false, true)) return
        GlobalScope.launch {
            runBlocking {
                repo.usersFlow().collect { users ->
                    onUsers(users)
                }
            }
        }
    }
}

object App {
    @JvmStatic
    fun main(args: Array<String>) {
        val presenter = Presenter(
            repo = UserRepository(FakeApi()),
            onUsers = { users ->
                println("Users: ${users.map { it.name }}")
            }
        )
        presenter.start()
        Thread.sleep(1200)
    }
}

コルーチンの誤った呼び出し、equals()hashCode()の不整合、並行処理の排他制御がないなど、さまざまな問題が含まれています。

来場者の中には、5つ以上のコメントをしてくれた人も何人かいました。皆さんは何か所の問題を見つけることができましたか?

アフターイベント

今年はLINEヤフーとZOZOでAfter DroidKaigi 2025を開催しました!

Design DocやAndroid Auto、DroidKaigiについての発表や、DroidKaigi 2025を振り返るパネルディスカッションを通して、楽しく交流しました。

after_droidkaigi

おわりに

DroidKaigi 2025でのLINEヤフーのスポンサーブース企画「AI-Code Review Challenge」について、簡単に紹介しました。

来年も皆さんとブースの企画やアフターイベントを通して交流できることを楽しみにしています!