이번 주차는 역량강화 마지막 주차이다.. 지금까지 진행해왔던 교양강화, 전공강화, 역량강화 팀과 함께할 수 있는 마지막 시간이다. 이런 부분이 시원섭섭하지만, 빡빡했던 스케줄을 가지고 있었던 역량강화 기간을 끝내고나니 후련하다는 생각도 들고 해방감(?)도 들게 되었다.
드디어 다음 주 부터는 팀 프로젝트 위주로 시간을 잘 활용할 수 있을 것 같고, 개발을 할 생각을 하니 한 편으로는 좀 걱정이 되긴 하지만, 진짜 드디어 내가 할 일을 맘 놓고 할 수 있다는 생각도 들고, 한 편으로는 설레기도(?) 한다 !!
물론 앞으로 전공 역량강화는 팀 프로젝트를 진행하면서 필요하거나 부족한 부분에 대해서는 자율적으로 학습하거나 강의를 듣고 보완을 할 수 있다고 생각한다.
이번, 애자일 마스터 발표 범위는 남은 범위인 13장~15장이다.
먼저, 13장에서는 리팩터링
이 무엇인지, 기술적 부채
를 갚아나감으로써 어떻게 소프트웨어를 빠르고 유연하게 만들 수 있는 지에 대한 내용을 다룬다.
우리는 먼저, 기술적 부채
란 무엇인지 살펴보고자 한다.
기술적 부채
생산성 또는 일정이라는 명목하에 무질서하게 코드를 배치하고 복사 붙이기를 함으로써 생기는 부채.
오랫동안 쌓여온 이러한 부채는 코드의 작동을 파악하기 어렵게 함.
이러한 결함들로 인해서 장애가 발생할 수 있고, 해결할 수 없음.
ex) 스파게티 코드, 복사 붙이기 등등...
이와 같은 기술적 부채는 리팩터링을 진행함으로써 해결해나갈 수 있다.
Refactoring
은 말 그대로, 코드의 구조를 재정의
한다는 것이다.
정확한 리팩터링
의 정의에 대해서 살펴보자.
리팩터링
겉으로는 큰 변화가 없지만, 설계(코드의 구조)를 점진적으로 향상시켜 코드의 이해력을 높이는 방법
리팩터링의 작업을 프로젝트 진행 중 꾸준히 했을 때, 작업 속도가 빨라질 수 있고, 유연하게 요구사항에 대응할 수 있고, 유지 보수성이 향상될 수 있다.
리팩터링의 종류
리팩터링 팁
14장에서는 테스트 주도 개발(TDD)이 무엇인지에 대해서 살펴본다.
먼저, TDD
가 무엇인 지 살펴보자.
매우 짧은 개발 주기를 사용하여 소프트웨어의 설계를 점진적으로 향상시키는 기법
매우 짧은 개발 주기를 가짐으로써, 그 기능에 대한 테스트를 통해 고객이 진짜 필요로 하는 것을 개발하였는 지, 그 기능이 잘 작동하는 지를 테스트하면서 개발을 하면 설계를 향상시켜나갈 수 있다는 얘기이다.
TDD 작동 원리
RED
- 실패하는 단위 테스트를 작성
한다.GREEN
- 테스트를 통과시키는 것
이 주 목적이다. 실행 흐름을 충분히 이해했다면, 최소한의 분량으로 코드를 추가한다.REFACTOR
- 설계를 개선하기 위해 코드들을 검토하는 단계이다. 테스트의 통과를 유지
하기 위해 리팩터링을 진행한다. TDD 규칙
작동원리와 유사하다.
TDD 이점
필요한 것만 개발할 수 있고, 동시에 잘 작동하는지 테스트 할 수 있다.
단순한 설계를 만들 수 있다.
짧고 품질이 좋은 코드를 유지할 수 있다.
코드에 대한 집단적 소유 의식을 통해 팀원 개인의 부담감을 덜 수 있다.
15장에서는 지속적인 통합(CI, Continuous Integration)
을 다루는 장이다.
먼저, 지속적인 통합
이란 무엇일까 ?
지속적으로 소프트웨어를 변경하고, 변경사항들을 계속해서 통합하는 활동
소프트웨어 출시 준비
를 너무 특별하지 않고 자연스럽게 하기 위해서 우리는 코드를 지속적으로 통합하고, 항상 출시에 대비해야 한다.
출시를 준비한다는 것은 소프트웨어를 개발, 통합, 배치하는 과정까지를 말한다.
지속적인 통합은 어떻게 하는가 ?
소스코드 저장소를 사용한다. Git, Subversion
체크인 프로세스를 수립한다.
자동화된 빌드를 사용한다.
(자동화된 빌드는 코드를 컴파일, 테스트 실행을 모두 자동화하여 정기적으로 처리하며 사람의 실수를 줄여준다.)
작은 단위로 나누어서 작업을 한다.
( 말 그대로 지속적인 통합 과정을 위해서는 작은 단위일수록 통합하기 유리하다. )
코루틴(Coroutine)은, 서로 협력하는 루틴을 말한다. Co(Cooperative)
+ Routine
일시 중단이 가능
한 작업 객체이다.
스레드의 생성 비용을 줄여 메모리를 절약할 수 있다.
경량 스레드
이며, 동시성을 보장
한다.
코루틴 Builder 의 종류로는 코루틴 스코프의 확장함수인launch
와 async
등이 있다.
launch
의 경우, 코루틴을 시작하고, 작업의 상태를 추적하고 변경할 수 있는 Job
객체를 반환한다. (결과값이 아니다)
import kotlinx.coroutines.*
fun main() = runBlocking {
// job은 생성과 동시에 실행된다.
// 따라서 job은 필요한 위치에 생성을 해야하고, 그 위치에서 바로 실행을 시켜야하므로 유연성이 떨어진다.
val job = GlobalScope.launch {
delay(3000L)
println("World!")
}
println("Hello")
job.join() // job 이 속한 coroutine 이 종료될 때까지 기다린다.
}
join()
메서드를 사용해서, 현재 스레드를 일시중단시키며, 작업이 마치기까지 기다린다.
현재 스레드에서 자식 코루틴으로 실행하려면 그냥 launch{ }
로 사용해도 된다.
async
의 경우, 결과값이 필요한 경우에 사용하며, 람다의 마지막 줄 값이 결과값이 된다.import kotlinx.coroutines.*
fun main() = runBlocking<Unit> {
val job3 = CoroutineScope(Dispatchers.Default).async {
kotlin.io.println("작업3 수행중")
val result = (1..10).sortedByDescending { it }
kotlin.io.println("작업3 수행완료")
result
}
val job1 = launch {
kotlin.io.println("작업1 수행")
kotlin.io.println("작업1 일시중단")
val job3Result = job3.await() // 작업3의 결과가 필요하여 작업1을 수행하는 코루틴이 일시중단 되었다.
kotlin.io.println("작업1 재개")
job3Result.forEach { print("$it ") }
println()
kotlin.io.println("작업1 수행완료")
}
val job2 = launch {
delay(1L)
kotlin.io.println("작업2 수행")
kotlin.io.println("작업2 수행완료")
}
}
launch
와 async
는 다음과 같이 사용하면 된다.
다음과 같이 async
는 await()
메서드를 통해, 현재 스레드를 일시중단 시키며, 결과값을 가져온다.
CoroutineScope
GlobalScope
코루틴은 항상 코틀린 라이브러리의 CoroutineContext
를 상속받는 문맥에서 동작한다.
코루틴에서 사용할 수 있는 여러가지 데이터 정보가 들어있다.
코루틴 이름, 디스패처, 작업 상세사항, 예외 핸들러 등
Dispatchers.Main
- Main 스레드에서 동작하며, Android 에서는 UI 스레드 역할을 하므로, UI를 업데이트하는 역할을 주로 한다.Dispatchers.Unconfined
- 지정되지 않은 Dispatcher로 문맥이 지정되지 않고, 호출된 문맥에서 실행된다.Dispatchers.IO
- 네트워크 통신, 입출력 작업 등에 주로 사용.Dispatchers.Default
- CPU 연산을 많이 하는 작업에 주로 사용.[ 사용 예시 ]
CoroutineScope(Dispatchers.Main).launch{
updateButton() // 필요한 작업 수행
}
예제)
fun main() = runBlocking { // main 스레드에서 동작
// 인자를 넘겨주지 않은 경우: 상위 코루틴의 context
launch {
println("main runBlocking : 나는 ${Thread.currentThread().name} 에서 돌아")
}
// 별도 지정 안함: 이를 호출한 스레드에서 동작
launch(Dispatchers.Unconfined) {
println("Unconfined : 나는 ${Thread.currentThread().name} 에서 돌아")
}
// 공유된 background 스레드 풀 사용
launch(Dispatchers.Default) {
println("Default : 나는 ${Thread.currentThread().name} 에서 돌아")
}
// 직접 만든 스레드 사용
launch(newSingleThreadContext("NewSingle_Thread")) { // 새로운 스레드 생성
println("newSingleThreadContext : 나는 ${Thread.currentThread().name} 에서 돌아")
}
println("runBlocking : 나는 ${Thread.currentThread().name} 에서 돌아")
}
//실행 결과
Unconfined : 나는 main @coroutine#3 에서 돌아
runBlocking : 나는 main @coroutine#1 에서 돌아
Default : 나는 DefaultDispatcher-worker-1 @coroutine#4 에서 돌아
newSingleThreadContext : 나는 NewSingle_Thread @coroutine#5 에서 돌아
main runBlocking : 나는 main @coroutine#2 에서 돌아
자식 코루틴에서 exception
이 발생하게 되면, exception
은 부모까지 전파된다.
이러한 경우 CoroutineContext
문맥에 CoroutineExceptionHandler
를 추가해서 예외를 처리할 수 있다.
import kotlinx.coroutines.*
suspend fun main(){
// handler는 CoroutineExceptionHandler을 구현하며
// exception이 왔을 때 받은 exception을 출력해줍니다.
val handler = CoroutineExceptionHandler{_, exception ->
println("CoroutineExceptionHandler : $exception")
}
val job = CoroutineScope(Dispatchers.IO).launch(handler){
throw IllegalArgumentException()
}
delay(1000)
}
import kotlinx.coroutines.*
suspend fun main(){
val handler = CoroutineExceptionHandler{_, exception ->
println("CoroutineExceptionHandler : $exception")
when(exception){
is IllegalArgumentException -> println("More Argument Needed To Process Job")
is InterruptedException -> println("Job Interrupted")
}
}
val job1 = CoroutineScope(Dispatchers.IO).launch(handler){
throw IllegalArgumentException()
}
val job2 = CoroutineScope(Dispatchers.IO).launch(handler){
throw InterruptedException()
}
delay(1000)
}
launch
의 경우, 바로 실행하기 때문에, 전파가 바로 되지만, async
는 await()
를 호출하기 전까지 전파하지 않는 성질이 있다.
async
빌더는 왜 전파되지 않을까 ?exception
으로 취소 될 자식에게 설정해두면, 그 자식이 취소되었을 때, exception
이 전파가 되지 않는다.supervisorScope{}
안에 자식 코루틴들을 실행하면 된다.디자이너님께서 저번 주말 작업을 하셔서 이번 주차에 프로젝트 앱 아이콘과, 메인 기능을 하는 화면들에 대한 디자인 레이아웃을 받았다.
처음에 아이콘을 봤을 때는 괜찮았는데, 팀 프로젝트 회의에서 한 팀원 분께서 아이콘에 대해 수정을 하는 것이 어떠냐는 의견을 제시하시고 논의 끝에 아이콘을 바꾸기로 했다.
그런데 아이콘 디자인을 바꾸는 부분에 있어서, 아이콘이 나왔을 때, 즉각적으로 피드백을 하였으면 좋았을텐데라는 아쉬운 점이 있다. 이미 디자이너님께 마음에 든다고 말을 한 뒤여서 앞 뒤가 말이 달라져버린 상황이 되어버린 것 같았다 ㅠㅠ
앞으로는 팀원 간 정기적인 회의도 진행하고, 이러한 산출물들에 있어서는 바로 즉각적으로 회의를 통해 결정을 하기로 하였다.
어제, 금요일에는 안드로이드 개발자 멘토님과 함께 멘토링하는 시간을 가졌다.
다음 주 부터 진행하게 될 팀 프로젝트를 진행하는 데에 있어 기술적인 부분이나 앞으로의 취업에 있어서 많은 정보를 얻을 수 있었고, 맛있는 점심식사와 유쾌하고 건설적인 시간을 가질 수 있었던 것 같다.
첫 만남이라 어색했던 부분이 있어서, 매끄럽게 진행되지는 못했지만 다음 멘토링 시간에는 질문도 많이하고 정보를 많이 얻어볼 예정이다 !!!!
이번 멘토링때는 질문을 많이 준비하지 못해서, 프로젝트의 기술적인 부분에 대한 답변만 기억에 남는다 ㅠㅠ
이번 주차까지 해서 역량강화 기간이 끝이났다.. 이번 역량강화 기간을 통해서 앞으로 안드로이드 프로젝트를 진행하는데에 있어서 부족한 코틀린, 코루틴 지식들을 보완할 수 있었고, 교양강화를 통해서 애자일 방법론
에 대해서 공부하고 앞으로 프로젝트에 어떻게 적용할 수 있는지, 프로젝트에 있어서 사고적인 부분이 애자일적으로 된 것 같다. ㅎㅎ 그리고 나머지 팀이 진행한 읽기 좋은 코드
, SQL 첫걸음
등을 통해서 코드를 클린하게 작성하는 방법과 정보처리기사 자격증을 취득한 이 후, 손 대지도 않은 SQL에 대해서 공부할 수 있던 기간이었다.
물론, 역량강화 기간이 끝났다고해서 본인이 역량강화가 필요 없다는 것은 아니라고 생각한다. 앞으로 프로젝트를 진행함에 있어 부족한 부분, 필요한 부분들은 당연히 찾아서 공부해야하고, 프로젝트 협업 부분에 있어서 어려움이나 갈등이 발생할 때, 이번에 배웠던 교양강화 부분을 생각하고 참고하여 해결할 수 있다고 생각한다. 부족하다면 교양도 더 공부할 수 있으면 좋을 것 같다.
유데미 바로가기: https://bit.ly/3SFlXDy
유데미 STARTERS 취업 부트캠프 공식 블로그 보러가기: https://blog.naver.com/udemy-wjtb
💡 본 후기는 유데미-웅진씽크빅 취업 부트캠프 2기 - 프론트엔드&백엔드 과정 학습 일지 리뷰로 작성되었습니다.
👍