소프트웨어 품질 향상을 위한 소프트웨어 개발환경 구축


2002년부터 소프트웨어 개발자로써 경력을 쌓아오면서 소프트웨어를 잘 개발하는 것보다 소프트웨어의 품질을 유지하고 효과적으로 배포하는 것에 더 큰 어려움을 느껴왔다. 올해는 특히 스타트업을 설립하면서 이러한 어려움이 더욱 표면으로 드러나기 시작했다. 산업체에 근무할 때에는 소프트웨어의 품질을 유지하고 운영하는 별도의 인력이나 팀이 존재했었기 때문에 비교적 손쉬울 수 있었으나, 인력이나 자금면으로 제한이 큰 스타트업에서는 직접적인 어려움으로 다가올 수 밖에 없었다. 소프트웨어를 개발하는 노력에 더불어 품질 유지와 운영의 노력까지 적은 인원이 감당해야 했기 때문이다. 이미 성숙한 기업들에 비해 소프트웨어의 규모가 좀 더 작을지라도 이러한 노력의 크기는 그에 비례하여 줄어들지 않기 때문에 품질 유지운영에 필요한 노력의 크기를 줄이는 것은 스타트업이 조금 더 적은 인력으로 조금 더 빨리 고객들의 요구사항을 제품에 반영할 수 있는 여유가 생긴다는 점에서 중요할 수 있다.



소프트웨어의 품질은 작은 관점에서는 소프트웨어를 잘 테스트하고 발견된 오류를 잘 수정하여 오류가 적은 소프트웨어를 만드는 것이며, 큰 관점에서는 소프트웨어가 사용자의 요구사항을 지속적이고 연속적으로 잘 반영하여 좋은 사용자 경험을 갖는 소프트웨어를 만드는 것이라 생각한다. 특히 스타트업이 성공하기 위한 요건으로써 사용자의 의견을 빠르게 반영하는 것도 중요한 요소라는 점에서 수시로 소프트웨어가 변경되더라도 일정한 품질을 유질할 수 있도록 하는 개발 프로세스를 마련하는 것이 필요하다. 특히 소프트웨어는 국소적인 변경이 일어나더라도 그 영향 범위를 쉽게 추정할 수 없어 매번 전체 테스트를 반복해야 한다는 점 때문에 소프트웨어의 요구사항을 관리하고 새로운 요구사항이 반영된 소프트웨어를 자동으로 테스트해줄 수 있는 방법이 필요하다. 그림 1은 일반적인 소프트웨어의 개발 프로세스를 보여주고 있다. 작은 관점에서의 방법은 검증 단계에 적용될 수 있으며, 큰 관점에서의 방법은 전체 개발 프로세스에 적용될 수 있다.
우리는 위에서 언급한 문제를 해결하기 위해 나름의 작은 프로세스를 구축하였으며, 이를 활용해 매일 업무를 진행하고 있다. 다양한 해결 방법 중 하나의 사례로써 가벼운 마음으로 소개하고자 한다. 또한 우리가 구축한 프로세스를 앞으로 어떻게 개선할 것이지에 대해서도  소개하고자 한다. 


우리 프로세스의 궁극적인 목적은 새로운 요구사항이 반영된 새 버전의 소프트웨어를 즉각적이고 자동화된 방법으로 사용할 수 있도록 하여 소프트웨어의 품질을 높일 수 있게 하는 것이며, 표 1은 이러한 목적을 달성하기 위해 우리가 이루어야 하는 목표를 소개하고 있다. 현재 산업에서는 표 1에서 제시한 각각의 문제를 해결하는 다양한 솔루션이 존재한다. 우리는 이러한 여러 가지 솔루션들을 이용해보면서 가장 우리의 입맛에 맞는 것들을 선택했다. 그리고 전체의 문제는 하나의 제품으로 해결할 수 없기 때문에 각각의 작은 문제를 해결하는 여러 솔루션들을 결합하여 전체 문제를 해결할 수 밖에 없다. 이로 인해 여러 솔루션을 번갈아 오가며 작업을 진행하는 것은 효과적이지 않을 수 있다. 따라서 이러한 각각의 솔루션을 최대한 하나의 개발 환경에 집중시킴으로써 프로세스의 효율성을 높이는데 중점을 두었다. 

1. 소프트웨어의 요구사항을 효과적으로 관리할 수 있을 것
2. 소프트웨어의 테스트와 통합 빌드를 자동으로 수행할 수 있을 것
3. 소프트웨어를 자동으로 운영 환경에 배포할 것

우리는 위에서 제시한 각각의 목표를 달성하여 소프트웨어 품질을 효과적으로 유지할 수 있는 소프트웨어 개발 프로세스를 만들기 위해  그림 2와 같이 솔루션들을 선정하고 구성하였다. JetBrains 사의 IntelliJ는 Java를 기반으로 하는 소프트웨어를 개발하기 위한 통합 개발환경으로써 현재는 자바 이외에도 다양한 프로그래밍 언어를 지원한다. 자바 진영의 가장 대표적인 개발환경인 이클립스에 비해 좀 더 가벼웠고, UI가 직관적이서 IntelliJ 를 이용하고 있다. 우리는 우리 프로세스의 대쉬보드로써 IntelliJ를 이용할 수 있도록 설정하였다. 개발자들은 JIRA나 Bamboo를 이용하기 위해 웹 브라우저를 이용할 필요 없이 IntelliJ안에서 모든 것을 볼 수 있다. 


Bitbucket 무료로 사용할 있는 Git Repository 서비스이며 GitHub 유사하다. 그러나 Bitbucket GitHub와는 다르게 무료로 Private Repository 사용할 있다. Atlassian Bamboos Continuous Integration (CI) 툴로써 여러 개발자가 개발한 소프트웨어의 소스코드가 지속적으로 통합되어 테스트되고 빌드될 있도록 지원한다. JIRA Issue Tracking Tool로써 소프트웨어의 이슈 (버그, 기능, ) 등록하고 진행 상황을 관리할 있도록 도와준다. 소프트웨어 이슈 뿐만 아니라 요구사항 등도 관리할 있다.  마지막으로 Docker 복잡한 소프트웨어의 배포 과정을 단순화시켜준다. 소프트웨어와 소프트웨어를 구동하기 위한 복잡한 설정 과정을 Container 불리는 블랙박스로 만들고 배포하기 때문에 모든 과정이 단순해진다. 위에 설명한 모든 시스템은 Google Cloud 환경 위에 구축되고  운영되고 있다. 스타트업에게 있어서 클라우드는 직접 서버를 구축할 필요가 없고, 비교적 저렴한 가격에 손쉽게 서버를 확장할 있다는 점에서 매력적인 도구이다.

여러 명의 개발자들은 위의 프로세스를 따라 개발을 진행한다. 개발자가 IntelliJ 상에서 개발하고 소스 코드를 Git Commit & Push한다. Bamboo 새로운 소스 코드가 Git Commit 마다 자동으로 이를 Pull하고 스스로 컴파일, 빌드, 테스트를 진행한다. 그리고 수행 결과는 JIRA 연동되어 나타나며, 동시에 개발자들에게 이메일로 통보된다. 테스트가 완료되면 자동으로 Docker 이용해 소프트웨어를 배포하며, 때부터 버전의 소프트웨어를 바로 사용할 있게 된다.

새로운 소스 코드가 Git 제출될 마다 소프트웨어의 기능 테스트가 자동으로 수행되며, 결과는 이메일로 리포팅된다. 개발자들은 통합된 소프트웨어의 품질 결과를 곧바로 있으며, 무엇이 문제인지 신속히 파악할 있게 된다. 무엇보다 지루한 테스팅 과정과 통합 과정을 사람이 매번 하지 않아도 되기 때문에 편리하다.


목표1 소프트웨어의 요구사항의 관리

스타트업에게 있어서 중요한 활동중에 하나는 사용자들의 피드백을 수집하고 분석하여 요구사항을 도출하고 이를 매우 빠르게 반영하는 것이라 생각한다. 분석 과정에서 수많은 요구사항이 도출될 있으며, 모든 욕구사항은 한번에 반영될 없다. 그러므로 어떤 버전에서 어떤 요구사항을 반영할지를 계획하는 것이 필요하다. 이러한 요구사항을 관리하고 계획할 있도록 돕는 많은 훌륭한 솔루션이 있다. 그러나 우리는 이미 소프트웨어의 버그, 개발 내용 일정 등의 이슈를 관리하기 위해 JIRA 사용하고 있기 때문에, 요구사항 역시 JIRA 이용해 관리한다면 매우 편리할 것이라 판단했다.

우리는 새로운 이슈 타입으로써 요구사항 정의하였고, 여기에 어떤 버전에서 개발할 것인지를 기술하였다. 그림 3 이러한 과정을 보여주고 있다. ‘요구사항 1’ 새로운 요구사항으로 등록하면서 Alpha 버전에서 개발하는 것으로 표시하였다.




이렇게 각각의 요구사항을 등록하고나면 JIRA 이슈 검색 기능을 이용해 어떤 버전에서 어떤 요구사항을 구현해야하는지를 쉽게 파악할 있다. 또한 요구사항의 구현을 위해 개발자에게 할당하려는 경우 새로운 이슈를 등록하는 번거로움 없이 요구사항의 이슈 타입을 변경하거나 복제하고서 담당자를 설정함으로써 바로 할당할 있다.

부가적으로 IntelliJ JIRA 통합되어 자신에게 할당 이슈를 기반으로 작업을 진행할 있게 해주며, 이슈별로 투입한 시간을 자동으로 측정해준다. 이렇게 측정된 시간은 JIRA 기록되어 어떤 기능을 구현하기 위해 얼마만큼의 시간을 투여했는지를 확인해볼 있다.

 

목표 2 소프트웨어 테스트와 통합 빌드의 자동화

여러 개발자가 참여하는 소프트웨어 프로젝트에서 어려운점 하나는 개발자들이 작성한 소스 코드를 통합하는 것이며, 통합된 소프트웨어를 테스트하는 것이다. 이러한 활동을 단순화 하고 최대한 자동화하기 위해서 우리는 Gradle 도입했다.  Gradle 자바를 위한 빌드 시스템으로써 단순히 소스 코드를 컴파일 하는 것을 넘어서 빌드된 소프트웨어를 테스팅해주고 결과 보고서를 생성하는 등의 표준적인 소프트웨어 빌드 절차를 정의할 있도록 해준다. 비록 Ant Maven 같은 툴들이 널리 사용되고 있지만, 우리는 Gradle 제공하는 DSL 이용해 우리가 원하는 소프트웨어 빌드 프로세스를 정의할 있다는 때문에 Gradle 표준적인 빌드 시스템으로 사용하게 되었다.

Bamboo Ant Maven 기본적으로 통합된다. 그러나 Gradle 만들어진 소프트웨어를 통합하기 위해서는 유료 플러그인 추가적으로 설치해야만 한다. 하지만 우리는 이를 이용하지 않고, 직접 Gradle 빌드 시스템을 호출함으로써 통합하였다.

Bamboo 이용하려면 먼저 빌드 태스크를 정의해야 한다. 그림 4 우리가 정의한 기본적인 기본적인 빌드 태스크를 보여주고 있다. 왼쪽은 태스크들의 실행 순서를 나타내며, 오른쪽은 태스크의 상세 설정 화면이다. 기본적으로Source Code Checkout 태스크를 이용해 소스 코드를 Git으로부터 가져오며, Gradle Build 태스크를 이용해 소스 코드를 빌드한다. Script location Inline으로 설정해주고 아래의 그림처럼 스크립트를 입력한다. Gradle 빌드를 수행하기 위해서는 gradlew파일을 실행하면서 인자로 build 명령어를 주면 된다. Build 소프트웨어 빌드 과정의 모든 절차 (Build-Assemble-Testing) 모두 수행하도록 하는 명령어다. 빌드 과정의 마지막에서 JUnit 이용해 자동으로 테스트가 수행된다. 마지막으로 Docker 이용한 태스크들은 목표3 테스트 프트웨어의 자동 배포 운영에서 설명한다.



빌드가 성공하거나 실패하면 이에 대한 리포트가 생성된다. Bamboo JUnit Parser 이용해 리포트를 분석하고, 필요한 정보를 가져온다. 만약 빌드가 실패했을 경우에는 무엇이 실패했는지에 대한 정보를 수집하며, 이를 개발자에게 알려준다. 현재 우리는 Git 새로운 소스 코드가 Commit 마다 이와 같은 과정을 반복한다. 그러나 이러한 정책은 프로젝트의 규모에 따라 적당하지 않을 있다. 그러므로 특정 시간에 빌드가 수행 되도록 하거나, 언제든지 수동으로 빌드를 수행할 수도 있다. 이러한 설정을 이용하면 모든 직원이 퇴근한 새벽 시간에 자동으로 빌드가 수행되고, 결과가 전달될 있어 편리하다.

목표3 테스트 프트웨어의 자동 배포 운영

모든 소프트웨어의 테스트를 자동화하는 것은 불가능하다.  Bamboo 의해 자동으로 수행된 테스트는 Unit 테스트라 불리는 기본적인 기능 테스트이며, 테스트에 통과하였다고 해도 소프트웨어에 오류가 없음을 보장할 없다. 단순한 테스트를 넘어 소프트웨어의 사용 시나리오를 기반으로 통합 테스트를 진행해야 한다. 이를 위해서는 버전의 소프트웨어가 실제로 구동되어야 하며, 테스터에 의해 바로 접속 가능해야 한다.

소프트웨어를 Docker 이용해 배포하려면 먼저 Dockerfile이란 것을 작성해야 한다. Dockerfile 소프트웨어가 어떻게 설정되고 배포되어야 하는지를 기술하는 스크립트이며, Docker 이를 이용해 소프트웨어를 실행하기 위한 모든 요소를 포함하고 있는 Self-Contained 이미지를 만든다. 그림 5 Docker 이미지를 만들기 위한 설정을 보여주고 있다.




소프트웨어를 실행하고 운영해야 하는 사람은 소프트웨어를 설치하거나 복잡한 설정 과정 없이 단순히 이미지를 실행함으로써 격리 환경에서 소프트웨어를 구동할 있다. Docker 이러한 특성은 격리된 환경에서 언제나 깨끗한 테스트가 가능하도록 해준다. 나아가 Dockerfile 소프트웨어를 실행하기 위한 복잡한 설정을 이미지 안에 숨겨줌으로써 소프트웨어의 내부에 대한 이해가 없더라도 소프트웨어를 운영하는 사람이 손쉽게 소프트웨어를 구동하고 관리할 있도록 해준다. 여러 사람이 만든 소프트웨어가 서로 연동되는 경우 다른 사람이 개발한 소프트웨어를 실행하기 위해 소프트웨어의 설정을 모두 이해하고 스스로 적용할 있어야만 하는 어려움이 있지만, Docker 이러한 어려움을 제거하여 비교적 쉽게 소프트웨어를 운영, 테스트 있도록 돕는다. 그림 5 이미지 빌드 스크립트가 실행되고나면 이미지가 Registry 등록된다. Registry 도커 이미지를 저장하고 있는 Repository로써 Docker 특정 소프트웨어의  설치를 위해 Registry 검색하고 등록된 이미지를 가져온다. Docker Docker Hub[1]라는 Public Registry 무료로 운영하고 있으며, 조직이 Private Registry 구축할 있도록 도와주고 있다. 물론 Registry 등록하지 않고도 Docker 이미지를 빌드하고 실행할 있다. 그림 6 빌드 이미지를 실행하는 과정이다. Docker 입력 파라마터에 따라 이미지를 실행한다. 시점부터 사용자들은 버전의 소프트웨어를 즉각 사용할 있게 된다.





기대효과


위와 같은 프로세스를 적용함으로써 우리는 빠르게 새로운 요구사항을 적용하고 결과를 모니터링 있었다. 또한 소프트웨어의 빌드, 테스트, 배포, 운영 등을 최대한 자동화함으로써 소요되는 시간과 노력을 최대한 줄이고, 대신 소프트웨어의 통합 테스트 유저 시나리오 기반의 테스트에 많은 시간을 할애할 있게 함으로써 나은 품질의 소프트웨어를 만들 있도록 하였다.

또한 JIRA 통해 요구사항과 소프트웨어의 이슈들을 체계적으로 관리함으로써 프로젝트의 진행 상황을 쉽게 모니터링하고 문제를 식별하고 대응할 있었으며, 개발자가 이슈들을 처리하는데 얼마나 많은 시간을 투자하고 있는지를 파악하여 비효율을 제거할 있었다. 나아가 JIRA Bamboo 개발환경에 통합함으로써 중앙 집중화된 관리가 가능하게 하였다.

마지막으로 Docker 사용해 테스트 환경을 구축함으로써 깨끗한 환경에서 테스트를 진행할 있도록 하여, 테스트의 결과의 일관성과 테스트의 품질을 확보하였다. 또한 소프트웨어를 실행하기 위한 복잡한 설정을 Docker 이미지 내로 숨김으로써 테스트 가용성을 높일 있었다.




프로세스는 지속적으로 개선되고 보완되어야 한다. 특히 소프트웨어 개발 프로세스의 효과는 프로세스를 사용하는 사람들에 의해 결정된다는 때문에, 구성원의 특성에 맞도록 지속적으로 보완될 필요성이 있다. 우리는 우리의 프로세스가 나은 품질 향상과 넓은 테스트 가능성을 확보해줄 있도록 하기 위해 노력하고 있다.

소프트웨어 나은 품질의 확보

단순히 소프트웨어의 기능 테스트를 통해 소프트웨어의 품질을 향상시켜주는 방법 이외에도 정적 분석 기법을 통해 소스 코드에 숨어있는 결함을 찾아내거나 Git 제출 소스 코드를 여러 사람이 리뷰할 있도록 함으로써 품질을 향상 시킬 있다. 대표적인 정적 분석 툴로는 FindBug, PMD, Checkstyle, SonarQube 등이 있으며, 우리는 SonarQube 프로세스에 통합하기 위해 작업을 진행하고 있다. 또한 코드 리뷰 툴로는 Crucible, Upsource 등이 있다.

넓은 테스트 가능성 확보

우리는 여러가지 운영체제와 모바일 환경에서 작업을 진행하고 있으며, 사용하는 프로그래밍 언어 또한 다양하다. Bamboo 다양한 플랫폼에서 동작하는 Build Agent 관리해준다. 테스트를 워하는 환경에 Build Agent 설치해줌으로써 Linux 소프트웨어는 Linux에서, Windows 소프트웨어는 Windows에서 테스트를 있다. 여러 개의 서버 컴퓨터가 필요한데, 클라우드 환경에서 여러 개의 컴퓨터를 관리하기 위해 Vagrant 같은 Provisioning Tool 도입할 필요가 있다.


Trackbacks 0 / Comments 0

Leave Comments

IntelliJ를 이용한 리펙토링 - Rename 편 (1/3)

IntelliJ를 이용해 리펙토링을 수행하는 방법(Rename, Extract, Move)에  대해 총 3편으로 나누어 설명하도록 하겠습니다. 

이번 편은 그 시작으로써 Rename에 대해 다룹니다.




IntelliJ를 이용한 리펙토링

주대연




목차


소개

리펙토링이란?

리펙토링의 필요성

IntelliJ가 지원하는 리펙토링 기능

Rename

Rename이란?

Rename을 수행하기 위한 절차

Extract

Move

참고자료

프로젝트 윈도우와 코드 에디터의 위치





소개


  IntelliJ는 JetBrains 사에서 판매하는 자바를 위한 통합 개발툴 (IDE, Integrated Development Environment)로써 자바 이외에도 다양한 언어를 지원하며 소프트웨어의 품질을 향상 시키기 위한 리펙토링이나 소프트웨어 분석 도구, 효율적인 소스 코드 관리와 협업을 위한 VCS (Version Control System) 기능 등을  제공하고 있다. 


  나는 작년 부터 더이상 Eclipse를 사용하지 않게 되었다. 자바 기반 소프트웨어 개발의 교과서인 Eclipse를 사용하지 않게 된 이유는 바로 느린 속도와 직관적이지 않은 사용성에 있었다. IntelliJ는 Eclipse와 비교했을 때 거의 동등한 수준의 자바 개발을 위한 환경을 제공하고 있으며, Eclipse에 비해 훨씬 가볍고, UI 또한 보다 더 직관적이다. 부가적으로 IntelliJ는 높은 수준에서의 Eclipse와의 호환성을 제공하고 있다.  Eclipse에서 작업한 프로젝트를 IntelliJ로 불러와 작업을 할 수 있으며, IntelliJ에서 작업한 프로젝트 역시 무리없이 Eclipse에서 작업할 수 있도록 내보낼 수 있다. 마지막으로 IDE의 외형을 결정하는 테마 기능이 더욱 다양하다. 매우 주관적인 기준일 수 있지만, IntelliJ로 교체한 후 생산성이 매우 향상되었음은 의심할 수 없는 사실이 되었다. 


  이러한 IntelliJ가 제공하는 여러 가지 기능 중 생산성 향상에 가장 많은 기여를 한 기능은 리펙토링 (Refactoring), 코드 포멧팅 (Code Reformatting and rearrangement) 그리고 코드 생성 (Code generating) 기능 이었다. 그 중에서도 가장 빈번하게 사용되는 리펙토링 기능에 대해서 소개해 보도록 하겠다.






리펙토링이란?

  리펙토링이란 이미 개발된 코드를 외부로 드러나는 동작의 변화 없이 재구성하는 과정이다. 이때 가장 중요한 것은 소프트웨어의 동작이 변경되서는 안된다는 것이다. 따라서 이를 확실히 하기 위해 리펙토링을 하면서 JUint과 같은 테스트 자동화 툴을 적극적으로 이용하는 것은 매우 큰 도움이 된다. 

  이러한 리펙토링을 제대로 적용하고 나면 코드의  나쁜 냄새 (Bad Smell) 이 사라지게 되고 코드의 품질은 향상되게 된다. 다시 말하면 중복 코드가 사라지고, 클래스의 역할이 명확해지며, 응집도 (Cohesion)가 높아지고 결합도 (Coupling) 이 낮아진다.





리펙토링의 필요성

  우리가 코드를 작성할 때 개발 완료 일정이 촉박하다면 코드를 급하게 작성할 수 밖에 없다. 이런 경우에 필연적으로 작성된 코드에서 여러 가지 나쁜 냄새가 날 수 밖에 없다. 예를 들어Copy & Paste 로 코드를 개발하여 많은 중복 코드가 존재한다던가 지나치게 매직 넘버를 사용했다던가 하여 코드의 유지보수를 어렵게 만드는 것들이 있을 수 있겠다. 

  툴의 도움없이 이러한 나쁜 냄새를 없애려면 매우 번거롭다. 만약 Copy & Paste를 100개쯤 했다고 치면, 우리는 먼저 이 중복 코드를 하나의 메소드로 만든 후 (Extract Method), 모든 중복 코드가 위치하는 부분을 찾아 새로 만든 메소드를 호출하도록 변경하여야 한다. 손으로 일일히 하는 것이 가능하기는 하지만 중간에 한개라도 빠뜨리는 경우, 완벽하게 나쁜 냄새가 제거되지 못하게 되어 리펙토링을 하는 의미가 퇴색될 수 있다. 게다가 ‘제대로 리펙토링’을 하는데 아주 많은 시간이 필요할 것이다.

  따라서 IntelliJ는 이러한 것을 자동으로 수행하여 개발자로 하여금 간편하고 신속하게 리펙토링을 할 수 있도록 지원하고 있다. 소스 코드의 구조를 자동으로 분석하여 리펙토링 기법을 적용했을 때 영향을 받는 코드를 자동으로 찾아내고 자동으로 적용한다.





IntelliJ가 지원하는 리펙토링 기능

  IntelliJ는 다양한 리펙토링 기능을 제공하고 있다. 이 중에서 내가 가장 잘 사용하는 것은 크게 Rename, Extract, Move 이 세 가지이다. 아마 대부분의 개발자들 역시 위의 세가지 기능을 가장 빈번히 이용할 것이라 생각한다. 

  IntelliJ 에서 이러한 리펙토링을 수행하는 방법은 크게 세 가지이다. 첫 번째는 상단 메뉴에서 ‘Refactor’ 를 이용하는 방법, 두 번째는 단축키를 이용하는 방법, 마지막으로  일종의 리펙토링 메뉴판인 ‘Refactor this’ 를 이용하는 방법이다. 

  앞으로 IntelliJ의 리펙토링 기능과 함께 상단 메뉴를 이용한 방법, 단축키를 이용한 방법에 대해 설명하도록 하겠다. Refactor this는 맥을 기준으로 단축키 ’Shift + Option + Command + T’를 이용해 접근할 수 있으며 나타나는 메뉴의 형태는 상단 메뉴를 이용하는 방법과 동일 하므로 제외하겠다.



Rename

Rename이란?

  Rename은 파일, 메소드, 변수, 상수 등의 이름을 편리하게 변경할 수 있도록 하는 기법이다. 이름을 변경하는 경우IntelliJ는 코드 내에서 이름이 변경되어야 하는 모든 요소들을 자동으로 분석하여 함께 변경해준다. 



Rename을 수행하기 위한 절차

Rename을 수행하기 위한 두 가지 접근 방법은 다음과 같다.

 접근 방법

 접근 경로 혹은 단축키 

 상단 메뉴

 ‘Refactor’ -> ‘Rename’ or ‘Rename file’ 

 단축키

 Shift + F6



메뉴에서 보면 두 가지이지만 실제로 하나의 기능이다. 나는 주로 단축키를 이용한다. Rename을 수행하기 위한 절차는 다음과 같다.


1) 이름을 변경하고자 대상을 선택


  이름을 변경할 수 있는 대상은 클래스, 인터페이스, 메소드, 변수, 상수, 파라메터 등이며, 대상을 선택하고 Shift + F6을 누른다.  만약 코드 에디터에서 대상을 선택했다면 2-1로, 프로젝트 윈도우에서 대상을 선택했다면 2-2를 본다.


* 프로젝트 윈도우와 코드 에디터의 위치는 맨 아래의 참고 자료에 표시되어 있다.


2-1) 새로운 이름을 코드 에디터에서 직접 입력


  코드 에디터에서 대상을 선택하고 이름 변경을 실행하였다면 다음의 그림 처럼 선택한 클래스명에 빨간색 입력창이 나타난다.  입력창에 새로운 이름을 입력하고 Enter 키를 누르면 된다. 녹색으로 강조된 클래스들은 새로운 이름으로 바뀌게 될 모든 후보들이다.







2-2) 새 이름 입력창에서 입력

  프로젝트 윈도우에서 대상을 선택했다면 다음의 그림에서 보는 것과 같은 이름 변경 윈도우가 나타난다. 여기에 새로운 이름을 입력하고 Refactor 버튼을 누르면 리펙토링이 실행된다. 만약 선택한 대상이 Public 클래스라면 파일명도 함께 변경된다. IntelliJ는 이 또한 자동으로 수행한다.


3) 함께 변경할 연관된 객체들의 선택

  객체 이름을 만들 때 클래스명과 비슷하게 짓는 습관이 있다면 IntelliJ의 Rename 기능은 더욱 유용할 것이다. Employee 클래스의 이름을 MyEmployee로 변경하였다 가정하고, 기존에 Employee 클래스의 인스턴스로를 employee1, employee2로 명명하였다면, IntelliJ는 이들의 이름도 myEmplyee1, myEmployee2로 일괄 변경해준다. 그러나 유사하지 않은 이름을 사용한 경우 자동으로 일괄 변경되지 않는다.




  위의 그림에서 볼 수 확인할 수 있듯이 employee 혹은 employee1 과 같은 이름은 모두 myEmployee 와 유사하게 변경된다. 함께 변경할 객체들을 선택한 후 OK 버튼을 누르면 실제로 변경 작업이 시작된다. 모든 변경 작업이 끝나고 나면 프로젝트 윈도우와 코드 에디터에 실제 변경된 결과가 나타난다. 아래의 그림들은 Employee 클래스의 이름을 MyEmployee로 변경한 화면이다. 제대로 Rename이 되어 클래스의 이름이 일괄 변경된 것을 볼 수 있다.






참고자료

프로젝트 윈도우와 코드 에디터의 위치






Trackbacks 0 / Comments 0

Leave Comments

IntelliJ 13.0.2 에서 Gradle 파일과 Sync하기


소개 


Android Studio는 최근에 추가된 공식 개발툴로써 아직 베타 버전이며, 현재 버전이 0.4로써 아직 가야할 길이 멀다. 실제로 사용하다보면 자잘한 버그를 많이 만날 수 있고, 좀 불안정한 모습이 있어서 본격적으로 사용하기는 좀 이르다. 그러나 Eclipse에 비해 매우 가볍고 확장성이나 사용성이 좋다는 이유로 지금 까지 사용해 오다가 Android Studio가 JetBrains의 IntelliJ Community 버전에 기반하고 있다는 소식을 듣고, 곧장 Android 개발 툴을 IntelliJ 13 Ultimate 버전으로 교체하였다. JetBrains 사에서는 Android 개발 지원 Plugin이 다른 소스 코드 Repository가 아니라고 공식적으로 이야기 하고 있으므로, Android Studio, IntelliJ Ultimate, IntelliJ Community 버전의 Android 개발 지원 수준은 모두 동일하다고 볼 수 있다. 이에 대한 자세한 내용은 이곳을 확인해보자: http://blog.jetbrains.com/idea/2013/05/intellij-idea-and-android-studio-faq/.



문제


Android Studio가 공식 개발툴이 되면서 Build 툴로써 Gradle이 도입되었다. Gradle이 좀 생소하기는 하지만 Dependency 관리를 편리하게 자동으로 해준다는 점에서 매우 유용하다. 다음 처럼 Dependency를 기술해주면 자동으로 Maven Repository로 부터 라이브러리들을 다운로드 받아 프로젝트에 추가해 준다.





그러나 Gradle 파일의 Dependency에 무언가를 추가하는 경우 자동으로 프로젝트의 Dependency가 업데이트가 되지 않는 경우가 있다. 이럴 때 Gradle 파일과 프로젝트의 Dependency 를 동기화 시켜주면 되는데,  이러한 기능이 Android Studio 에 있지만 IntelliJ 에는 없다. 



따라서 IDE 상에서는 코드를 보면 ‘Cannot resolve symbol’ 이라는 오류가 발생한다. 그러나 빌드를 하게 되면 Gradle 파일로부터 Dependency를 가져와 컴파일을 수행하므로 오류가 발생하지는다. 그림에서 볼 수 있듯이 com.android.support:appcompat-v7, com.android.support:support-v4가 Gradle 파일에는 기술되어 있지만 실제 프로젝트 Dependency에는 자동으로 추가되어 있지 않아 발생하는 오류이다.





위 그림에서 볼 수 있듯이 두 개의 파일이 프로젝트에 등록되어 있지 않으며, 이 때문에 IDE 에서 보면 다음과 같은 에러들이 발생한다. 이러한 에러를 유발하는 모든 클래스들은 저 두 라이브러리에 포함된 클래스들이다.





하지만 컴파일은 부드럽게 성공한다.




해결 방법


이를 해결하기 위해서는 Gradle 파일과 프로젝트 파일을 Sync 시켜주어야 한다. 이러한 기능이 Android Studio 에는 ‘Tools -> Android -> Sync Project File With Gradle’ 이라는 메뉴에 있지만, IntelliJ 에는 없다. 그러나 이와 동등한 기능을 가지고 있는 메뉴가 있다. 메뉴 에서 ‘View -> Tool Windows -> Gradle’ 





위의 버튼을 누르고 나면 Sync 작업을 진행하게 되고, 작업이 완료되면 프로젝트 Dependency에 누락된 파일들이 모두 추가되며, IDE 상에서의 오류도 사라진다. 물론 컴파일도 잘 된다.

Trackbacks 0 / Comments 0

Leave Comments

Mac OS X 10.9.1, IntelliJ 13.0.3 에서 Android 프로젝트 생성 시 ANDROID_HOME 환경 변수를 찾지 못해 발생하는 오류의 해결 방법

IntelliJ 13 Ultimate 이란?





JetBrains 사에서 개발한 통합 IDE로써, Eclipse 에 비해 가벼우며, 다양한 기능과 다양한 언어를 사용할 수 있도록 확장할 수 있어서 1년 정도 전쯤에 Eclipse를 대신해 사용하고 있다. 특히 Refactoring, Code Style Formatter, Code Completion 기능 등이 매우 유용하며, Version Control System 들과도 연동이 잘 되어 있다.


나는 Java, Ruby on Rails, Node.Js, Android 개발 환경을 모두 IntelliJ 13으로 통합하여 사용하고 있고, C/C++ 플러그인이 업데이트 되길 기다리고 있다.




문제가 발생한 환경


Mac OS X 10.9.1

IntelliJ 13.0.2 Ultimate with Android 



문제 상황


IntelliJ 13.0.1 에서 13.0.2로 업그레이드를 한 후 Android 프로젝트 생성 및 빌드에 문제가 발생하였다.

오류 화면과 메시지는 다음과 같았다.





3:23:28 PM Gradle 'untitled11' project refresh failed: 

Could not execute build using Gradle distribution 'http://services.gradle.org/distributions/gradle-1.9-bin.zip';. 

Build file '/Volumes/Project/development/Example/untitled11/untitled11/build.gradle' line: 9 

A problem occurred evaluating project ':untitled11'. 

A problem occurred evaluating project ':untitled11'. 

SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable. 




위 오류는 ANDROID_HOME를 설정하지 않아 발생한 것이었다. ANDROID_HOME은 Android SDK 의 폴더 위치를 저장하고 있는 환경 변수로써, IntelliJ가 이 환경 변수를 참고하여 Android 프로젝트를 생성한다. 그런데 이 과정에서 이 변수가 존재하지 않자, 몇 가지 필요한 과정을 거치지 못했기 때문에 오류가 발생한 것이다.


원래 정상적으로 프로젝트가 생성되었다면 다음과 같은 프로젝트 폴더 구조가 만들어져야 하고, Gradle Task 들도 정상적으로 목록에 나타나야 한다.





위의 두 스크린샷을 보면 알겠지만 루트 폴더 바로 아래의 생성되어야 할 폴더가 하나와 두 개의 Gradle 관련 파일이 누락되었다. 아래 그림을 보면 확실히 알 수 있다. 왼쪽이 오류로 생성된 프로젝트, 오른쪽이 정상적으로 생성된 프로젝트 구성이다.





위의 오류를 정확히 이야기 하면 Gradle을 이용해 프로젝트를 생성하는 도중 ANDROID_HOME 환경변수를 찾을 수 없어서, 오류가 발생했고, 이 과정에서 프로젝트 생성이 중단되면서 빌드에 필요한 몇몇 파일이 생성되지 않은 것이다.




문제 해결 방법



이를 해결하는 방법은 ANDROID_HOME 환경 변수를 만들어주고, PATH 환경 변수에 Android 관련 폴더 두 개를 설정해주는 것이다. 이를 위해 2개의 과정이 필요하다. 모든 과정이 끝나면 반드시 재부팅 한다.


1) 환경변수 PATH에 platform-tools, tools 폴더 설정해주기


먼저 bash 스크립트의 PATH에 Android SDK에 포함된 platform-tools, tools 폴더를 등록해주는 것이다. 이를 위해 터미널에서 다음과 같이 입력하면 된다.


vi ~/.bash_profile



그 다음 다음의 스크립트를 추가해준다.


export PATH=/[My Android SDK Path]/platform-tools:/[My Android SDK Path]/tools:$PATH 


물론 [My Android SDK Path] 는 자신의 컴퓨터의 Android SDK의 실제 경로로 바꿔주어야 한다.


참고 사이트: http://cduu.wordpress.com/2011/12/21/setting-android-and-path-environment-variables-on-mac-os-x/




2) /etc/launchd.conf 파일에 ANDROID_HOME 환경 변수 등록하기


여러 가지 profile 파일에 시도해 보았으나, 제대로 동작하지 않았다.

실제로 문제를 해결할 수 있었던 것은 launched.conf에 환경 변수를 등록해 주는 방법이었다.

이를 위해 터미널에서 다음과 같이 입력한다. 주의할 점은 launched.conf가 없을수도 있는데, 이 경우 그냥 새로 만들어 주면 된다는 것이다.


vi ~/etc/launchd.conf 



그 다음 다음과 같은 명령어를 추가해주고 저장한 다음 재부팅하였다.


setenv ANDROID_HOME /[My Android SDK Path]


그 다음 터미널에서 export를 실행해보자. 이 때 ANDROID_HOME이라는 환경 변수가 목록에 나타난다면 성공한 것이다.




결론


위의 오류 상황은 Android SDK 의 위치를 지정하는 ANDROID_HOME 환경 변수가 설정되지 않아, Gradle이 프로젝트를 생성하는 과정에서 발생한 것이다.  IntelliJ 13.0.2 에서는 프로젝트 내의 local.properties 파일에서 Android SDK의 경로를 읽어왔으나, 13.0.3 에서는 local.properties 파일이 아니라  운영체제의 환경 변수에서 이를 읽어오도록 수정되었다. 이렇게 변경됨으로써 다른 개발환경에서 개발한 Android 프로젝트를 다른 개발환경으로 옮겼을 때 일일히 local.properties 내의 SDK 경로를 수정해줘야만 하는 버거로움이 해소되었다. 


따라서 13.0.3 에서 기존 프로젝트를 정상적으로 이용하기 위해서는 /etc/launchd.conf 에 ANDROID_HOME 이라는 환경 변수를 설정해주어야 한다. 이렇게 설정해주고 재부팅하면 문제가 해결된다.


Trackbacks 0 / Comments 0

Leave Comments

RoR 사용시 Rake 에서 발생하는 Library not loaded libmysqlclient.18.dylib 오류 해결법


우선 나의 작업 환경은 다음과 같다.

Mac OS X  10.7.2
         Ruby   1.9.2p180
         Rails    3.1.3 
                      mysql2 gem 0.3.11
RubyMine   3.2.4 


얼마전부터 개발용 IDE를 Aptana Studio 3 에서 RubyMine으로 바꾸었는데, IDE 자체가 가볍고 기능도 더 직관적이라 매우 만족하며 사용하고 있었다. 그러던 중 문제가 하나 발생하였다.

RubyMine의 Rake 명령어 자동 완성 기능은 꽤나 유용해서 자주 사용하던 것이었는데, 프로젝트 생성시 데이타베이스를 mysql로 선택하면 오류가 발생하면서 rake 명령어 목록을 불러오지 못하는 것이었다.

/Users/ror/projects/restaurant/highline/ruby/1.9.1/bundler/gems/rails-30dae273c85a/activesupport/lib/active_support/dependencies.rb:236:in `require': dlopen(/Users/ror/projects/restaurant/highline/ruby/1.9.1/gems/mysql2-0.3.6/lib/mysql2/mysql2.bundle, 9): Library not loaded: libmysqlclient.18.dylib (LoadError)

  Referenced from: /Users/ror/projects/restaurant/highline/ruby/1.9.1/gems/mysql2-0.3.6/lib/mysql2/mysql2.bundle

  Reason: image not found - /Users/ror/projects/restaurant/highline/ruby/1.9.1/gems/mysql2-0.3.6/lib/mysql2/mysql2.bundle

    from /Users/ror/projects/restaurant/highline/ruby/1.9.1/bundler/gems/rails-30dae273c85a/activesupport/lib/active_support/dependencies.rb:236:in `block in require'

    from /Users/ror/projects/restaurant/highline/ruby/1.9.1/bundler/gems/rails-30dae273c85a/activesupport/lib/active_support/dependencies.rb:222:in `block in load_dependency'

    from /Users/ror/projects/restaurant/highline/ruby/1.9.1/bundler/gems/rails-30dae273c85a/activesupport/lib/active_support/dependencies.rb:616:in `new_constants_in'

    from /Users/ror/projects/restaurant/highline/ruby/1.9.1/bundler/gems/rails-30dae273c85a/activesupport/lib/active_support/dependencies.rb:222:in `load_dependency'

    from /Users/ror/projects/restaurant/highline/ruby/1.9.1/bundler/gems/rails-30dae273c85a/activesupport/lib/active_support/dependencies.rb:236:in `require'

    from /Users/ror/projects/restaurant/highline/ruby/1.9.1/gems/mysql2-0.3.6/lib/mysql2.rb:9:in `<top (required)>'

    from /Users/ror/.rvm/gems/ruby-1.9.2-p290/gems/bundler-1.0.15/lib/bundler/runtime.rb:68:in `require'

    from /Users/ror/.rvm/gems/ruby-1.9.2-p290/gems/bundler-1.0.15/lib/bundler/runtime.rb:68:in `block (2 levels) in require'

    from /Users/ror/.rvm/gems/ruby-1.9.2-p290/gems/bundler-1.0.15/lib/bundler/runtime.rb:66:in `each'

    from /Users/ror/.rvm/gems/ruby-1.9.2-p290/gems/bundler-1.0.15/lib/bundler/runtime.rb:66:in `block in require'

    from /Users/ror/.rvm/gems/ruby-1.9.2-p290/gems/bundler-1.0.15/lib/bundler/runtime.rb:55:in `each'

    from /Users/ror/.rvm/gems/ruby-1.9.2-p290/gems/bundler-1.0.15/lib/bundler/runtime.rb:55:in `require'

    from /Users/ror/.rvm/gems/ruby-1.9.2-p290/gems/bundler-1.0.15/lib/bundler.rb:120:in `require'

    from /Users/ror/projects/restaurant/config/application.rb:7:in `<top (required)>'

    from /Users/ror/projects/restaurant/highline/ruby/1.9.1/bundler/gems/rails-30dae273c85a/railties/lib/rails/commands.rb:38:in `require'

    from /Users/ror/projects/restaurant/highline/ruby/1.9.1/bundler/gems/rails-30dae273c85a/railties/lib/rails/commands.rb:38:in `<top (required)>'

    from script/rails:6:in `require'

    from script/rails:6:in `<main>'

<에러메시지가 더이상 발생하지 않아서 웹에 있는 다른 사람의 로그를 가져왔다>

매우 복잡하지만 중요한 메시지는 libmysqlclient.18.dylib를 불러올 수 없다는 것이다. 라이브러리를 찾을 수 있도록 경로를 설정하여 주거나 라이브러리를 복사해 넣으면 이 것을 해결할 수 있다.

sudo ln -s /usr/local/mysql/lib/libmysqlclient.18.dylib /usr/lib/libmysqlclient.18.dylib


위와 같은 명령어를 콘솔에 실행하고 나니까 문제가 해결되었다. rake 의 명령어 리스트를 오류없이 RubyMine이 읽어올 수 있게 되어서 다음에서 보는 것처럼 rake 명령어를 좀 더 손쉽게 사용할 수 있게 되었다.


명령어 자동 완성 기능이 되니까 너무 편하다!!!! ㅋㅋㅋㅋ

참고한 웹 사이트의 URL: http://rorguide.blogspot.com/2011/07/getting-error-library-not-loaded.html

Trackbacks 0 / Comments 1

  • todds 2013.04.01 19:37 신고

    오 내 세상 가득 빛을 내리고

Leave Comments