안녕하세요 공공돌🧸 입니다!!
프리코스가 끝나고 결과가 나오기 한달정도 기간이 남았는데요.
짧은 한 달 동안 몰랐던 부분과 부족했던 부분에 대해서 배울 수 있어서 뜻깊은 시간이었던 것 같습니다.
남은 기간 동안 회고록과 재 구현을 해보며 블로그에 남겨보려 합니다.
프리코스의 목적
우아한테크코스 교육과정은 강의식으로 진행하는 주입식 교육이 아닙니다. 여러분이 해결해야 할 미션을 부여하고, 미션을 구현한 후 피드백을 받는 방식으로 진행합니다. 이 교육 방식이 기존의 교육방식과 완전히 다르기 때문에 프리코스는 본 과정을 미리 경험해 보는 단계입니다.
프리코스는 여러분이 해결해야 할 미션과 간단한 가이드를 제공하지만, 본 과정과 다른 점은 1:1 피드백이 없고 공통 피드백만 있습니다. 4주 동안 공통 피드백만 있는 상태에서 여러분 주도적으로 학습하고, 미션을 진행하고, github을 통해 구현한 결과물을 제출해야 합니다.
이 과정을 통해 지원자는 우아한테크코스 과정을 미리 경험해 보면서 교육의 참여 여부를 결정할 수 있고, 저희는 우아한테크코스 과정을 소화하는데 어려움이 없는지 판단할 수 있는 기간이 될 수 있을 것 같아요. 서로가 같이할 수 있는지를 탐색할 수 있는 시간이라고 생각하면 됩니다.
프리코스를 진행해 우아한테크코스에 최종 합격하는 것이 더 중요할 수 있겠지만, 그보다 개인의 성장을 목표로 한다면 결과가 어떠하든 의미 있는 시간이 될 수 있으리라 생각합니다. 이런 시간들이 쌓인다면 여러분 모두 뛰어난 개발자로 성장해 나갈 것이라 믿습니다.
회고의 방식은 4F회고 방식을 활용해 보려 합니다.
4F 회고
4F 회고는 사실 (Fact), 느낌 (Feeling), 교훈 (Finding), 향후 행동 (Future Action) 순서대로 회고하는 방법입니다.
4F 에서 Finding 까지만 회고하면 3F 회고, 마지막에 Feedback 이 추가되면 5F 회고라고 합니다.
각 단계를 조금 더 자세히 설명하면 아래와 같습니다.
Fact : 무슨 일이 있었는지, 어떤 일을 했는지
Feeling : 어떤 감정을 느꼈는지
Finding : 어떤 지식과 인사이트를 얻게 됐는지
Future Action : 앞으로 무엇을 할 계획인지
✏️ 다 지키면서 쓸 수 있을지 모르겠지만 도전해보겠습니다..!!
미션 진행 전 공부
제일 먼저 목표로 삼았던 것은 코틀린 문법에 대한 공부였습니다.
다른 언어는 익숙했지만, 코틀린 언어에 있어서는 무지한 상태였기에 코틀린 언어의 기본은 잡고 가야겠다는 생각이 들었기 때문입니다.
우선 ‘코틀린 이란 무엇인가?’를 알아보았습니다.
그 다음으로는 인텔리제이 개발 툴에 적응하기 위해 ‘Hello World’부터 시작하여 개발 환경설정을 완료시킨 후 코틀린의 함수 구현은 어떻게 이루어지는지를 살펴보았습니다.
이후 코틀린 관련 서적으로 아래 두 권을 참고하며 미션을 진행했습니다.
미션 진행
1주차 미션은 개인적으로 간단한 미션이었던 것 같습니다.
아마 우테코 프리코스를 본격적으로 진행하기 앞서 언어, git, 미션 사이클에 익숙해지도록 하기 위한 것으로 보였습니다.
프리코스에서 과제 진행 요구사항 중 README에 구현할 기능 목록을 정리하여 추가하는 것이 있습니다.
기능 목록은 아래와 같이 정리하였습니다.
이후, Application.kt 파일에 모든 구현을 했습니다.
코드는 아래 링크를 통해서 보실 수 있습니다.
개인 피드백
1. 클래스 분리
미션이 끝난 후 다른 지원자들이 작성한 코드를 확인해 보았습니다.
여기서 찾아볼 수 있는 차이는 클래스의 분리입니다.
저의 경우 아래와 같이 한 개의 파일에 모든 구성을 다 담아 작성한 코드라면,
package baseball
import camp.nextstep.edu.missionutils.Randoms
import camp.nextstep.edu.missionutils.Console
class Game {
// 코드
}
fun play {
// 코드
}
private fun 함수명 {
// 코드
}
fun main() {
//코드
}
다른 여러 지원자분들은 각각의 기능별 클래스로 나누어 작성한 것을 많이 봤습니다.
더 잘하시는 분들은 MVC 패턴까지 생각하시면서 하더라구요...🥹🥹
2. GitHub
2-1 커밋 컨벤션
여러분들은 깃허브 커밋 컨벤션이 존재한다는 걸 아셨나요?
네.. 저는 몰랐습니다.. HAHAHAHAHA 🫣
커밋 컨벤션을 쓰는 이유는 일관된 커밋 메시지를 통해 소스 변경 이력을 효율적으로 추적할 수 있습니다. 이를 통해 문제 발생 시 더 빠르게 원인을 찾아 수정할 수 있으며, 전반적인 프로젝트 안정성을 높일 수 있다고 합니다.
위의 커밋은 제가 미션을 진행하면서 올린 커밋입니다. 첫 커밋을 보면 커밋 컨벤션을 지키지 못하고 올린 것을 확인할 수 있습니다.
2-2 커밋 주기
커밋의 주기는 언제 올리는 게 가장 좋을까요?
1주 차 미션을 진행하면서 올린 커밋은 위에 사진에 나와있는 커밋 메시지가 전부입니다.
미션이 끝난 후 커밋의 주기에 대해 알아봤습니다.
정답은?? 저도 모르겠습니다..
하지만 커밋 주기에 대해 "우아한테크코스 프리코스 커뮤니티" 에서 다른 지원자분들의 이야기를 들어봤습니다.
여기서 공통적으로 찾아볼 수 있었던 점은 커밋을 작은 단위로 끊어 할수록 코드의 변화를 알 수 있고, 추적이 쉬워진다는 점입니다.
그럼 우리가 여기서 또 고민해 볼 수 있는 점은 "커밋의 작은 단위는 어떻게 정해야할까 ?"입니다.
이 고민을 해결해 준 2주 차 과제 요구사항 !!
미리 스포 합니다..🚨
2주차 미션 부터는 위에 제시된 요구에 맞춰 커밋을 올리려고 노력했습니다!
커밋 메시지 컨벤션은 위의 링크를 보고 공부를 했습니다.
코드 리뷰
미션 진행 후 코드 리뷰를 받은 것들을 보며 배운 점과 느낀 점들을 정리해 봤습니다.
1. 객체 분리 피드백
위에서도 말했듯이 클래스 별로 파일을 분리했으면 더 좋았을 것이라고 생각했습니다.
지금 생각해 보면 객체 지향 프로그래밍의 기본인 객체들을 분리하는 작업조차 하지 않았던 것 같습니다.
2. 중복 기능 함수 통일 피드백
위 코드를 보면 숫자를 입력받는 함수와 재시작 여부를 받는 함수의 기능이 공통되는 점을 볼 수 있습니다.
문구는 불변 값이기 때문에 상수로 지정을 하여 아래와 같이 코드를 작성했으면 함수가 통일이 되면서 재사용성도 높아졌을 것 같습니다.
3. 들여쓰기 ( Depth ) 피드백
코드를 보면 리뷰와 같이 함수의 Depth가 3이 되는 걸 볼 수 있습니다.
이때 해당 기능들을 각각 한 가지의 기능을 할 수 있게 아래와 같이 함수로 분리했으면 코드 전체의 가독성과 유지 보수성을 향상시킬 수 있었을 것 같습니다.
while (true) {
user = getUserInput()
if (!processGameRound(computer, user)) {
computer = handleGameRestart()
}
}
}
fun processGameRound(computer: Int, user: Int): Boolean {
val result = checkNumbersAndPrintResult(computer, user)
if (result == "3스트라이크") {
announceGameEnd()
return false
}
return true
}
fun handleGameRestart(): Int {
return if (isGameRestartNeeded()) {
generateRandomNumber()
} else {
computer
}
}
fun checkNumbersAndPrintResult(computer: Int, user: Int): String {
checkNumbers(computer, user)
println(checkNumResult)
return checkNumResult
}
fun announceGameEnd() {
println("3개의 숫자를 모두 맞히셨습니다! 게임 종료")
}
fun isGameRestartNeeded(): Boolean {
return restartGame() == "2"
}
4. 조건 분리 피드백
코드 작성 시 한 가지의 코드로 모든 조건들을 검사하면 좋을 것 같다는 생각을 했습니다.
하지만 이는 아래와 같은 문제를 일으킬 수 있다는 점을 리뷰를 받아보면서 배울 수 있었던 것 같습니다.
- 가독성 저하: 여러 조건이 하나의 if 문에 결합되면, 코드를 읽고 이해하는 것이 어려워집니다. 각 조건의 목적과 로직을 파악하기 위해 추가적인 시간과 노력이 필요할 수 있습니다.
- 디버깅 어려움: 여러 조건이 함께 있을 때, 어떤 조건이 false로 평가되어 if 블록이 실행되지 않는지 파악하기 어려울 수 있습니다. 이는 디버깅을 복잡하게 만들며 오류를 찾는 데 더 많은 시간이 소요될 수 있습니다.
- 유지보수의 어려움: 조건이 많아질수록 해당 if 문을 수정하거나 확장하는 것이 더 복잡해집니다. 특히, 여러 조건들이 서로 관련이 있거나 서로에게 영향을 미칠 때, 변경 사항이 하나의 조건에만 국한되지 않고 다른 조건에도 영향을 줄 수 있습니다.
- 유연성 부족: 각 조건을 별도로 처리할 필요가 있을 때, 하나의 if 문에 모든 조건을 결합하는 것은 유연성을 제한합니다. 예를 들어, 각 조건에 대해 다른 종류의 피드백이나 처리가 필요한 경우, 이를 구현하기 어려워집니다.
위 조건식을 지금 고쳐보면 아래와 같이 고칠 수 있을 것 같습니다.
이렇게 각 검사를 분리함으로써, 각 검사의 로직을 명확히 하고, 유지 보수와 확장성을 개선할 수 있었습니다.
fun isLengthValid(user: String): Boolean {
return user.length == 3
}
fun areAllCharactersUnique(user: String): Boolean {
return user.toSet().size == 3
}
fun areAllCharactersDigits(user: String): Boolean {
return user.all { it in '1'..'9' }
}
fun validateUserInput(user: String): Boolean {
return isLengthValid(user) && areAllCharactersUnique(user) && areAllCharactersDigits(user)
}
5. 상수 활용 / 출력 부분 로직 분리 피드백
해당 피드백을 받으면서 상수를 활용하는 데 있어서 도움이 되었습니다.
상수에 이점에 대해 아래와 같이 알아봤습니다.
- 명확성과 가독성 향상: 상수는 특정한 값을 명확하게 표현하고, 그 의미를 이해하기 쉬운 이름으로 대체합니다. 이는 코드의 가독성을 높이고, 다른 개발자들이 코드를 더 쉽게 이해할 수 있게 합니다.
- 오류 감소: 상수를 사용하면 같은 값을 여러 번 재사용할 수 있어, 오타나 잘못된 값 입력으로 인한 오류를 줄일 수 있습니다. 값을 한 곳에서 변경하면 코드 전체에 반영되므로 일관성을 유지하기 쉽습니다.
- 유지보수 용이성: 프로그램에서 사용하는 중요한 값들이 한 곳에 정의되어 있으면, 나중에 그 값을 변경해야 할 때 한 곳만 수정하면 됩니다. 이는 코드 유지보수를 훨씬 쉽게 만듭니다.
- 성능 최적화: 컴파일 타임 상수는 실행 시간 동안 값이 변하지 않음을 보장합니다. 이는 컴파일러가 더 효율적인 코드를 생성하는 데 도움이 될 수 있으며, 때때로 성능을 향상시킬 수 있습니다.
- 타입 안전성: 상수는 특정 타입의 값으로 선언됩니다. 이는 프로그램에서 타입 안전성을 강화하고, 잘못된 타입의 값이 사용되는 것을 방지합니다.
- 문서화의 역할: 상수 이름은 그 값이 프로그램 내에서 어떤 역할을 하는지 설명하는 데 도움이 됩니다. 이는 코드 자체가 일종의 문서 역할을 하게 만들어, 코드의 의도를 명확히 전달할 수 있습니다.
두 번째로 출력 부분을 로직과 분리해서 관리를 할 때 이 점 입니다.
- 유지보수성 향상: 핵심 로직과 사용자 인터페이스를 분리하면, 하나를 변경해도 다른 부분에 영향을 미치지 않습니다. 이는 코드의 유지보수를 더 쉽고 효율적으로 만듭니다.
- 재사용성 증가: 로직이 사용자 인터페이스와 분리되어 있으면, 동일한 로직을 다른 인터페이스(예: 웹, 모바일, 콘솔)와 함께 재사용할 수 있습니다.
- 테스트 용이성: 로직이 출력과 분리되어 있으면, 로직을 독립적으로 테스트할 수 있습니다. 사용자 인터페이스 없이 로직의 정확성을 검증할 수 있기 때문에, 테스트가 더 쉬워지고 효율적입니다.
- 확장성과 유연성: 사용자 인터페이스가 변경되거나 다양한 인터페이스가 필요할 때, 중앙 집중식 로직을 유지하면서 쉽게 확장하거나 수정할 수 있습니다.
피드백을 반영하여 간단하게 수정한다면 아래와 같이 분리할 수 있었습니다.
const val THREE_STRIKE = "3스트라이크"
fun printCheckNumResult(checkNumResult: String) {
println(checkNumResult)
}
try {
checkNumbers(computer, user)
printCheckNumResult(checkNumResult)
if (checkNumResult == THREE_STRIKE) {
}
}
느낀점
1주 차 미션을 진행을 해보면서 가장 배움이 크다고 생각했던 점은 미션이 끝난 후 코드 리뷰를 진행했을 때입니다.
지금까지 공부를 하면서 다른 사람의 코드 리뷰를 해보고 받아 볼 수 있는 경험을 할 수 없었습니다.
하지만 프리코스를 진행하면서 다른 참가자들의 코드를 리뷰하고 또 리뷰 받는 과정에서 생각하지 못했던 구현, 여러 코드 스타일, 문법 등을 리뷰를 진행함과 동시에 자연스럽게 물어보고 찾아볼 수 있었습니다.
추가로, 이를 직접 적용해 보는 것은 프로그래머로서 계속해서 성장하기 위한 중요한 과정이라는 걸 깨달았습니다.
여러분 코드 리뷰💬 꼭 해보세요 진짜x100000 좋은 경험이고 좋은 배움의 시간이었습니다.
재구현
☁️ 재구현이 완료되면 올려보도록 하겠습니다 !! ☁️
공부하는 공돌이, 공공돌입니다🐻
@sheep1sik
'우테코 프리코스' 카테고리의 다른 글
[우테코 프리코스] 6기 안드로이드 3주차 회고록 (1) | 2023.12.26 |
---|---|
[우테코 프리코스] 6기 안드로이드 2주차 회고록 (13) | 2023.12.05 |