잘하는 개발자가 되는 그라데이션 사고법 (추상화 계층과 데이터 흐름 이해하기)

teo.v·2023년 6월 2일
93

테오의 프론트엔드

목록 보기
40/48
post-thumbnail

이 컨텐츠는 테오의 컨퍼런스에서 발표한 내용을 바탕으로 재구성된 컨텐츠입니다. 글 보다는 프레젠테이션에 가까운 형식이 될 것 같네요. 주요 장표를 중심으로 작성하였습니다. 전체 발표자료를 원하시면 https://www.teoconf.com/ 홈페이지에서 다운로드 받을 수 있습니다.

내용에 앞서...

가장 최근에 작성했었던 개발을 잘하기 위해 생각하는 틀을 설명하는 글을 썼고 좋은 반응을 얻었습니다.

컴퓨팅 사고와 개발 실력 늘리는 공부법
https://velog.io/@teo/computational-thinking

후속작으로 이전 글에서 분량관계상 작성하지 못했던 데이터의 보관과 전파 라는 내용을 정리해 글을 작성하고 있었는데 해당 글에 대한 댓글 중에서 추상화에 대해서 설명이 좀 아쉽다고 하는 내용을 보았기에 추상화와 관련된 이야기를 덧붙여 글을 쓰고자 했습니다.

때 마침 자체적으로 진행을 하고 있던 컨퍼런스(테오콘)와 일정이 맞물리게 되면서 글로 쓰려고 작성하고 있던 미완의 원고를 바탕으로 테오의 컨퍼런스에서 발표를 하게 되었습니다.

발표자료가 생기고 나니 추상적인 글로 다시 쓰는 것보다는 충분히 시각적으로 구성이 된 발표자료를 중심으로 글을 쓰는게 더 낫겠다 싶어 이번 글은 프레젠테이션 형식으로 글을 작성해보려고 합니다.

이 글이 컨퍼런스에 참여하지 못한 분들에게 조금 더 생생한 발표 형식으로 전달이 되기를 바랍니다.

잘하는 개발자가 되기 위한 그라데이션 사고!

잘하는 개발자가 되기 위해서 뭘 알아야 될까요? 구현에 익숙해지고 나면 프로젝트 관리, 설계, 테스트, 의사소통, 유지보수 등 여러가지 그 다음 중요한 것들이 생기고 여전히 우리는 배워야 할 것들이 많습니다.

각각의 내용도 기회가 되면 설명을 드리겠지만, 그에 앞서 이번 시간에는 Next Step으로 가기 위해 개발자라면 꼭 알아야할 중요한 개념과 관점이 되어 줄 추상화 계층데이터 흐름 이라고 하는 개념에 대해서 한번 이야기를 해보려고 합니다.

이 내용은 이전 글에서 설명했던 데이터 관점으로 바라보기와 이어지는 내용이며, 개발을 잘하기 위해서 계층을 분리하고 연결하여 생각하기라는 관점을 추가하여 어떻게 하면 더 요구사항을 코드로 잘 만들어 낼 수 있는지 이야기해보고자 합니다.

프롤로그

우선 데이터 관점으로 바라보기에 대해서 한번 복습하면서 어떤 개념인지 다시 한번 생각해봅시다.

테트리스를 만들어 보면서 이해하는 "데이터 관점으로 바라보기!"

개인적으로 개발을 배우면서 뭔가 한단계 성장했다라고 느꼈을 때가 바로 테트리스를 처음 만들어봤을 때였습니다. 당시 책으로 배웠던 기억이 있는데 책의 구성은 대략 다음과 같았습니다.

1) 만들어야 할 프로젝트를 설명하고 (테트리스의 규칙과 요구사항)
2) 만들기 위해서 필요한 모든 문법을 설명해주고
3) 어떻게 생각해야 하는지 알려주고
4) 각 부분을 조립해나가는 방식으로 설명을 했었습니다.

테트리스 규칙은 당연히 알고 있었고, 테트리스를 만들기 위한 기본적인 문법들은 그렇게 어렵지 않았습니다. 문법을 익히기 위한 간단한 예제들도 너무 쉬워보였습니다.

그렇지만 책을 보지 말고 한번 어떻게 만들어볼지 고민해보고 시도해보라는 말에 한번 책을 덮고나서 코드를 치려고 하니 순간 너무나 막막했습니다.

개발 문법도 다 배웠고, 분명 테트리스 규칙도 다 아는데 이걸 구현하는 게 왜 어려웠을까요?

당시에는 컴퓨적으로 사고하는 법을 전혀 몰랐었기 때문이라고 생각합니다. 즉, 데이터의 관점으로 바라보는 방법을 제대로 몰랐기 때문에 문법을 알고 그전에 별그리기나 숫자야구와 같은 간단한 예제들은 가지고 있던 직관력으로 어떻게든 헤딩을 하면서 구현을 했지만, 조금만 복잡한 것을 만들라고 하니 막막함이 느껴진것이죠!

테트리스를 데이터의 관점으로 볼 수 있게 된다면 어떻게 될까요?

테트리스의 세상을 이차원 배열로 바라보는 데이터의 관점으로 생각하고 표현을 하는 사고 방식과 관점을 알고나면 테트리스의 구현이 훨씬 더 쉬워진다는 것을 배웠습니다.

테트리스의 세상이 이차원 배열이 되면 테트리스 블록블록이 아니라 데이터 0과 1이 조합된 배열로 데이터로 취급할 수 있습니다. 블록의 회전은 이미지를 90도로 조작하는게 아니라 미리 회전된 데이터들의 배열의 집합으로 취급 할 수 있게 되고, 한줄을 제거하기 위해 다 차있는지는 같은 열의 모든 값들이 0보다 크다면 과 같은 식으로 표현을 할 수 있게 됩니다.

이렇게 요구사항을 데이터의 관점으로 볼 수 있고 표현할 수 있게 되면 개발자로써 새로운 성장을 맞이하게 됩니다. 컴퓨터 언어를 알고 문법을 이해하고 숙련된 것을 넘어서 만들고자 하는 요구사항을 실제로 구현을 할 수 있게 됩니다. 마치 외국어를 문법만 알고 있다가 어느 순간 말의 트이는 것과 비슷하다고 볼 수 있습니다.

깨달음을 얻고 다시 태어난 매트릭스의 네오처럼 우리도 개발자로써 요구사항을 들었을때 "이렇게 저렇게 만들어주세요~" 라고 했을 때, '아~ 이런저런 Data형태로 표현하고, 이 Data와 저 Data를 이렇게 저렇게 바꾸면 되겠네' 라고 하는 생각을 나게 만들어 주는 것이 바로 데이터의 관점으로 사고하는 방법입니다.

실제로도 이것은 일종의 깨달음의 영역입니다. 이러한 부분은 많은 훈련과 경험의 축적으로 인해 더 빨리 알 수 있게 됩니다. 그래서 그 전에 말했던 의식적으로 데이터로 생각해보는 것을 연습을 해보면서 코딩을 하게 되면 더 빨리 늘 수 있게 됩니다. 의식적으로 연습하는 것이 훈련이고 우리가 익숙해져서 코딩을 하고 있는 것은 그 훈련된 결과입니다.

그리고 그 다음 이야기, 추상화 계층과 데이터 흐름

하지만 이렇게 데이터의 관점에 눈을 뜨고 구현이 쉬워지더라도 여전히 어려운 것들이 남아있습니다. 이게 블록과 회전과 바닥을 닿거나 1줄이 맞춰지는 것과 같은 것들을 데이터로 쉽게 표현을 하고 구현을 했지만 프로그램은 이 모든 것들이 하나로 온전히 조립이 되어 제 기능을 했을 때 비로소 제대로 구현한 것이 됩니다.

그래서 그 다음 개발의 레벨은 이러한 각각의 구현을 어떻게 잘 조립하는가? 에 있습니다.

그리고 이러한 구현된 코드간의 조립은 생각보다 결코 쉽지 않습니다.

그리고 대부분 이때의 개발자들이 일단 구현은 계속 하고 있지만 이 코드가 여기에 있어야 하는지 저기에 있어야 하는지 어떤 위치에서 어떻게 조립을 해야하는지에 대한 경험이 없기 때문에 우리들의 코드는 스파게티가 되고 맙니다.

분명 이건 잘못되었다는 것은 알겠지만 그래서 어떻게 해야하는 걸까? 하는 새로운 막막함이 다가오게 됩니다.

요구 사항을 데이터로 바라보게 되어 이제 어떻게든 구현이 가능해졌다면 그 다음으로 터득해야 하는 것은 어떻게 잘 배치하고 조립을 할 것인가? 이며 이를 이해하기 위해서 먼저 추상화 계층 이라고 하는 개념과 데이터 흐름 이라고 하는 개념을 이해해보도록 합시다.


추상화(Abstraction)

추상화라는 부분들부터 이해를 해봅시다. 우선 뜻을 이해하기 위해서 gpt에게 한번 물어보았습니다.

중요한 키워드를 먼저 잡아보고 가도록 하겠습니다.

추상화의 핵심 키워드

  • 개발에서 중요한 개념이다.
  • 복잡한 시스템이나 개념을 간결하고 이해하기 쉬운 형태로 단순화하는 과정이다.
  • 복잡한 세부내용을 숨기고 핵심 개념과 기능에 집중할 수 있다.
  • 데이터를 표현하고 다루는 방식을 단순화하는 데이터 추상화
  • 복잡한 동작을 단순한 인터페이스나 함수로 추상화하는 프로세스 추상화가 있다.
  • 추상화를 통해서 코드를 재사용하고 유지보수하기 쉽게 만들 수 있다.

추상화에 대해서 알고 있는 사람이라면 너무나 당연한(?) 소리이기에 때문에 잘 정리된 내용이라고 보이겠지만 정확한 개념을 모르는 사람에게는 이 내용이 너무나도 추상적인 내용이 될거라고 생각합니다. 추상화라고 하는 단어 자체가 굉장히 추상적인 개념을 설명하고 있기 때문이죠.

그래도 개발에서 중요한 개념이라고 하니 추상화의 이해를 돕기 위해서 반대 개념으로부터 한번 접근해가며 설명을 해보려고 합니다.

Push의 반대말이 Pull이라고 할때 Push가 밀다라는 것을 알면 Pull이라는 말을 몰라도 유추를 해볼 수 있듯이 추상화의 반대개념을 먼저 이해하면 추상화의 개념을 조금 더 쉽게 잡을 수 있을 거라고 생각합니다.

추상화의 반대? = 구현!

추상화의 반대는 구현입니다.

이러한 생각을 머리속에 넣고 한번 간단한 예시를 통해서 한번 추상화에 대해서 조금 더 알아보도록 합시다.
이전 글에도 간단히 언급했던 불을 켜고 끄는 프로그램을 만들어보도록 하겠습니다.

위와 같은 요구사항이 있을 때 어떤식으로 코드로 작성을 하면 좋을까요? 맞습니다! isLight = true 라고 적어주면 되겠죠.

불을 켠다라고 하는 요구 사항을 데이터를 표현을 하게 되면 구현이 된다라는 사실을 제가 계속해서 설명하고 있었습니다.

그러면 반대로 구현된 코드를 통해서 물음표를 한번 채워보도록 합시다. 이 코드에는 무엇이 들어가야 할까요? 그렇습니다. turnOffLight(), toggleLight() 와 같은 코드들로 채워질 겁니다.

이렇게 구현한 코드를 추상화를 하게 되면 복잡한 세부 사항은 숨겨지고 더 이해하기 쉬운 단순화된 코드가 됩니다.

우선 추상화에 대한 기본적인 접근을 내가 구현한 코드에 적절한 이름을 붙여주는 것 이라고 생각하면서 시작해봅시다. 이렇게 구현된 코드에 이름을 붙여주게 되면 복잡한 코드 구현부분을 감추고 조금 더 사람이 이해하기 쉬운 이름으로 부를 수 있게 됩니다.

그래서 우리가 구현한 코드를 반대로 추상화를 하게 될 경우에는 구현은 요구사항을 데이터의 관점으로 기술하는 것이라면 데이터의 관점에서 기술된 것을 보다 사람의 언어에 가까운 코드로 표현 하는 것이 추상화가 됩니다.

📌 그래서 추상화는 복잡한 구현부분을 감추면서,
1. 보다 명세에 가까운
2. 행동을 기술하는
3. 선언적인
4. 사람의 개념에 가까운 코드를 작성할 수 있게 됩니다.

따라서 추상화를 하면 코드를 더 사람의 언어에 가까운 형태로 표현할 수 있기에 더 가독성이 좋은 코드를 작성할 수 있고 코드는 컴퓨터가 이해하는 거지만 결국 사람이 작성하는 것이기에 추상화를 잘하면 지속적으로 유지보수를 하기 더 좋은 코드를 만들 수 있게 됩니다.

나아가 복잡한 시스템을 구현하면서 협업을 해야할 때에는 이러한 추상화의 강점이 더욱 두드러 집니다. 추상화는 코드를 간소화하기에 시스템의 복잡성을 관리 가능한 수준으로 줄이는 데 도움이 됩니다.

충분한 추상화가 없으면 코드의 복잡성으로 인해 실수를 하기 쉬워지고, 버그를 찾기 어려워지며, 유지보수가 어려워집니다. 또한 코드의 가독성이 낮아져서 다른 사람이 코드를 이해하거나 수정하기 어렵게 만듭니다.

특히 다른 프로그래머들과 협업할 때, 추상화는 중요한 역할을 합니다. 추상화를 통해 다른 사람들이 당신의 코드를 쉽게 이해하고 수정할 수 있게 해주며, 팀의 생산성을 높일 수 있습니다.

여기까지 설명이 길었지만 대충 '개발에서 추상화가 이렇게 중요하구나. 대략 이름을 잘 지어서 잘 읽히도록 만들어 준다는 느낌? 아직 어떻게 하는 건지는 잘 모르겠지만 하게 되면 이러한 것들이 잘 되도록 하게 해야겠다!' 정도의 생각을 일단 가지고 넘어가도록 합시다.

그리고 또 추상화가 중요한 이유는 추상화된 코드는 잘 변하지 않는다 라는 점입니다.

구현의 세부내용은 바뀔 수 있지만 추상화된 코드는 곧 명세이자, 사용자의 요구사항에 가까운 코드이며 요구사항이 변하기 전까지는 그 이름과 코드는 거의 유지가 된다는 의미입니다. 불을 켜고 끄는 프로그램에서 turnOnLight() turnOffLight() toggleLight() 등은 핵심 기능이기 때문에 잘 변하지 않습니다.

그리고 이렇게 잘 변하지 않는 코드들로 조립을 해야만 조립이 틀어지거나 구현이 복잡해져서 코드가 같이 복잡해져도 조립을 담당하고 있는 코드들은 유지가 됩니다. 이러한 것을 인터페이스(Interface)라고 합니다.

이렇게 추상화된 코드가 쌓이게 되면 잘 변하지 않는 경계(인터페이스)가 생기면서 추상화 계층(Abstraction Layer)이 만들어지게 됩니다.

이렇게 추상화 계층이 만들어지고 나면 우리는 계층과 계층간의 조립으로 프로그래밍을 할 수가 있고 이러한 추상화 계층은 기존과는 다른 새로운 세상과 관점으로 프로그래밍을 할 수 있도록 만들어줍니다.

추상화 계층(Abstraction Layer)

컴퓨터는 0과 1로 이루어졌고 데이터의 관점으로 계속 구현을 하라고 하는데, 그렇다면 왜 우리는 0과 1로 직접 구현은 하지 않은 걸까요? 바로 컴퓨터가 알아들으면 더 빠를텐데 말이죠.

당연히 말도 안되는 질문이죠. 우리는 사람이고 코딩도 사람이 하는 거니까 컴퓨터에 가깝게 생각을 하는 것은 중요하지만, 언어 자체의 구현이나 내용들은 사람의 언어에 가까운 개념과 생각으로 코딩을 하고 싶어 합니다. 아래와 같이 0과 1로 표현을 하면 굉장히 이해하기가 어렵기 때문입니다.

왼쪽의 방식으로 코딩하고 싶은 분은 없으시죠? (여담으로 컴퓨터의 창시자인 천재 폰노이만은 이진법으로 코딩하는 것을 즐겼다는 얘기를 나무위키에서 봤어요. 우리는 천재도 아니고 그게 더 좋은 것도 당연히 아니죠!)

결국 추상화는 복잡하고 저수준의 컴퓨터에 가까운 코드들을 인간에 가까운 개념으로 다시 정의해서 만들 수 있있다는 점에서 중요하다는 점을 다시 한번 설명을 드립니다. 또한 그리고 이러한 계층이 한번 만들어지고 나면 우리는 그 이하의 수준에서 생각을 하지 않고 고수준의 사고로 프로그래밍을 할 수 있게 됩니다.

프론트엔드의 관점에서 한번 생각을 해본다면 우리가 주요하게 작업을 하는 화면을 만들 때 실제로 화면의 데이터는 2차원 배열의 픽셀값으로 되어 있지만 실제 프론트엔드 개발자는 아무도 픽셀의 배열 데이터를 상상하면서 개발하지는 않습니다. (Canvas를 쓴다면 생각을 해볼 수도 있겠지만요...) 우리는 HTML과 CSS를 통해서 화면을 생각하고 만들고 있다는 것을 알고 있습니다. 뿐만 아니라 DOM대신에 React나 Svelte같은 프레임워크를 기반으로 새로운 계층 위에서 사고를 할 수 있게 됩니다.

결국 좋은 추상화계층은 코드를 더 적게 쓰면서도 더 많은 행위를 더 나은 고수준의 사고로 개발을 할 수 있게 만들어 줍니다. 이렇게 보다 코드를 낫게 만들어 주는 추상화를 어떻게 하는게 더 좋은 것인지 예시를 통해서 한번 살펴보도록 합시다.

좋은 추상화 코드를 작성하는 방법

그래서 다음과 같은 코드가 있다고 한번 해볼게요.

const currentDate = new Date()
const firstDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1)
const firstDay = firstDate.getDay()
firstDate.setDate(firstDate.getDate() - firstDay);

일단 다음 내용을 보기전에 먼저 위 코드가 어떤 코드일지 잠깐 생각해보시고 넘어가는 것을 추천드립니다. 위 코드는 어떤 코드일까요?

해당 코드는 현재 날짜의 달력을 그리기 위해서 달력의 첫번째 날을 구하고자 하는 코드였습니다.

코드를 보자마자 바로 이해하신 분들도 있겠지만 해당 맥락을 모른채로 코드만 보고서 해당 코드를 바로 이해하는 것은 쉽지 않을 수 있습니다. 그렇기에 이러한 코드에 적당히 이름을 지어준다면 이제 훨씬 더 복잡한 구현이 숨겨지고 간결해지고 가독성이 좋아지는 코드가 될 수 있습니다.

그렇다면 무조건 복잡해보이는 코드를 이름을 붙여 단순화하기만 하면 좋은 추상화일까요?

추상화의 함정 - 추상화는 구현을 숨긴다!

추상화는 실제로 구현을 숨깁니다. 그렇지만 추상화를 한 사람에게는 그렇지 않습니다.

추상화는 구현을 숨기기 때문에 코드의 맥락을 모르는 사람은 함축된 이름만 가지고 이게 어떤 구현인지 예측을 해야 합니다.
맥락을 알고 만든 사람은 이 맥락을 정확하게 이해하지만 맥락을 모르는 사람은 이름만 가지고 복잡한 구현내용을 추측을 해야 됩니다.

이러한 코드를 작성한 사람과 그렇지 않은 사람의 맥락차이가 존재하는데 우리는 언제나 협업을 해야하는 존재이며, 설사 혼자 개발을 하더라도 언제나 미래와 나와 협업을 하는 것이기에 추상화를 할 때에는 함축된 이름을 가지고도 복잡한 구현이 예측이 가능하도록 딱 맞는 좋은 이름을 짓는 것이 추상화의 가장 큰 중요한 핵심입니다.

그리고 이건 절대로 쉽지 않습니다. 모든 개발자가 오늘도 이름을 짓는 것으로 고민을 하고있고 GPT나 코파일럿이 나왔을 때에는 '아 이제 이름좀 짓는게 편해지겠다.'라고 생각했습니다. 그만큼 프로그램에서 코딩과 관계없이 가장 힘들고 어렵고 중요한 것이 바로 이름짓기입니다.

이게 쉽지 않은 이유가 함축적이고 간결한 이름을 지으면서도 복잡한 구현을 감춰야 되기 때문에 예측이 가능하고 설명적인 이름을 지어야 되면서도 복잡한 구현에 딱 맞는 직관적인 단순한 이름을 발견하기가 어렵고, 이름은 이제 한 번만 짓는 게 아니라 계속 지어야 되기 때문에 일관성을 지닌다는게 굉장히 어렵죠.

💪 그렇기에 이름을 지을때마다 대충짓지 말고 의식적으로 꼭 고민을 하면서 이 이름을 좋은지 딱 맞는 이름인지 항상 고민을 하는 것이 개발을 잘하게 만들어 주는 핵심 포인트입니다!

개발자가 글을 잘 쓰면 개발을 잘 하게 되는 것도 코딩과 관계없이 이름을 잘 짓는다는 것 자체가 좋은 개발자로 만들어줍니다. 이 이름 짓기는 개발을 하면서 거의 매일매일 하는 행동이고 이때마다 좋은 이름을 짓겠다는 어떤 생각을 끊임없이 계속 가져야 되고, 이 이름이 좋은 이름인지 혹시 더 좋은 이름이 없는지에 대해서 끊임없이 함께 고민하는 게 여러분들이 개발을 잘하기 위한 추상화가 알려주는 첫 번째 내용이라고 보시면 될 것 같습니다.

좋은 추상화는 이름뿐만 아니라 수준(Level)도 중요하다!

추상화에서 좋은 이름보다 더 중요한 것은 추상화의 수준(Level)입니다!

추상화를 하게 되면 복잡한 구현 부분이 숨겨지고 그 구현을 설명하는 함축적인 이름이 된다고 하였습니다. 반대로 말하면 그 함축적인 이름에서 복잡한 구현 부분을 예측해야 하는 문제가 발생을 하게 됩니다. 어떻게 하면 더 예측가능하게 표현을 할 수 있을까요?

추상화는 한번에 다 이뤄질 필요가 없습니다. 추상화에도 단계와 수준을 조절할 수가 있습니다. 추상화의 과정을 한번에 가는 것이라 아니라 여러번에 걸쳐 조립을 해서 사용할 수 있도록 적절한 수준으로 나눠줄 필요가 있습니다.

GPT가 알려준 추상화 방식 요약

데이터 추상화: 데이터를 표현하고 다루는 방식을 단순화 하는 과정
프로세스 추상화: 복잡한 동작 또는 시스템을 단순한 인터페이스나 함수로 추상화 하는 과정

추상화에는 다양한 방식이 존재합니다. 데이터를 추상화 할 수가 있고, 프로세스를 추상화 할 수 있습니다. 추상화는 결국 이름을 붙이는 것이라고 생각하면 데이터의 추상화는 변수명을 짓는 것이고 프로세스의 추상화는 함수명을 짓는 행위라고 생각해도 좋습니다.

그렇기 때문에 찬찬히 우리가 만들었던 코드에 이미 붙여진 변수명들(데이터 추상화)과 이러한 이름들이 변화하는 과정에 이름을 붙이는 것(프로세스 추상화)라는 관점에서 코드를 살펴보면 그 사이에서 적절한 수준을 발견해 볼 수 있습니다.

데이터 추상화
currentDate, firstDate, firstDay // 데이터 추상화!

프로세스 추상화
currentDate -> firstDate
firstDate -> firstDay

한번 좋은 추상화의 수준과 좋은 이름을 함께 고민해서 어떻게 만들면 좋은 코드가 될지 한번 생각을 해봅시다.

어떤가요? 추상화의 수준을 적절하게 조절했더니 단순하고, 외우기도 쉽고, 재사용도 가능하고 모듈화도 가능한 멋진 코드가 되었습니다!

우리는 이제 .startOf() 라고 하는 좋은 이름적절한 수준을 추상화를 통해서 복잡한 구현부분이 숨겨지면서직관적이고 간결한 이름을 가지면서도 재사용이 가능하면서 무엇보다 기존의 복잡한 날짜계산이 아니라 새로운 고수준의 사고로 생각할 수 있도록 만들어 주는 좋은 예시라고 생각합니다.

그래서 지금처럼 코드를 작성을 했을 때 데이터의 이름과 데이터의 이름이 어떻게 변하는지에 대한 이 과정을 적절히 추상화를 하면서 여기에 정말 좋은 이름을 붙여보면 재사용도 가능하고 모듈화도 가능하면서 가능한 수준의 추상화 계층을 만들어낼 수 있을 거라고 생각을 합니다.

그래서 여러분들이 코드를 잘 작성을 하게 되면 좋은 추상화된 코드들은 다음과 같은 특징들을 가집니다. 그래서 내가 가진 코드들이 이러한 코드들을 속성을 가지고 있는지 잘 생각을 하시면서 이름을 잘 붙였는지 생각을 해주시면 좋을 것 같아요.

좋은 추상화된 코드의 특징

안정성:
좋은 코드는 안정적이고 변하지 않는 특성을 갖습니다. 이는 코드의 예측 가능성과 유지 보수성을 높여줍니다.

단순성:
좋은 코드는 단순합니다. 단순한 코드는 이해하고 사용하기 쉽게 만들어주며, 버그 발생 가능성을 낮춥니다.

목적에 적합한 수준:
좋은 코드는 적절한 추상화 수준을 가집니다. 너무 추상화되면 특수한 경우에만 쓰이는 코드가 됩니다. 덜 추상화되면 여전히 복잡한 코드가 됩니다.

재사용 가능성:
좋은 코드는 재사용 가능해야 합니다. 유사한 도메인이나 기능에서 쉽게 확장하고 적용할 수 있습니다.

가독성:
좋은 코드는 가독성이 높습니다. 함축된 이름으로도 코드의 목적과 의도를 쉽게 이해할 수 있도록 합니다.

일관성:
좋은 코드는 일관성을 유지합니다. 그래서 숨겨진 구현에 대해 예측할 수 있습니다.

추상화는 한 번에 만들어지는 게 아닙니다. 추상화는 점진적으로 만들어 질 수 있다는 것을 기억해야합니다. 너무 미세한 추상화는 의미가 없고 너무 많은 추상화 또한 의미를 가지기 힘드므로 적절한 계층을 나눠서 조립한다는 관점을 가지고 있어야 합니다.

추상화 이야기를 정리해보자.

개발을 위해 추상화된 세계를 이해하는 것은 매우 중요합니다. 우리는 종종 실세계의 복잡성을 단순화하여 이해하기 위해 추상화라는 도구를 사용합니다. 이것은 프로그래밍에도 동일하게 적용되며, 복잡한 문제를 더 이해하기 쉽고 관리하기 쉬운 조각으로 분해하는 데 도움이 됩니다.

이러한 과정에서 중요한 두 가지 요소가 있습니다: 좋은 이름 부여적절한 추상화 수준 설정입니다. 좋은 이름은 코드의 의도와 기능을 명확하게 전달하고, 적절한 추상화 수준은 복잡성을 효과적으로 관리하며 필요한 정보만을 제공합니다.

하지만 이 두 가지 요소를 생각하고 있다고 해서 자연스럽게 코드에 적용되는 것은 아닙니다. 의식적인 노력이 필요합니다. 그렇게 함으로써 우리는 데이터 흐름(Data Flow)이 명확하게 표현된 코드를 작성할 수 있습니다.

추상화된 계층을 만들면서 데이터 흐름을 구성하는 것은 코드가 어떻게 동작하는지 이해하고 예측하기 더 쉬워집니다. 이것은 오류를 찾아내고 해결하는데에도 도움이 되며, 새로운 기능을 추가하는 데에도 유용합니다.

1) 요구사항을 데이터의 관점으로 바라보고 코드로 작성하는 관점이 잘하는 개발자가 되기 위한 첫번째 과정이라면 두번째는 구현된 2) 코드를 좋은 이름과 적절한 수준으로 추상화를 하는 것이 될 것입니다.

그리고 이렇게 3) 추상화된 계층을 만들게 되면 자연스럽게 계층간의 데이터 흐름이 생겨나게 됩니다. 다음 장에서는 이 데이터 흐름에 대해서 이야기를 해보려고 합니다.


데이터 흐름(Data Flow)

추상화는 수준이 존재한다고 하였습니다. 소프트웨어를 구성하는 계층을 극단적으로 추상화를 하면 아래와 같이 그림을 그려볼 수 있습니다. 이렇게 가장 추상화된 계층으로 소프트웨어를 구성하는 것을 우리가 아키텍쳐라고 부릅니다.

일반적으로 - 특히 프론트 엔드에서 - 사용하고 있는 아키텍처는 다음과 같이 생겼습니다.

소프트웨어의 데이터 흐름 사이클

사용자와 컴퓨터간의 소통 과정이 인테페이스를 통해 전달되고 비지니스 로직을 통해 데이터 변경을 요청하며 데이터 접근자가 실제 데이터를 변경합니다. 변경된 데이터는 다른 데이터 접근자를 통해서 새로운 데이터의 형식으로 변경이 되며 비지니스로직으로 인해 화면이나 음성등의 인터페이스가 되어 사용자에게 전달이 되게 됩니다.

그리고 이러한 아키텍처를 프론트엔드에서 주로 사용하는 용어로 표현해서 조금 더 익숙한 형태로 만들어 본다면 아래와 같이 표현할 수 있습니다.

프론트엔드를 배우면서 특히 웹 프레임워크를 배우면서 프로그램을 만들다 보면 각 계층에 맞는 영역이나 관련 라이브러리들이 자연스럽게 떠오르실거에요!

그래서 이러한 데이터 흐름은 사용자를 중심으로 컴퓨터까지 그리고 다시 사용자에게로 적절히 순환하는 구조를 가지면서 자연스럽게 계층 간 연결되는 구조를 가지게 됩니다.

이때 중요한 것은 각 계층만이 아니라 흘러가는 프로세스 역시 하나의 계층이라는 것을 꼭 기억을 해주셨으면 좋겠습니다. 가령, 이벤트에서 상태 변경으로 이어지는 구간은 EventHandler의 계층이고, 상태가 화면으로 변하는 것은 JSX와 같은 계층으로 표현할 수 있겠죠.

추상화된 계층간에 데이터의 흐름이 존재하고 데이터의 흐름은 순환적이며 자연스럽게 연결되는 구조를 가진다는 것을 이해한다면 이제 제가 이 발표에서 말하고자 하는 것을 이해하실 준비가 되었습니다.

지금까지 예기했던 순환적인 데이터의 흐름과 점진적으로 쌓여있는 추상화 계층에 대한 부분들의 개념을 결합해서 제가 얘기하고 싶었던 그라데이션 사고에 대한 이야기를 드려볼까 합니다.

그라데이션 사고?(Gradation Thinking)

⚠️ 주의: 그라데이션 사고라는 말은 제가 시각적으로 상상할 수 있고 이해를 돕기 위해서 임의로 붙인 이름입니다. 검색하면 나오는 내용이 아니니 궁금한 내용이 있다면 댓글로 물어보시거나 추상화데이터 흐름이라는 키워드를 가지고 찾아보시면 좋을 것 같습니다.

그라데이션 지도 - 코드의 역할과 추상화 수준

추상화의 방향은 데이터(저수준)에서 요구사항(고수준)이라고 하는 단방향적인 흐름을 가지고 데이터의 흐름은 순환적인 흐름을 가집니다. 추상화의 수준과 데이터의 흐름에 따른 역할에 따라 코드가 어디에 있어야 하는지 결정이 되고 이미 만들어진 프레임워크나 라이브러리들은 이러한 수준과 역할에 따라 배치가 됩니다.

우리가 모든 것들을 처음부터 만들지 않고 저수준으로 프로그래밍을 하지 않고 고수준의 프로그래밍을 하기 위해서는 저수준의 영역을 차지하고 있는 계층을 이해하고 고수준의 사고를 기반으로 프로그래밍을 할 수 있어야 합니다. 그렇기에 우선 현재 내가 알고 있는 것들 혹은 내가 원하는 것들을 구현하는 과정에서 필요한 것들이 어떠한 흐름 계층에서 어느정도의 추상화 수준을 가지고 있는지 이해가 필요합니다.

가령 비슷한 역할과 데이터 흐름에 존재하는 axios랑 React-Query는 어떻게 다른 것인지 해당 라이브러리가 어떤 수준에 있는 것인지 fetch 하고는 어떻게 다른지를 이러한 지도가 머리속에 있다면 훨씬 더 이해를 하기 쉬울 것이며, 나중에 새로운 것이 나왔을 때에도 이 것이 어느구간에 속해 있는 것인지를 안다면 훨씬 더 적용을 하기에 수월할 것입니다.

그리고 이미 만들어진 프레임워크나 라이브러리가 아닌 비어있는 구간은 실제 내가 만들고자 하는 요구사항을 구현하기 위해서 내 코드로 채워야 할 곳이며 이때 어떤 계층에 어느정도의 수준으로 채워야할지를 머리속에 그려놓는 것이 중요합니다.

그렇다면 기존 생태계를 이해하는 것이 아니라 실제로 내가 코드를 잘 작성하고 잘 조립하기 위해서는 이제 어떻게 해야 할까요?

요구사항에서 코드까지 가는 그라데이션 사고!

"요구사항에서 코드로 이어지는 과정을 그라데이션처럼 서서히 변화하는 과정으로 생각해봅니다."
= 데이터 흐름과 추상화 수준을 계층으로 나눠 비어있는 공간을 요구사항에 따라 채우기
= 요구사항을 세부적으로 분해해 각 구간에 맞게 생각하기

우리가 앞서 살펴본 데이터 흐름 계층과 추상화 수준으로 나눠진 구간에서 비어 있는 곳들을 요구사항에 맞게 채우는 것이 내 코드의 역할이라고 하였습니다. 그렇다면 내 코드가 커지고 복잡해지기 전에 미리 적절히 구간별로 쪼개둔 형태로 생각을 해보는 건 어떨까요?

예를 들어 "테트리스의 블록 회전하기"라는 요구사항을 다시 한 번 살펴봅시다. 사용자로부터 키 입력 이벤트가 발생하면, 이 이벤트는 블록을 회전하는 비즈니스 로직을 거쳐 데이터를 처리하고, 그 결과로 상태가 변경되며, 변경된 상태는 화면에 렌더링됩니다. 이런 과정을 세부적으로 나누어 각각의 요구사항을 구체적으로 만들 수 있게 됩니다.

그라데이션 사고법이라고 하는 키워드는 두 가지의 의미를 가지고 있습니다.

첫번째는 코드가 데이터 흐름과 추상화 수준, 즉 계층을 따라 어떤 역할을 하는지를 이해하는 것입니다.
두번째는 요구사항이 코드로 변환되는 과정을 단계적으로 바라보며, 각 단계를 세부적으로 나누고 채워 나가는 것입니다.

이러한 관점을 통해 자연어로 표현되는 요구사항을 미리 만들어진 구조화된 틀로 나눠져서 복잡한 문제를 간단하고 작은 문제들로 분리하면서 동시에 자연스러운 연결을 생각하도록 만들어주는 것을 의미합니다.

💪 이 또한 역시 의식적인 연습이 필요합니다. 단순히 알고만 있는 것에서 끝날게 아니라, 말로 하는 요구사항을 글로 적어보면서 이러한 틀에 맞는 표현으로 바꾸어보고 적어보고 그 표현과 비슷한 형태로 코드로 만들어보는 연습을 하는 것이 중요합니다.

그라데이션 사고방식은 복잡한 문제를 단순화하고, 코드 작성 및 소프트웨어 설계 과정에서 구조적인 접근을 취할 수 있도록 도와줍니다.

코드 밖 그라이데이션 사고

요구사항이 코드가 되는 과정은 개발만 있는게 아니다 = 요구사항의 그라데이션

요구사항이 코드가 되는 과정은 개발과 코드에만 국한되는 것은 아닙니다. 추상적인 요구사항이 좋은 코드가 되기 위해서는 적절한 틀에 맞춰서 잘라서 생각을 해야하는 것처럼 요구사항이 개발의 영역에 포함되기 전에도 복잡한 어플리케이션의 요구사항들을 적절한 틀안에서 잘라서 표현하는 것이 필요합니다.

제가 운영하고 있는 스프린트에서도 이러한 과정을 알려드리고 있습니다. 어떻게 하면 만들고 싶은 아이디어를 잘게 쪼개서 적절한 추상화 수준을 가지면서 코드가 되기 위해서 필요한 단계와 틀을 배울 수 있습니다.

해당 내용은 분량 관계상 예전에 작성한 글을 링크하는 것으로 하며 이와 관련해서는 협업과 태스크 분배 및 관리 와 관련해서 새롭게 글을 한번 작성해 보려고 합니다.

BDD? SDD? 팀 프로젝트 다같이 개발설계하는 방법
https://velog.io/@teo/behavior-driven-development-schema-driven-development

끝으로...

요구사항을 데이터의 관점으로 바라보면 구현이 됩니다.

그리고 구현된 코드를 적절한 수준으로 쪼개어 좋은 이름을 붙이면 복잡한 내용은 숨기면서 더 사람의 언어에 가까운 간결하고 가독성이 좋은 코드를 만들어 낼 수 있습니다.

이러한 적절한 수준의 추상화가 쌓이면 변하지 않는 좋은 코드를 만들 수 있고 이는 추상화 계층이 되어 줍니다. 추상화 계층을 통해서 우리는 훨씬 더 고수준의 사고와 관점으로 개발을 할 수 있게 됩니다.

고수준의 프로그래밍이란 이러한 계층간의 데이터 흐름으로 표현되는 것을 의미하며 데이터의 흐름은 사용자를 중심으로 순환하는 구조를 가집니다.

이러한 데이터의 흐름과 추상화된 수준이라는 두가지의 개념으로 코드의 역할과 위치가 결정이 주어지게 되며 적절한 위치와 자연스러운 연결이 스파게티 코드가 아닌 좋은 구조를 가진 좋은 코드를 만들어냅니다.

반대로 이러한 좋은 구조를 이해하고 있다면 요구사항을 적절하게 쪼개어 좋은 구조에 맞게 표현을 하는 사고를 익히게 된다면 복잡한 개발을 단순화하고 구조화 하면서도 항상 좋은 코드를 유지할 수 있도록 만들어 준다는 것을 이번 발표에서 알려드리고 싶은 내용이었습니다.

그리고 좋은 추상화의 예시를 통해서 조금이라도 어떻게 하는 것이 좋은 것인지 아는 계기가 되었으면 좋겠습니다.

그라데이션 사고법 이라고 하는 여덟 글자의 이름이 이 모든 내용들을 포함하면서 동시에 시각적인 어떤 느낌과 감각을 전달할 수 있는 잘 추상화된 이름이기를 바랍니다.

정말 정말 끝으로... 개발은 이해가 아니라 깨달음이다.

지난 글에서 저는 개발은 학문보다는 운동에 가깝다고 생각한다고 말했습니다. 결국 아는 것이 중요한 것이 아니라, 이러한 지식을 통해 어떠한 깨달음을 얻는 과정이 필요하다는 것입니다. 그리고 깨닫기 위해서는 단순히 아는 것에서 그치는 것이 아니라 몸소 해보면서 경험해야만 느낄 수 있는 것이라고 생각합니다.

이번 발표에서 추상화와 데이터의 흐름, 좋은 추상화를 해야하는 이유와 어떻게 하면 좋은 추상화인지, 그리고 이러한 개념들을 통해 프론트엔드의 생태계를 바라보는 관점을 이해해서 좋은 구조를 머리속에 그리고 어떻게 하면 요구사항을 이 구조에 맞게 쪼개어 생각할 수 있는 지 관점을 얻어가는 것이 이해의 영역이라면,

의식적으로 개발을 하면서 좋은 이름을 짓고자 노력하는 것, 내가 작성한 코드의 위치가 적절한지 신경 쓰는 것, 함수를 만들 때 적절한 수준으로 쪼개고 있는지 고민하는 것, 새로운 라이브러리가 나오거나 기존 생태계를 공부할 때 어떠한 역할과 수준인지 생각해보고 실제로 지도를 그리고 연결을 하는 것, 요구사항이 주어졌을때 내가 만든 틀에 맞는 표현으로 적어보는 실제 경험들을 통해서 이 모든 이해들이 깨달음으로 연결이 될 것이고 그래야 잘하는 개발자가 될 수 있을 거라고 생각합니다.

이 글이 정보를 소개하고 이해에서 그치는 글이 아니라 조금 더 빨리 깨닫게 되는 데 도움이 되는 글이길 바랍니다.

감사합니다!

profile
AdorableCSS를 개발하고 있는 시니어 프론트엔드 개발자입니다. 궁금한 점이 있다면 아래 홈페이지 버튼을 클릭해서 언제든지 오픈채팅에 글 남겨주시면 즐겁게 답변드리고 있습니다.

9개의 댓글

comment-user-thumbnail
2023년 7월 17일

흥미롭게 잘 읽었습니다. 감사합니다.

1개의 답글
comment-user-thumbnail
2023년 7월 22일

매번 좋은글 감사합니다!

1개의 답글
comment-user-thumbnail
2023년 8월 15일

공부하는 방향을 잡아주시는 좋은 글 너무 감사합니다 :-)
의식적으로 노력해서 좋은 개발자가 되겠습니다!

1개의 답글
comment-user-thumbnail
2023년 8월 26일

어떻게 작성하는 코드가 좋은코드일지 만약 그렇지 않은 코드가 있어서 리팩토링할때는 어떻게 해야할지 고민중인 요즘 많이 도움이 된 글인것 같습니다!
항상 좋은글 감사합니다 테오:)

답글 달기