현재 진행중인 반려동물 기록 서비스 'ZOOC'을 개발핟면서 생긴 이슈다. 아래는 우리 앱의 메인 화면이다. 호스팅 액티비티에 바텀 네비게이션이 있고 홈, 마이페이지 두 개의 프레그먼트가 전환되는 형태이다. 가운데 + 버튼을 누르면 기록을 위한 새로운 액티비티가 생성되는데, 해당 액티비티를 갔다오면 홈 프레그먼트의 데이터를 리프레시해야했다. 그래서 Activity Result API를 이용해 기록 액티비티에서 돌아오는 시점을 알고 데이터를 리프레시 하려고했다. 그런데 여기서 문제가 발생했다. 바텀 네비게이션은 호스팅 액티비티에, 리프레시할 데이터는 홈 프레그먼트에 있었기 때문이다. 즉, 바텀 네비게이션이 액티비티에 있으므로 기록 액티비티에서 돌아오는 시점을 프레그먼트가 아닌 액티비티가 아는 것이 문제였다..
지난 번에는 MVC to MVP를 작성했었다. 우테코 레벨 2 내내 MVP 패턴으로 개발했고 느낀 것들로 MVP가 좋은 점에 대해 설명했다. 그래서 이번엔 레벨 3 내내 함께한 MVVM 패턴에 대해 이야기해보려고 한다. MVVM을 간략하게 설명하자면 Model + View + Viewmodel 이다. MVVM도 MVP와 마찬가지로 MVC에서 파생된 패턴이라고 할 수 있다. MVP에서 바뀐 부분은 한 가지로 Presenter가 ViewModel이 된 것이다. 이제 이 부분에 대해 살펴보자. 뷰와의 의존 관계 MVP에선 (추상화를 통해) 뷰와 프레젠터가 서로를 (느슨하게) 알고있었다. 뷰와 프레젠터 모두 서로를 인터페이스에 정의된 함수들을 통해 호출하였다. 그러므로 뷰와 프레젠터 서로에게 의존하는 양방향 의..
"사용자들이 사진을 공유할 수 있는 기능이 필요하다" 와 같은 문제가 있다고 해보자. 이 문제를 해결하기 위해선 사진 저장, 사진과 사용자의 연결, 사진 보여주기 와 같은 하위 문제를 해결해야한다. 우리는 이렇듯 상위 수준의 문제를 풀 때 여러 개의 하위 문제들로 나누며 이는 코드를 작성할 때도 마찬가지다. 코드를 구성하는 방법은 코드 품질의 기본적인 측면 중 하나이며, 코드를 잘 구성한다는 것은 간결한 추상화 계층을 만드는 것으로 귀결될 때가 많다. 이 장에서는 추상화 계층이 무엇을 의미하는지, 문제를 추상화 계층으로 나누는 방법, 나눠진 추상화 계층을 반영하도록 코드를 구성하는 방법에 대해 알아본다. 왜 추상화 계층을 만드는가? 사용자의 어떤 장치에서 실행되면서 서버에 메시지를 보내는 코드를 작성한다..
코드 품질이 소프트웨어 품질에 어떤 영향을 미칠까? 고품질 코드 저품질 코드 최초 요구 사항 완전하게 충족 경계 조건을 처리하지 못하기 때문에 완전하게 충족하지 못함 요구 사항 변화 사소한 추가 작업 필요 대규모의 코드 변경 및 리팩터링 필요 오류 발생 시 시스템이 복구되거나 부분적으로 작동 시스템은 미리 정의되지 않은 상태에 놓이고 데이터는 손상될 가능성이 있음 처음 접하는 상황 명백히 예상되지 않은 상황도 처리 시스템은 미리 정의되지 않은 상태에 놓이고 데이터는 손상될 가능성이 있음 시스템 공격 시스템은 완전한 상태이고 손상되지 않음 시스템은 미리 정의되지 않은 상태에 놓이고 손상될 가능성이 있음 좋은 코드가 좋은 소프트웨어를 만들기 위한 유일한 조건은 아니지만, 중요한 조건 가운데 하나다. 고품질의..
MVC 우테코의 레벨 1 미션은 MVC 패턴으로 수행했다. MVC를 간략히 설명하자면, 모델과 뷰를 분리하고 모델과 뷰 사이를 컨트롤러가 연결해주는 형식이다. 컨트롤러는 유저가 뷰를 보고 발생시키는 이벤트를 전달해 모델을 변경하고 모델의 변경 사항을 다시 뷰에 적용한다. 컨트롤러는 한 개만 존재하므로 컨트롤러와 뷰의 관계는 1:N이 된다. 어찌 됐든 중요한 점은 모델과 뷰를 분리한다는 것이다. 레벨 1은 코틀린으로만 미션을 진행했지만 레벨 2는 안드로이드 프레임워크 위에서 미션이 진행되었다. 그래서 안드로이드에 종속적이게 되었고 이전과는 몇 가지 다른 점이 발생한다. MVC In Android 안드로이드에선 뷰 그 자체인 xml 파일과, 해당 뷰의 이벤트를 전달 받고 변화시키는 액티비티가 존재한다. 하나..
당신이 코틀린을 사용하고 있다면, '확장 함수'를 사용해봤거나 들어봤을 것이다. (아니어도 상관없다. 지금부터 알아보자) 코틀린은 확장 함수라는 기능을 제공한다. 우선 확장 함수가 어떻게 생긴 녀석인지 예시를 한 번 보자! 예시 String 클래스는 문자열의 처음, 끝을 가져올 수 있는 first(), last() 함수를 제공한다. 그런데 정말 만약에 문자열의 두 번째 글자가 필요한 일이 생겼다고 가정해보자. 이때 String에 대한 확장함수로 second() 함수를 만들어 볼 수 있을 것이다. (물론 [1]로 가져올 수 있겠지만, 좀 더 예쁘게 확장함수를 만들어보자!) fun String.second(): Char { if (this.isEmpty()) { throw NoSuchElementExcept..
코틀린을 처음 시작하면 프로퍼티라는 용어가 굉장히 헷갈릴 수 있다. 그래서 프로퍼티에 대한 용어 정리를 한 번 해보려고 한다. 프로퍼티 Kotlin In Action의 말을 빌리자면 코틀린 프로퍼티는 자바의 필드와 접근자 메서드(getter, setter)를 완전히 대신한다. 오해하지 말자. 이 말은 필드와 접근자 메서드를 모두 합친게 프로퍼티라는 말이 아니다. 프로퍼티는 필드의 역할도, 접근자 메서드의 역할도 할 수 있구나! 라고 받아들이면 된다. + 코틀린에선 자바의 필드를 뒷받침하는 필드(backing field) 라고 부른다. 코틀린을 처음 배울 때 가장 먼저 접하는 프로퍼티는 아래와 같은 형태일 것이다. val name: String = "빅스" 위 name 프로퍼티는 뒷받침하는 필드와 접근자 ..
코틀린에서의 인터페이스와 추상클래스의 차이에 대해 알아보자 구현적 관점에서의 차이 개념적 관점에서의 차이 구현적인 관점에서의 차이 프로퍼티 선언 다중, 단일 상속 구현적인 관점에서 (코틀린의) 인터페이스와 추상클래스의 큰 차이는 없다고 생각한다. 프로퍼티 선언 인터페이스와 추상클래스 모두 자체로는 생성이 불가능하며 구현부(함수 바디)가 있는 함수가 존재할 수 있다. 뿐만 아니라 프로퍼티 또한 둘다 선언할 수 있는데 여기서 조금의 차이가 발생한다. 코틀린 인 액션 (이하 코인액)에서는 이렇게 말한다. (말이 어렵다면 넘어가도 좋다) 인터페이스에는 추상 프로퍼티뿐 아니라 게터와 세터가 있는 프로퍼티를 선언할 수도 있다. 물론 그런 게터와 세터는 뒷받침하는 필드를 참조할 수 없다. (뒷받침하는 필드가 있다면 ..