저는 개발을 해나가며 많은 시간을 네이밍을 고민하는 데에 씁니다. 높은 퀄리티의 코드를 작성하기 위해서입니다.
일련의 코드를 작성하고 모두에게 이해되게끔 제목을 짓는 일은 참 어렵습니다. (모든 코드가 단일책임을 만족하며 쓰인다면 다행이지만요.) 코드가 가진 정체성을 식별해야 알맞은 이름을 부를 수 있게 되고, 그것들을 조립하여 논리적인 해법으로 문제를 풀어낼 수 있게 됩니다.
저만의 네이밍을 바라보는 시각을 정리해보려 합니다. 같은 고민을 해오신 분들에게 뜬구름같던 개념이 조금이라도 정립될 수 있을 것이라 생각합니다.
목차
1️⃣ Naming things
2️⃣ Component, React module
3️⃣ The process of Naming component
4️⃣ Conclusion
1️⃣ Naming things
There are only two hard things in Computer Science: cache invalidation and naming things.
- Phil Karlton
네이밍은 어렵습니다. 이에 대해 공감하지 못하는 사람이라면, 프로그래밍적 사고에 통달했거나 어려움을 외면하거나.. 둘 중 하나라고 생각 들 정도입니다.
When you write code, it's a good idea to step back from time to time and imagine someone looking at your code for the first time. How difficult would it be for them to get what's going on? Do you need extensive comments to describe what a method does? If so, could you come up with a better name that makes it more obvious?
- 🔗 Jon Moter
코드를 작성하는 개발자(우리)의 입장만을 생각한다면, 네이밍은 전혀 고려될 사안이 아닙니다. 어떤 동작을 하는 코드인지, 무슨 의도를 가지고 있는지 전부 알고 있기 때문입니다.
하나의 상황을 가정해볼게요. “구름 같은 얼룩을 가진 동네 길고양이”를 보고 “구르미”라는 이름을 지어주었습니다.
나는 “구르미”로써 ‘어느 고양이인지’, ‘이 고양이가 어느 얼룩을 가졌는지', ‘구르미는 어느 구름에서 나온 이름인지’ 등 모든 컨텍스트를 알고 있게 됩니다. 하지만 옆 친구는 나의 구구절절한 설명을 모두 이해해야 비로소 “구르미”가 어떤 고양이인지를 알게 됩니다.
함수의 이름을 update_state() 와 같이 모호한 이름으로 지정한 경우도 마찬가지입니다. 다른 프로그래머가 코드를 읽으러 오면, 그들은 모든 것이 어떻게 동작하는지 이해할 수 없습니다. 그래서 그들은 update_state 함수를 보고 "뭐야? 어떤 상태를 업데이트하는 거지? 이건 언제 발생하는 거지?"라고 말합니다.
코드를 작성할 때, 가끔은 한 걸음 물러나서 누군가가 처음으로 코드를 볼 때를 상상해 보는 것이 좋습니다. 그들이 어떤 동작이 일어나는지 이해하기 어려울까요? 메소드가 무엇을 하는지 설명하기 위해 상세한 주석이 필요한가요? 그렇다면, 더 명백하게 와닿는 더 좋은 이름을 생각해 보는 것이 어떨까 한다는 것입니다.
그중에서, 저희에게 익숙한 “컴포넌트의 네이밍”으로 범위를 좁혀 이야기를 해보려 합니다.
2️⃣ Component, React module
우리에게 익숙한 컴포넌트는 가장 대표적인 리액트의 🔗 모듈입니다. 모듈이라는 개념이 나오게 되면서, 우리는 다른 개발자(next engineer who has no context)의 관점을 고려해야 하게 됩니다.
다른 이가 내가 만든 컴포넌트를 가져오고 사용하는 것을 기대합니다. (적어도 그 컴포넌트를 사용하는 ‘나’도 그 다른 개발자가 될 수도 있습니다.) 그러기 위해서는 이름만 보고도 이 컴포넌트가 어떤 역할을 할지, 이 컴포넌트는 어떤 인터페이스(props)를 가지는지가 기대되어야 원활한 재사용이 이루어지게 됩니다.
그것이 아니라면, 그저 무의미한 생산에 수렴하는 비효율이 일어나게 됩니다. 내가 만든 컴포넌트가 있다는 것을 학습하지 못한 Next Engineer는 고통스럽습니다. 극단적으로 “찾고 읽고 이해할 시간에 새롭게 하나 더 만들어야겠다.” 라는 결론에 다다르게 될 수 있습니다.
가장 좋은 컴포넌트는 내부 구현 코드를 읽을 필요가 없습니다 . 모든 구현 코드를 다시 읽지 않고도 사용할 수 있기 때문에 매우 강력합니다. 이러한 컴포넌트는 Next Engineer도 쉽게 사용할 수 있고, 만들고자 하는 것을 논리적으로 조립하여 풀어낼 수 있습니다. 좋은 컴포넌트들은 결국에 다음과 같은 특징들을 가질 수 있습니다. 충분조건이 되기도, 필수조건이 되기로 하는 긴밀한 관계를 가진 특징들이라 생각됩니다.
- 단일 책임 원칙을 이루고, atomic에 가깝게 설계됩니다.
- 모호한 이름이 없고, 중복적인 이름이 제거되어 있습니다.
- 일관성이 유지되어 있습니다.
이러한 특징의 컴포넌트화를 위해, 어떤 방식으로 어떤 것들을 고려해볼 수 있을까요?
3️⃣ The process of Naming component
중복을 분리하여 재사용을 하려 하거나, Component Life Cycle을 분리하여 리렌더링을 최적화하려 하거나, 이러나저러나 컴포넌트를 하기로 했다고 가정해 보겠습니다.
가장 먼저, 정체성을 식별하는 일이 중요합니다. 그리고 본질에 가까운 정체성을 식별하기 위해서는 관점을 분리하며 모두에게 통용되는 포인트를 식별해야 합니다.
저희 프론트엔드 개발자에게 익숙한 text “Input”을 상상해 봅시다.
우리에겐 <input /> 태그로부터 온전한 입력창, 담기는 데이터, 기본 스타일 등이 떠오르게 됩니다. 하지만 이는 비(非) 엔지니어 관점에서는 그저 “InputBox”에 가까운 입력창일뿐이고, form 내부에서 통신을 위한 데이터를 관리한다면 “TextField”에 가까운 동작이 기대가 됩니다. 정말 이것도 아니고, 저것도 아니고, 그냥 이 프로젝트에서의 온전한 특수성을 가진다 하면 "SnupiInput"이 될 수도 있습니다. 이와 같이, 같은 Input 이더라도 기획자의 의도와 서비스의 맥락, 코드의 관점 등 정체성이 달라지는 요인들이 결코 단순하지 않습니다.
이와 같은 정체성과 적절한 이름이 설정되어야, 그제야 인터페이스를 설계할 수 있습니다. 또한, 인터페이스가 설계되어야 내부 로직이 구현될 수 있습니다. 정체성과 네이밍이 바뀌게 되면 그 인터페이스와 내부는 함께 흔들리기 때문입니다. “Input”이라면 HTML Input Attributes가, “InputBox”라면 내부 스타일이, “TextField”라면 fieldName, value, onChange 등이 인터페이스화 될 것이고, 이에 따른 컴포넌트 동작이 구현될 것입니다.
무슨 말을 하고 싶은지 감이 조금 오시나요? 결국 같은 UI와 동작 기능을 가지더라도, 이를 바라보는 시각에 따라 정체성과 네이밍, 그리고 그에 대한 로직까지 모두 달라질 수 있습니다. 이를 적절하게 컴포넌트로 구성하기 위해서는, 다양한 맥락을 파악하고, 많은 관점에서의 사고 과정이 필요합니다.
사실 이는 답이 명확히 떨어지는 수학의 영역이 아니기 때문에 되려 문과의 영역에 가깝다 생각이 됩니다. Identity를 식별하는 과정은 그만큼 개개인의 역량에 달려있습니다. 이는 이후에도 인공지능이 아닌 인간이 판단할 수 있는 일 중 하나가 될 것이라 생각합니다.
어떻게 보면 도메인에 대한 🔗 E-R 식별의 과정과 유사합니다. ER은 비즈니스 도메인에서의 다이어그램을 그리는 것이고, 컴포넌트는 User Interface(UI)과 API 수준에서의 레이어를 나누어 구성하는 것이라는 차이만 있을 뿐이죠. 논리적, 물리적인 Table 설계 이전에 ER을 식별하고 개념적인 설계를 하듯이, 컴포넌트에도 정체성을 식별하고 알맞은 레이어와 인터페이스를 설정해 주는 것이 중요합니다.
4️⃣ Conclusion
그저 구현에 매몰되어 네이밍을 고려하지 않은 컴포넌트가 쌓이다보면, 더이상 그 컴포넌트들은 재사용하기 힘들어집니다. 정체성이 제대로 식별되지 않은 컴포넌트일 가능성이 높고, 로직과 컴포넌트 네이밍이 일치하지 않는 경우가 많습니다. 그러한 컴포넌트들은 유지보수를 하며 네이밍부터 리팩토링하는 경우가 허다합니다. 재사용을 위한 문서화를 필요로 할 수 있고, 그것을 찾는 코스트를 따져보니 아예 새로 컴포넌트를 작성할 것이 예상됩니다.
이러한 악순환이 반복되면 번들 사이즈만 커져만 갈 것이고, 로직들의 정합성은 저하될 것이고, 훗날에는 아무도 건들고 싶지 않은 Legacy 프로젝트로써 변질되어 갈 수 있습니다. 유지보수성이 저점을 찍은 상태에서 디버깅을 하고자 한다면, 상당한 리소스를 들이게 될 수밖에 없습니다.
이를 방지하기 위해 이와 같은 정체성 식별과 적절한 네이밍을 지으려는 습관은 필수적이라는 생각이 듭니다.
최근에는 속도는 기술이지만, 정확성은 능력이라는 생각을 주로 합니다. 짧은 경력이니만큼 퀄리티를 위한 개발을 많이 접하며 사고를 고도화하고자 합니다.
제가 잘못 생각한 부분이나, 공감되는 부분 등에 대해 피드백 주시면 감사하겠습니다!
글 읽어주셔서 감사합니다 :))
ref
https://tcpschool.com/c/c_complie_module
https://martinfowler.com/bliki/TwoHardThings.html
'Web.d' 카테고리의 다른 글
[React][TypeScript] Generic Props on Functional Component (10) | 2023.12.24 |
---|---|
[Web][Network] About URI Encoding & Decoding (8) | 2023.12.07 |
[Web][Network] Session vs Token Authorization (1) | 2023.10.29 |
[GraphQL] How to use GraphQL Properly (1) | 2023.08.18 |
[React] For react States that represent only Valid State (w. Reducer) (5) | 2023.04.06 |