ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TECHIT 앱 스쿨 2기: Android 23일차 (23.05.26)
    [THEC!T] 앱 스쿨2기 : Android 2023. 5. 27. 02:44
    728x90

    자료 출처 : 안드로이드 앱스쿨 2기 윤재성 강사님 수업 내용

     

    오늘 오전은 강사님께서 내주신 문제를 작성하는 시간을 가졌으며, 어제 같은 조원들과 이야기 한대로

    각자 작성한 코드를 리뷰를 하는 시간을 가졌습니다. 다른 사람들의 코드를 보며 느꼈던 점은 구현하려는 기능이 동일하다 보니 비슷한 부분이 많기는 하였지만, 완전히 다르게 구현한 부분도 있었습니다. 완전히 다르게 구현한 분은 파일을 날짜별로 만들어 관리하는 코드를 작성하였었습니다. 저 포함 그 외의 분들은 파일 하나에 이어쓰고 읽는 방식으로 구현하였기에 해당 분의 코드를 보며 한 수 배웠다는 생각이 들었습니다. 

     

    마지막으로 리뷰를 마친 후 각자 다른 사람들이 작성한 코드를 보며 수정을 하면 좀 더 좋을 거 같은 부분들을 수정하는 시간을 가졌습니다. 저는 리뷰를 마친 후 반성을 하게 되었습니다. 왜냐하면 예외처리를 똑바로 하지 않았기 때문입니다.

    다른 분들은 대부분 예외처리에 대한 코드를 작성하였다는 점에서 앞으로 코드 작성에 있어 예외처리에 대한 코드를 작성하는 것을 반드시 해야겠다고 생각하여 코드를 수정하였습니다.

     

    오후는 강사님께서 내주신 문제를 작성하면서 설명해주셨습니다.

    강사님이 코드를 작성해주신 코드에서 헷갈리거나 그런 점은 없었지만, 차이점은 확실하였습니다. 저와 같은 프레임워크를 사용하였지만 설계 방식이 달랐습니다. 강사님께서는 협업을 하는 상황을 가정하여 프로그램 상태 별로 클래스를 만들어 작성하셨으며, 데이터저장 방식 또한 날짜별로 파일을 생성하여 저장을 하는 방식으로 코드를 작성하셨습니다.

     

    작성을 하시면서 말씀해주신게 있는데 일반적으로 프로그램 구조는 유지보수가 유용하도록 작성해야 한다고 말씀해주셨습니다. 처음에는 괜찮을 수 있지만, 시간이 지남에 있어 기능 추가 혹은 기능 변경 및 삭제등을 할 수도 있기 때문에 프로그램을 처음부터 설계 및 작성에 있어 유지보수 등이 용이하도록 작성하는 것이 중요하다고 말씀해 주셨습니다. 

     

    그리고 코드를 작성하시면서 스캐너가 편하지만 많이 사용하지 않는 이유에 대해서 설명해주셨습니다.

    입력 부분을 제대로 마무리를 해야하는데 제대로 못할 경우 예외를 계속 반복하게 되는 문제가 있으며, 만약 nextLine()을 사용하기 전에 다른 것을 사용하였을 경우 nextLine() 사용전 nextLine()을 사용하여 줄바꿈을 해야한다는 점등이 있다고 설명해주셨습니다. 그래서 강사님은 스캐너는 잘 사용하지 않는다고 말씀하셨습니다.

    스캐너를 안쓴다면 쓸 수 있는건 BufferedReader만 생각이 나는데 이 부분은 추후 한번 질문해볼 수 있도록 하겠습니다.

     

    그리고 매직 넘버를 사용하지 말아라 라는 말이 개발자 사이에 있다고 말씀해주셨으며, 그에 대한 설명도 해주셨습니다. 만약 결과 혹은 상태에 따라 1,2 등을 사용한다면 코드에 따라 많은 곳에서 사용할텐데 해당 숫자가 무엇을 의미하는지 파악하려면 코드들을 분석해야 하기 때문이라고 설명해주셨습니다.

     

    마지막으로는 추세에 대해서 말씀을 해주셨습니다. 요즘은 모든 데이터를 저장하여 분석하는데 사용하기 때문에

    사용자가 어떤 메뉴를 골랐는지 등 모두 저장한다고 말씀해주시면서, 강사님의 경험을 바탕으로 설명을 해주셨습니다.

    게임으로 따지면 게임 이탈하려는 사용자들과 꾸준히 하는 사용자들의 패턴을 분석한다던가, 쇼핑몰로 따지면, 해당 물건을 살지말지 고민했다는 것을 분석한다던가......등등

     

    하기는 강사님께서 내주신 문제에 대해서 제가 작성한 코드에서 예외처리를 추가한 코드입니다.

    강사님이 작성하신 코드를 반영하지 않은 코드 입니다.

    import java.io.FileInputStream
    import java.io.FileOutputStream
    import java.io.ObjectInputStream
    import java.io.ObjectOutputStream
    import java.io.Serializable
    import java.lang.NumberFormatException
    import java.time.LocalDate
    import java.util.*
    import kotlin.collections.ArrayList
    
    fun main(){
        val mainClass = MainClass()
        mainClass.running()
    }
    
    // 메인 클래스
    class MainClass{
    
        // 프로그램 상태를 담는 변수에 초기 상태를 설정한다.
        var programState = ProgramState.PROGRAM_STATE_MENU_SELECT
        val health = Health()
    
        // 프로그램 상태 전체를 관리하며 운영하는 메서드
        fun running(){
            while(true) {
                // 프로그램 상태에 따른 분기
                when (programState) {
                    ProgramState.PROGRAM_STATE_MENU_SELECT -> {
                        // 메뉴화면
                        programState = health.menuSelect()
                    }
    
                    ProgramState.PROGRAM_STATE_ADD_TODAY_HEALTH -> {
                        // 운동 추가 후 메뉴 선택으로 돌아감
                        programState = health.todayHealthSave()
                    }
                    ProgramState.PROGRAM_STATE_LOAD_HEALTH_STOREAGE -> {
                        // 날짜별 운동 기록
                        val check = health.historyHealthLoad()
                        if(check){
                            programState = health.printDayHealth()
                        } else {
                            programState =  ProgramState.PROGRAM_STATE_MENU_SELECT
                        }
                    }
                    ProgramState.PROGRAM_STATE_POWER_SHUTDOWN -> {
                        // 프로그램 종료
                        break
                    }
                }
            }
        }
    }
    
    // 프로그램 상태를 나타내는 enum
    enum class ProgramState(){
        PROGRAM_STATE_MENU_SELECT,
        PROGRAM_STATE_ADD_TODAY_HEALTH,
        PROGRAM_STATE_LOAD_HEALTH_STOREAGE,
        PROGRAM_STATE_POWER_SHUTDOWN
    }
    
    // 저장할 파일 명을 관리하는 enum
    enum class FileName(val fileName :String){
        FILE_NAME("data1.dat")
    }
    
    // 운동에 관한 정보를 저장하는 데이터 클래스
    data class HealthData(val kind: String, val count: Int, val set: Int, val date: String): Serializable{
        // 정보를 출력하는 함수
        fun printInfo(){
            println()
            println("운동 타입 : $kind")
            println("횟수 : $count")
            println("세트 : $set")
        }
    }
    class Health {
        val loadList = ArrayList<HealthData>()
        // 메뉴화면을 구성하고 메뉴 번호를 입력 받아 상태를 반환하는 함수
        // 1~3이 아닌 번호를 넣으면 다시 메뉴 호출함.
        fun menuSelect(): ProgramState {
            var select:Int
            while(true) {
                try {
                    println("메뉴를 선택해주세요")
                    println("1. 오늘의 운동기록")
                    println("2. 날짜별 운동 기록 보기")
                    println("3. 종료")
                    val scanner = Scanner(System.`in`)
                    print("번호 입력 : ")
                    var temp = scanner.next()
                    select = temp.toInt()
                    if(select !in 1 .. 3) throw Exception()
                    break
                } catch (e: Exception) {
                    println("1 부터 3까지의 숫자만 입력바랍니다")
                    println()
                }
            }
    
            val nextState = when (select) {
                1 -> ProgramState.PROGRAM_STATE_ADD_TODAY_HEALTH
                2 -> ProgramState.PROGRAM_STATE_LOAD_HEALTH_STOREAGE
                3 -> {
                    println("프로그램을 종료 합니다.")
                    ProgramState.PROGRAM_STATE_POWER_SHUTDOWN
                }
                else -> ProgramState.PROGRAM_STATE_MENU_SELECT
            }
            println()
            return nextState
        }
    
    
        // 오늘의 운동기록을 추가하는 함수
        fun todayHealthSave(): ProgramState {
    
            var kind : String
            var count : Int
            var set : Int
    
            while(true){
                try{
                    val scanner = Scanner(System.`in`)
                    print("운동 타입 : ")
                    kind = scanner.nextLine()
                    print("횟수 : ")
                    var temp1 = scanner.next()
                    count = temp1.toInt()
                    print("세트 : ")
                    var temp2 = scanner.next()
                    set = temp2.toInt()
                    break
                } catch (e: Exception){
                    println("올바른 정수 값을 넣어 주세요")
                }
            }
    
            val date = LocalDate.now().toString()
    
            //val date2 = "2023-05-15"
            val fos = FileOutputStream(FileName.FILE_NAME.fileName, true)
            val oos = ObjectOutputStream(fos)
    
            oos.writeObject(HealthData(kind, count, set, date))
    
            oos.flush()
            oos.close()
            fos.close()
    
    
            return ProgramState.PROGRAM_STATE_MENU_SELECT
        }
    
        fun historyHealthLoad() : Boolean {
            loadList.clear()
            var fis : FileInputStream? = null
            try {
                fis = FileInputStream(FileName.FILE_NAME.fileName)
            }catch (e: Exception){
                println("읽어올 파일이 없습니다.")
                return false
            }
    
            if(fis != null){
                var ois: ObjectInputStream? = null
                while (true) {
                    try {
                        ois = ObjectInputStream(fis)
                        loadList.add(ois.readObject() as HealthData)
                    } catch (e: Exception) {
                        if (ois != null) {
                            ois.close()
                        }
                        break
                    }
                }
            }
            return true
        }
    
        fun printDayHealth(): ProgramState {
    
            // 날짜 표시를 위해 중복 제거
            var dayList = mutableListOf<String>()
            // 가져온 정보 모두 넘김
            for (i in loadList) {
                dayList.add(i.date)
            }
            // 중복 날짜 제거
            dayList = dayList.distinct().sorted().toMutableList()
    
            var select : Int
    
            while(true){
                try {
                    // 0을 입력 받으면 메뉴로 돌아간다.
                    val scanner = Scanner(System.`in`)
                    // 저장된 날짜 표시
                    for (i in 0..dayList.size - 1) {
                        println("${i + 1} : ${dayList[i]}")
                    }
                    print("날짜를 선택해주세요(0. 이전) : ")
                    var temp = scanner.next()
                    select = temp.toInt()
                    if(select !in 0 .. dayList.size) throw Exception()
    
                    if (select == 0) {
                        println()
                        return ProgramState.PROGRAM_STATE_MENU_SELECT
                    }
    
                    break
    
                }catch (e: Exception){
                    println("0 부터 ${dayList.size}번 내로 선택해주십시오.")
                    println()
                }
    
            }
    
            // 리스트에 저장된 객체의 날짜와 선택한 날짜가 같다면
            // 객체의 정보를 출력한다.
            val selectDay = dayList[select - 1]
            println()
            println("${selectDay}의 운동 기록입니다.")
            for (i in loadList) {
                if (i.date == selectDay) {
                    i.printInfo()
                }
            }
            println()
    
            return ProgramState.PROGRAM_STATE_MENU_SELECT
        }
    
    }

     

    마무리

    지금 앱 스쿨 2기 과정을 듣기 시작한지 얼마 안된 것 같은데 날짜를 확인해보니 시작 일수로만 계산하였을 때

    한달이 벌써 지났습니다. 한달 전의 저와 지금 저를 비교한다면 가장 큰 차이로는 코드를 그냥 작성하는 것이 아닌 해당 개념과 코드 작성에 있어 설계에 대한 중요성을 확실히 알고 있다는 점이 가장 큰 차이라고 말할 수 있습니다.

    이 외의도 많은 것이 변하였습니다. 당일 배운 내용들을 정리하면서 현재 저에게 부족한 점이 무엇인지, 이해도는 어떠한지 알 수 있어 검색을 하는 것과 강사님께 질문하기도 편했졌으며, 앱 스쿨 2기 교육과정을 지금까지 진행하면서 조별로 문제를 푼다던가 하면서 협업에 대해서 정말 베스킨31에 맛보기 처럼 조금이나마 경험을 하게 된 점과 배우려는 욕구가 높고, 잘하고 싶어 하는 사람들이 보여 저도 자극 받았던 점들이 가장 좋았습니다.

    원래 이번 주말에는 정보처리기사 필기만 공부하려고 하였지만, 다음주 월요일이 대체공휴일이라 3일을 쉬게 되어 강사님이 작성하신 코드를 분석하고, 협업을 한다는 가정하에 다른 기능을 추가하여 작성해보는 시간을  추가로 가져보도록 하겠습니다.

     

    오늘의 마음가짐

    하루하루가 쌓여 큰 발전의 계기가 된다는 생각으로 허투로 보내는 날이 없도록 노력하자~!

     

Designed by Tistory.