강의는 3강으로 되어있지만 내용이 길어 두 편으로 나눈다.
3-1의 내용은 이전에 배웠던 컴파일의 흐름을 좀 더 자세하게 익히고 디버깅하는 방법, 그리고 코드의 디자인이 중요한 이유, 러버덕이 무엇인지를 간단히 설명한다.
컴파일의 흐름과 코드의 디자인이 중요한 이유에 대해 알고나서 배열에 대해 강의를 시작하는데 키야아아아! 기가막힌다. 한낱 배열이 아닌 배열이 킹갓코드임을 알 수 있게 해주는, 메모리에서 저장방식과 알고리즘의 기본 초석이 되는 중요한 배열이라는 것이다. 이것이 하버드의 강의인가? 나도 배웠는데 기억을 못하는 걸까? 혹은 내가 제대로 공부하지 않은걸까? 아마 셋 모두 해당하지 않을까 싶고 반성해본다.
일단 본문에서 다루는 내용은 배열이 왜 중요한 지 알 수 있게끔 해주는 컴파일의 흐름, 디버깅, 코드의 디자인을 작성해 보려한다.
컴파일링의 네 단계
컴파일링은 총 네 단계를 거치게 된다.
- 전처리
- 컴파일링
- 어셈블링
- 링킹
1. 전처리
컴파일 하기전 전처리기에 의해 실행된다.
예를 들어 #include <~.h> 이 문장은 전처리기에게 다른 파일의 내용을 포함시키라고 알려주게 된다.
전처리기는 <~.h> 헤더에 담긴 함수등을 C언어 형태로 변환시켜준다.
2. 컴파일
이제 진짜 컴파일인데, 컴파일러라고 불리는 프로그램이 구체적으로 전처리한 소스코드를 어셈블리어 코드로 변환시켜준다.
어셈블리어 코드란 컴퓨터 언어에 가장 근접한 최소한의 명령어 단위로 이루어진 코드인데, 이 최소한의 명령어를 섞어 사용하면 C언어 소스코드에 담긴 함수를 모두 해석 할 수 있다. 아주 오래전 C언어가 개발되기 전 어셈블리어로 코드를 작성했다고 한다.
3. 어셈블
어셈블러라는 프로그램이 이전 단계에서 작성된 어셈블리 코드를 오브젝트 코드로 변환한다. 오브젝트 코드는 연속된 0과 1로 이루어진 코드이다.
어셈블리 코드까지 사람이 이해할 수있는 최소한의 언어로 작성될 수 있었다면, 오브젝트 코드는 컴퓨터가 해석 할 수 있는 0과 1만으로 이루어진 코드이다.
기본적으로 컴파일 되어야 하는 파일이 한개라면 여기서 과정은 끝이난다. 하지만 #include <cs50.h> 이런 다른 파일과의 연결이 필요한 경우 한단계가 추가되는데 그것이 링크라는 단계이다.
4. 링크
프로그램이 라이브러리를 포함해 여러 개의 파일로 이루어져 있을때 하나의 오브젝트 파일로 합치는 과정이다.
link 라는 단어에서 직관적으로 이 단계의 의미를 내포하고 있다.
링커는 여러개의 오브젝트 코드를 실행가능한 오브젝트 코드 파일로 합쳐주게 된다.
디버깅
디버깅은 소스코드상의 에러를 찾아 해결하는 것을 의미한다. 디버깅이라는 단어의 유래를 알아보면 아주 옛날에 grace hopper 라는 컴퓨터 과학자가 있었다. 이분이 mark2라는 시스템을 계발중이었는데 어느 날 갑자기 시스템안에 벌레가 들어가 문제를 일으켰다. 이 사건을 벌레가 들어간 첫 사례라고 기록하게 되었고, 오늘 날 의도치 않은 에러를 의미하는 단어가 되었다.
소스코드의 에러를 찾는 디버깅을 빠른시간에 해결하는 것이 중요하지만 그러기 위해서는 적절한 방법으로 디버깅을 하는 것이 중요하다.
CS50강의에서는 직접 help50이라는 프로그램을 제공해 help50 명령어를 사용하면 소스코드에서 어떤 에러인지를 유의미하게 알려준다.
하지만 코드상의 에러가 생겨 컴파일이 불가능한 오류가 생긴 것이 아니라 코드상의 에러는 없지만 논리 오류가 생긴 경우가 있다. 이 경우는 컴파일에는 문제가 없고 실행 된 파일이 의도대로 동작 하지 않는 경우이다.
예를 들어 '#'이란 단어를 10번 출력하고 싶었는데 11번이 출력이 되는 것이다.
이럴 때 내가 사용한 반복문의 흐름을 파악하기 위해 printf() 함수를 사용해 반복문의 사용된 변수의 흐름을 파악 할 수 있다. JS를 사용하는 경우 console.log 를 사용하는 것과 같다.
개발과정에서 오타로 나는 코드는 아주 극초반 초보들이 흔히 하는 실수지만 이런 오류보다는 앞으로 개발과정에서 논리오류가 훨씬 많이 생긴다. 나 또한 예전에 안드로이드를 개발해보면서 Activity의 생명주기 과정 중간중간 log를 찍어보고 에러를 찾으며 디버깅을 익혔다.
또 다른 디버깅 방법은 IDE를 사용하는 것인데, IDE마다 디버깅 툴이 존재한다.
이 디버깅 툴에는 여러가지 기능이 있는데, 간단히 소스코드를 중간에 멈추게 할 수 있고, 한 줄씩 코드를 실행해 볼 수도있다.
그리고 한가지 "러버덕" 에 관하여 말하고 있다.
러버덕이란 개발을 모르는 누구여도 상관없이 내가 머리 속에 있는 코드라던가 흐름이라던가 그냥 풀리지 않는 무언가를 설명하는 것이다. 그러면 설명하는 과정에서 정리되어있지 않던 코드, 혹은 여러가지 들이 자연스럽게 어떠한 점에서 문제가 생겼는지 알 수 있는 방법이다. 내가 혼자있는 상황이여도 가능하다. 앞에 오리인형을 두고 말하는 것이다. 오리가 없다면 내 스스로에게 말하며 설명해 볼 수도 있다. 중요한 요점은 스스로 말하면서 정리를 하는 과정에 문제를 찾는 것을 말한다.
코드의 디자인
코드를 작성하는 것 만큼 중요한 것은 코드가 정확한지를 확인하는 테스트를 만드는 것이다.
작동여부를 계속해서 확인해야하는데, 이것은 나 혼자만 개발을 하는게 아니기 때문이다. 큰 프로젝트의 소프트웨어를 만들기 위해서는 항상 다른 사람들과 함께 개발을 하기 때문이다. 나만이 알 수 있는 코드가 아니라 한명이 짠 코드처럼 코드 작성시 규칙을 정하고 그 규칙을 맞게 개발을 하게 된다. 이것이 코드의 디자인이 된다. 이렇게 잘 짜여진 코드를 중간 중간 다른 사람들이 디자인에 맞게 작성한 코드를 삽입하고, 잘 동작 하는지 테스트를 하는 것이다.
앞으로 내가 취업을 하게 되면 가장 필요한 것이 아닐까 생각한다. 그동안 내가 스스로 코드를 짰던 것을 나중에 보면 스파게티 라고 느낀 코드들이 새삼 많다. 더 배우고 좋은 코드를 작성할 수 있게끔 성장해야겠다.
'Development > CS' 카테고리의 다른 글
[CS50] 5강 메모리 (0) | 2021.12.23 |
---|---|
[CS50] 제 4강 알고리즘 (0) | 2021.12.20 |
[CS50] 제 3-2강 배열 (0) | 2021.12.20 |
[CS50] 제 2강 - C언어 (0) | 2021.12.18 |
[CS50] 제 1강 - 컴퓨팅 사고 (0) | 2021.12.16 |
댓글