나의 개발철학

Kenneth·2022년 5월 30일
0

컴퓨터 사이언스라면 모를까, 소프트웨어 엔지니어링에 있어서는 정답이 없는 문제가 더 많고, 그렇기에 엔지니어링 결정은 가치판단을 동반합니다. 이런 가치판단은 개개인의 개발철학에 기반하는데요, 저도 이제 저만의 스타일이 조금씩 생기는 것 같아 제 개발철학을 한번 정리해보려고 합니다.

사람에 따라서는 동의하기 어려운 부분도 있을텐데, 읽어주시는 독자분들과 제가 엔지니어로서 쌓아온 경험이 다르기에 당연한 부분이라고 생각합니다. 다른 경험을 공유해주고 싶으시면 편하게 커피챗 잡아주세요 :)

Simplicity

심플한 단어에 심플하지 않은 설명이 필요합니다.

개인이 감당할 수 있는 복잡도의 한계를 나날이 갱신해가는 요즈음, 크게는 조직 구조나 시스템 구조부터 작게는 코드 조각을 간소하고 간결하게 유지함으로 얻는 부가적인 가치는 이와 충돌하는 다른 어떤 가치보다도 더 큽니다.

심플함을 구성하는 여러 하위항목들 중 일부를 이야기해보겠습니다.

일관된 기술스택

모든 SW 회사에서는 가급적 내부의 기술스택을 일관성 있게 유지하려고 합니다. 프로젝트마다 다른 스택을 사용하게 되면 엔지니어간의 기술공유나 협력도 어렵고, 유지보수와 커뮤니케이션 비용도 늘어나기 때문입니다.

이는 검증된 가치로, 특별한 사정이 없는 한 절대적으로 좋은 가치입니다. 하지만 간혹 지키지 못하는 경우와 지켜지지 않는 경우가 생깁니다.

지키지 못하는 경우

  1. 기존의 기술스택으로는 기술적인 한계가 있어 새 기술스택을 추가하고 저변을 확장하는 경우
  2. 시스템 규모가 커지면서 관리, 컴플라이언스 등의 목적으로 기존에는 필요 없던 구성요소가 필요해지는 경우
  3. 숙련된 엔지니어의 부족으로 (조직 구성상의 이유, 외주 사용 등) 기존 기술스택으로 프로젝트를 진행하기 어려운 경우

지켜지지 않는 경우

  1. 새 임원 또는 리더가 들어와 기존 기술스택을 본인에게 익숙한 것으로 갈아엎는 경우
  2. 임원 또는 리더가 본인의 치적을 위해 새로운 기술 도입을 추진하는 경우
  3. 엔지니어가 동일한 환경에 질려 변화를 위한 변화를 갈망하는 경우

저는 비용을 영구적으로 늘리는 이런 결정에 대해 단호히 반대하는 입장이고, 지키지 못하는 경우인지 검토할때도 굉장히 엄격합니다.

컨벤션주의

Convention over Configuration. 논쟁의 여지는 사라진지 오래라고 생각합니다. 나날이 복잡해져가는 문제들을 더 쉽게 풀기 위해 많은 시스템들이 convention을 중심으로 돌아가고 있습니다.

컨벤션은 밀집된 정보의 덩어리

컨벤션은 굉장히 밀집된 정보의 덩어리로서, 시스템의 요소에 대해 구구절절 설명할 일을 없애줍니다. 문서화 또는 주석 기타 부연설명을 덧붙일 필요가 없습니다.

컨벤션은 결정을 줄여준다

컨벤션은 결정을 줄여줍니다. 심리학적으로 결정은 심력 소모가 큰 행동이라고 합니다. 엔지니어가 매번 설정에 대해 고민과 결정을 하는 것은 그 자체로도 비용이 굉장히 크고, 컨벤션에 의존하는 것으로 낭비를 없앨 수 있습니다.

컨벤션의 종류

프레임워크의 기본 설정도, 개발팀 내부적으로 합의한 약속도 모두 컨벤션이라고 할 수 있습니다. 단, 일반적이지 않은 약속은 문서화하여 모두가 쉽게 찾아볼 수 있고 바로 적용할 수 있어야 컨벤션이라고 할 수 있겠습니다.

예측 가능성

컨벤션은 예측 가능성을 높여줍니다. 구체적인 설정을 적극적으로 활용하는 시스템에 비해 돌발적인 변수나 에러, 장애가 적을 수밖에 없습니다. 컨벤션을 사용하는 다른 레퍼런스들을 참조하기도 용이합니다.

표준 준수

또한 표준을 중심으로 완성된 컨벤션은 내가 특별히 노력하지 않아도 표준을 준수하고, 표준을 준수하는 다른 시스템들과도 자연스럽게 어우러지도록 도와줍니다.

설정이 필요하다면

대부분의 프레임워크가 필요하다면 구체적인 설정을 적용할 수 있는 기능을 제공하고 있습니다. 컨벤션을 따라간다고 구체적인 설정이 불가능해지는 경우는 매우 드뭅니다.

컨벤션을 최대한 사용하되, 불가피한 경우에만 구체적인 설정을 적용하는 방식이 바람직합니다.

사실 그럼에도 불구하고 설정을 건드릴 일 자체가 잘 없습니다. 만약 그런 경우가 잦다면 방향성이나 설계가 잘못되어 재검토가 필요하다는 신호일 수 있습니다.

Over-engineering 경계

저는 적절한 수준의 엔지니어링을 지향합니다. 사실 너무도 당연한 내용이라 구체적인 사례를 통해 설명드리겠습니다.

검증된 라이브러리 선호

DRY원칙을 지키기 위해 꼭 필요한 경우가 아니라면 검증된 오픈소스 라이브러리를 적극적으로 활용합니다. 선택할때는 하위 디펜던시가 깔끔한 라이브러리를 선호하고, 기능이 겹치는 라이브러리를 복수로 도입하는 것은 허용하지 않습니다.

불필요한 추상화 배제

Java / Spring 스택을 사용할때 종종 해당되는 부분인데, Java 개발 관행이 유독 불필요한 추상화 레이어를 추가하는 경향이 있습니다.

대표적으로 잘못 사용하는 경우가 디커플링이 의미가 없는 상황에서 인터페이스를 생성하는 경우입니다. 예를 들자면 Spring controller와 service가 한 module 안에 있고 runtime에 다른 service를 제공할 이유가 없음에도 관행적으로 인터페이스 레이어를 넣는 경우가 있겠습니다.

Spring을 사용한다고 하면 대부분 외부 요청에 대해 서비스를 제공하기 위한 목적이고, 모듈 자체를 제공하는 것이 아니기 때문에 encapsulation과 decoupling이 구체적 실익이 없는 경우가 대부분입니다.

인터페이스를 사용하는데는 비용이 있습니다. 인터페이스가 중첩되면 코드 뎁스가 깊어지고, 코드를 보는 엔지니어가 코드를 인지하는데 부담을 줍니다.

Leverage ORM

저는 query builder를 일반적으로 사용하는건 over-engineering 이라고 생각합니다. Raw query는 ORM에 비해 손이 많이 갑니다. 시작부터 퍼포먼스를 최우선적으로 고려해야 하는 프로젝트가 아니라면, ORM의 이점을 누리면서 최적화 이슈에 부딪힐 경우 raw query를 혼용하는 형태가 바람직하겠습니다.

같은 이야기, RISC vs CISC

옆동네에도 유사한 패러다임 경쟁이 있었는데, 최근에 나온 Apple M1 프로세서가 ARM기반 RISC입니다. 또 요즘 데이터 처리에 많이 쓰이는 GPU도 굳이 분류하자면 RISC쪽으로 분류할 수 있습니다. 저는 심플함의 판정승이라고 봅니다.

코드 흐름에 대한 가독성 중시

생소할 수 있는 의견이지만, 저는 중복 제거나 cpu cycle 몇 개의 이득보다는 가독성을 우선합니다. 저는 코드가 더 직관적이고 쉽게 읽혀 누구든 최소한의 노력으로 코드를 유지보수 할 수 있는 상태로 있는 것을 중요하게 생각합니다.

컴퓨팅 최적화보다는 개발 및 유지보수 최적화

예를 들자면, 저는 최대 범위(n)에 대한 확신만 있다면 O(nLog(n)) 알고리즘 대신 더 읽기 쉬운 O(n^2) 알고리즘을 사용하는 것도 상황에 따라 검토할 수 있습니다. 마찬가지로 한참 들여다봐야 이해가 되는 복잡한 쿼리보다는, 비효율적인 쿼리더라도 더 직관적인 쿼리를 사용하고 비즈니스 레이어에서 후처리를 추가해 같은 결과를 얻어내는걸 검토하기도 합니다.

최적화를 위해 복잡한 설계나 로직, 쿼리 등을 적용하게 되면 퍼포먼스를 얻는 대신 심플함과 가독성을 희생하는 경우가 많습니다. 하지만 비즈니스 로직은 당연하지만 언젠가는 변하고, 그 상황에 최적화된 무언가를 바꾸는건 더 큰 노력이 필요합니다. 최적화를 위한 어려운 코드는 로직이 정착된 이후에 적용해도 늦지 않습니다.

컴퓨팅 비용만 비용이 아닙니다. 피쳐를 개발하고 유지보수 하기 위해 들어가는 엔지니어의 노력 또한 비용이고, 무시할만한 수준의 컴퓨팅 비용의 차이라면 더 간단하고 가독성이 높은 쪽을 선호합니다.

긴 함수 허용

저는 기계적으로 중복되는 코드를 분리해내는 종류의 리팩토링, 그리고 코드가 길어서 인위적으로 분리하는 리팩토링에 대해서는 굉장히 조심스럽게 접근합니다. 분리 후 코드 흐름을 파악하기 어려워지기 때문입니다.

어떤 클래스의 method a, b, c 중 c가 길어 c의 코드만 다시 x, y, z로 분리한다고 했을 때, a b c는 depth 1, x y z는 depth 2 라고 할 수 있습니다. x y z가 더욱 세분화 될 수도 있습니다. 이렇게 되면 하나의 클래스 내에 여러 depth의 함수가 존재하게 되고, 진입지점을 따로 표시해서 위에서부터 타고 내려가면서 확인하거나 아무 함수에서 위아래로 타고 내려가는 형태로 코드를 읽어야 하고, 코드 탐색이 산만해집니다.

그렇기에 응집도 높은 비즈니스 로직이라면, 과감하게 긴 함수도 허용합니다.

코드 내 주석 활용

저는 관리 안되는 주석은 없느니만 못하다는 말에 동의하지 않습니다. 코드나 주석이나 같은 파일 안에 있으면서 코드는 관리하고 주석을 관리 안 한다는건 개발자가 꼼꼼하지 못한 것인데, 코드는 못 없애지만 주석은 없앨 수 있으니 없앤다는 단편적인 생각 같습니다. 주석도 코드와 다르지 않아요. 인접 코드가 업데이트 될 때마다 꾸준히 업데이트 되어야 합니다.

코드를 말로 설명하기보다는 코드 자체가 스스로 설명할 수 있어야 한다는 말에는 동의합니다. 하지만 코드 일부를 외부 함수로 빼내는 기법은 앞서 말씀드린 긴 함수 허용의 의도에 반할 수 있고, 네이밍을 길게 가져가는건 코드를 장황하게 만들기 쉽습니다. 최대한 코드가 스스로 명백하도록 하되, 주석으로 목차/부제 혹은 설명을 추가하면 코드가 훨씬 가독성이 좋아집니다.

Growth Mindset

저는 조금 피곤하게 사는 편일지도 모르겠습니다.

비교할 때는 더 높은 곳을 봐야지. 그래야 재밌잖아?

제 고등학교 시절부터의 모토입니다.
그리고 아래는 제 레주메의 자기소개 부분 일부를 가져왔습니다.

제 모토처럼, 적당과 충분을 넘어서 항상 최선을 지향합니다. 조직에서 그것이 나 혼자만의 노력으로 이루어지지 않는 것을 배웠습니다. 그렇기에 어떻게 하면 다 같이 더 즐겁고 생산적으로 일할 수 있을지 항상 고민하고 개선합니다. 최선을 위한 아키텍쳐, 프로세스, 팀이 이루어내는 케미에 관심이 많습니다.

제가 관심있는 최선은 저 개인의 최선이 아닌 팀으로서 만들어내는 결과물의 최선이고, 그래서 저는 제 IC로서의 성장과 조직의 일원으로서의 성장 양쪽 모두를 중요하게 생각합니다.

Study

오프때도 석사 과정이라던지 교육을 수강하면서, 아니면 개인적으로 부지런히 공부하시는 분들이 많이 계셔서 부끄럽지만, 저도 그런 분들을 롤모델로 나름대로 꾸준히 공부를 하고 있습니다.

Weekends

주말 중 적어도 하루는 카페에 나와 한두시간씩 기술 서적이나 글을 읽기도 하고, 블로그 글을 쓰거나 토이프로젝트 개발을 합니다.

Blog

배운 것을 정리하는 차원에서 블로그에 글도 올리고 있습니다. 언젠가는 지식공유가 가능한 수준까지 올라가는 것을 목표로 하고 있어요.

소모임

코로나 시국에 개발자 모임을 추진했다가 사적 모임 인원제한 등의 이유로 흐지부지 되었습니다.

임의의 모임 관리는 참 어려운 것 같아요. BE / FE / Data / ... 등등 관심사도 경험도 달라 어설프게 모이면 그냥 캐주얼한 자리로 끝나게 된다는 것을 경험으로 배웠습니다. 확실한 중심점이 필요하다고 느꼈어요. 다시 하게된다면 모임 범위를 좁히고 좀 더 시간을 투자해서 준비하거나, 이미 궤도에 오른 모임에 참석하는 방향으로 생각하고 있습니다.

Role Model

가까이 있는 사람들로부터 자극을 많이 받는 편입니다. 특히 동갑, 동연차 엔지니어가 저보다 실력이 뛰어나면 그 사람의 뛰어난 면을 따라잡겠다는 목표가 큰 동기부여가 돼요. (J씨!)

살갑고 정감가는 친화력처럼 모방하려고 해도 좀처럼 쉽지 않은 것들도 꾸준히 노력하고 있고, 가끔 노력이 빛을 발해서 그런쪽으로 칭찬을 들을때 기분이 참 좋습니다.

요즘은 본인의 단점을 보완하기 위해 노력하기보다는 장점을 살리는게 팀 차원에서 더 유리하다는 의견쪽으로 기울면서 제가 더 자신있는 영역 - 중요한 것들 챙기기, 해야 할 말 하기, 회색 영역에서 더 선제적으로 커뮤니케이션 하기 등의 방면에서 더 적극적으로 노력하고 있습니다.

엔지니어의 숙명

소프트웨어 기술은 오늘도 더 빠른 속도로 발전하고 있고, 이를 따라가기 위해서는 엔지니어 스스로가 지속적으로 학습해야 합니다. 엔지니어의 피할수 없는 숙명이지요. 그러지 못하면 정체됩니다. 지금의 기술로 향후 몇 년 동안의 문제를 해결하는게 불가능하지는 않을거에요. 하지만 다룰 수 있는 도구와 기술환경에 대한 이해에 있어서 점차 괴리가 생길겁니다.

Proactivity

문제해결 과정에서 관련 영역의 전문가가 비전문가보다 적극적이고 선제적으로 커뮤니케이션 하는 것이 좋습니다. 그 부분에 있어서는 비전문가보다 더 많은 것들을 보고 고려할 수 있기 때문입니다. 같은 이유로 조직의 소프트웨어 개발 과정에서는 엔지니어가 보다 적극적인 것이 좋습니다.

Proactive Communication

회색지대

일을 역할로 구분할 경우 프로젝트 진행을 위해 필요한 일임에도 불구하고 반드시 누구의 역할이라고 할 수 없는, 하지만 누군가는 해야하는 종류의 일이 적지 않습니다. 저는 제 성향이 그래서인지 웬만한 영역은 다 건드려 본 것 같아요.

엔지니어는 분명 엔지니어링 과제에 충분히 몰입할 수 있는 환경에서 최고의 성과를 낼 수 있습니다. 그럼에도 불구하고 저는 엔지니어가 개발 업무만 하는 것에 반대합니다. 제 지향점은 IC로서의 성과가 아니라 팀으로서의 결과물에 있기 때문입니다. 물론 IC로서의 역할에 지장이 있을 정도가 된다면 곤란합니다. (invoicing...)

Overstepping 에 대한 우려가 있을 수도 있습니다. 회색지대가 나보다 다른 팀원에게 더 가깝다면, 그 팀원을 배려하는 방향으로 잘 접근해야 하겠습니다.

Retrospective

주기적인 회고를 통해 피드백을 주고 받습니다. 좋았던 점, 개선할 부분, 때로는 프로젝트 진행 과정에서는 하지 못했던 이야기도 하고, 다음 프로젝트는 더 즐겁고 유의미한 프로젝트가 되도록 노력합니다.

상황이나 분위기에 따라서 누구를 탓하는 것 처럼 들리지 않도록 조심스럽게 문제 제기를 하는 경우도 있고, 어느정도 공감대가 형성된 문제라면 바로 구체적인 action plan까지 논의하기도 합니다.

때로는 회고 없이 앞만 보고 달리는 경우가 생기기도 합니다. 무언가 문제가 있다는 이야기인데, 그럴때는 지체 없이 더 위로 issue raising 해서 회고 자리를 마련하고 회고가 미뤄지는 이유도 살펴보면 좋습니다.

경청

적극적이되, 열린 태도로 경청해야 합니다.

팀의 개발철학

컨센서스

사람이 다 같을 수 없고, 팀원들의 개발철학이 같을 수도 없습니다. 하지만 팀으로서 일하기 위해서는 매번 논의를 하기는 어렵고, 팀으로서의 컨센서스에 도달한 다음부터는 모두가 그 컨센서스에 입각해서 개발을 진행하는게 좋습니다. 건전한 개발문화 하에서는 이런 견해 차이가 발전적인 논의 안에서 발산되고 다시 하나의 안으로 수렴합니다.

컨센서스가 고정불변은 아닙니다. 팀원의 판단에 따라 컨센서스에 새로운 의견을 더할 수도 있겠지만, 합의 없이 컨센서스를 위반하는건 곤란합니다.

가치가 충돌할 때

조금 더 솔직한 이야기를 해보자면, 저는 조건 (상황, 스펙, 환경 등등) 이 명확하게 주어진다면 어느 가치가 더 실익이 큰지에 대해 정답이 있는 경우가 더 많다고 생각합니다. 견해의 차이도 조건을 다르게 인지하고 있어서 발생하는 경우도 많구요.

보통은 논의 끝에 엔지니어링 리더의 결정을 따라가게 됩니다. 그래서 엔지니어링 리더가 각 팀이 처한 상황을 자세하게 알고 있는게 중요합니다. 상황을 오해하고 있다면 그 리더의 실력이나 경험과 별개로 팀의 상황과 맞지 않는 방향으로 결정이 이루어질 수 있습니다.

맺음말

아직 배울게 산더미인데, 취향이나 스타일이 너무 일찍 생긴게 아닌가 하는 걱정도 들고, 한편으로는 경험에 의해 호불호가 생길만큼 시간이 지났구나 하는 생각도 듭니다. 두서없는 글이고 당연하게도 매우 주관적이지만, 그래서 다르게 생각하시는 부분들이 당연히 많이 있으시겠지만, 그냥 한 개인의 생각이니 유쾌하게 봐주셨으면 좋겠습니다.

커피챗은 언제든 환영입니다. https://coffeechat.kr/with/케네스

profile
개발자 + @

0개의 댓글