구조화된 코드를 작성하는법에 대한 토론

저는 구조화된 코드를 작성하기 위한 일종의 팁으로,

"어떻게 구현하느냐?"에 초점을 두는게 아니라

"어떻게 사용하느냐?"에 초점을 두고 코딩을 전개하면 자연스럽게 구조화 된 코드를 맞이하게 된다고 믿고 있습니다.

관련해서 소중한 경험을 댓글로 공유해주셔서 의미있는 글을 만들어 보는 것은 어떨까요? ^______^

9개의 좋아요

이런 관점에서 저는 TDD가 구조화된 코드를 작성하기 위한 훌륭한 접근법이라고 생각하고 있습니다. 일단 구현했다고 치고 껍데기를 만들어 놓고 테스트를 통과할 수 있도록 구현하는 역순환의 접근이 되기 때문입니다.

5개의 좋아요

상황에 따라 다르겠지만, 개인적으로는 "단일 역할 원칙"이나 여러 “디자인 패턴”, 그리고 "의존성 주입"이나 “의존성 역전” 같은 패턴을 얼마나 잘 활용할 수 있는가를 고민했던게 좋은 포인트였던 것 같습니다. 그리고 이런 주제들은 완성된 주제라기보다 계속 탐구하고 체화하는데 신경을 쓸 만한 주제들인 것 같기도 하고요. :smiley:

6개의 좋아요

경험 해본 것은 아니나, 경험 해보고 싶은 것은 있습니다.

CRC 카드 - 위키백과, 우리 모두의 백과사전 (wikipedia.org)

저는 객체지향설계라는게 RDD를 기반해야한다고 생각하는데, RDD를 하기 위한 추상화 도표를 CRC 카드로 할 수 있는 것으로 알고 있습니다.

RDD가 되어야 OOP의 꽃인 캡슐화를 명확하게 할 수 있다고 생각하기 때문입니다.

그래서 캡슐화를 해치는 상속을 걷어내고 합성으로 최대한 코드를 작성할 수 있을거라고 믿기 때문입니다.

물론…혼자하거나 소규모 프로젝트에서 이렇게 처음부터 구조를 다 잡고 가는 것은 반대지만, 내가 개발자로서 소프트웨어를 정말 잘 만들고, 잘 유지보수하고 싶으며, 내 좋은 이력이 되기 원한다면 구조화를 지향하는 것은 바람직하다고 생각합니다.

5개의 좋아요

객체 지향이 현실 세계를 모사한 프로그래밍 패러다임이라는 관점에서 저는 2가지가 가장 중요하다고 생각합니다.

  • 책임
  • 관계

명확한 책임을 가진 클래스는 굳이 코드를 읽지 않아도 의도를 파악하기가 쉬워 가독성과 유지보수성에 도움이 됩니다.
이들을 군집화하면 Bounded Context로 구성되고, 수평적 관점으로 나열하면 레이어가 될 수 있을 것 같습니다.
그리고 다른 클래스들과 느슨하게 연결된 클래스는 확장성과 재사용성이 높고, 코드 변화에 따른 영향 범위를 효과적으로 제어하는데 도움이 되는 것 같습니다.

4개의 좋아요

좋은 의견들 감사합니다. @rkttu 님의 “단일 역할 원칙”, "의존성 역전"과 @nyjin 님의 책임관계 와 일맥상통해 보이는군요.

즉, 명확한 책임으로 클래스를 설계하고, 클래스와 클래스간 느슨한 연결을 통해 확장성과 재사용성을 높일 수 있을 것 같습니다.

한편, 입문자가 접근하기에는 다소 어려워 보이기도 하는데요, 입문자 입장에서 단계적으로 구조화된 코드를 짤 수 있는 좋은 방법은 무엇일지도 나누면 여러 분들께 도움이 될 것 같습니다.

3개의 좋아요

RDD에 대한 기본적인 개념은 알지만 RDD를 따로 공부해서 프로그래밍 해보지는 않았습니다. CRC 카드라는것도 @Vincent 님 덕분에 알게 되었는데요, 혹시 CRC 카드를 서비스 형태로 만들 수 있는 툴이라던가 알고 계신게 있을까요?

3개의 좋아요

안타깝게도 저도… 오브젝트라는 책에서 개념적으로만 접했고 자료를 찾아보니 대충…어떻게 하는거다 라는거만 알겠어서 툴은 잘 모르겠습니다.

언젠가 팀에서 사용해보고 싶은 방법입니다.

브레인스토밍이니까 머리에서 나오는 아이디어를 스케치하는 만큼 우선 노트같은데서 기획팀하고 함께 뇌피셜적으로 작업하다가… 대충 클래스 다이어그램 같은 것으로 그림을 그려보면 되지 않을까 하고 생각했었습니다.

3개의 좋아요

구현할 수 있는 기술의 범위 내에서 구조와 설계가 나오는 것 같습니다.
같은 기능을 구현하는 데에 있어서 a, b 라는 방법이 존재한다면
b방법을 모르는 사람은 그에 맞는 설계조차 할 수가 없듯이요…
예컨대 async/await 패턴을 모르는 사람들에겐 그에 맞는 설계가 불가능한 건처럼요.
callback을 구현하는 패턴, 구조말고는 다른 방법이 없으니까요.

아, 결론을 안 적었네요…
“되도록 많은 기술을 경험해봐야 구조적인 설계가 가능하다”

다 쓰고보니 웬 뻘글이…

7개의 좋아요

개발 처음할 때를 더듬어 봐야 되겠네요 ㅎㅎ;;

UML 책도 보고, 디자인 패턴 책도 보고 했던 것 같은데 이상하게 실무까지 연결이 잘 안됐던 것 같습니다.
TDD도 사실 막상 하려면 주니어 개발자들은 대하기 어려울 것 같아요.

그래서 저도 한참 멀었지만 입문자분들에게 구조적인 코드 작성에 대한 방법으로 2가지 정도 말씀 드릴 수 있을 것 같아요.

첫번째는 남의 코드를 많이 봐야 됩니다.
단순히 보는게 중요한게 아니고, 관심을 가질 수 있는 분야의 좋은 코드를 보는 것이죠.
예를 들어서 현재 회사의 기술 스택이 WPF면 MVVM 패턴으로 잘 작성된 어플리케이션의 github 코드를 clone해서 ViewModel과 View와의 관계는 어떻게 설정 했는지… IoC/DI는 어떤 프레임워크를 썼고, 어떻게 적용했는지, 그리고 ViewModel 내에서 서비스 클래스들은 어떻게 사용하고 관계를 맺게 하는지 등을 분석하는거죠.
테스트 코드도 함께 분석할 수 있으면 좋고, 분석 대상 어플리케이션이 많으면 많을수록 좋을 것 같습니다.
그리고 좋은 코드라고 생각되는 부분들은 자신의 분야에 적용해 보는 것으로 체득해 나갈 수 있을 것 같아요.

두번째는 자기 코드를 의심(?) 하는 코드 부채 관리 또는 나쁜 냄새를 맡는 습관을 갖는 것입니다.
개발 업무만 계속하여 개발 실력이 향상되면서 구조화된 코드를 작성할 수 있을 것 같지만, 실제 현실은 그렇지 않은 경우가 대부분입니다.
작성하는 코드가 최선인지 더 좋은 방법은 없는지 끊임 없이 자신의 코드를 의심 코드 부채를 관리하는 습관을 가지는 것이 좋을 것 같습니다.
예를 들어서 xaml의 버튼 클릭 이벤트 핸들러로 코드 비하인드에서 웹API 호출하여 메시지 박스를 처리하는 시나리오가 있다고 가정하면, 다음과 같은 과정으로 리팩토링을 해나갈수 있을 것 같아요.

  • 이벤트 핸들러 대신 ViewModel로 작성하는 게 좋지는 않은지 고민해 보고, ViewModel의 Command 함수로 서비스 시나리오를 작성해 봅니다.
  • ViewModel의 API 서비스 호출 코드가 클래스로 분리할 필요가 있는지 고민해 보고, 서비스 클래스로 분리한 후 관계를 설정합니다.
  • API 호출 이후 메시지 박스 처리가 ViewModel 내에서 이뤄지는게 적절한지 고민해 보고, 서비스 클래스로 분리하거나 메시지 버스를 연결하는 등으로 확장해 나갈 수 있을 것 같습니다.

결국 리팩토링을 통해 관심사의 분리를 체득해 나갈 수 있는데, 근본적으로 코드에 얼마나 많은 관심과 애정을 갖느냐에 따라 그 역량이 좌우되는 것 같아요.
리팩토링하면서 테스트 코드를 작성하면 금상첨화겠네요.

8개의 좋아요

글 감사드립니다.

계속해서 자신의 코드를 의심하고 좀 더 상황에 맞는 구조를 찾는 노력은 성장하고 있는 프로그래머라면 공감해야 하는 올바른 방향성이라고 생각합니다.

결국에는 사부작 사부작 리팩토링을 친구로 삼아 다듬는게 필요한 것 같네요.

한편 저는 프로그래밍 기본을 숙달하는 것이 사고력 훈련과 밀접한 관련이 있다고 생각하고 있습니다.

하지만 개인의 성향으로 인해 사고력을 키워나가면서 스스로 프로그래밍을 정복하는 사람이 있는 반면, 사회 생활의 목적이라던가 훈련 방법을 잘 몰라서 비효율적으로 (물론 우리는 모두 비효율적으로 성장해온 경험을 가지고 있고 어느정도 가져야 하지만!) 성장할 수밖에 없는 것 같은데요,

제가 화두로 꺼내온, “이미 있다고 가정하고” 구조화 하는 훈련이라던가, 뭔가 좀 더 쉽게 접근할 수 있는 가이드라인이 있으면 어떨까 하는 생각도 듭니다.

그러니까 “어떻게 하는지는 모르겠는데 잘못된 건 알겠더라” 정도까지의 감각이랄까.

예를 들어 큐브를 맞춘다고 할 때 내가 모든면을 다 맞추지는 못했지만 최소한 안맞는것은 눈으로 확인할 수 있듯이 뭔가 기준이 명확하다면 계속해서 수정해 나갈 수 있을 것 같습니다.

이런것이 말씀하신 "책임"과 “관계” 겠지요!

5개의 좋아요

이런 노력들이 건강한 코드를 만드는 문화로 자리 잡을 수 있으면 좋겠네요~
정답은 없지만, 작성한 코드를 올려 놓고 토론할 수 있는 창구가 있으면 사례가 쌓여 가이드라인까지 발전할 수 있지 않을까하는 희망회로를 돌려 봅니다~ :grinning:

4개의 좋아요

@CODE_REAPER 님의 의견도 맞습니다.

내가 뭘 모르는지 모르는 것 에서 최소한 내가 뭘 모르는지 아는 것 정도의 지식과 경험을 습득해야 찾아가면서 그 문제를 풀 수 있을 것 같습니다.

이러한 맥락에서 되도록 많은 기술을 경험해야 할 것 같네요 ^^

3개의 좋아요

저도 @nyjin 님의 의견에 매우 동감합니다.

저도 코드를 만들 때 역할(책임 범위)을 가장 먼저 생각하고
클래스를 만들 때는 관계추상화 수준을 중요하게 봅니다.

역할을 고민한다는 것은 SRP를 준수하는 코드를 생성하려 노력하는 것이고
관계와 추상화 수준을 고민한다는 것은 캡슐화와 객체지향적 코드 생성을 고민한다는 것 같습니다.

추상화 수준을 고민한다는 것은 또한 객체의 관계를 설정하는 아주 중요한 행위이고
이러한 고민의 결과가 전체적인 코드의 추상화 수준을 높혀, 변화에도 강하며
자잘한 if문으로 세세하게 작성된 코드가 아닌 논리적인 흐름으로 동작하는 코드를 작성하는데 도움을 준다고 생각합니다.

그리고 마지막으로 가장 중요한 리펙토링을 합니다.

정확히 기억은 나지 않지만 아마, 클린코드의 저자 이신 로버트C마틴도 그의 저서에서
어떻게 이런 완벽한 코드를 작성합니까?”에 대한 대답으로
아무리 본인이라도 한번에 이런 코드는 나오지 않습니다. 여러 번의 리펙토링을 하지 않으면 이런 코드는 만들어 낼 수 없습니다.” 라고 답변하였던 걸로 기억합니다.

저도 로버트C마틴님과 같은 생각을 합니다. 아무리 고민하고 여러 번 읽어보며 작성된 코드라도
작성 완료 후 리펙토링을 해야 진정으로 작성자가 만족할 수준의 코드가 생성 되었습니다.
작성된 코드를 다시 보면 꼭 처음에 선언했던 변수의 이름이 제가 처음에 생각했던 의미가 아닌 경우가 많았습니다.

6개의 좋아요

여기까지 찾아오신 분들이니 만큼…역시 다들 구조화를 중요하게 생각하시네요.

물론 저도 같은 구조화, 추상화, 책임… 이런 단어들을 언급했지만 그것을 인식하는 단계이고 실제 구루같은 분들보다는 한참 아래의 추상화 훈련도를 가졌을 거 같아서 노력을 많이 해야 할 것 같긴 합니다.

문제는 그런 경력을 쌓을 수 있는 회사가 많지 않다는 점인 것 같습니다.
20년차, 30년차 개발자가 되더라도 이런 인식이 있지 않은 채 경력이 쌓인 분이면…저는 좀 상상이 어렵군요 ㅠ

3개의 좋아요

사실 구조화 공력이 경력과 반드시 따라가지는 않는 것 같아요. 개인의 욕심과 성향도 영향을 주고 또 팀의 분위기도 중요한 것 같아요. 또 구조화에 욕심이 생겨서 회사를 고르다가 실망도 하게 될 것 같고요. 왜냐하면 현실은 꼭 훌륭한 구조화가 모든 답은 아니니까요. 납기일도 중요하고 구조가 단순해야 후임이 학습하기 용이한 것도 있지요.

4개의 좋아요

네 저도 간단한 프로그램에 대해 너무 고도의 추상화는 오히려 불필요하다고 생각합니다.
대규모 프로젝트일수록 고도의 추상화가 되어야한다고 생각하는데…대규모프로젝트를 하는 회사를 가보는 게 중요할 것 같네요…ㅎㅎ

5개의 좋아요

캬… 여러모로 좋은 말씀 감사합니다.

2개의 좋아요

변성(Mutable)과 불변성(Immutable) 관점에서 구조화를 조명해보면 또 재밌을 것 같습니다.

객체지향 프로그래밍 언어는 이미 검증된 훌륭한 개발 방법론을 전개할 수 있지만 개체의 상태 변화로 인해 다양한 문제가 발생할 수 있다는 점은 약점일 수 있겠습니다.

이와 관련해서 또 댓글을 통해 나눔을 했으면 좋겠어요 ^_____^

4개의 좋아요

나와 관계된 모든 사람들에게 내 사생활까지 공유할 필요는 없는 것 처럼 코드 또한 마찬가지로 어떻게 구현되었는지는 노출하지 않고(private) 어떻게 사용할 수 있는지만 노출(public)하는 전략이 중요합니다. 모든 것이 노출된다면 원하지 않는 기능 때문에 원하는 기능을 찾고 사용하는게 더 많은 에너지가 필요할 테니까요. 이것을 이해했다면 객체지향 프로그래밍 방법론의 캡슐화를 이해한 샘입니다.

한편 객체지향 프로그래밍 방법론에서는 상태가 변할 수 있음(mutable)과 상태가 변할 수 없음(immutable)을 구분하지 않습니다. 상태가 변할 수 있음은 코드 블럭이 커져서 객체의 특성을 완전히 파악할 수 없게 되었을 때 버그를 만들어낼 여지를 줍니다. 예를 들어보죠.

C#에서 문자열은 불변성을 가집니다. 문자열의 가공이라던가 효과적인 메모리의 사용 측면에서는 변성이 더 유리한데요, C#의 문자열이 불변성이 된 이유는 변하게 될 경우 그것을 마땅히 통제할 방법이 없다는 점입니다.

불변성의 장점은 스레드 동시성의 문제가 없다는 점인데요, 상태가 확정되어 있다면 되도록 불변성 객체를 사용하는것이 좋겠습니다.

하지만 상태가 확정되어 있지 않을 경우 불변 객체는 성능에 문제가 발생합니다. 불변 객체로 변한 상태를 표현하는 유일한 방법은 새롭게 객체를 생성하는 방법뿐인데요. 그래서 상태가 빈번히 바뀔 경우 비효율적입니다.

이렇게 대상의 상태가 변하는지 변하지 않는지에 따라 변성으로 객체를 생성할지 불변성으로 객체를 생성할지를 구분해준다면 또 그런 구조에 대한 고민이 좀 더 안정적인 구조를 만들 수 있는 방법이라고 생각합니다.

6개의 좋아요