(코드 컴플리트2) 10장 변수 사용 시 고려할 사항 - 1

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을 사용하는 코드
/**
*
*/

 

알고리즘 문제를 풀거나 할 때 이러한 경험이 다들 한 번쯤은 있을 것이다.

문제를 풀다 보면 필요한 변수가 생겨서 가장 상단으로 올라가서 필요한 변수를 선언하고 다시 내려오는 일 말이다.

(나만 그렇다면...내가 코드를 못 짠 거겠지..)

 

왜 아래와 같은 방식이 더 좋은 코드일까?

위와 같은 방식으로 변수를 사용하는 곳과 멀리 떨어져서 선언하거나 초기화할 경우,

선언부와 사용부 사이에서 엉뚱한 값으로 수정될 가능성이 있고, 마치 변수가 전체 코드에 사용될 것처럼 보이는 인상을 줄 수 있기 때문이다.

 

세 번째, 이상적으로 각 변수가 처음 사용되는 곳 가까이에서 변수를 초기화하고 정의한다.

두 번째 해결방법과 비슷한 얘기이다. 선언, 초기화를 최대한 사용 파트 부근에서 하자.

 

그리고 여러가지 가이드라인을 제시한다.

카운터와 누산기를 특히 주의한다, 클래스의 멤버 데이터를 생성자에서 초기화한다, 다시 초기화해야 할 필요가 있는지 검사한다, 이름 상수를 한 번 초기화하고 실행 코드로 변수를 초기화한다... 등등 좋은 얘기이다.

하지만 위의 예시보다 개인적으로 중요하지는 않다고 생각한다.

 

 

📕 선생님, 범위는 어디까지예요??!!


중요한 변수의 범위가 나올 차례이다.

이 부분은 따로 적겠다.

반응형