본문 바로가기

안드로이드앱 코딩_AndroidApp/안스_코틀린_쪼개기

파편008_Debug_디버그_breakpoints

Debugging(디버깅)

컴퓨터 프로그램에서 bug(버그)라는 말은 프로그램이 어떤 원인에 의해 일어나는 오동작, 오류, 결함 등을 말한다.

간단하게 말하면 '코드 오류'

 

프로그램 또는 앱을 만들다 보면 의도하지 않는 문제가 흔히 일어난다.

대부분의 원인은 코드를 프로그래밍 언어의 규칙에 맞지 않게 작성했거나 논리적 모순에 의한 경우가 많다.

이것을 해결하는 것도 어떤 경우는 상당히 해결하기 어려운 골치 아픈 문제이거나 해결하는데 상당한 시간이 필요한 경우도 있다. 프로그램의 코드가 길어지고 복잡해 질 수록 에러가 날 확률은 점점 더 증가한다.

 

어쨌든 버그의 대부분은 개발하는 사람에 의해 일어나므로 버그를 줄이기 위해서는 프로그래밍 실력을 높이는 노력을 게을리 하지 않아야 할 것이다. 규모가 큰 프로그램의 경우 많은 노력과 테스트에도 불구하고 버그가 없는 경우가 거의 없을 정도다. 그런 경우 업그레이드를 통해 프로그램을 수정하여 다시 배포한다.

 

더 큰 문제는 버그로 인해 심각한 상황이 발생할 수 있다는 것이다. 게임이나 일반 프로그램의 경우는 버그가 생겨도 그 피해가 크지는 않지만 비행기나 무인자동차 등에서 버그로 인해 에러가 발생한다면 끔직한 상황이 일어날 수도 있는 것이다. 실제로 비행기나 의료기기의 버그로 인해 인명 피해가 난 경우가 있었다고 한다.

 

bug는 본래 ‘벌레’라는 뜻인데 컴퓨터가 만들어진 초기에 컴퓨터 속에 들어간 벌레로 인해 컴퓨터가 오동작을 일으킨데에서 유래했다고 한다.

 

debug(디버그) 또는 debugging(디버깅)이라는 말은 프로그램의 버그를 찾아서 해결하는 과정이나 작업을 말한다.

즉, '버그 없애기' 이다.

 

코딩 작업을 하다 보면 예기치 못한 에러가 발생한다. 이런 경우 원인을 찾아내는 것이 해결의 첫걸음이다.

안드로이드 스튜디오에는 이런 버그 상황에 대비해 원인을 찾을 수 있는 도구가 마련되어 있다.

 

 

 

먼저 프로그램의 오류에는 어떤 유형이 있는 지 알아보자.

 

Syntax Errors (구문 오류)

 

Syntax(구문)는 코딩 언어의 문법이다.

코딩 언어는 문법에 맞게 작성해야 하는데 구문에 맞지 않게 작성했을 때 Syntax 에러가 생긴다.

 

 

위 그림의 예 처럼 안드로이드 스튜디오에서 코드를 잘못 작성하면 빨간줄이나 빨간색 문자 등이 생기는데 그것이 구문 오류를 나타낸다. 경험해 보았다면 알겠지만 코드를 작성할 때 이렇게 경고를 해 주기 때문에 에러를 즉시 알 수 있고 해결하는 방법도 설명해 주므로 이 구문 오류는 대처가 쉬운편이다.

 

마우스 포인터를 빨간줄 부분에 가져가면 에러 설명과 해결을 위해 선택할 수 있는 옵션을 보여준다. 코드 줄 번호 옆에 있는 빨간색 전구를 클릭해도 된다.

 

 

Runtime Errors (실행 오류)

 

런타임 에러는 실행할 때 예상치 못하게 발생하는 에러이다.

코드를 작성할 때는 에러가 나타나지 않다가 실행했을 때 비로소 드러나는 에러를 말한다.

코드가 syntax(구문)로는 이상이 없어서 compile(컴파일; 번역) 되어 실행은 되었지만 실행 중에 에러가 나타나는 경우이다.

 

예를 들면 파일을 호출하는 코드가 있다고 할 때 해당 파일이 없다든지 손상되어 있다면 에러가 발생할 수 있다. 또한 수학의 경우 코드에서 0으로 나누는 경우가 발생한다면 에러가 발생할 수 있다. 그러므로 이런 상황에 대비해서 코드를 짜야한다.

 

실습해 보려면 새 프로젝트를 생성한 후 acitvity_main에 버튼을 하나 만들고 버튼 id를 buttonRoll이라고 하면 된다.

 

위 코드의 divide라는 함수는 Int 타입의 a, b를  매개변수로 가지며 실행할 내용은 a를 b로 나누어서 그 값을 Int타입으로 반환하는 함수이다.

 

MainActivity는 위와 같이 코드를 작성한다.

위 코드는 buttonRoll 버튼을 클릭하면 divide함수에 매개변수 8과 0을 전달해서 계산한 값을 반환 받는 코드이다.

 

 

실행 후 확인해 보면 버튼을 클릭하기 전까지는 문제가 생기지 않는다.

이제 buttonRoll 버튼을 클릭해보자.

 

AndroidRuntime에서 가상기기(VM)가 멈춘다(Shutting down)

그 아래 FATAL EXCEPTION(치명적인 예외)가 발생했다고 표시하고 그 아래에 발생한 원인을 나타낸다.

java.lang.ArithmeticException( 자바 언어의 연산 예외)가 발생했고 '0으로 나누었다'는 메시지가 보인다.

 

참고로 0으로 나눌 때 나는 에러는 Int(정수) 타입에서만 나타난다.

 

Logic Errors (논리 에러)

 

Logic(로직)은 '논리'라는 뜻이다.

코딩에서 논리란  코드에 따라 '이치에 맞게 해결되는 과정'이라고 할 수 있다.

내가 이런 순서로 작동하라고 코드를 짰으면 그것에 맞게 단계적으로 수행하면 되는데 그 도중에 다음 단계로 넘어가지 않고 멈추는 것이 '논리 에러'이다.

 

다른 에러에 비해 논리 에러는 원인을 찾아내기 어렵다.

 

논리 에러에 대비해서 수행할 수 있는 작업 중에서 대표적인 것이 logging(로깅) breakpoints(브레이크 포인츠)이다.

또는 간단하게 println(화면 출력) 함수를 이용하여 표시할 수도 있다.

 

먼저 로깅(logging)에 대해 알아본다.

logging(로깅)은 가장 기본적인 debugging(디버깅) 기술이다.

로깅은 로그 코드(로그문)를 작성하여 실행 중인 앱의 특정 위치의 변수 값을 검사하는 것이다.

 

1. logging(로깅) 작성법

로깅을 하기 위해서는 필요한 위치에 로그문을 작성한다. 로그(log)는 ‘기록하다’라는 뜻이다.

 

아래 내용은 전자 문서로 제작한 3번째 게임인 구하라 게임 중의 코드를 사용한 예이다.

예를 들어 아래 위치에 다음과 같이 작성하자.

 

Log.d를 입력하면 Log클래스에 있는 d 메써드(함수)의 매개변수로 넣을 수 있는 옵션 예가 나타난다. 

d는 ‘debug’의 첫글자를 딴 것이므로 Log.d‘디버그용 기록’이라는 뜻이다.

 

이런 식으로 작성하는 이유는 앱을 실행하면 많은 로그(Log)가 만들어지기 때문에 원하는 부분을 찾기 힘들 수 있다.

그래서 로그 클래스와 함수를 적어 놓으면 해당 함수를 로그캣(Logcat)에서 쉽게 확인할 수 있기 때문이다.

 

Log클래스에 있는 이런 함수는 5가지 있다.

 

w, e, d, i, v

 

함수의 뜻은 다음과 같다.

w(waring ; 경고), e(error ; 에러), d(debug ; 디버그), i(info ; 정보), v(verbose ; 장황한, 상세하게)

 

 

위 그림을 보면 d라는 함수의 매개변수는 tag(꼬리표)와 msg(message(메시지))가 있는 것을 알 수 있다.

 

d에 괄호를 넣고 매개변수를 넣어보자.

 

tag는 Log(로그)로 만든 값이라는 걸 알아보기 쉽도록 하기 위해 log와 대문자로 logTAG를 적었다.

다시말해서 tag에는 자신이 붙이고 싶은 태그 이름을 적으면 된다.

logTAG를 보면 빨간색이다. 이것은 logTAG 변수를 선언하지 않았기 때문이다. 변수 선언을 다음과 같이 한다.

 

변수에 Activity이름을 넣는 것이 기본이다. 이렇게 하면 로그값이 어디에서 온 것인지 파악할 수 있다. 

만약 변수 선언을 const(상수)로 선언하려면 다음과 같이 class MainActivity 위에 선언하면 된다.

두 가지 방법 중에서 편한걸 선택하면 된다. 여기서는 첫번째 방법을 사용했다.

 

계속해서 mag(메시지)에는 로그캣에서 실제로 출력할 메시지를 String(문자열)으로 작성한다.

이렇게 문자열 안에서 변수값을 알고 싶으면 변수명 앞에 $기호를 사용한다.

 

“onCreate 함수가 호출됨. 점수는 $score이다”

 

앞에서 점수를 나타내기 위해 score변수를 만들고 초기화 했었다. 그리고 코틀린에서 변수명 앞에 $기호를 붙이면 변수값을 불러올 수 있다. 그래서 위와 같이 작성하면 28번줄 코드 위치에서 괄호 안의 문자가 나타나고 그 위치의 score 변수값이 나타나게 된다.

 

이 로그값은 안드로이드 스튜디오의 아래쪽 Logcat(로그캣)에서 확인할 수 있다.

 

Logcat 에서는 앱 외부에서 들어오는 메시지를 포함하여 에뮬레이터나 장치가 하는 모든 작업을 로그 메시지를 통해 확인할 수 있다.

확인 해 보기 위해  가상기기(에뮬레이터)를 실행한다.

로그문은 주석과 마찬가지로 앱의 실행에 영향을 주지 않는다.

에뮬레이터에 첫화면이 나타났으면 Logcat을 클릭해 보자.

 

검색창에 MainActivity를 입력해보자. 옆에 Debug(디버그)를 선택하면 MainActivity 클래스의 Debug 관련 데이터만 추려서 볼 수 있다. 즉, Log.d()로 작성한 부분을 볼 수 있다.

로그에 기록했던 내용대로 점수가 0으로 나온 것을 확인할 수 있다.

 

이런 방법으로 로그문과 Logcat을 활용하여 에러가 난 원인을 찾는 것이 Debugging(디버깅)의 한가지 예이다.

 

참고로 Log를 사용하는 대신 println()함수를 사용해서 출력할 수도 있는데 이 경우 Logcat 옵션 중에서 d, i, v 모드에서만 출력된다. println() 함수는 문자열을 출력해주는 함수이므로 println("onCreate called. Score is $score")라고 하면 된다.

 

콜백(callback) 함수 확인 로그

참고로 lifecycle(생명주기)의 콜백(callback) 함수가 실행되는 지 확인하려면 onCreate함수 바깥에 다음과 같이 코드를 작성하면 된다.

 

다른 콜백 함수들도 같은 방법으로 작성하면 된다.

 

2. breakpoints

다시 말하지만 프로젝트를 만들다 보면 많은 문제가 생긴다.

작성한 코드 끼리 잘 맞지 않거나 엉켜서 예기치 않은 에러가 발생하기도 하고 실수나 실력 부족으로 잘못된 코드를 입력했을 때도 에러가 발생한다.

다른 코딩 언어에서도 이런 문제로 스트레스를 많이 받는다고 한다. 그래서 코틀린과 같은 최신 코딩 언어들은 에러가 되도록 발생하지 않는 방향으로 발전하고 있다고 한다.

 

디버그 또는 디버깅은 버그를 해결하는 작업이다.

버그를 해결하려면 프로젝트에서 어떤 일이 일어나는지 알아야 한다. 

앞에서 logging(로깅)을 디버깅 도구로 사용하는 방법을 알게 되었고 화면이 바뀔 때에도 적용해 보았다.

그런데 로깅 작업은 로그 메시지를 작성하고, 앱을 다시 실행하고, 로그를 확인하며, 무엇이 잘못될 수 있는지 알아내는 것은 시간이 많이 걸리기도 하고 매우 지루할 수도 있다.

 

이번에는 Android Studio(안드로이드 스튜디오)가 제공하는 또 다른 편리한 디버깅 도구인 breakpoints(중단점)에 대해 알아본다.

 

breakpoints를 사용하면 지정한 코드 라인에서 앱 실행을 일시 중지할 수 있으므로 프로그램의 상태와 해당 시점의 데이터를 검사할 수 있다.

 

앞에서 작성한 로그문에 breakpoints를 만들어 보자.

 

코드 번호 옆 부분(gutter, 거터라고 부른다)을 마우스로 클릭하면 다음과 같이 된다.

gutter는 지붕 끝에 있는 빗물 받이 홈통 같은걸 말하는데 딱 맞는 이름 같다.

 

숫자 옆에 생긴 빨간점이 breakpoint(중단점)이다.

break는 ‘깨다’라는 뜻이고 point는 ‘점’이다. 

breakfast는 ‘깨다+단식’이므로 ‘잠자는 동안 먹지 못한 것을 깨다’ 그러므로 아침식사라는 뜻이다. 참고로 fast는 ‘금식,단식하다’의 뜻이 있지만 ‘빠른’ ‘고정된’이라는 뜻도 있다. 뱀발: 영어 학습은 코드 작성에 도움이 된다.

위와 같이 중단점을 찍어 놓으면 해당 위치에서 코드가 중단된다. 하지만 아무때나 중단하면 안되기 때문에 ‘디버그 모드’에서만 중단점이 작동한다.

디버그 모드는 벌레처럼 생긴 아이콘을 클릭하면 된다. Debug’app’ 은 Run 메뉴에서도 실행할 수 있다.

디버그 모드로 실행한 후 화면 방향을 바꾸면 중단점에서 멈춘 후 Debug 창이 나타난다. 해당 라인은 파란색으로 표시된다.

 

이후 실행하면 중단점 직전에서 코드 실행이 중지된다.

 

 

왼쪽에는 디버그 모드에서 활용할 수 있는 여러 버튼들이 있다.

  • Resume(계속하기)

  • Pause(일시정지)

  • Stop

  • View Breakpoints(중단점 보기)

  • Mute Breakpoints(중단점 무시)  

 

윗쪽에는 코드 흐름을 관리할 수 있는 버튼들이 있다.

  • show execution(실행 보이기)은 실행 지점을 보여준다. 디버깅 중인 지점으로 커서가 이동한다.

  • step over(단계 넘기)은 다음 코드 줄로 이동한다. 코드 줄이 메써드(함수)인 경우에는 해당 단계를 넘어간다. 

  • step into(단계 안으로) 버튼은 메써드(함수) 내부를 살펴볼 때 사용한다.

  • force step into(강제 단계 안으로)는 디버거가 메써드(함수)로 들어가도록 강제한다. 함수 안으로 들어갈 수 없을 때 사용한다.

  • step out(단계 밖으로) 버튼은 메써드 밖으로 나갈 때 사용한다.

  • run to cursor는 코드 실행이 메소드가 호출 된 위치로 돌아갑니다.

디버그 모드 왼쪽과 오른쪽에 Frames(프레임)창과 Variables(변수)창에서 상태를 확인할 수 있다.

왼쪽 프레임을 선택하면 오른쪽 변수창에서 확인할 수 있고 삼각형 버튼을 누르면 확장해서 속성이나 값을 자세히 검사할 수 있다.

 

끝.

Wraven...