GPT-4にリファクタリングとコメント全部任せてみた

# 環境
chat-GPT plus (GPT-4)
# 会話

Person: 
- 以下のコードをリファクタリングして
```kotlin
package com.example.myLifeLog.model.receiver

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.example.myLifeLog.*
import com.example.myLifeLog.model.db.MainRoomDatabase
import com.example.myLifeLog.model.db.location.Location
import com.example.myLifeLog.model.db.location.LocationRepository
import com.example.myLifeLog.model.db.transition.Transition
import com.example.myLifeLog.model.db.transition.TransitionRepository
import com.google.android.gms.location.*
import java.time.LocalDateTime

private const val TAG = "ActivityUpdatesBroadcastReceiver"

class ActivityUpdatesBroadcastReceiver: BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        if (ActivityTransitionResult.hasResult(intent)) {
            val result = ActivityTransitionResult.extractResult(intent)!!
            myLog(TAG, "receive ${result.transitionEvents.size} transition events")
            val dB: MainRoomDatabase = MainRoomDatabase.getInstance(context)
            val locationRepository = LocationRepository(dB.LocationDao())
            val transitionRepository = TransitionRepository(dB.TransitionDao())
            val locationClient = LocationServices.getFusedLocationProviderClient(context)

            for (event in result.transitionEvents) {
                myLog(TAG, "get event: ActivityType=${event.activityType}, TransitionType=${event.transitionType}")
                val dateTimeNow = LocalDateTime.now().toMilliSec()
                if (
                    event.activityType == DetectedActivity.STILL &&
                    event.transitionType == ActivityTransition.ACTIVITY_TRANSITION_ENTER
                ) {
                    doSomethingWithLocation(
                        context, locationClient,1, 5,
                        onSuccess = { location ->
                            val nearLocation =
                                locationRepository.getNearLocation(location.latitude, location.longitude)
                            val locationId: Int
                            if (nearLocation != null) {
                                locationId = nearLocation.id
                            } else {
                                locationRepository.insertLocation(
                                    Location(
                                        name = "",
                                        latitude = location.latitude,
                                        longitude = location.longitude
                                    )
                                )
                                locationId = loadSharedPrefInt(context, "locationNum")
                                saveSharedPref(context, "locationNum", "${locationId+1}")
                            }
                            transitionRepository.insertTransition(
                                Transition(
                                    activityType = event.activityType,
                                    transitionType = event.transitionType,
                                    locationId = locationId,
                                    dateTime = dateTimeNow,
                                    latitude = location.latitude,
                                    longitude = location.longitude
                                )
                            )
                        },
                        onFailure = {
                            transitionRepository.insertTransition(
                                Transition(
                                    activityType = event.activityType,
                                    transitionType = event.transitionType,
                                    locationId = null,
                                    dateTime = dateTimeNow,
                                    latitude = null,
                                    longitude = null
                                )
                            )
                        }
                    )
                } else {
                    transitionRepository.insertTransition(
                        Transition(
                            activityType = event.activityType,
                            transitionType = event.transitionType,
                            locationId = null,
                            dateTime = dateTimeNow,
                            latitude = null,
                            longitude = null
                        )
                    )
                }
            }
        }
    }


    companion object {
        const val ACTION_PROCESS_UPDATES =
            "com.example.myLifeLog.action.TRANSITION_UPDATES"
    }
}
```

ChatGPT: 
- 以下のようにコードをリファクタリングしてみました。主な変更点は、クラス内にメソッドを分割し、見やすくした点です。

```kotlin
package com.example.myLifeLog.model.receiver

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.example.myLifeLog.*
import com.example.myLifeLog.model.db.MainRoomDatabase
import com.example.myLifeLog.model.db.location.Location
import com.example.myLifeLog.model.db.location.LocationRepository
import com.example.myLifeLog.model.db.transition.Transition
import com.example.myLifeLog.model.db.transition.TransitionRepository
import com.google.android.gms.location.*
import java.time.LocalDateTime

private const val TAG = "ActivityUpdatesBroadcastReceiver"

class ActivityUpdatesBroadcastReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        if (ActivityTransitionResult.hasResult(intent)) {
            val result = ActivityTransitionResult.extractResult(intent)!!
            myLog(TAG, "receive ${result.transitionEvents.size} transition events")

            val dB = MainRoomDatabase.getInstance(context)
            val locationRepository = LocationRepository(dB.LocationDao())
            val transitionRepository = TransitionRepository(dB.TransitionDao())
            val locationClient = LocationServices.getFusedLocationProviderClient(context)

            for (event in result.transitionEvents) {
                processEvent(context, event, locationClient, locationRepository, transitionRepository)
            }
        }
    }

    private fun processEvent(
        context: Context,
        event: ActivityTransitionEvent,
        locationClient: FusedLocationProviderClient,
        locationRepository: LocationRepository,
        transitionRepository: TransitionRepository
    ) {
        myLog(TAG, "get event: ActivityType=${event.activityType}, TransitionType=${event.transitionType}")
        val dateTimeNow = LocalDateTime.now().toMilliSec()

        if (event.activityType == DetectedActivity.STILL && event.transitionType == ActivityTransition.ACTIVITY_TRANSITION_ENTER) {
            processStillTransition(context, event, locationClient, locationRepository, transitionRepository, dateTimeNow)
        } else {
            insertTransition(transitionRepository, event, dateTimeNow)
        }
    }

    private fun processStillTransition(
        context: Context,
        event: ActivityTransitionEvent,
        locationClient: FusedLocationProviderClient,
        locationRepository: LocationRepository,
        transitionRepository: TransitionRepository,
        dateTimeNow: Long
    ) {
        doSomethingWithLocation(
            context, locationClient, 1, 5,
            onSuccess = { location ->
                val locationId = getLocationId(context, location, locationRepository)
                insertTransition(transitionRepository, event, dateTimeNow, locationId, location.latitude, location.longitude)
            },
            onFailure = {
                insertTransition(transitionRepository, event, dateTimeNow)
            }
        )
    }

    private fun getLocationId(
        context: Context,
        location: android.location.Location,
        locationRepository: LocationRepository
    ): Int {
        val nearLocation = locationRepository.getNearLocation(location.latitude, location.longitude)

        return if (nearLocation != null) {
            nearLocation.id
        } else {
            locationRepository.insertLocation(
                Location(
                    name = "",
                    latitude = location.latitude,
                    longitude = location.longitude
                )
            )
            val locationId = loadSharedPrefInt(context, "locationNum")
            saveSharedPref(context, "locationNum", "${locationId + 1}")
            locationId
        }
    }

    private fun insertTransition(
        transitionRepository: TransitionRepository,
        event: ActivityTransitionEvent,
        dateTime: Long,
        locationId: Int? = null,
        latitude: Double?
```

Person: 
- つづけて

ChatGPT: 
- 続きは以下のとおりです。

```kotlin
longitude: Double? = null
    ) {
        transitionRepository.insertTransition(
            Transition(
                activityType = event.activityType,
                transitionType = event.transitionType,
                locationId = locationId,
                dateTime = dateTime,
                latitude = latitude,
                longitude = longitude
            )
        )
    }

    companion object {
        const val ACTION_PROCESS_UPDATES =
            "com.example.myLifeLog.action.TRANSITION_UPDATES"
    }
}
```



リファクタリングにより、`onReceive`メソッドの処理が複数のメソッドに分割され、コードが読みやすくなりました。各メソッドが具体的なタスクを実行するようになり、それぞれの役割が明確になっています。

Person: 
- さらにコメントを付けて

ChatGPT: 
- コメントを追加し、各メソッドの説明を提供しました。

```kotlin
package com.example.myLifeLog.model.receiver

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.example.myLifeLog.*
import com.example.myLifeLog.model.db.MainRoomDatabase
import com.example.myLifeLog.model.db.location.Location
import com.example.myLifeLog.model.db.location.LocationRepository
import com.example.myLifeLog.model.db.transition.Transition
import com.example.myLifeLog.model.db.transition.TransitionRepository
import com.google.android.gms.location.*
import java.time.LocalDateTime

private const val TAG = "ActivityUpdatesBroadcastReceiver"

class ActivityUpdatesBroadcastReceiver : BroadcastReceiver() {

    // Handle incoming broadcast messages
    override fun onReceive(context: Context, intent: Intent) {
        if (ActivityTransitionResult.hasResult(intent)) {
            val result = ActivityTransitionResult.extractResult(intent)!!
            myLog(TAG, "receive ${result.transitionEvents.size} transition events")

            val dB = MainRoomDatabase.getInstance(context)
            val locationRepository = LocationRepository(dB.LocationDao())
            val transitionRepository = TransitionRepository(dB.TransitionDao())
            val locationClient = LocationServices.getFusedLocationProviderClient(context)

            for (event in result.transitionEvents) {
                processEvent(context, event, locationClient, locationRepository, transitionRepository)
            }
        }
    }

    // Process a single activity transition event
    private fun processEvent
```

Person: 
- さらに日本語のコメントを付けて

ChatGPT: 
- 日本語のコメントを追加しました。

```kotlin
package com.example.myLifeLog.model.receiver

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.example.myLifeLog.*
import com.example.myLifeLog.model.db.MainRoomDatabase
import com.example.myLifeLog.model.db.location.Location
import com.example.myLifeLog.model.db.location.LocationRepository
import com.example.myLifeLog.model.db.transition.Transition
import com.example.myLifeLog.model.db.transition.TransitionRepository
import com.google.android.gms.location.*
import java.time.LocalDateTime

private const val TAG = "ActivityUpdatesBroadcastReceiver"

class ActivityUpdatesBroadcastReceiver : BroadcastReceiver() {

    // 受信したブロードキャストメッセージを処理する
    override fun onReceive(context: Context, intent: Intent) {
        if (ActivityTransitionResult.hasResult(intent)) {
            val result = ActivityTransitionResult.extractResult(intent)!!
            myLog(TAG, "receive ${result.transitionEvents.size} transition events")

            val dB = MainRoomDatabase.getInstance(context)
            val locationRepository = LocationRepository(dB.LocationDao())
            val transitionRepository = TransitionRepository(dB.TransitionDao())
            val locationClient = LocationServices.getFusedLocationProviderClient(context)

            for (event in result.transitionEvents) {
                processEvent(context, event, locationClient, locationRepository, transitionRepository)
            }
        }
    }

    // アクティビティ遷移イベントを一つずつ処理する
    private fun processEvent(
        context: Context,
        event: ActivityTransitionEvent,
        locationClient: FusedLocationProviderClient,
        locationRepository: LocationRepository,
        transitionRepository: TransitionRepository
    ) {
        myLog(TAG, "get event: ActivityType=${event.activityType}, TransitionType=${event.transitionType}")
        val dateTimeNow = LocalDateTime.now().toMilliSec()

        if (event.activityType == DetectedActivity.STILL && event.transitionType == ActivityTransition.ACTIVITY_TRANSITION_ENTER) {
            processStillTransition(context, event, locationClient, locationRepository, transitionRepository, dateTimeNow)
        } else {
            insertTransition(transitionRepository, event, dateTimeNow)
        }
    }

    // DetectedActivity.STILL の遷移イベントを処理する
    private fun processStillTransition(
        context: Context,
        event: ActivityTransitionEvent,
        locationClient: FusedLocationProviderClient,
        locationRepository: LocationRepository,
        transitionRepository: TransitionRepository,
        dateTimeNow: Long
    ) {
        doSomethingWithLocation(
            context, locationClient, 1, 5,
            onSuccess = { location ->
                val locationId = getLocationId(context, location, locationRepository)
                insertTransition(transitionRepository, event, dateTimeNow, locationId, location.latitude, location.longitude)
            },
            onFailure = {
                insertTransition(transitionRepository, event, dateTimeNow)
            }
        )
    }

    // 現在位置のIDを取得する
    private fun getLocationId(
        context: Context,
        location: android.location.Location,
        locationRepository: LocationRepository
    ): Int {
        val nearLocation = locationRepository.getNearLocation(location.latitude, location.longitude)

        return if (nearLocation != null) {
            nearLocation.id
        } else {
            locationRepository.insertLocation(
                Location(
                    name = "",
                    latitude = location.latitude,
                    longitude = location.longitude
                )
            )
            val locationId = loadSharedPrefInt(context, "locationNum")
            saveSharedPref(context, "locationNum", "${locationId + 1}")
            location
```

Person: 
- つづけて

ChatGPT: 
- 続きは以下のとおりです。

```kotlin
locationId
        }
    }

    // 遷移イベントをデータベースに挿入する
    private fun insertTransition(
        transitionRepository: TransitionRepository,
        event: ActivityTransitionEvent,
        dateTime: Long,
        locationId: Int? = null,
        latitude: Double? = null,
        longitude: Double? = null
    ) {
        transitionRepository.insertTransition(
            Transition(
                activityType = event.activityType,
                transitionType = event.transitionType,
                locationId = locationId,
                dateTime = dateTime,
                latitude = latitude,
                longitude = longitude
            )
        )
    }

    companion object {
        // アクティビティ遷移アップデートのアクション
        const val ACTION_PROCESS_UPDATES =
            "com.example.myLifeLog.action.TRANSITION_UPDATES"
    }
}
```



これで、コード全体に日本語のコメントが追加され、各メソッドの説明が提供されました。これにより、コードの読みやすさが向上し、メソッドの目的がより明確になります。

# まとめ
スパゲッティコードが見事に整理されてわかりやすくなった。GPT-3に比べてとても高速、正確な気がする。

# 追記
Person: 
- もう少し詳細にコメントが欲しい

ChatGPT: 
- より詳細な日本語のコメントを追加しました。

```kotlin
package com.example.myLifeLog.model.receiver

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.example.myLifeLog.*
import com.example.myLifeLog.model.db.MainRoomDatabase
import com.example.myLifeLog.model.db.location.Location
import com.example.myLifeLog.model.db.location.LocationRepository
import com.example.myLifeLog.model.db.transition.Transition
import com.example.myLifeLog.model.db.transition.TransitionRepository
import com.google.android.gms.location.*
import java.time.LocalDateTime

private const val TAG = "ActivityUpdatesBroadcastReceiver"

class ActivityUpdatesBroadcastReceiver : BroadcastReceiver() {

    // このレシーバがブロードキャストメッセージを受信したときに呼び出されるメソッド
    override fun onReceive(context: Context, intent: Intent) {
        // ActivityTransitionResult の結果がある場合に処理を行う
        if (ActivityTransitionResult.hasResult(intent)) {
            val result = ActivityTransitionResult.extractResult(intent)!!
            myLog(TAG, "receive ${result.transitionEvents.size} transition events")

            // データベースとリポジトリの初期化
            val dB = MainRoomDatabase.getInstance(context)
            val locationRepository = LocationRepository(dB.LocationDao())
            val transitionRepository = TransitionRepository(dB.TransitionDao())
            val locationClient = LocationServices.getFusedLocationProviderClient(context)

            // すべての遷移イベントを処理する
            for (event in result.transitionEvents) {
                processEvent(context, event, locationClient, locationRepository, transitionRepository)
            }
        }
    }

    // アクティビティ遷移イベントを処理するメソッド
    private fun processEvent(
        context: Context,
        event: ActivityTransitionEvent,
        locationClient: FusedLocationProviderClient,
        locationRepository: LocationRepository,
        transitionRepository: TransitionRepository
    ) {
        // イベントの詳細をログに出力
        myLog(TAG, "get event: ActivityType=${event.activityType}, TransitionType=${event.transitionType}")
        val dateTimeNow = LocalDateTime.now().toMilliSec()

        // イベントが静止状態で、遷移タイプがエンターの場合、位置情報を処理する
        if (event.activityType == DetectedActivity.STILL && event.transitionType == ActivityTransition.ACTIVITY_TRANSITION_ENTER) {
            processStillTransition(context, event, locationClient, locationRepository, transitionRepository, dateTimeNow)
        } else {
            // それ以外の場合、遷移イベントをデータベースに挿入する
            insertTransition(transitionRepository, event, dateTimeNow)
        }
    }

    // DetectedActivity.STILL の遷移イベントを処理するメソッド
    private fun processStillTransition(
        context: Context,
        event: ActivityTransitionEvent,
        locationClient: FusedLocationProviderClient,
        locationRepository: LocationRepository,
        transitionRepository: TransitionRepository,
        dateTimeNow: Long
    ) {
        // 位置情報を取得し、成功時と失敗時にそれぞれ対応する処理を行う
        doSomethingWithLocation(
```

Person: 
- つづけて

ChatGPT: 
- 続きは以下のとおりです。

```kotlin
context, locationClient, 1, 5,
            onSuccess = { location ->
                // 位置情報が取得できた場合、位置IDを取得して遷移イベントをデータベースに挿入する
                val locationId = getLocationId(context, location, locationRepository)
                insertTransition(transitionRepository, event, dateTimeNow, locationId, location.latitude, location.longitude)
            },
            onFailure = {
                // 位置情報が取得できなかった場合、遷移イベントをデータベースに挿入する（位置情報なし）
                insertTransition(transitionRepository, event, dateTimeNow)
            }
        )
    }

    // 現在位置のIDを取得するメソッド
    private fun getLocationId(
        context: Context,
        location: android.location.Location,
        locationRepository: LocationRepository
    ): Int {
        // 近くの位置情報をデータベースから取得する
        val nearLocation = locationRepository.getNearLocation(location.latitude, location.longitude)

        // 既存の位置情報があればそのIDを使用し、なければ新たに位置情報をデータベースに挿入してIDを取得する
        return if (nearLocation != null) {
            nearLocation.id
        } else {
            locationRepository.insertLocation(
                Location(
                    name = "",
                    latitude = location.latitude,
                    longitude = location.longitude
                )
            )
            val locationId = loadSharedPrefInt(context, "locationNum")
            saveSharedPref(context, "locationNum", "${locationId + 1}")
            locationId
        }
    }

    // 遷移イベントをデータベースに挿入するメソッド
    private fun insertTransition(
        transitionRepository: TransitionRepository,
        event: ActivityTransitionEvent,
        dateTime: Long,
        locationId: Int? = null,
        latitude: Double? = null,
        longitude: Double? = null
    ) {
        // 遷移イベントのデータを作成し、データベースに挿入する
        transitionRepository.insertTransition(
            Transition(
                activityType = event.activityType,
                transitionType = event.transitionType,
                locationId = locationId,
                dateTime = dateTime,
                latitude = latitude,
                longitude = longitude
            )
        )
    }

    companion object {
        // アクティビティ遷移アップデートのアクション定数
        const val ACTION_PROCESS_UPDATES =
            "com.example.myLifeLog.action.TRANSITION_UPDATES"
    }
}
```



これで、コード全体により詳細な日本語のコメントが追加されました。これにより、コードの読みやすさがさらに向上し、各メソッドの目的がより明確になります。

# 追記まとめ
ところどころ、ん？となるところもあるが、こちらのコードの意図を大体汲み取ってくれている。