2021. 11. 30. 01:10ㆍ독서
코드를 작성하다 보면 많은 어려움과 직면하게 된다.
어떻게 아키텍처를 설계할까, 어떻게 루틴을 설계할까 등등.
이번 장에서는 위의 문제보다는 간단하면서도, 해결하기 까다로운 '변수'라는 변수를 다뤄본다.
3부 변수 파트에는 변수 사용 시 고려할 사항, 변수 이름의 기능, 기본 데이터형, 특이한 데이터형 등 이렇게 4가지 파트로 나눠져 있고,
이 글에서는 첫 번째 파트인 '변수 사용 시 고려할 사항'에 대해서 다뤄보려 한다.
📕 변수가 뭘까?
변수를 직역하면 "변하는 수"이고, 사전적 정의는 "어떤 관계나 범위 안에서 여러 가지 값으로 변할 수 있는 수."이다.
두 설명에서 공통되는 것은 '변한다'라는 성질이다.
이렇듯 변수는 변하는데, 어떻게 변하며, 언제 변하며, 무엇 때문에 변하는지가 프로그래밍에서 핵심이라고 생각한다.
프로그래밍에서 변수는 주로 정수나 배열과 같이 기본으로 제공되는 데이터형을 가리키지만,
이 장에서는 위의 것들 뿐만 아니라 클래스로부터 생성한 객체도 포함한다.
📕 변수 == 유리병의 모래
책의 첫 줄에 다음과 같이 적혀있다.
요구사항과 아키텍처에서 채우지 못한 세부적인 내용은 구현을 통해 비로소 완성된다.
모든 세부 사항까지 완전하게 명시하는 미세한 수준으로 설계도를 그리는 것은 비효율적이다.
우리가 뭔가의 가능성을 얘기할 때 주로 마요네즈병의 비유를 떠올리곤 한다.
모두가 아는 그 골프공으로 채우고, 조약돌로 채우고, 모래로 채우고 하는 그 이야기 말이다.
마치 아키텍처로 다 구현한 것 같지만 변수로 그 사이를 채우는 것이 마치 마요네즈병의 모래 같다고 생각했다.
그렇다. 이 변수라는 것이 우리의 아키텍처에 미새한 부분을 채워줄 것 같다.
📕 변수 선언을 쉽게 만드는 법
언어에는 변수를 선언하는 두 가지 방식이 있다.
첫 번째는 명시적 선언이고, 두 번째는 암시적 선언(묵시적 선언)이 있다.
명시적 선언의 대표적인 언어로는 자바, C++ 이 있다.
#include <iostream>
using namespace std;
int main() {
int number = 10;
cout << number;
return 0;
}
이렇게 C++의 경우 변수 number를 int형으로 선언해줘야 한다.
반면, Javascript의 경우
let number = 10;
console.log(number);
이처럼 number라는 변수를 데이터 타입을 지정하지 않고 선언할 수 있다.
이를 암시적 선언(묵시적 선언)이라고 부른다.
이 암시적 선언을 두고 저자는 "언어가 지원하는 가장 위험한 기능의 하나"라고 말한다.
(이와 관련해서는 암시적 선언 방식의 문제점에 대해 다룰 때 얘기하는 게 적절할 것 같다.)
그리고 저자는 암시적 선언 방식에서 오는 문제점을 해결하기 위해서 다음과 같은 방식을 제시한다.
- 암시적 선언 기능을 사용하지 않는다.
- 모든 변수를 선언한다.
- 이름 규칙을 정한다.
- 변수의 이름을 검사한다.
어떤 컴파일러에서는 암시적 선언 기능을 사용하지 않을 수 있다. 또한 필요한 변수를 미리 모두 선언함으로써, 문제를 줄이고, 이름에 매직넘버를 사용하지 않고 일정한 규칙을 정하며, 변수의 이름을 루틴이나 컴파일러의 기능을 통해 검사하면
암시적 선언 방식의 문제점을 최소화할 수 있다고 말한다.
📕 변수 초기화 가이드라인
부적절한 데이터 초기화는 컴퓨터 프로그래밍에서 오류를 발생시키는 가장 빈도가 높은 원인이라고 말하고 있다.
그럼 부절 절한 데이터 초기화가 뭘까?
책에선,
- 변수에 값을 할당한 적이 없다.
- 변수에 있는 값이 더는 유효하지 않다.
- 변수의 일부에는 값을 할당하고 나머지 부분은 값을 할당하지 않았다.
이런 문제들은 코드를 작성하면서 한 번쯤은 겪어봤을 문제들이다.
그럼 이런 문제들을 어떻게 해결하면 좋을까?
먼저 변수를 선언할 때 초기화한다.
float studentGrades[MAX_STUDENTS] = {0,0};
이렇게 변수를 초기화해주는 것이, 방어적 프로그래밍이며, 초기화 오류를 막는 좋은 방법이다.
두 번째, 변수가 처음 사용되는 곳 근처에서 초기화한다.
이 방법이 실질적으로 나에게 가장 와닿았던 부분이다.
예제를 살펴보자.
* 나쁜 예시
int accountIndex;
float total;
bool done;
accountIndex = 0;
total = 0.0;
done = false;
// accountIndex를 사용하는 코드
/**
* ...
*/
//total을 사용하는 코드
/**
* ...
*/
// done을 사용하는 코드
/**
*
*/
*좋은 초기화
int accountIndex;
accountIndex = 0;
// accountIndex를 사용하는 코드
/**
* ...
*/
float total;
total = 0.0;
//total을 사용하는 코드
/**
* ...
*/
bool done;
done = false;
// done을 사용하는 코드
/**
*
*/
알고리즘 문제를 풀거나 할 때 이러한 경험이 다들 한 번쯤은 있을 것이다.
문제를 풀다 보면 필요한 변수가 생겨서 가장 상단으로 올라가서 필요한 변수를 선언하고 다시 내려오는 일 말이다.
(나만 그렇다면...내가 코드를 못 짠 거겠지..)
왜 아래와 같은 방식이 더 좋은 코드일까?
위와 같은 방식으로 변수를 사용하는 곳과 멀리 떨어져서 선언하거나 초기화할 경우,
선언부와 사용부 사이에서 엉뚱한 값으로 수정될 가능성이 있고, 마치 변수가 전체 코드에 사용될 것처럼 보이는 인상을 줄 수 있기 때문이다.
세 번째, 이상적으로 각 변수가 처음 사용되는 곳 가까이에서 변수를 초기화하고 정의한다.
두 번째 해결방법과 비슷한 얘기이다. 선언, 초기화를 최대한 사용 파트 부근에서 하자.
그리고 여러가지 가이드라인을 제시한다.
카운터와 누산기를 특히 주의한다, 클래스의 멤버 데이터를 생성자에서 초기화한다, 다시 초기화해야 할 필요가 있는지 검사한다, 이름 상수를 한 번 초기화하고 실행 코드로 변수를 초기화한다... 등등 좋은 얘기이다.
하지만 위의 예시보다 개인적으로 중요하지는 않다고 생각한다.
📕 선생님, 범위는 어디까지예요??!!
중요한 변수의 범위가 나올 차례이다.
이 부분은 따로 적겠다.
'독서' 카테고리의 다른 글
프로그래머의 뇌 서평 (0) | 2022.03.30 |
---|---|
(클린코드) 2장. 의미 있는 이름 (0) | 2022.03.04 |
(클린코드) 1장. 깨끗한 코드 (1) | 2022.02.20 |
(코드 컴플리트2) 25 - 27장 회고 (0) | 2021.12.30 |
(코드 컴플리트2) 10장 변수 사용 시 고려할 사항 - 2 (0) | 2021.11.30 |