Android Developer Document에서 권장하는 가이드 내용입니다.

https://developer.android.com/jetpack/docs/guide

Android 앱에는 여러가지 구성요소가 포함되며, 이런 내용들은 Manifest 에서 선언되어 있습니다.

ex) Activity, Fragment, Service, Content Provider, Broadcast Receiver

 

사용자는 짧은 시간 내에 여러 앱과 상호작용 할 경우도 많습니다.

앱은 사용자 중심의 다양한 워크플로 및 작업에 맞게 조정될 수 있어야 합니다.

 

예를 들어 SNS 앱에서 사진 앱을 통해 사진을 공유하거나 앱 사용 중 전화나 알림으로 사용 환경이 중단될 수도 있죠.

또한 모바일 기기는 리소스가 제한되어 언제든 일부 앱 프로세스가 종료할 수 있습니다.

 

이러한 환경을 고려할 때, 앱 구성 요소는 개별적이고 비순차적 실행이 될 수 있으며 언제든 구성 요소가 제거 될 수 있습니다.

이러한 이벤트는 직접 제어가 불가하기 때문에 앱 구성 요소에는 앱 데이터나 상태를 저장하면 안됩니다.

그리고 앱 구성 요소가 서로 종속되면 안됩니다.

일반적인 아키텍처 원칙

앱 데이터와 상태를 앱 구성 요소에 저장할 수 없다면?

관심사 분리

Activity나 Fragment에 모든 코드를 작성하는 실수는 흔합니다.

UI 기반 클래스는 UI 및 OS 상호작용 등의 로직만 포함해야 합니다.

이러한 클래스를 최대한 가볍게 유지하면 생명 주기(LifeCycle) 관련 문제들을 피할 수 있습니다.

 

Activity 및 Fragment 구현은 소유의 대상이 아니며 Android OS 와 앱 사이의 계약을 나타내는 클래스일 뿐입니다.

언제든지 OS가 클래스를 제거할 수 있으니 이러한 클래스에 대한 의존성을 최소화 하는 것이 좋습니다.

Model에서 UI 구동

또 하나의 중요한 원칙은 Model에서 UI를 구동해야 한다는 것입니다.

가급적 지속성 있는 Model을 권장합니다.

 

Model은 앱의 데이터 처리를 담당하며, 앱의 View 객체 및 앱 구성요소로부터 독립되어 있습니다.

그래서 앱의 생명 주기 관련 문제의 영향을 받지 않습니다.

지속성 있는 Model이 이상적인 이유입니다.

  • Android OS에서 리소스를 확보하기 위해 앱을 제거해도 사용자 데이터는 삭제되지 않음.
  • 네트워크 연결이 취약하거나 연결되어 있지 않아도 앱이 계속 작동함.

데이터 관리 책임이 잘 정의된 Model 클래스를 기반으로 앱을 만들면 쉽게 테스트하고 일관성을 유지할 수 있습니다.

권장하는 앱 아키텍처

이 섹션에서는 Android Architecture Component 를 사용하여 앱을 구성하는 방법을 보여줍니다.

모든 시나리오에 최적화된 하나의 앱 작성 방법은 없지만 이 아키텍처가 유용한 출발점이 될 것입니다.

일반적인 아키텍처 원칙을 따르는 Android 앱 작성법을 사용하고 있으면 변경할 필요가 없습니다.

사용자 프로필 UI를 가정해보면, 비공개 백엔드 및 REST API를 사용하여 지정된 프로필 데이터를 가져옵니다.

개요

앱을 설계한 후 모듈들이 서로 어떻게 상호작용해야 하는지 다이어그램이 보여줍니다.

각 구성요소가 한 수준 아래의 구성요소에만 종속됨을 볼 수 있습니다.

Activity 및 Fragment는 ViewModel에만 종속됩니다.

 

Repository는 여러 개의 다른 클래스에 종속되는 유일한 클래스입니다.

Repository는 지속성 있는 데이터 모델과 원격 백엔드 데이터 소스에 종속됩니다.

이 설계는 일관되고 쾌적한 사용자 환경을 제공합니다.

 

사용자가 앱을 닫은 후 재사용시 앱이 로컬에 보존하는 사용자 정보가 바로 표시됩니다.

이 데이터가 오래된 경우 앱의 Repository 모듈이 백그라운드에서 데이터 업데이트를 시작합니다.

UI 빌드

UI 에 필요한 데이터는 ViewModel 아키텍처 구성요소에 기반한 ViewModel에서 정보를 유지합니다.

ViewModel 객체는 UI 구성요소에 관한 데이터를 제공하고 모델과 커뮤니케이션하기 위한 데이터 처리 비즈니스 로직을 포함합니다. ViewModel 은 UI 구성요소에 관해 알지 못하므로 구성 변경(세로 -> 가로모드)의 영향을 받지 않습니다.

ViewModel에서는 데이터 객체에 대한 변경 등을 View에 알려야 합니다.

여기에서 LiveData 가 사용됩니다.

 

LiveData는 객체 변경사항을 모니터링 할 수 있으며, Activity/Fragment/Service 와 같은 앱 구성요소의 생명 주기 상태를 고려한 로직을 포함합니다. (LiveData 필드는 생명 주기로 인해 더 이상 필요하지 않은 참조를 자동으로 정리합니다.)

RxJava와 같은 라이브러리를 사용 중이라면 그대로 사용해도 됩니다. 단 앱 생명 주기를 올바르게 처리해야 합니다.

Activity나 Fragment 에서 LiveData 객체를 observe 후 변경시에 대한 콜백 onChanged() 를 사용해 UI를 새로고침할 수 있습니다.

 

LiveData는 생명 주기를 인식하기 떄문에 Activity 나 Fragment의 onStop(), onDestroy() 메서드 등에 대한 처리하지 않아도 됩니다.

Data 가져오기

데이터를 가져오는 방식은 내부 데이터나 외부 API를 통한 데이터를 가져오는 방식들이 있습니다.

예제에서는 Retrofit 라이브러리를 통해 백엔드 REST API를 사용합니다.

 

ViewModel에서 직접 해당 라이브러리를 이용하여 데이터를 LiveData 객체에 할당하는 방법이 있습니다.

이 경우 ViewModel 클래스에 너무 많은 책임이 부여되어 관심사 분리 원칙을 위반하게 됩니다.

또한 ViewModel의 범위는 Activity나 Fragment 생명 주기에 연결되어 있으므로 데이터가 손실될 수도 있습니다.

그래서 Repository 모듈을 사용하여 데이터 작업을 처리합니다.

 

Repository는 지속적인 모델, 웹 서비스, 캐시 등 다양한 데이터 소스 간 중재자로 볼 수 있습니다.

이제 ViewModel이 데이터를 가져오는 방법을 직접 알지 못하기 때문에 Repository에서 서로 다른 데이터 가져오기 구현을 통한 데이터를 ViewModel에 제공할 수 있습니다.

구성요소 간 종속성 관리

Repository 클래스에서 WebService를 통해 데이터를 가져올 경우 WebService 클래스의 종속성을 알아야 합니다.

이러한 상황에서 다른 클래스에서도 WebService가 필요한 경우 코드를 복제해야 합니다.

이런 문제는 아래 설계 패턴을 사용하여 해결할 수 있습니다.

  • 종속성 주입(DI) : 클래스가 자신의 종속성을 구성할 필요 없이 종속성을 정의할 수 있습니다.

     

    런타임시 다른 클래스가 이 종속성을 제공해야 합니다.
    Android 앱에서는 Dagger 2 라이브러리 사용이 좋습니다.
    Dagger 2 는 종속성 트리를 따라 객체를 자동으로 구성하고 종속성을 컴파일 시간에 보장합니다.
  • 서비스 로케이터 : 클래스가 자신의 종속성을 구성하는 대신 종속성을 가져올 수 있는 레지스트리를 제공합니다.

DI 사용보다 서비스 레지스트리 구현이 쉬우므로 DI가 익숙치 않다면 서비스 로케이터 패턴을 사용해도 됩니다.

이 패턴은 코드를 복제하거나 복잡성을 추가하지 않아도 종속성을 관리하기 위한 명확한 패턴을 제공하므로 코드를 확장할 수 있습니다.

이러한 패턴을 사용하면 테스트 및 프로덕션 데이터 가져오기 구현 등을 신속하게 전환할 수 있습니다.

ViewModel 과 Respository 연결

ViewModel에서 DI (Dagger 2) 를 사용하여 Repository를 주입시켜 봅니다.

Repository가 WebService 객체 호출을 하지만 하나의 데이터 소스에만 의존하면 유연성이 떨어집니다.

따라서 매번 WebService를 호출하는 방식은 네트워크 낭비 및 새 쿼리 완료시까지 사용자가 기다려야 하는 문제가 있습니다.

이런한 문제를 해결하기 위해 Repository에 데이터를 캐시하는 소스를 추가해 봅니다.

지속되는 데이터

위에까지 구현 방식은 앱이 나갔다 들어오거나 하는 경우 Repository가 메모리 내 캐시에서 데이터를 가져옵니다.

하지만 장시간 프로세스를 종료 후 들어온다면 다시 네트워크에서 데이터를 가져와야 합니다.

이런 경우 Room 같은 라이브러리가 필요합니다.

이미 SQLite 같은 ORM을 사용 중이라면 꼭 Room으로 대체할 필요는 없습니다.

Room에서는 Annotation으로 로컬 스키마 정의가 가능합니다. (@Entity, @PrimaryKey)

RoomDatabase를 구현하여 추상 클래스를 만들면 Room에서는 자동으로 구현을 제공합니다.

 

데이터를 데이터베이스에 액세스하기 위해 데이터 액세스 객체 (DAO) 를 만듭니다.

Room 메서드에서 LiveData를 사용하면 데이터 변경시 자동으로 모든 Observer들에게 알리게 됩니다.

DAO를 정의했으면 데이터베이스 클래스에서 DAO를 참조 후 Repository 소스를 수정하면 됩니다.

단일 소스 Repository

다양한 REST API 엔드포인트는 흔히 동일한 데이터를 반환합니다.

일관선 확인 없이 Repository가 WebService 요청으로부터 응답을 있는 그대로 반환한다면 Repository 의 데이터 버전과 형식이 가장 최근에 호출된 엔드포인트에 종속되므로 UI에서 혼란스러운 정보를 표시할 수 있습니다.

 

그렇기에 Repository 구현에서는 데이터베이스에 WebService 응답을 저장합니다.

그러면 데이터베이스 변경시 LiveData 객체에 콜백이 트리거 됩니다.

 

이 모델을 사용하면 데이터베이스가 단일 소스 Repository 역할을 하며 앱의 다른 부분은 Repository를 사용하여 데이터베이스에 엑세스 합니다. 디스크 캐시 사용 여부와 상관없이 Repository에서 데이터 소스를 나머지 앱의 단일 소스 Repository 로 지정하는 것이 좋습니다.

진행 중인 작업 표시

SwipeRefresh 같은 사용 사례에서는 네트워크 작업시 UI 표시가 중요합니다.

다양한 이유로 데이터가 업데이트 될 수 있으므로 실제 데이터와 UI 작업을 분리하는 것이 좋습니다.

  • LiveData 유형의 객체를 반환하도록 변경하고, 이 객체에는 네트워크 작업 상태가 포함됩니다.
  • Repository 클래스에 데이터 새로고침 상태를 반환할 수 있는 다른 함수를 제공합니다.

각 구성요소 테스트

관심사 분리의 원칙을 따랐을 때 한 가지 중요한 이점은 테스트 가능성입니다.

  • UI 및 인터렉션 : Android UI Instrumentation Test 를 사용합니다. Espresso 라이브러리를 사용하는 것이 가장 좋으며, Mock으로 ViewModel을 제공할 수 있습니다. Activity나 Fragment는 ViewModel 하고만 통신하므로 이 클래스만으로도 충분히 UI 를 테스트 할 수 있습니다.

  • ViewModel : JUnit Test 를 사용하여 ViewModel 클래스를 테스트할 수 있습니다. Repository만 Mock 객체로 테스트하면 됩니다.

  • Repository : 역시 JUnit Test로 테스트할 수 있습니다. WebService난 DAO를 Mock 객체로 테스트하면 됩니다.

    • Repository가 올바른 WebService를 호출하는지
    • Repository가 데이터베이스에 결과를 저장하는지
    • 데이터가 캐시되고 최신인 경우 Respository가 불필요한 요청은 안만드는지
  • WebService와 DAO 는 모두 인터페이스이므로 더 복잡한 테스트를 위해 Mock이나 fake 구현을 만들 수 있습니다.

  • DAO : Instrumentation Test를 사용하여 테스트합니다. UI 구성요소가 필요하지 않으므로 빠르게 실행되며, 각 테스트에서 메모리 내에 데이터베이스를 만들어 테스트 부작용이 없게 합니다. (ex. 디스크의 DB 파일 변경)

    • Room에서 데이터베이스 구현을 지정하도록 허용하므로 SupportSQLiteOpenHelper 의 JUnit 구현을 제공하여 DAO를 테스트할 수 있습니다. 하지만 기기에서 실행 중인 SQLite 버전이 개발 PC의 SQLite 버전과 다를 수 있으므로 이 방법은 권장되지 않습니다.

  • WebService : 테스트에서 백엔드로 네트워크 호출하지 않도록 합니다. 웹 기반 테스트를 포함한 모든 테스트가 외부로부터 독립적이어야 합니다. MockWebServer 를 포함하여 여러 라이브러리를 활용하여 가짜 로컬 서버를 만들 수 있습니다.

  • 아티팩트 테스트 : 아키텍처 구성요소는 백그라운드 스레드를 제어할 수 있는 maven 아티팩트를 제공합니다.

    `androidx.arch.core:core-testing` 아티팩트에는 다음과 같은 JUnit 규칙이 있습니다.
    • InstantTaskExecutorRule : 호출 스레드에서 백그라운드 작업을 즉시 실행합니다.
    • CountingTaskExecutorRule : 아키텍처 구성요소의 백그라운드 작업을 기다립니다. Espresso와 연결할 수 있습니다.

권장사항

다음 권장사항은 필수는 아니지만 경험에 의한 권장사항을 따르는 경우 장기적으로 더 강력하고 테스트 및 유지관리가 쉬운 코드 베이스를 만들 수 있습니다.

  • Activity, Service, Broadcast Receiver와 같은 앱의 진입점을 데이터 소스로 지정하지 마세요.
  • 앱의 다양한 모듈 간 책임이 잘 정의된 경계를 만듭니다.
  • 각 모듈에서 가능하면 적게 노출합니다.
  • 각 모듈을 독립적으로 테스트하는 방법을 고려합니다.
  • 다른 앱과 차별되도록 앱의 고유한 핵심에 초점을 맞춥니다.
  • 가능한 한 관련성이 높은 최신 데이터를 보존합니다.
  • 하나의 데이터 소스를 단일 소스 저장소로 지정합니다.

추가: 네트워크 상태에 따른 노출 처리 로직

SonarQube 와 Jenkins 서버를 가지고 있다는 전제 하에 시작되는 이야기입니다.

개인이 아닌 팀 규모의 개발팀에서는 보통 CI 관련하여 Jenkins 등을 많이 사용하고 있습니다.

JenkinsSonarQube 를 활용하여 사용하는 이야기 입니다.

 

먼저 시나리오를 써봅니다. 어떤 시나리오냐?

Jenkins 와 SonarQube 를 언제 어떤 용도로 사용하느냐에 대한 시나리오 입니다.

 

보통은 소스 관리를 하기 위해 GitHub, GitLab 등을 사용을 합니다.

그러면 보통은 아래와 같은 구성들이 나오겠죠

 

  • GitHub - Jenkins - SonarQube
  • GitLab - Jenkins - SonarQube

제가 사용하던 동작 흐름은 아래와 같습니다.

 

  • 소스 작업 commit 후 push
  • GitLab 에서 변화 감지후 Jenkins로 WebHook 발생
  • Jenkins에서 WebHook 인지 후 소스 pull 후 build
  • build 완료 후 deploy

이 중에 build 전후로 SonarQube 를 추가해보기로 합니다.

그러기 위해서 Jenkins에서 SonarQube 를 연동하는 법을 정리해봅니다.

제가 알아본 방법은 크게 2가지가 있었습니다.

 

  1. Jenkins Plugin 으로 사용하는 방법
  2. gradle Task 추가 후 사용하는 방법

1. Jenkins Plugin 사용하는 방법

먼저 Jenkins 에 SonarQube Scanner 플러그인을 설치합니다.

 

SonarQube Scanner for Jenkins

Jenkins 관리 - 플러그인 관리 - SonarQube Scanner for Jenkins 설치

(https://plugins.jenkins.io/sonar)

 

그리고 적용하려는 프로젝트 구성에 SonarQube 연동하는 스텝을 추가합니다.

Jenkins - 프로젝트 - 구성 - Add build step - Execute SonarQube Scanner 추가

Analysis properties 작성

 

아래 이미지와 같이 작성하며, 아래 요소들을 주의하여 작성합니다.

  • sonar.host_url : SonarQube 서버 url 및 port
  • sonar.login : SonarQube ID 혹은 token
  • sonar.password : SonarQube Password (ID에서 token 사용시는 공백)
  • sonar.projectKey : SonarQube 프로젝트 값 참조
  • sonar.projectName : SonarQube 프로젝트 값 참조
  • sonar.java.binaries : Jenkins workspace 내에서 컴파일 후 생성된 class binary 경로
  • sonar.profile : SonarQube 프로젝트 값 참조
  • sonar.coverage.jacoco.xmlReportPaths : Jenkins workspace 내에서 JaCoCo Report 생성 경로 (JaCoCo 미사용시 skip)

위 Step을 추가 후 빌드를 돌려봅니다.

빌드가 잘 되었으면 콘솔 로그도 한번 구경해봅니다.

+) Coverage Report를 작성해주는 JaCoCo 플러그인도 있습니다.

 

JaCoCo plugin

Jenkins 관리 - 플러그인 관리 - JaCoCo plugin 설치

(https://plugins.jenkins.io/jacoco)

 

적용하려는 프로젝트 구성에 Coverage Report를 작성하는 스텝을 추가합니다.

Jenkins - 프로젝트 - 구성 - Add build step - Record JaCoCo coverage report 추가

아래의 항목들을 추가 작성합니다.

 

  • Inclusions (e.g.: **/*.class) : **/*.class

  • Exclusions (e.g.: **/*Test*.class) : **/R.class, **/R$*.class, **/BuildConfig.*, **/Manifest*.*, com/android/**/*.class

변경한 구성을 저장 후 빌드를 진행해 봅니다.

빌드가 성공하였다면 역시나 콘솔 로그를 확인해봅니다.

2. gradle Task 추가 후 사용하는 방법

먼저 Android 앱 소스에 gradle Task 추가하는 방법은 아래 링크를 참고하시면 됩니다.

그리고 Jenkins 프로젝트 구성에서 아래와 같이 gradlew 명령을 직접 써주시면 됩니다.

Jenkins - 프로젝트 - 구성 - Add build step - Execute shell 추가

 

chmod +x gradlew

# JaCoCo 커버리지 리포트 작성
./gradlew coverageReport

# SonarQube 분석
./gradlew sonarqube

빌드 후 확인을 해봅니다.

3. 2가지 방법의 차이?

먼저 플러그인을 사용하면 프로젝트 소스 레벨에서 추가할 부분이 없습니다.

그리고 Jenkins 프로젝트 상태 화면에 관련 UI도 이쁘게 생긴답니다.

하지만 JaCoCo플러그인 은 빌드 후 조치 구성에서만 추가가 가능하였고, Build 구성에는 추가가 불가하였습니다. SonarQube 플러그인은 Build 구성에서만 추가가 가능하였고요.

(Jenkins 프로젝트가 Maven 프로젝트였다면 다 가능한 걸로 보였습니다.)

 

gradle Task 방식으로 진행하면 Excute shell 항목에서 SonarQube, JaCoCo 사용이 자유롭게 가능합니다.

 

하지만 프로젝트 소스 레벨에서 gradle Task를 추가해야 했으며, Jenkins 프로젝트 상태 화면도 다시 평범해졌습니다.

두 방식을 사용시 장단점들이 있는 상태였습니다.

그 후...

저 이 후로 GitLab MergeRequest 시 Jenkins가 위 동작들을 처리 후 SonarQube 결과를 GitLab에 MR 메세지로 남길 수 있지 않을까 했습니다만...

특히나 검색해보니 GitHub 플러그인 사용시 아래와 같이도 사용이 가능해 보였습니다.

하지만 제가 써야 하는 건 GitLab 이었고, GitLab 플러그인은 지원이 중단되었습니다...

정확히는 기존에 있던 개인 개발자가 만들던 플러그인이 SonarQube 7.7 버전부터 중단되었습니다.

https://github.com/gabrie-allaigre/sonar-gitlab-plugin/issues/222

위 링크의 코멘트나 아래 링크를 보면 GitLab과 콜라보레이션을 위해 SonarQube 에서 플러그인 지원을 중단한 것으로 보입니다...

https://www.sonarqube.org/sonarqube-8-1/

아쉬운 대로 Jenkins에서 빌드 후 조치에 GitLab 관련된 플러그인 기능을 사용해 보았지만.... 이렇네요..

네 그래서 일단은 접었습니다.

추후에 여유가 생긴다면 다른 방법들을 생각해보던지 해야겠습니다.

'IT > ETC' 카테고리의 다른 글

Eclipse Copilot  (0) 2024.10.17
Copilot 리서칭  (1) 2024.10.17
[SonarQube] SonarQube 도입기?  (0) 2020.02.07
[Docker] Docker란?  (0) 2018.03.23
Expert Beginner란...  (0) 2018.03.12

먼저 SonarQube 서버가 확보된 상태에서 시작합니다.

서버가 없으시다면 아쉬운 대로 개인 로컬에서 서버를 돌린 뒤 사용해보시면 됩니다.

참고 : https://nobase-dev.tistory.com/275

간단합니다.

build.gradle에 아래 내용만 추가해주면 됩니다.

buildscript {
    dependencies {
        classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8"
    }
}

apply plugin: "org.sonarqube"
sonarqube {
    properties {
        property "sonar.host.url", "http://localhost:9000/"
        property "sonar.login", "admin"        // 로그인 id 또는 인증토큰
        property "sonar.password", "admin"    // 인증토큰 사용시는 공백으로
        property "sonar.projectKey", "projectKey"
        property "sonar.projectName", "projectName"
        property "sonar.projectVersion", "1.0"
        property "sonar.sourceEncoding", "UTF-8"
        //property "sonar.sources", "src/"
        property "sonar.profile", "Sonar way"
        property "sonar.coverage.jacoco.xmlReportPaths", "build/reports/coverageReport/coverageReport.xml"    // Test Coverage Report 생성한 경우 사용
    }
}

SonarQube에서 다양한 Property들을 제공하고 있습니다.

보다 많은 설정이나 상세한 내용은 아래 링크를 참고하시면 됩니다.

https://docs.sonarqube.org/latest/analysis/analysis-parameters/

다 되었다면 Android StudioTerminal 탭에서 실행하면 됩니다.

> gradlew sonarqube

그리고 SonarQube 프로젝트 리스트에서 리포트가 잘 생성이 되었는지 확인하면 끝~

은 아니고 이제부터 시작입니다.

버그와 취약점, 악취들을 제거하기 위한 준비는 끝~ 입니다~

참고링크 :

https://question0.tistory.com/2

https://plugins.gradle.org/plugin/org.sonarqube

Android Studio에서는 간단히 Run ... with coverage 를 통해 Test Coverage를 확인할 수 있습니다.

다만 SonarQube 사용시 Coverage 항목을 위해서는 xml 형태의 Test Coverage Report가 필요하였고요.

그래서 JaCoCo 플러그인을 사용하여 간단히 뽑아볼 수 있었습니다.

아래의 포스팅에 잘 정리가 되어 있어 따라가면 되었고요.

https://www.androidhuman.com/lecture/quality/2016/02/13/jacoco_unit_test_android/

 

JaCoCo를 사용하여 안드로이드 프로젝트 유닛 테스트 커버리지 측정하기

#Android, #Koltin, and #Tesla

www.androidhuman.com

 

다만!! 일부 설정이 제 환경과 다른 부분들이 발생을 하였습니다.

해당 포스팅에서 설정은 다 gradle 파일 안에서 이루어지면 크게 3단계로 나뉘어져 있습니다.

  1. JaCoCo 플러그인 설정
  2. 커버리지 측정 태스크 정의
  3. 커버리지 측정 실행

이 중에서 제 환경에서 다른 부분은 커버리지 측정 태스크 정의 에서 일부 항목이었습니다.

    classDirectories.from = fileTree(
            dir: "${buildDir}/tmp/kotlin-classes/debug",
            excludes: ['**/R.class',
                       '**/R$*.class',
                       '**/BuildConfig.*',
                       '**/Manifest*.*',
                       'com/android/**/*.class']
    )

    sourceDirectories.from = files(coverageSourceDirs)
    executionData.from = files("${buildDir}/jacoco/testDebugUnitTest.exec")

 

차이라면 제가 작성한 테스트 프로젝트는 Kotlin 코드만 있었습니다.

그러다 보니 classDirectories 경로가 달랐습니다.

  • dir: "${buildDir}/intermediates/classes/debug",

  • dir: "${buildDir}/tmp/kotlin-classes/debug",

그리고 몇몇 속성이 Deprecated 되었다고 떠서 검색해보니 .from 을 추가하라 하더군요.

그래서 아래 항목들에 .from이 추가되었습니다.

  • classDirectories.from
  • sourceDirectories.from
  • executionData.from

 

추가로 Flaovr 를 사용하는 프로젝트에서는 아래의 항목들이 FlavorBuildType 옵션에 맞춰 설정이 필요하였습니다.

ex) Flavor 가 dev이고, BuildType이 debug일 경우

task coverageReport(type: JacocoReport, dependsOn: 'testDevDebugUnitTest') {
    ...
    classDirectories = fileTree(
            dir: "${buildDir}/intermediates/classes/dev/debug",
    ...
    )
    ...
    executionData = files("${buildDir}/jacoco/testDevDebugUnitTest.exec")
    ...
}

 

제가 사용한 최종 수정본입니다~

apply plugin: 'jacoco'

jacoco {
    reportsDir = file("${buildDir}/reports")
}

task coverageReport(type: JacocoReport, dependsOn: 'testDevDebugUnitTest') {
    group = "Reporting"
    description = "Generate Jacoco coverage reports"

    def coverageSourceDirs = ['src/']

    classDirectories = fileTree(
            dir: "${buildDir}/intermediates/classes/dev/debug",
            excludes: ['**/R.class',
                       '**/R$*.class',
                       '**/BuildConfig.*',
                       '**/Manifest*.*',
                       'com/android/**/*.class']
    )

    sourceDirectories = files(coverageSourceDirs)
    executionData = files("${buildDir}/jacoco/testDevDebugUnitTest.exec")

    reports {
        xml.enabled = true
        html.enabled = true
    }
}

 

빌드 완료 후에 지정된 폴더 밑에 Report 파일이 잘 들어갔는지 확인해봅니다.

 

SonarQube 사용 중이라면 저 Report 경로를 잡아주면 gradle task 에 추가하면 됩니다.

apply plugin: 'org.sonarqube'
sonarqube {
    properties {
        ...
        property "sonar.coverage.jacoco.xmlReportPaths", "build/reports/coverageReport/coverageReport.xml"
    }
}

 

하는 김에 SonarQube 도 다시 돌려봅니다.

> gradlew sonarqube

 

SonarQube 프로젝트 리스트에서 Coverage를 확인합니다. -끝-

!!! Windows 환경에서 설치된 Android Studio 기준으로 작성한 내용입니다 !!!!

한글 Windows 환경에서 Android Studio 설치 후 기본 설정으로 사용시 종종 문제가 생기는 경우들이 발생합니다.

저같은 경우는 주로 Windows 내에서 사용자명을 한글로 사용하다보니 발생하는 이슈가 많았습니다.

cmd 창에서 set 명령을 쳐보면 아래와 같은 항목들이 보입니다.

HOMEPATH=\Users\한글유저명
...
TEMP=C:\Users\한글유저명\AppData\Local\Temp
TMP=C:\Users\한글유저명\AppData\Local\Temp
...
USERPROFILE=C:\Users\한글유저명

 

Windows 내 Android Studio에서는 저 값들을 기본으로 잡혀있는 것들이 있습니다.

대표적으로 설정파일들이 그러하지요.

사용 중에 또 언제 어떤 문제가 발생할지 몰라 먼저 바꿔봅니다.

gradle이나 Android SDK 경로는 바꿔 보았는데요.

(https://nobase-dev.tistory.com/273)

정작 Android Studio 설정 파일들은 아직 못바꾸고 있었네요.

 

c:\Program Files\Android\Android Studio\bin\idea.properties

 

위 파일이 해답을 가지고 있었습니다.

#---------------------------------------------------------------------
# Uncomment this option if you want to customize path to IDE config folder. Make sure you're using forward slashes.
#---------------------------------------------------------------------
# idea.config.path=${user.home}/.AndroidStudio/config
idea.config.path=d:/.AndroidStudio3.5/config

#---------------------------------------------------------------------
# Uncomment this option if you want to customize path to IDE system folder. Make sure you're using forward slashes.
#---------------------------------------------------------------------
# idea.system.path=${user.home}/.AndroidStudio/system
idea.system.path=d:/.AndroidStudio3.5/system

idea.config.path=d:/.AndroidStudio3.5/config

idea.system.path=d:/.AndroidStudio3.5/system

위 2 라인이 제가 추가한 부분입니다.

 

원래는 user.home으로 잡혀 있던 경로들입니다. (주석# 으로 처리되어 있으면 기본으로 먹힙니다.)

c:\Users\한글유저명\.AndroidStudio3.5\

위 경로가 기본으로 설정되었던 경로이고 하위에 config와 system 폴더가 자리잡고 있지요.

 

이제 두 폴더를 idea.properties에 설정한 경로로 복사하면 됩니다.

그리고 Android Studio를 재실행하면 끝!! 입니다~

 

다만 Android Studio 업데이트시는 idea.properties가 새로 설치되는 것으로 보이네요.

업데이트 후 재설정이 필요할 것으로 보입니다....

 

!!! Android 개발에 있어 많고 많은 빌드 에러 중 Windows 환경에서 종종 발생하는 에러에 대한 내용입니다 !!!!

Android Studio에서 Test Coverage를 돌릴 경우 발생하는 에러에 대해서 얘기해보려 합니다.

 

먼저 작성한 코드의 테스트 코드를 작성 후 Run 으로 동작이 잘 됨을 확인한 상태였습니다.

그 후 Run ... with Coverage 동작시 아래와 같은 에러가 발생하더군요.

java.lang.reflect.InvocationTargetException
FATAL ERROR in native method: processing of -javaagent failed
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:386)
	at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:401)

 

구글링을 해보아도 딱히 짐작이 가는 부분이 없습니다.

더 찾아보다보니 아래와 같은 내용이 있더군요.

https://youtrack.jetbrains.com/issue/IDEABKL-5941

안타깝게도 러시아 사용자도 유사한 증상을 겪은 것으로 보이죠.

Temp 경로에 러시아 문자가 들어가면서 발생한 것으로 보고 있고요.

저는 한글 유저명이 문제가 된 것으로 추정할 수 있었습니다.

다시 Android Studio 로 돌아가서 Run 윈도우를 뒤져 실행다시 커맨드를 봅니다.

 

아 제 환경은 gradle 경로도 미리 D 드라이브로 변경해놓은 상태였습니다.

https://nobase-dev.tistory.com/273

원인은 Temp 경로가 Windows 환경에서는 사용자 홈으로 잡혀서 생긴 문제로 보입니다.

https://stackoverflow.com/a/29716813

https://docs.microsoft.com/ko-kr/windows/win32/api/fileapi/nf-fileapi-gettemppatha?redirectedfrom=MSDN#remarks

위 글들을 보면 기본으로 사용자 홈이 잡힌 이유는 아래와 같네요.

  1. Java에서 temp 경로를 Windows 환경에서는 Win32API 인 GetTempPath를 사용함
  2. GetTempPath에서는 아래의 순서로 경로를 지정함.
  3. The path specified by the TMP environment variable.
  4. The path specified by the TEMP environment variable.
  5. The path specified by the USERPROFILE environment variable.
  6. The Windows directory.

아무튼 다시 아래 글을 보아 Android Studio에서도 temp 경로를 수정해봅니다.

https://intellij-support.jetbrains.com/hc/en-us/community/posts/360000020720-IntelliJ-Idea-generate-classpath-jar-files-in-C-Users-User-AppData-Local-Temp-

 

IntelliJ Idea generate classpath.jar files in C:\Users\User\AppData\Local\Temp\

I need change location where IntelliJ Idea generate the classpath.jar files. When I generate a new service, controller or domain file, is generated a new classpath.jar file in C:\Users\User\AppData...

intellij-support.jetbrains.com

Help -> Edit Custom VM Option 에서 아래 문구 추가 후 Android Studio 재시작

(studio64.exe.vmoptions)

# custom Android Studio VM options, see https://developer.android.com/studio/intro/studio-config.html
-Djava.io.tmpdir=d:/temp

 

이제 다시 Run ... with Coverage를 돌려봅니다.

 

오오 이제 잘 나오네요.

한글 Windows에서 개발은 참 다양한 어려움들이 있는 것 같네요. ^^

SonarQube(소나큐브) 도입 및 적용에 대한 내용입니다.

먼저 소나큐브란 무엇인가?

위키에서는 아래와 같이 소나큐브를 설명하고 있습니다.

소나큐브(SonarQube, 이전 이름: 소나/Sonar)[2]는 20개 이상의 프로그래밍 언어에서 버그, 코드 스멜, 보안 취약점을 발견할 목적으로 정적 코드 분석으로 자동 리뷰를 수행하기 위한 지속적인 코드 품질 검사용 오픈 소스 플랫폼이다. 소나소스(SonarSource)가 개발하였다. 소나큐브는 중복 코드, 코딩 표준, 유닛 테스트, 코드 커버리지, 코드 복잡도, 주석, 버그 및 보안 취약점의 보고서를 제공한다.

개발자에게 좋은 정적분석 툴이라는 내용 같네요.

https://www.sonarqube.org/ 에 적혀있는 대문 문구입니다.

Your teammate forCode Quality and Security

SonarQube empowers all developers to write cleaner and safer code.

역시 소나큐브가 모든 개발자(가)보다 깨끗하고 안전한 코드를...

뭐 아무튼 코드 품질과 보안에 대한 도움을 준다는 내용 같네요.

슬라이드쉐어에 소나큐브에 대해 잘 정리된 슬라이드가 있어 달아봅니다~

https://www.slideshare.net/curvc/sonarqube-sonarqube

저는 어떤 타이밍에 어떻게 소나큐브를 활용할지에 대한 부분에 앞서 실제로 써보는 시간을 가져보았습니다.

소나큐브를 설치할 서버를 만들 능력은 없어 제 Windows 10 PC에 Docker 설치 후 SonarQube Image를 받은 후 돌려보았습니다.

Docker Image는 SonarQube Community Edition을 기본 지원하는 것 같네요.

Docker 설치 및 설정 등은 아래 링크들을 참고하면 됩니다.

참고로 포스팅 글에서 sonar-scanner 부분은 스킵하였습니다.

그냥 설치시는 아래 링크 참조하시면 될 것 같네요.

https://docs.sonarqube.org/latest/setup/get-started-2-minutes/

Docker에 소나큐브 서버는 아래와 같이 돌렸습니다.

> docker pull sonarqube > docker run -d --name sonarqube_com -p 9000:9000 sonarqube

잘 돌아가는지 소나큐브 페이지에 들어가봅니다.

http://localhost:9000/

Android 개발자다 보니 Android 개발 환경에서 설정하였고, Android Studio에서 포스팅 글을 참고하여 설정하니 잘 되었습니다.

Android Studio의 Terminal에서 아래와 같이 실행하면 로컬 Docker에 설치된 소나큐브 서버에 결과가 잘 올라가더랍니다.

> gradlew sonarqube

진행하다보니 같이 일하는 iOS 개발자의 소스도 돌려보려 하니 안되더군요.

Docker로 돌린 소나큐브는 Community Edition 이었고, Objective-C나 Swift는 과금해야 사용할 수 있는 Developer Edition 부터 사용이 가능한 문제가 있었습니다.

 

어떻게 활용할지보다 일단 써보자는 취지로 접근한 지라 Trial 로 써보기로 합니다.

https://www.sonarsource.com/plans-and-pricing/

How are the plans licensed?

Community Edition is free.

Developer Edition, Enterprise Edition and Data Center Edition are priced per instance per year and based on your lines of code. You pay per instance for a maximum number of lines of code to be analyzed.

Determine your max number of LOCs on your edition of choice and see what it will cost you.

Can I get an evaluation license?

It is possible to get a free, 14 day evaluation license of any commercial edition by filling in the form you see once you select your edition.

마침 소나큐브 Docker Image도 Developer Edition을 지원을 하고는 있네요.

> docker run -d --name sonarqube_dev -p 9001:9000 sonarqube:developer-beta

Community Edition과 동시에 돌려보려 포트 설정을 요리조리 바꿔봤지만... 워낙 Docker 및 서버 문외한이라 결국 실패하였고.. 필요시마다 하나씩만 돌려보기로 합니다;;

Docker로 설치한 소나큐브 Developer Edition도 서버가 잘 돌아감을 확인하고 역시나 Andorid 소스 환경에서 자연스럽게 gradlew sonarqube를 쳐보았습니다.

잘 분석을 하고 잘 올린거 같습니다.

한번 소나큐브 페이지에 들어가서 확인해봅니다.

http://localhost:9001/

이런.. 프로젝트 Overview부터 결과들이 안나옵니다.

몇 군데를 들락거리니 라이센스 키를 입력하라는 페이지가 뜨네요.

알고보니 Developer Edition 을 Trial 버전으로 사용하려고 해도 키를 발급받아야 했습니다.

키를 발급받기 위해 소나소스에서 시키는 대로 고분고분 폼을 작성하여 제출해봅니다.

https://www.sonarsource.com/plans-and-pricing/developer/

성심성의 껏 작성하면 고맙다고 하네요.

https://www.sonarqube.org/forms/success-developer-edition/

하지만 라이센스 키가 바로 안옵니다.

단순하게 폼 작성 후 제출하면 자동 생성해서 키를 줄거라 생각했는데, 그게 아니었습니다.

어느 정도 시간이 흐른뒤 정말 담당자에게서 메일이 왔습니다.

또 고맙다면서 이것저것 묻더군요.

  • 이전에 소나큐브를 쓰고 있었냐?
  • 소나큐브 어떤 기능에 관심이 있고 어떤 프로그래밍 언어를 스캔할거냐?
  • 사용하려는 서버가 Developer Edition이냐? Community Edition 이냐?

대략 저에게는 저 정도를 궁금해 하셨습니다. 스위스 분께서요..

암튼 구글의 도움으로 더듬더듬 영작해서 회신을 해봅니다.

Hello

I'm not...

I blabla..

I would be grateful if you could provide license.

...

구글의 힘으로 14일 후 만료되는 Developer Edition Trial 라이센스 키를 발급 받게 되었습니다.

다시 소나큐브 페이지에 들어가서 라이센스 입력화면에서 입력해봅니다.

http://localhost:9001/

잘 됩니다.

하지만 라이센스 등록 전 돌렸던 분석결과는 볼 수가 없습니다;;

새 출발하는 마음으로 새로 돌려봅니다.

gradlew sonarqube

...

잘 됩니다.

이젠 Overview도 잘 나오고 소나큐브에서 지원하는 다양한 기능을 써볼 수 있었습니다.

Community Edition 대비 Developer Edition 사용시 느낀 차이점은 가장 큰 건 지원하는 언어의 차이도 있겠지만, branch 관리도 차이가 있더군요.

gradle에 branch 속성을 설정해서 올리면 소나큐브 내에서 한 프로젝트에서 다른 brach로 관리가 가능하였습니다.

앞으로 소나큐브로 어떤 타이밍에 어떤 수준까지 고려하여 사용할지를 고민해보아야 할 것 같네요.

+) 소나큐브 가격표입니다. (2020.02.07 기준) 

'IT > ETC' 카테고리의 다른 글

Copilot 리서칭  (1) 2024.10.17
[SonarQube] SonarQube & Jenkins 이야기  (0) 2020.02.14
[Docker] Docker란?  (0) 2018.03.23
Expert Beginner란...  (0) 2018.03.12
[Cloud9][Ruby on Rails] C9 생성 후 간단한 Ruby on Rails 페이지 만들기  (0) 2017.12.29

!!! Android 개발에 있어 많고 많은 빌드 에러 중 Windows 환경에서 종종 발생하는 에러에 대한 내용입니다 !!!!

개인적으로 Android 개발에 있어서 Android Studio에서 Build나 Run 하는 경우가 많았는데요.

주로 툴의 UI 버튼등을 단순히 눌러서 해왔죠.

하지만 Terminal 에서 Build 가 필요할 때도 있지요.

기껏 Terminal 에서 Build 하는 명령어 등을 검색 후 실행했을때 에러가 뜬다면 참 번거럽겠죠.

그 수많은 에러 중 아래의 에러 문구시에 대한 해결책입니다.

C:\Users\?????\.gradle\caches\transforms-1\files-1.1\appcompat-v7-28.0.0.aar\50aa894a55f6ff1ab5e7586893bfabff\res\layout\abc_dialog_title_material.xml: error: file not found.
C:\Users\?????\.gradle\caches\transforms-1\files-1.1\appcompat-v7-28.0.0.aar\50aa894a55f6ff1ab5e7586893bfabff\res\drawable\abc_spinner_textfield_background_material.xml: error: file not found.

> Task :mobile:mergeDebugResources
Error: java.util.concurrent.ExecutionException: com.android.builder.internal.aapt.v2.Aapt2Exception: AAPT2 error: check logs for details


FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':mobile:mergeDebugResources'.
> Error: java.util.concurrent.ExecutionException: com.android.builder.internal.aapt.v2.Aapt2Exception: AAPT2 error: check logs for details

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 18s
14 actionable tasks: 6 executed, 8 up-to-date

D:\HelloWorld>

 

어디가 문제일까요?

그냥 느낌적인 느낌으로 눈에 들어오는 부분이 있을 겁니다?????

C:\Users\?????\.gradle\caches\transforms-1\files-1.1\appcompat-v7-28.0.0.aar\50aa894a55f6ff1ab5e7586893bfabff\res\layout\abc_dialog_title_material.xml: error: file not found.

 

gradle 캐시에 외부 라이브러리들을 저장해놓고 빌드시 사용하는 것으로 보이죠.

그 경로에 한글이 들어가서 문제가 발생한 것으로 보이고요.

그럼 왜 굳이 gradle은 캐시 위치를 저리 잡는지에 대한 궁금증이 생깁니다.

https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_environment_variables

gradle docs에서 뒤져보니 이런 문구가 있네요.

GRADLE_USER_HOME

Specifies the Gradle user home directory (which defaults to $USER_HOME/.gradle if not set).

맞습니다.

저는 GRADLE_USER_HOME 을 설정하질 않았었네요.

Android Studio에서는 Setting 에서 설정이 가능해보이네요.

Gradle home 항목이 그걸로 보이는데... 사실 안해봐서 모릅니다;;

일단 저는 Terminal 이나 Windows CMD 창에서 작업을 시작했으니 그 곳에서 설정을 해봅니다.

Windows에서 환경변수를 보는 것이 set이라는 명령어를 사용하네요.

> set
ALLUSERSPROFILE=C:\ProgramData
ANDROID_HOME=d:\Android\sdk\
ANDROID_SDK_HOME=d:\Android\sdk\
APPDATA=C:\Users\유저명\AppData\Roaming
classpath=%classpath%;
...

참고로 GRADLE_USER_HOME 은 안보이네요.

저는 d:\.gradle\ 경로로 지정을 해보겠습니다.

>set GRADLE_USER_HOME=d:\.gradle\
>set
...
GRADLE_USER_HOME=d:\.gradle\
...

이제 되었네요.

다시 Terminal 에서 빌드를 진행해보면 두가지의 경우가 발생할 겁니다.

잘 되거나.. 다른 에러가 발생하겠죠.

Good Luck!!

+) Windows 에서는 보통 시스템 환경변수 설정에서 직접 입력하기도 하지요.

Android Studio 3.5 버전 기준으로 작성했어요

한글 Windows 환경에서 한글 계정으로 개발을 하다보니 종종 USER HOME 문제로 경로가 제대로 인식 안되는 경우들이 생기네요.

그래서 Android Studio에서 Android SDK 및 gradle 경로를 특정 위치로 변경하는 방법에 대해 소개합니다.

Android Studio 메뉴에서 File-Settings... 를 선택합니다.

Appearance & Behavior - System Setting - Android SDK 를 선택합니다.

그리고 Android SDK Location 을 원하는 경로로 지정합니다.

하는 김에 gradle 경로도 바꿔봅니다.

똑같이 Setting에서 Build, Exception, Deployment - Gradle 을 선택합니다.

여기서 Service directory path 에 원하는 경로를 지정합니다.

이제 Android SDK도 다운로드 해보고 gradle sync도 해봅니다.

잘 되면 그걸로 된 겁니다. ^^

초청 특강 Recommendation Systems : Concepts, Techniques, and Research Results

키워드 : 추천 시스템, 머신러닝

소개 : 최근 온라인 비즈니스에서 크게 각광을 받고 있는 추천 시스템 기술에 대해서 다룹니다. 먼저, 추천 시스템의 기본 개념, 최신 기술, 응용에 대해서 설명하고, 머신 러닝 기술을 이용하여 추천 시스템을 어떻게 실현하는가에 대해서 설명합니다. 또한, 최근 제안된 무관심 아이템이라는 새로운 개념을 제시하고, 이 개념을 통하여 기존 추천 시스템의 정확도가 어떻게 개선 되는가에 대해서 다양한 관점에서 논의합니다. 또한, 추천 시스템에서 다루는 그래프 데이터를 효과적으로 저장하는 새로운 그래프 엔진 RealGraph를 소개하고, 이를 통하여 추천 시스템의 성능을 크게 개선시킬 수 있음을 설명합니다.

추천 시스템은 예전 데이터가 많은 업체만 하던 것을 작은 업체들도 시도하고 있음.

추천 기술은 몇가지 기반 기술이 있음

Content-based filtering은 내 데이터만 봄

Trust-based 는 트러스트라는 관계 데이터가 필요함. 주변인 추천 같은?

Collaborative filtering (CF)는 나와 취향이 비슷한 이웃을 찾고 내가 모르는 아이템을 얼마나 좋아하는지 예측함. Rating Matrix 사용

1단계 취향유사도 계산은 Pearson Correlation Coefficient based Collaborative Filtering(PCC) 사용

2단계 내가 얼마나 좋아할지는 Heuristic based methods 사용

일반 평균, 유사도에 따른 가중치를 주거나 각 이웃의 평균치도 고려함

위 단계가 Matrix Factorization, Tensor Factorization 이며 점차 딥러닝으로 넘어가는 중

Social network analysis, Deep Learning 등

정확도를 높이기 위해 Unrating 개념 추가

Unrating은 존재를 모르거나 알고도 관심이 없는 경우도 있음(부정적인)

기존 선호도로 쓰이던 부분을 사전/사후 선호도를 나눔.

Uninteresting item 찾는게 과제임.

기존 사용자가 좋아하는 것만 추천했지만 한양대에서는 싫어하는 것까지 고려하려 함.

작은 Interesting 그룹과 큰 Uninteresting 그룹이 필요함

깃'깔나는 Git 워크플로 알아보기

키워드 : 개발 방법론, 생산성

소개 : 주요 Git 워크 플로우의 이해 각자 상황에 적합한 Git 워크플로를 찾는 팁

Git flow

메인브랜치 : master, develop (master에 버전 태그 추가)

서포팅브랜치 : feature, release, hotfix (필요시 생성/제거)

hotfix는 마스터에서 브랜치 생성

Github flow

master 브랜치는 항상 배포 가능한 상태 유지

topic 브랜치 (Git flow의 feature) 는 기능 설명이 명확하게 작명하고 merge시 pull request 사용

topic 브랜치는 CI 빌드 통과해야 함.

배포는 merge 순간 bot을 통해 진행함.

매우 빈번하게 배포함.

Gitlab flow

Git flow는 너무 복잡, Github flow는 너무 간단하게 생각되어 나옴.

Gitlab flow - 지속적인 배포가 어려울때

master에서 production 브랜치로 머지 후 배포

Gitlab flow - 환경별 배포시

Gitlab flow - 릴리즈 소프트웨어시

Commit과 Push는 자주 할것

Merge Request or Pull Request 는 완료 전이라도 논의 및 피드백 받을 목적으로도 사용.

merge 전엔 테스트 필요

NHN Edu 사례

단기간,

장기간 배포 일정(코드네임 부여)

rebase 로 정리함.

QA 수정사항은 각 프로잭트 브랜치에서 추가함.

Release 브랜치 사용안함.

배포 후 각 프로젝트 브랜치에 rebase

각 프로젝트 rebase시 conflict이 발생할 수 있고, 그 경우가 복잡할 경우 프로젝트 브랜치 재생성하고 cherry-pick 함.

hotfix 는 Pull Request 로 코드 리뷰와 테스트만 하고 배포는 직접 진행함.

업무프로세스

Pull Request 시 사내 메신저 연동

Pull Request 통과 조건을 부여하여 통과시만 merge 가능(github 설정)

- 코드 리뷰 승인시 조건

- 테스트 옵션 – Unit Test와 Sonarqube

(Sonarqube 는 테스트 결과와 별개로 패스되므로 참고만 함.)

- develop에 최신 master 적용여부 체크

Pull Request 생성시 Jenkins 빌드 및 Unit Test연동

Sonarqube 결과도 댓글로 달림

Github Pull Request + Jenkins + Sonarqube

실용적인 프런트엔드 테스트 전략

키워드 : 프런트엔드, 테스트, 아키텍처

소개 : 프런트엔드 코드는 사용자 환경과 밀접하게 연결되어 있고 복잡한 시각적 요소를 다루기 때문에 테스트를 자동화하기가 어렵습니다. 본 세션에서는 수년간 다양한 방식으로 테스트를 작성해 온 경험을 공유하며, 최신 테스트 도구를 사용해서 실용적으로 프런트엔드 코드를 테스트하는 방법을 설명합니다.

테스트는 왜 하는가?

대부분 개발자가 테스트 코드 작성 후 자동화함

그 이유는 Confidence 때문임.

백엔드의 경우 테스트는 https 요청에 대한 응답이 대부분.

프런트엔드는 마우스 키보드 등 입력과 시각적 정보 출력하고 코드로 확인하기 어려움.

입력 : DOM Event, Routing IO

출력 : Html, css 비교 등

결과 확인

\1. Html 비교

\2. 스냅샷 테스트 : 에전 테스트 결과와 파일 비교. Jest 사용

하지만 html 확인만으로는 테스트 결과에 신뢰를 줄 수 없음

구현상세테스트 vs 동작테스트 로 테스트 성향을 구분.

위의 결과 확인은 구현상세테스트 성향임.

동작테스트로 시각적 회귀 테스트 진행함. (회귀란 기존 버전과 비교하기 떄문)

하지만 픽셀 단위 비교도 브라우저 렌더링 등에 영향을 받음

그리고 커맨드 라인에서 테스트 결과 확인이 어려움.

테스트 실행 단위별 이미지 파일 히스토리 관리 필요.

결정적으로 시각적 테스트 전문 도구(유료)

Applitools, Percy, Chromatic

시각적 테스트는 속도 문제와 테스트의 장점 중 하나인 문서화 기능을 처리하기 어려움

이로 인해 TDD 진행도 어려움.

그리고 단일 테스트에 영향 주는 요소 많음.

시각적 테스트 vs 기능적 테스트

기능 테스트시 시각적 요소 의존성 제거해야 함

JQuery의 Selector들 같은 경우가 이에 속하며, 이를 제거하기 위해 data 속성을 이용해 test-id 등을 부여할 수 있음.

Storybook 툴 추천함.

- 독립된 컴포넌트 개발 환경 (안스 xml 에디터 같음)

- 그러나 시각적 테스트 툴은 아니지만 노트 기능에 테스트 정의 하고 사용해도 됨

- 디자인 피드백 용으로도 쓰임

단위테스트 vs 통합테스트

단위 테스트에 대한 위와 같은 시선도 존재하며, 실제 꼭 필요하지 않은 테스트들도 있음.

Sociable Test / Solitary Test

컴포넌트 단위로 하나로 묶어 테스트 하는 것을 추천

Cypress 통합(추천) / E2E test

개발시 TDD 도구로도 사용 가능

세션에서 강조하고 싶은 내용들

벅스 5.0 (feat. Kotlin, Jetpack)

키워드 : 모바일, 언어

소개 : 벅스 Android 5.0에 Kotlin, Jetpack을 적용하면서 얻은 노하우와 시행착오를 공유합니다.

벅스 앱은 5년간 mvc로 관리 방치되어 왔음.

한 파일에 수만 라인 넘어가기도….

4.x에서 5.x 업데이트에서 Kotlin, MVVM, Retrofit, API 개선 등의 개편을 진행함

작게 작게 나누는 것을 신경 썼으며 클래스, 메서드, 필드 수가 70%정도 증가함.

정적 분석 결과 지표들이 개선됨.

Kotlin Migration

코틀린 전환 후 라인 줄어들고 대신에 품질 고민의 시간을 가질 수 있었음.

Android Studio의 Converting 기능, Plugin, Json 및 Parcelable, Nullable 등의 마이그레이션 진행함.

마이그레이션시 이슈로는 서비스 onStartCommand 등에서 intent가 null 인 경우 발생.

Cursor 반환시 등에도 발생하는 경우가 생김.

AAC

벅스에는 UI담당팀이 따로 있어 로직 분리가 필요하였고, JetPack에서 제공하는 MVVM 사용

데이터바인딩

뷰 의존성 제거 및 findViewbyId 등의 반복코드 제거 등

Observable 객체들 사용 등

바인딩 클래스 내부에서 데이터 셋팅함.

이슈로 RecyclerView 등에서 복잡한 아이템 레이아웃에서 frame drop이 발생함

일반적으로 안드로이드 단말에서는 초당 60프레임을 위해 16ms마다 Draw 함.

데이터바인딩의 ExecutePendingBindings 호출하거나 LifeCycleOwner 지정으로 해결

뷰를 gone 처리시 깜빡거림 이슈 발생

visibility 속성을 ObservableBoolean 처리시 발생했으며, 프레임 드랍 현상에 대한 처리를 하고 xml에 초기값 설정 defalu= 식으로 추가하여 수정함.

Paging

끊김없는 스크롤 구현 가능해짐.

오류처리 등이 변경됨

리스트의 아이템뷰는 뷰홀더에서 뷰모델을 설정함

트랙뷰가 다양하여 공통뷰를 Base로 뽑아냄.

AAC ViewModel

라이프싸일클 동안 뷰와 관련된 데이터 관리

다크모드 등에서 유용했음.

LifecycleOwner, Lifecycle, LifecycleObserver

옵저버에 LifecycleObserver 상속받아 처리함

미디어 앱 아키텍처

벅스뮤직: 정산로그,재생방식 등 복잡한 비지니스 로직

다양한 UI 제공함

기존 Stub으로 받던 부분이 미디어컨트롤러 콜백으로 변경됨

서비스의 실행시점 클라이언트가 아닌 서비스 스스로 실행.

백그라운드 실행 제한, 안스9 이상에서 실행제한 탐지 API 제공

Notification이나 Lock Screen 파편화 대응

PAYCO 매거진 서버 Kotlin 적용기

키워드 : 백엔드, 언어

소개 : 서버 사이드에서도 Spring 5를 통해 공식적으로 지원이 시작된 후,

Spring을 이용한 많은 서비스가 Java를 대신하여 Kotlin을 적용하고 있습니다.

본 세션에서는 PAYCO 매거진 프로젝트에 Kotlin을 적용했던 경험과 시행착오를 나누어 보려 합니다.

페이코 매거진 서비스

페이코 매거진은 위의 기술들을 사용 중이며, Java만 Kotlin으로 바뀜.

스프링 진영도 코틀린 전환이 점점 늘어나고 있음

코틀린 선택의 이유들

Migration

간단한 테스트코드부터 점진적으로 전환해 감

데이터클래스 등에서 getter/setter 등과 toString() 등의 편의성이 제공됨.

자바는 boxing 된 타입과 primitive 타입이 있음.

코틀린은 boxing된 타입임.

자바는 Integer 타입을 널로 설정 후 integer에 대입시 런타임서 에러남.

코틀린은 컴파일시 에러 발생.

Kotlin decompile기능으로 마이그레이션시 도움이 됨

Migration - Plan

코드 자동 변환시 Lombok은 커버 안됨.

private 변수가 프로퍼티 자체에 적용되어 문제가 됨.

위와 같은 처리라 그러함.

코틀린에서는 프로퍼티가 있어 롬복은 불필요하다 보고 제거하게 됨.

의존성 삽입을 위한 애노테이션 안먹음

@Autowired 등

이 경우 Nullable 선언이 필요하나 lateinit으로 처리함. 그리고 final의 의미로 val 로 선언함.

@RequestParam의 required 속성을 true 등으로 하면 Nullable 이 됨. 물음표 떼기.

static 키워드는 companion object 사용

변수는 const, 메서드는 jvmstatic 사용

리팩토링

if else는 when으로 변경.

IDE에서 자동 변환은 안되어서 alt+enter 단축키 활용

스프링 5.0의 model을 코틀린 확장함수로 사용

성능

빌드 타임 및 응답시간 차이는 크게 없었음

Sonarqube 로 라인 수는 6프로, 글자수 10프로 정도 줄어듬.

구문, 순환 반복도 12프로 정도 감소.

생각보다 차이는 작아보이나 import 등 반복은 대거 줄어들었고 마이그레이션시 개선사항들이 추가된 것을 고려하여 좋아진 걸로 생각함.

문법이 간결해지고 함수형 프로그래밍을 고려한 collection 등 효율성이 좋아짐.

 

'IT > 행사' 카테고리의 다른 글

[행사] Droid Knights 2024  (0) 2024.06.26
[행사] Naver Tech Concert Day-2 요약  (0) 2019.01.14
[행사] Naver Tech Concert Day-1 요약  (0) 2019.01.14
[행사] Naver Tech Concert Day-2 06  (1) 2019.01.14
[행사] Naver Tech Concert Day-2 05  (0) 2019.01.14

+ Recent posts