안녕하세요! 그로스로그 입니다!😊 🌱
값을 보고 갈라지는 법, 비어 있는지를 보고 갈라지는 법, 그리고 두 갈래를 하나로 합치는 법. 2기 5회차 세 편입니다.
성장일지는 멤버들이 2주에 한 번씩 자신의 성장을 기록하는 활동이에요. 지난 기수의 성장일지를 다시 읽으면서, 그때 소개해드리지 못한 글을 하나씩 꺼내고 있습니다.
2기 5회차, 2024년 11월 초입니다. 이번 회차에는 분기를 다룬 세 편이 서로 다른 층위에서 모였어요.
01
🔀 C언어 기초 선택 제어문
전일수 님
C의 선택 제어문 다섯 가지를 정리한 글입니다. 단순
if, if~else, 다중 if~else, switch, 그리고 goto요.각각에 설명 · 구문 · 예제를 붙이고, 마지막에 다섯 줄로 요약했습니다.
goto에는 경고도 함께 달았어요. "너무 자주 사용하면 코드가 복잡하고 이해하기 어려워지므로 적절히 사용해야 합니다."2·4회차에서도 이분의 C 정리를 소개해드렸습니다. 선행처리기, 연산자에 이어 이번엔 제어문이에요. 교재 목차를 순서대로 밟아가는 연재입니다.
조금 더 들어가 보면
🎚️ if와 switch는 언제 갈리나
다섯 가지 중 실무에서 고민이 되는 건 다중 if~else와 switch 중 무엇을 쓸까입니다. 글이 둘의 성격을 이렇게 갈랐어요.
switch문 — 변수의 값에 따라 여러 경우를 처리
"조건"과 "값"이라는 단어 차이가 핵심입니다.
if는 무엇이든 조건으로 쓸 수 있습니다. 점수 >= 90처럼 범위를 볼 수도 있고, 두 값을 비교할 수도 있고, 함수 호출 결과를 쓸 수도 있어요.
switch는 하나의 변수가 어떤 값인지만 봅니다. 그래서 범위 비교를 못 해요. 성적 등급을 매길 때 switch를 쓰기 어려운 이유입니다.
대신 얻는 게 있습니다. 값이 딱 정해져 있으면 컴파일러가 점프 테이블을 만들어 한 번에 해당 위치로 갈 수 있어요. if는 위에서부터 하나씩 확인하는데, switch는 조건이 스무 개여도 곧장 찾아갑니다.
무엇을 보고 갈라지느냐가 성능까지 바꾸는 셈입니다.
⚠️ break를 빠뜨리면
switch 설명에 짧지만 중요한 대목이 있습니다.
"종료를 명시"라는 표현이 정확합니다. break가 없으면 다음 case로 그대로 흘러 내려가거든요. 이걸 폴스루(fall-through)라고 합니다.
처음 배울 때 가장 많이 하는 실수가 이겁니다. case 1:의 코드만 실행될 줄 알았는데 case 2:, case 3:까지 다 실행돼요. 에러가 아니라 문법적으로 허용된 동작이라 컴파일러가 잡아주지도 않습니다.
왜 이렇게 만들었을까요. 일부러 쓸 데가 있기 때문입니다. 여러 값에 같은 처리를 하고 싶을 때 case 1: case 2: case 3:을 연달아 쓰고 마지막에만 코드를 두면 되거든요.
의도한 폴스루와 실수를 구분할 방법이 없다는 게 문제인데, 그래서 요즘 언어들은 기본 동작을 반대로 바꿨습니다. 코틀린이나 스위프트의 when·switch는 자동으로 빠져나가고, 이어가려면 명시적으로 표시해야 해요.
🚫 goto는 왜 살아 있나
마지막 항목이 goto인데, 글이 경고를 달아뒀습니다.
goto는 프로그래밍 역사에서 가장 유명한 논쟁거리였습니다. 어디로든 뛸 수 있으니, 남발하면 코드 흐름이 실타래처럼 얽히거든요. 위에서 아래로 읽어서는 어디로 가는지 알 수가 없습니다.
그런데 C에서는 아직 쓰이는 자리가 하나 있습니다. 여러 겹의 반복문에서 한 번에 빠져나올 때, 그리고 에러가 났을 때 정리 코드로 뛸 때요.
C에는 예외 처리가 없습니다. 함수 중간에서 실패하면 그때까지 할당한 메모리를 직접 풀어줘야 하는데, if를 겹겹이 쌓으면 코드가 지저분해져요. 그래서 실패 시 goto cleanup;으로 뛰고, 함수 끝에서 정리를 몰아 하는 방식을 씁니다. 리눅스 커널 코드에서 흔히 보이는 형태입니다.
"쓰지 마라"가 아니라 "적절히"라고 적은 게 정확합니다.
📝 원문에서는 이렇게 요약합니다
글 끝의 다섯 줄이 좋습니다.
if ~ else문: 조건에 따라 두 가지 분기.
다중 if ~ else문: 여러 조건을 체크하고 분기.
switch문: 변수의 값에 따라 여러 경우를 처리.
goto문: 프로그램 흐름을 특정 지점으로 무조건 이동시킴.
분기의 개수 순으로 늘어서 있습니다. 하나 → 둘 → 여럿 → 값별 → 무조건. 다섯 항목이 그냥 나열된 게 아니라 순서가 있어요.
그리고 마지막 문장에서 이렇게 닫습니다.
"적절히"가 두 번 나옵니다. 문법을 익히는 단계인데 이미 고르는 문제를 의식하고 있어요.
큐레이터 노트
기초 문법 정리인데 틀이 일정해서 골랐습니다.
전일수 님의 C 연재는 매 편이 같은 형식입니다. 개념 → 구문 → 예제 → 요약. 회차가 쌓이면 이게 한 권의 노트가 됩니다. 자료형, 선행처리기, 연산자, 선택 제어문, 반복 제어문, 함수까지 순서대로요.
기초 문법은 검색하면 다 나옵니다. 그런데 검색 결과는 매번 형식이 다르고, 어디까지가 기본이고 어디부터가 응용인지 구분이 안 됩니다. 같은 틀로 정리된 내 노트는 그 점에서 다릅니다.
그리고 goto에 경고를 붙인 것. 교재에 나오니까 적긴 하되, 쓸 때 조심하라는 말을 함께 남겼습니다.
02
🧪 9장. 조건 연산자 요약
남기준 님
RxJS의 조건 연산자를 다룹니다.
defaultIfEmpty와 isEmpty요.시작이 중요한 구분입니다. 필터링 연산자와 조건 연산자는 무엇을 보는지가 다릅니다. 하나는 발행된 값을 보고, 하나는 옵저버블 자체의 특성을 봅니다.
그리고
defaultIfEmpty는 구현 코드 일부까지 가져와서 동작을 확인합니다.앞의 글이 값을 보고 갈라진다면, 이 글은 흐름 자체의 성질을 보고 갈라집니다.
조금 더 들어가 보면
🔍 값을 보는가, 흐름을 보는가
첫머리의 구분이 이 글의 핵심입니다.
조건 연산자 — 이미 발행한 값이 아닌 소스 옵저버블의 특성에 따라서 조건 자체를 분기해야 할 때 사용하는 연산자
"이미 발행한 값이 아닌"이 핵심입니다.
3회차에서 다룬 filter는 값 하나하나를 보고 통과시킬지 정합니다. 짝수만 남기는 식이죠. 그런데 "값이 하나도 안 왔다"는 상황은 값을 봐서는 알 수 없습니다. 볼 값이 없으니까요.
이건 흐름이 끝나야만 알 수 있는 정보입니다. 그래서 조건 연산자는 다른 층위에서 동작해요.
🪹 비어 있을 때를 대비하기
defaultIfEmpty가 푸는 문제가 이겁니다.
글이 구현 코드 일부까지 가져왔는데, 이게 동작을 아주 명확하게 보여줍니다.
_next(value) {
this.isEmpty = false; // 값이 하나라도 오면 표시를 끈다
this.destination.next(value); // 그대로 흘려보낸다
}
_complete() {
if (this.isEmpty) { // 끝날 때까지 아무것도 안 왔으면
this.destination.next(this.defaultValue); // 기본값을 발행
}
this.destination.complete();
}
깃발 하나로 됩니다. 값이 오면 깃발을 내리고, 완료 시점에 깃발이 그대로 서 있으면 기본값을 내보내는 거예요.
여기서 왜 "완료 시점"이어야 하는지가 분명해집니다. 중간에는 판단할 수 없거든요. 지금까지 값이 안 왔어도 곧 올 수 있으니까요. 3회차에서 다룬 reduce가 완료를 기다리는 것과 같은 이유입니다.
실행 결과가 그 동작을 확인해줍니다.
개수(count): 0, 값(value): EMPTY 개수(count): 3, 값(value): 1 개수(count): 3, 값(value): 2 개수(count): 3, 값(value): 3
0개일 때만 EMPTY가 나오고, 3개일 때는 원래 값이 그대로 흐릅니다.
이게 실무에서 왜 필요할까요. 화면에 목록을 그리는데 데이터가 하나도 없으면, 그냥 아무것도 안 그려집니다. "결과 없음"이라는 안내조차 안 나와요. 빈 화면과 로딩 중인 화면이 구분되지 않죠. 기본값을 하나 흘려보내면 그 자리를 채울 수 있습니다.
🚥 확인만 하고 끝내기
isEmpty는 비슷해 보이는데 하는 일이 다릅니다. 글이 차이를 정확히 짚었어요.
isEmpty — 소스 옵저버블이 empty 옵저버블인지 확인 후 true/false 값을 발행하고 구독을 완료
defaultIfEmpty는 흐름을 이어가고, isEmpty는 흐름을 판정으로 바꿔버립니다.
isEmpty를 거치면 원래 값들은 사라지고 true 또는 false 하나만 남아요. 원형에도 그게 적혀 있습니다.
isEmpty<T>(): OperatorFunction<T, boolean>
들어오는 타입이 T인데 나가는 타입은 boolean입니다. 3회차에서 짚은 "들어오는 타입과 나가는 타입이 다를 수 있다"는 이야기가 여기서도 보입니다.
그래서 쓰임이 갈립니다. 데이터가 필요하면 defaultIfEmpty, 있는지 없는지만 알면 되면 isEmpty입니다.
📝 원문에서는 이렇게 확인합니다
두 연산자 모두 같은 형태의 테스트 함수를 만들어 확인했습니다.
const getRangeObservable = count => range(1, count);
function subscribeWithDefaultIfEmpty(count) {
getRangeObservable(count)
.pipe(defaultIfEmpty('EMPTY'))
.subscribe(value => console.log(`개수(count): ${count}, 값(value): ${value}`));
}
subscribeWithDefaultIfEmpty(0); // 비어 있는 경우
subscribeWithDefaultIfEmpty(3); // 값이 있는 경우
개수를 인자로 받게 만들어놓고 0과 3을 넣어봤습니다.
이게 좋은 확인 방법입니다. 코드를 두 벌 쓰는 대신 경계값과 일반값을 같은 함수에 넣어 비교하는 거예요. 그리고 로그에 count를 함께 찍어서, 출력만 봐도 어느 경우인지 알 수 있게 했습니다.
isEmpty도 똑같은 틀로 테스트했고요. 같은 방법으로 두 연산자를 재보니 차이가 그대로 드러납니다.
큐레이터 노트
구현 코드를 가져온 게 이 글의 특징입니다.
RxJS 연산자를 정리하면서 라이브러리 내부 코드를 열어본 사람은 많지 않습니다. 사용법만 알아도 쓸 수 있으니까요. 그런데 defaultIfEmpty처럼 동작 시점이 헷갈리는 연산자는 안을 보면 한 번에 풀립니다. 깃발 하나 세우고 완료 때 확인한다는 게 열 줄로 끝나거든요.
4회차 큐레이션에서 이분의 tap 정리를 소개하며 "값이 흐르는 걸 눈에 보이게 만든다"고 적었습니다. 이번엔 연산자 자체의 안을 들여다봤어요. 로그로 밖에서 관찰하는 것과, 코드를 열어 안을 확인하는 것. 두 가지 방법을 다 쓰고 있습니다.
03
👁️ 비밀번호 보이게하기, 숨기기 기능 구현
정원석 님
비밀번호 입력칸의 보기·숨기기 토글을 순수 자바스크립트로 만든 기록입니다.
시작이 가볍습니다. "어느날, 갑자기 (…) 궁금해졌다. 그래서 따로 심심해서 만들어보았다."
그리고 같은 기능을 두 벌로 올렸습니다. 먼저 "정리 되지 않은" 코드, 그다음 "함수형으로 정리"한 코드요.
3회차에서 이분의 검색 필터 구현을 소개해드렸습니다. 이번에도 라이브러리 없이 만듭니다.
조금 더 들어가 보면
🔤 type 속성 하나를 바꾼다
핵심 동작이 한 줄입니다.
inputType.setAttribute("type", "text"); // 보이게
inputType.setAttribute("type", "password"); // 숨기게
입력칸의 type 속성만 바꿉니다. 별도의 입력칸을 두 개 만들어 번갈아 보여주는 게 아니라, 하나를 그대로 두고 성격만 바꾸는 거예요.
이게 왜 나은 방법이냐면, 입력한 값이 유지되기 때문입니다. 입력칸을 갈아끼우면 그때까지 친 글자가 사라지죠. 속성만 바꾸면 값은 그대로 있고 표시 방식만 달라집니다.
버튼 두 개를 번갈아 보여주는 것도 CSS 클래스 하나로 처리했습니다.
.btn,.btn2{display:none;}
.on{display:block;}
기본은 둘 다 숨기고, on 클래스가 붙은 것만 보입니다. 자바스크립트에서는 classList.add('on')과 remove('on')만 하면 되고요. 스타일 계산을 CSS에 맡기고 JS는 상태만 바꾸는 구조입니다.
🧯 값이 비었을 때 막기
정리되지 않은 첫 코드에 이미 들어 있는 처리가 있습니다.
if(inputType.value == ''){
alert("Please enter your password.");
inputType.focus();
return;
};
아무것도 안 쳤는데 "보기"를 누르면 막습니다.
기능만 생각하면 없어도 됩니다. 빈 칸을 보이게 해도 아무 일이 안 일어나니까요. 그런데 사용자 입장에서는 버튼을 눌렀는데 아무 변화가 없으면 고장 난 것처럼 느껴집니다.
그래서 알림을 띄우고 focus()로 커서를 입력칸에 놓습니다. 막기만 하는 게 아니라 다음에 할 일을 안내하는 처리예요.
앞의 남기준 님 글과 겹치는 지점이기도 합니다. 비어 있는 경우를 따로 다룬다는 것. 한쪽은 기본값을 흘려보내고, 한쪽은 안내를 띄웁니다.
🔗 분기를 두 군데에서 한 군데로
이 글에서 가장 볼 만한 건 두 벌의 코드입니다.
처음 코드는 버튼마다 리스너를 따로 달았습니다. 보기 버튼에 하나, 숨기기 버튼에 하나요. 그런데 두 리스너가 하는 일이 거의 같습니다. type을 바꾸고, 클래스를 붙였다 떼는 것. 방향만 반대예요.
정리한 코드는 그걸 하나로 합칩니다.
function toggleVisibility(show) {
if (show) {
// 보이게 하는 처리
} else {
// 숨기게 하는 처리
}
}
inputBtn.addEventListener("click", () => toggleVisibility(true));
inputBtn2.addEventListener("click", () => toggleVisibility(false));
분기가 리스너 두 개에 흩어져 있다가, 함수 안의 if 하나로 모였습니다.
이게 왜 나은가 하면, 바뀔 때 한 군데만 고치면 되기 때문입니다. 예를 들어 토글할 때 아이콘도 바꾸기로 하면, 처음 코드에서는 두 리스너를 다 손봐야 합니다. 정리한 코드에서는 함수 하나만 고치면 되고요.
그리고 두 동작이 짝이라는 게 코드에 드러납니다. 흩어져 있으면 남이 읽을 때 둘의 관계를 스스로 찾아내야 하는데, 한 함수 안에 있으면 바로 보입니다.
글이 붙인 한 줄이 담백합니다.
뭐가 됐던 보기 편할거 가져다 쓰자.
📝 원문에서는 이렇게 씁니다
글의 목적이 처음에 분명히 적혀 있습니다.
순수자바스크립트로 구현하였다. 어려운 내장함수는 없으므로 바로 가져다 쓰면 좋을 듯 싶다.
미래의 자기를 위한 저장소로 쓰고 있습니다.
기술 블로그의 쓰임 중 하나가 이겁니다. 남에게 설명하려고 쓰는 글도 있지만, 다음에 같은 걸 만들 때 꺼내 쓰려고 적어두는 글도 있어요. 후자는 완결성보다 바로 복사해서 쓸 수 있는지가 중요합니다.
그래서 HTML·CSS·JS를 전부 올렸고, 라이브러리를 안 썼고, "어려운 내장함수는 없으므로"라고 조건까지 밝혔습니다. 가져다 쓸 사람이 확인할 것을 미리 답해둔 셈입니다.
큐레이터 노트
같은 기능을 두 벌로 올린 게 이 글을 고른 이유입니다.
보통은 정리된 코드만 올립니다. 지저분한 버전을 함께 두면 부끄러우니까요. 그런데 두 벌이 있으면 무엇이 리팩터링인지가 보입니다. 결과만 있으면 "원래 이렇게 쓰는 거구나"로 끝나는데, 전후가 있으면 "아, 이렇게 바꾸는 거구나"가 됩니다.
4회차에서 이주희 님 글의 특징으로도 같은 걸 짚었습니다. 바꾸기 전후를 나란히 두는 것. 두 분이 같은 습관을 갖고 있어요.
그리고 "심심해서 만들어보았다"로 시작하는 것. 필요해서가 아니라 궁금해서 만든 것도 기록이 됩니다. 그렇게 만들어둔 조각이 나중에 쓰일 때가 오고요.
💡 세 편을 겹쳐 읽으며
세 글이 다루는 것이 같습니다. 갈라지는 일이에요. C 문법으로, 스트림 연산자로, 화면 토글로 층은 다르지만요.
그런데 무엇을 보고 갈라지는지가 셋 다 다릅니다.
전일수 님의 제어문은 값을 봅니다. 점수가 90 이상인지, 변수가 2인지. 조건식 안에 판단 재료가 다 들어 있어요.
남기준 님의 조건 연산자는 흐름의 특성을 봅니다. 값 하나하나가 아니라 "값이 하나라도 왔는가"를 보죠. 이건 끝나봐야 아는 것이라 값만 봐서는 판단할 수 없습니다.
정원석 님의 토글은 상태를 봅니다. 지금 보이는 중인가 숨긴 중인가. 그리고 그 상태를 on 클래스로 화면에 저장해뒀어요.
비어 있는 경우를 따로 다루기
두 편에 공통으로 나오는 게 있습니다. 아무것도 없을 때의 처리요.
남기준 님의 defaultIfEmpty는 값이 하나도 안 오면 기본값을 흘려보냅니다. 정원석 님의 코드는 입력칸이 비었으면 알림을 띄우고 커서를 옮기죠.
둘 다 "없음"을 하나의 경우로 취급합니다. 그냥 두면 아무 일도 안 일어나는데, 사용자 입장에서 "아무 일도 안 일어남"은 고장과 구분되지 않거든요.
이건 실무에서 자주 빠뜨리는 지점이기도 합니다. 데이터가 있을 때만 테스트하면 빈 경우가 안 보이니까요.
분기를 어디에 둘 것인가
정원석 님의 두 번째 코드가 던지는 질문도 있습니다. 분기를 밖에 둘까 안에 둘까.
버튼마다 리스너를 다는 건 분기를 밖에 둔 것이고, 함수 하나에 if를 두는 건 안에 둔 것입니다. 동작은 같은데 고칠 때 드는 품이 다릅니다.
전일수 님의 switch도 비슷한 이야기를 합니다. 조건이 여러 개일 때 if를 늘어놓을지, 값 하나로 묶어 switch로 갈지. 분기를 어떻게 배치하느냐의 문제죠.
이번 회차에서 가져갈 것
1. switch에서 break를 빠뜨렸는지 확인하기.
없으면 다음 case로 흘러 내려갑니다. 문법 오류가 아니라서 컴파일러가 안 잡아줘요. 일부러 그러는 경우와 실수를 구분할 방법이 없으니, 의도한 폴스루라면 주석으로 남겨두세요.
2. 비어 있는 경우를 하나의 경우로 세기.
데이터가 0건일 때, 입력칸이 빈 칸일 때. 그냥 두면 아무 일도 안 일어나는데, 사용자에게는 그게 고장으로 보입니다. 기본값을 흘려보내거나 안내를 띄우는 처리가 필요합니다.
3. 같은 일을 반대로 하는 코드가 둘이면 하나로 합치기.
보기와 숨기기처럼 방향만 다른 처리는 함수 하나에 if로 모으는 편이 낫습니다. 고칠 때 한 군데만 보면 되고, 둘이 짝이라는 것도 코드에 드러납니다.
4. 경계값과 일반값을 같은 틀로 테스트하기.
남기준 님이 count를 인자로 받는 함수를 만들어 0과 3을 넣어본 방식입니다. 코드를 두 벌 쓰는 것보다 간결하고, 로그만 봐도 어느 경우인지 알 수 있습니다.
5. 헷갈리는 라이브러리 함수는 안을 열어보기.
defaultIfEmpty가 언제 기본값을 내보내는지는 구현 열 줄을 보면 바로 풀립니다. 문서가 애매할 때 소스를 여는 것이 가장 빠른 길일 때가 있습니다.
2기 5회차는 2024년 11월 초였습니다. 학기 후반으로 접어들며 각자 진도가 깊어지던 때예요.
C 교재와 RxJS 교재와 순수 자바스크립트라는 서로 다른 자리에서, 세 분이 나란히 "갈라지는 법"을 다뤘습니다. 2주에 한 번 같은 자리에 글이 모이니까 보이는 우연입니다.
좋은 글 남겨주신 전일수 님, 남기준 님, 정원석 님께 감사드립니다. 그리고 2기를 함께 채워주신 모든 멤버분들께도요! 😊
다음 큐레이션으로 다시 찾아오겠습니다! 🌱
- 에디터 · 성장일지 큐레이터 -
※ 본 큐레이션은 각 저자가 공개한 글을 소개하는 것이며, 모든 원문의 저작권은 저자에게 있습니다. 저자 본인의 요청이 있을 경우 즉시 수정 또는 삭제합니다.