AI Coding Assistant 개인 프로젝트 그 이후 업무에 적용하기 위한 고민

 최근 사이드 프로젝트로 앱을 만들고 출시하면서 AI Agent 기반 개발을 여러 방식으로 실험해봤습니다.


개인 프로젝트에서 이것저것 부딪혀보고 나서, 실제 업무에 적용해보기 위해 회사에서 사용하던 스프린트 방식을 이 흐름에 적용해보고 싶어졌습니다.

기존의 터미널 기반 방식이나 랄프 스타일의 흐름은 분명 강력했지만, 지금 어떤 작업이 어떻게 진행되고 있는지 한눈에 파악하기 어렵고, 실제 업무처럼 플랜을 검토하고 승인한 뒤 다음 단계로 넘기는 흐름을 담기에는 아쉬움이 있었습니다.

그래서 이번에는 OpenCode Agent 기반 개발 방식을 실제 업무에서 사용하던 스프린트 프로세스와 결합해, 웹에서 진행 상황을 칸반 형태로 확인할 수 있는 Assistant Agent Kanban을 구현해봤습니다.

이 시스템은 파일 기반으로 동작하며, 플랜, 구현, 리뷰, 인간 검토, 최종 완료까지 단계를 나누고 각 단계에서 Agent와 사람이 역할을 나눠 작업하도록 구성했습니다.

플랜 에이전트가 요구사항을 바탕으로 계획을 만들고, 사람은 그 플랜을 검토하고 수정한 뒤 구현 단계로 넘깁니다.

이후 구현 에이전트와 리뷰 에이전트가 서로 주고 받으면서 작업을 반복해서 진행하고, 마지막에는 사람이 브랜치, git diff, 코멘트 기반으로 직접 검토할 수 있도록 했습니다.

또 최종 완료된 작업은 기준 브랜치 단위로 AI 회고를 남길 수 있게 해서, 단순히 작업을 끝내는 데서 그치지 않고 스프린트 단위로 작업 내용을 돌아볼 수 있도록 구성했습니다.

제가 해오던 업무 방식이 정답은 아니겠지만 이번 작업을 통해, 사람이 익숙하게 사용해오던 업무 프로세스가 AI와 협업하는 환경에서도 충분히 유효하고 강력할 수 있다는 점을 확인할 수 있었습니다.

지금은 OpenCode 기반으로 동작하고 있지만, 앞으로는 codex-cli나 Claude 기반으로도 확장할 수 있을지 검토해볼 예정입니다. 그리고 이 방식이 실제 업무 환경에서도 지속적으로 유의미하게 작동하는지 계속 실험해보려고 합니다.







+@
Coding Assistant(OpenCode + ChatGPT) 를 사용하고 경험를 토대로 만든 도구를 사용해 간단한 게임 앱을 30분 안되서 초안 만드는 것을 영상으로 담아봤습니다.

터미널을 사용할 때 하면 시각화가 조금 아쉬웠는데, 시각화 해서 단계별 진행이 되니까 조금 더 가속도가 붙는거 같았습니다.

ps. 영상은 롱테이크로 끊지 않고 한번에 녹화로 빠른배속으로 편집했습니다.

OpenCode 로 앱 개발 및 출시 회고




배경

  • 우리 회사에서는 개발 업무에 AI를 적극 도입해 활용하고 있음.
  • 업무에서의 활용을 넘어, AI Agent를 개발 파트너로 두고 실제 제품을 기획부터 출시까지 끝까지 완주해보는 경험을 해보고 싶었음.
  • 이전에 직접 사용하려고 스캔 앱을 하나 만들었고, 그걸 출시해보려고 했음.
  • 스캔 앱은 너무 타겟팅 되어 있고, 고도화 기능들이 필요하기 때문에 간단한 앱을 추가로 해서 배포를 검토함.
  • 그러던 중 지하철에서 영상 같은걸 보면서 출퇴근 시간을 보내기 보단 간단하게 뇌를 활성화 하기 위해 스도쿠 게임을 하고 싶었음.
  • 스도쿠 게임을 받았는데 광고가 너무 많고 게임 자체를 방해하는 것에 화가 나서 직접 만들기로 결정.
  • 하나만 하면 아쉬우니까 아이들이 간단하게 즐길 수 있는 게임도 하나 개발하기로 결정.

목적

  • 내가 직접 할 “스도쿠” 게임을 만들자

  • 아이들에게 시킬 간단한 게임으로 “세모 땅따먹기” 게임을 만들자

    (회고를 작성하던 도중 2일 정도 투자하여 “메모리 게임” 도 추가)

  • iOS / Android 출시까지 진행해보자

방식

  • Agent 에게 일을 시키고 직접 확인하고 다시 일을 시키고 다시 확인하고, 더 나은 방향을 검토하고 지속적으로 개선

진행

초기 뼈대 작업

  • OpenCode 를 통해서 Flutter 로 앱 개발 진행
  • 어떻게 설명해야 좋을지 LLM과 대화를 통해 방향을 같이 정하고, 어떻게 Agent 에게 일을 시켜야할지 정리를 함
  • 초기에는 작은 기능으로 시작하기로 결정하고 Agent 에게 간단한 기능 부터 구현

개발자 라이센스 취득

  • Apple Developer 등록
    • 개인 개발자 계정으로 등록
    • 1년마다 연장해야하고, 비용이 약간 있는 편, 프로세스 별로 진행을 하면 어렵지 않게 가능
  • Google Developer 등록
    • 개인 개발자 계정으로 등록 (혹시 모르니 유료 상품 가능한 계정으로 등록)
    • 한번만 결제하면 영구적, 비용 저렴
    • 다만, 계정을 생성을 하기 위해 인증을 해야하는 과정이 상당히 복잡했음
      • 현 주소를 인증할 수 있는 자료를 제공해야함. 주민등록등본 제출이 제일 간단

광고 삽입 검토

  • Google AdMob 을 통해서 앱에 광고를 심어보기로 결정
  • 역시 어떻게 가입하고 설정 해야할지 부분은 LLM과 대화를 통해 진행
  • 일단 코드 개발을 했다가, AdMob 에 앱인증이 출시 후 가능해서 .. 화면 영역에서 제거 진행

인앱 상품 검토

  • RevenueCat 이라는 서드파티를 통해서 진행 검토
  • 테스트 모드로는 손쉽게 가능해서 릴리즈에도 사용가능할 것이라는 것을 검토함
  • 코드 구현 까지 해서 연동은 했지만 초기 출시시 제외하기로 결정

앱 심사 요청

  • 앱 심사의 복잡한 절차를 어떻게 해야할지 LLM과 대화를 통해 진행

  • 심사요청은 Apple Store, Google Play 둘다 일단 어렵지 않게 올릴 수 있었음

    → 개인 정보 처리 방침 페이지가 있어야 하기 때문에 Notion 으로 생성

고난의 시작

  • 애플 심사 도중 광고가 없는데 왜 광고 있다고 하냐고 리젝 당함

    → 코드 완전 클린하게 제거해버림

  • 구글 심사 는 무난하게 통과 했지만 예기치 못한 상황에 직면

    • 수익을 내가 위한 계정으로 만들면 Google Play 에 가입 시 인증했던 “주소” 가 노출이 되어버림..
    • 수익 = 인앱 외 광고도 수입으로 보기 때문에 주소가 노출이 되버림.
    • 이건 사업자 등록도 하고 공유 오피스 같은곳의 주소로 인증을 해야하기 때문에 포기.. ㅠㅠ
  • 연관해서 애플쪽 정책도 알아 봄

    • 주소공개 같은 것 없이도 광고까지는 개인 개발자도 가능
    • 인앱 결제를 추가하려고 하면 사업자 등록을 해야 함

앱 심사 통과

  • 앱스토어는 어렵지 않은 수정으로 통과 됨
  • 플레이 스토어는 일단 포기

앱스토어 출시 후 빠르게 기능 업데이트

  • 공유를 해서 사용자가 직접 바이럴을 하면 좋을 것 같아 공유 가능한 컨텐츠 추가

  • 초기 의도가 나와 아이들이 하기 위한 것을 만드는 것이었기 때문에 아이들의 과한 플레이를 제한하기 위한 방어장치 도입

  • 제거 했던 광고를 다시 붙여보기로 결정

  • 본인과 아이들이 사용하는 환경이 iOS 이기 때문에 안드로이드 출시는 과감하게 보류

    → 그래도 아까우니까 원스토어에 출시. (원스토어는 개인 개발자도 광고를 붙일 수 있음)

    → 갤럭시 스토어도 검토를 했었으나, 해당 스토어에 앱을 등록하려면 사업자 등록증을 제출해야 했음

결과물

앱 소개 페이지

iOS (App Store)

Android (원스토어)

회고

  • 단순 개발까지는 빠르게 진행할 수 있었고, LLM 과의 핑퐁을 통해 서드파티를 사용하는 것이나 빠르게 진행가능한 방향성도 결정할 수 있었음.
    • Agent 에게 개발을 요청할 때 뼈대를 처음에 만들고.
    • 작은 기능 단위로 요청 & 확인을 반복하는 방식의 작업이 상당이 용이 했음.
    • 그리고 기능 개발을 할 때 실패하는 것에 대해서는 과감하게 되돌리고 시작할 수 있는 용기도 생겨야하기 때문에 작은단위 및 git 을 사용하며 진행해야 용이 할 수 있음.
    • 그리고 한번 만들고 나면 그 다음부터는 속도가 더 빨라졌음.
      • 진행을 하면서 관련된 지식을 획득하고, 그 기반으로 Agent 에게 요청하기 때문이라 생각함.
  • 하지만 더 어려운건 그 다음 이었음.
    • 앱 심사 및 출시를 하는 것이 의외로 스트레스 영역이었음.
    • 개발자 계정 같은것은 제대로 사전조사를 통한 검토하지 않고 시작한 문제도 있었음.
  • 앱을 만들고 내가 직접 플레이를 하고, 아이들이 재미있게 플레이를 하는 모습을 보면 뿌듯했음.
  • 하지만, 누군가 경험을 위해 앱을 만들고 소소하게 돈을 벌어보고 싶어서 앱을 만든다고 하면 말리고 싶음.
    • 그냥 웹 기반의 서비스가 훨씬도 빠르고 간편하게 셋업이 가능할 것이라고 생각했음.
    • OCI 같은것을 이용하면 비용없이 초기 서버 셋팅도 가능하고, DB 도 firebase 같은걸 활요해서 무료로 시작해볼 수 있을 것이라 생각함.

OpenCode를 활용한 문서 스캔 앱 개발 회고


배경

  • 아이 문제집 종류가 많아, 매번 외부로 갈 때 문제집을 가지고 가서 하는 것은 번거로움이 있음
  • 스캔을 해서 PDF 로 만들어서 해당 PDF 를 가지고 문제를 풀고 싶음
  • 가정용 스캐너로 많은 양의 스캔은 상당한 번거로움이 발생
  • 전문 스캐너를 통해 스캔하는 방법은 별도의 비용이 발생되고 문제집을 전부 커팅해야 함
  • 유사 앱이 존재하지만 무료버전에서는 제약이 존재하기 때문에 번거로움

목적

  • 생활속에서 필요한 부분을 직접 구현을 해보자
  • 직접 구현하기 보단 에이전트 방식의 개발로 진행을 통한 AI 시대의 개발 방법을 경험하자

사용 툴 및 LLM 모델

  • OpenCodeoh-my-opencode 를 활용
  • github copilot 에서 제공하는 모델 사용
    • gpt 5.2
    • gpt 5-mini
    • gpt 4o
    • gpt 4.1
    • claude opus 4.5
  • 직접 생각 및 고민을 위해 google gemini 추가 활용

oh-my-opencode.json

{
  "$schema": "<https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/assets/oh-my-opencode.schema.json>",
  "agents": {
    "sisyphus": {
      "model": "github-copilot/gpt-5-mini"
    },
    "librarian": {
      "model": "github-copilot/gpt-4.1"
    },
    "explore": {
      "model": "github-copilot/gpt-5-mini"
    },
    "oracle": {
      "model": "github-copilot/gpt-5-mini"
    },
    "frontend-ui-ux-engineer": {
      "model": "github-copilot/gpt-4o"
    },
    "document-writer": {
      "model": "github-copilot/gpt-4.1"
    },
    "multimodal-looker": {
      "model": "github-copilot/gpt-4o"
    }
  }
}

개발 진행

1차) 최초 진행

  • 카메라로 사진을 찍고, 해당 사진을 PC 로 이동하여 파이선으로 구현하여 cli 를 통해 진행하는 방식으로 OpenCode에게 요청.
  • 문서 영역을 잡기 위해 OpenCV 기반 파이선 라이브러리 검토
    • 원하는 퀄리티가 나오지 않음
  • 문서 영역을 더 잘잡기 위해 딥러닝 기반 라이브러리 검토
    • 어느정도 퀄리티가 나왔지만, 일부 사진을 픽해서 영역을 수정할 수 없고 오직 자동화만 가능 (cli 기반)

2차) 생각의 전환

  • 최초 진행한 파이선 cli 코드 기반으로 OpenCode에게 flutter 앱 구현 요청
  • 역시나 원하는 퀄이 나오지 않고, 진행을 할 수록 점점 이상 동작을 하기 시작

3차) 다시 생각의 전환

  • 최초 진행했던 것에 대한 소스코드 및 기반 문서 전부 폐기 후 새로 시작
  • 모든 기능을 한번에 OpenCode에게 요청을 해 한번에 “짠” 하고 싶었지만, 이 부분도 원할하게 되는 것 가지 않았음
  • “어느정도” 의 기능을 축소하여 바이브 코딩형태로 단계별 개발을 진행해보는 방법으로 전환

4차) 최종 진행

  • 단계 별로 OpenCode 에 요청 하고, 결과가 원하는 수준이 아니면 개선 요청 또는 rollback 하고 다시 요청
  • 토큰을 아껴쓰기 위해 모델 변경하며 작업
    • 큰 작업일 때만 sisyphusoracle 을 opus 4.5 와 gpt 5.2 로 전환해서 사용
    • 일반적인 작업일 때는 위 설정과 같이 gpt 5-mini 를 사용

대략적인 작업순서

  • 초기 프로젝트 요청
    • 카메라에서 이미지 추가 기능 구현
    • cunning_document_scanner 패키지 사용. 카메라로 문서를 스캔 → 이미지 목록에 추가
    • 갤러리에서 이미지 사진 선택 기능 구현
      • edge_dection 패키지 사용. 갤러리에서 이미지 사진 선택 후 문서 스캔 → 이미지 목록에 추가
    • 추가된 이미지 관리 구현
    • 추가된 이미지 클릭 시 미리보기 구현
    • 권한 관련 문제 해결하기 위해 gemini 를 통한 자료 조사 후 개선 요청
  • 버튼 UI/UX 개선 요청
  • PDF 기능 구현 (생성, 미리보기, 목록, 관리, 공유)
  • 추가된 이미지에 메모하기 기능 구현 (펜, 형광펜 메모)
  • 이미지 사진 여러장 선택 기능 추가 구현
    • 몇 번 시도해봤지만 정확히 되지 않아 gemini 와 리서치를 통해 기존 라이브러리로 불가능한 것을 깨달음
    • 해당 부분은 image_picker 후 opencv 를 통해 커스텀 구현이 필요했기 때문에 고성능 모델 활용
  • 버그 개선 및 UI/UX 개선 요청
  • 이미지 목록 그룹 기능 구현 요청
    • 단일 이미지 관리에서 복수 이미지 관리하게 개선
  • 소스코드 클린징 요청
    • 전체 코드를 읽고 잘 작업해야하는 부분이 있어 고급 모델로 수행

결과물

회고

  • flutter를 개발해본적이 없었기 때문에 초기에 어떻게 진행해야할지 고민이 있었음
    • gemini 같은 것과 간단한 검색을 통해 플루터 껍데기 돌아가는 것부터 터득해야했음
    • xcode, 인증서 관련, 실행방법 등등..
  • 코드를 직접적으로 수정을 하지 않았기 때문에 글을 작성하는 지금도 flutter 나 swfit 문법은 전혀 모름
  • 몇번의 실패는 있었음
    • 전체 요구사항을 한번에 제공을 하면 어려움이 있음
    • 기능 하나씩 작계 쪼개서 성공할때까지 작업을 하라고 하고 성공을 하면 사용성이나 진짜 내가 원하는 바와 동일하게 구현이 됐는지 확인이 필요했음
    • 만약, 이때 작게 쪼개지 않고 작업을 하면 원하는 결과물이 나오지 않았을때 rollback 하는 선택지가 쉽지 않을것 같음
  • Coding AI 를 활용하는 경험을 해볼 수 있었음.
    • 진행 전 은 아래와 같은 단편적인 작업들을 진행해봄
      • 간단한 코드 도움, 테스트 코드 작성 등을 시작으로 Coding AI 를 시작
      • 내가 작성한 코드에 Review 하는 것으로 처음 Agent 를 활용해봄
      • 조금 더 확장해보기 위해 Agent 를 통해 작은 기능 개발을 진행해 봄
    • 가끔 답답하긴 하지만 그래도 내가 하는 업무에 도움이 되고 시간을 쭐여주는 고마운 존재가 됐음
    • 새로운 걸 만들면 더 잘 할 거 같은데.. 어떻게 시작해야할지 엄두가 나지 않았을때 적절한 주제가 나타나서 시도해봄
      • OpenCode 를 활용을 적극적으로 해볼 수 있었고, 어떻게 일을 시켜야할지 조금더 꺠닫는 시간이 될 수 있었음
      • 해당 방법을 통해 현재 구현된 코드.. 현재 업무에 어떤식으로 적용을 하는게 좋을지 감을 조금더 잡을 수 있던것 같음

도서 내용 정리 - 스태프 엔지니어

개요


네이버 도서 정보: https://bit.ly/3JzLvQr

개발자는 관리자로만 커리어를 쌓아야 하는가?
관리자가 아닌 기술 리더로 성장하는 길은 없을까?

IT 업계가 계속 성장하면서 전에 없던 팀과 조직의 경계를 넘어서는 큰 문제를 다루게 되었다. 그러면서 많은 기업에서 기술적 전략을 주도하고, 경계를 넘어 프로젝트를 리드할 수 있는 관리자가 아닌 ‘경험 있는’ 엔지니어가 필요하다는 점을 자각하고 있다. 이러한 엔지니어는 어떻게 탄생하며, 이들의 역할과 업무는 무엇일까? 아직 여러 기업이 공유하는 보편적인 경력 개발 방법이 없거나, 그 직함이 일관적이지 않고 매우 다양하게 존재한다.
이 책은 이런 엔지니어를 ‘스태프 엔지니어’라는 직함으로 설명하고 있다. 모호한 스태프 엔지니어의 역할과 유형을 정리했으며 엔지니어링 전략 작성하기, 기술 품질 관리하기 등 스태프 엔지니어로서 해야 할 일들도 소개한다. 또한, 스태프 엔지니어가 될 수 있는 현실적인 주제인 스태프 프로젝트 수행하기나 조직에서 자신을 드러내는 법, 이직하기 등도 설명한다. 마지막으로 우버, 매일침프 등의 현업 스태프 엔지니어 14명에게 듣는 생생한 경험과 노하우까지 살펴볼 수 있다.



스태프 엔지니어 유형


기술리드

특정 팀의 방법과 실행을 가이드 한다. 단일 매니저와 밀접하게 협업하지만, 필요할 경우 둘 또는 세 명의 매니저와 협업 하기도 한다. 일부 기업에서는 기술 리드와 유사한 기술 리드 매니저라는 역할도 있다. 이 역할은 엔지니어링 관리자 진로에 해당하며 사람 관리에 대한 책임도 겸한다.

아키텍트

중요한 영역에서 엔지니어링의 방향과 품질, 접근법의 정의를 책임진다. 이 과정에서 기술 제한, 사용자 요구, 조직의 리더십에 대한 상세한 지식을 활용한다.

해결사

여러 복잡한 문제를 파고들어 적절한 해결책을 찾아낸다. 일부는 오랫동안 특정 분야에만 집중하지만 조직 리더십의 지시에 따라 여러 분야를 넘나 들기도 한다.

오른팔

임원의 주의를 넓히고 임원의 역할과 권한을 위임받아 특히 더 복잡한 조직을 운영한다. 대규모 조직에서는 리더의 리더십이 미치는 범위를 넓혀준다.



스태프 엔지니어의 실제 업무


  • 기술적 방향의 설정과 수정
  • 멘토십과 스폰서십
  • 의사 결정에 엔지니어링 관점의 제공
  • 새로운 해결책 모색
  • 접착제 역할 하기 → 눈에 띄지 않더라도 팀이 계속해서 발전하고 완료한 작업을 내보내는데 필요한 작업을 하는 것

직책이 중요한가?

  • 비공식적으로 실력을 검증하는 절차를 우회할 수 있다. → 신뢰를 위한 에너지를 소비할 필요가 없다.
  • 스태프 엔지니어링 회의에 들어갈 자격을 얻는다.
  • 현재의 직장 생활과 경력에 대한 보상이 증가한다.



스태프 엔지니어로 활동하기


중요한 일에 집중하자

  • 쉬운 일을 주워 먹지 말자 
  • 자기 과시하지 말자
  • 과거 경험에 너무 의존하지 말자
  • 실제로 문제가 되는 부분에 참여 하자
  • 자리가 있으면서 관심도 받는 업무를 추진하자
  • 주변 팀이 성장하도록 도와주자
  • 프로젝트 방향이 엇나가지 않도록 수정하자
  • 프로젝트 마무리할 수 있는 수준으로 조정해주고 올바른 방향으로 전환해주자 
  • 나만 할 수 있는 일을 하자

엔지니어링 전략을 기록하자

<설계문서를 작성하자>

  • 언제 작성하나?
    • 나중에 진행할 여러 프로젝트가 공통적으로 사용할 기능인 경우
    • 사용자에게 의미 있는 영향을 주게될 프로젝트 인 경우
    • 기간이 할 이상이 걸리는 일인 경우
  • 어떻게 작성하나?
    • 문제를 확실하게 제시
    • 간결한 템플릿 사용
    • 작성은 혼자 리뷰는 함께
    • 완벽주의를 버리자

<전략 문서 작성에 대해..>

  • 현재 가진 것 부터 시작
  • 구체적인 사항을 기술
  • 주장을 분명히 해야 함
  • 작업물을 보여줘야 함.

<비전 수립>

  • 향후 2-3년을 위한 내용을 작성
  • 비즈니스와 사용자를 토대로
  • 거만한 태도보다는 낙관적인 태도를 갖자
  • 구체적이고 명확하게 작성하자
  • 한두 페이지로 정리하자

기술 품질의 관리

<문제점>

  • 즉각적인 문제를 유발하는 바로 그 지점을 수정한다.
  • 품질을 개선하는 것으로 알려진 권장 사례를 도입한다.
  • 소프트웨어의 변화에 따라 품질을 유지할 수 있는 지렛점에 우선순위를 둔다.
  • 조직에서 소프트웨어를 변경하는 방법에 대한 기술적 요소를 조정한다.
  • 기술 품질을 측정해서 품질 향상에 대한 더욱 많은 투자를 종용한다.
  • 품질 개선을 위한 시스템과 도구를 구현한 기술 품질 팀을 꾸린다.
  • 품질 프로그램을 실행해서 품질 수준을 측정 및 추적하고 낮은 품질 수준이 발견되면 이를 개선한다.

<계단 오르기>

  • 빠르게 적용할 수 있는 것부터 먼저 시작하자! (어려운 것을 도입했다 실패하는 것보다 쉬운 것을 도입했다 실패하는 것에서 더 빨리 배울 수 있다.)

<작게 시작하고 천천히 추가하자>

  • 작은 것 부터 시작하고 정상 궤도에 올라설 때까지 반복
  • 그런 다음 다른 기법을 추가하고 또 다시 반복

지휘권 가진 사람과 긴밀하게

리드하려면 따라야 한다

  • 우선순위가 높은 것이 무엇인지 스스로 명확히 이해하고 주변에서 일어나는 일 때문에 흔들리지 말자
  • 뭔가를 개선하기 위해 일하는 다른 리더를 신속하게 지원하자
  • 일을 방해하지 않도록 피드백하자. (강요가 아닌 제안 .. ‘원한다면 받아들일 수 있는’ 것으로 주석 표시)

절대 틀리지 않는 방법을 배우자

  • 경청하고 명확히 하며 주변의 분위기를 읽자
  • ‘머저리들’ - 그룹 내에서 동의를 거부한 사람, 타협할 의사가 없는 사람, 다른 사람 말을 듣지 않는 사람 등등..
    • 머저리들이 힘을 쓰지 못할 사람을 회의에 참여 시킨다
    • 회의를 시작하기 전에 머저리들이 자신의 의견도 받아들여지고 있다고 느끼면서 토론에 집중할 수 있도록 교감하는 방법을 찾아본다.

타인을 위한 공간의 창출

내가 아닌 다른 사람을 발전시킬 수 있는 스폰서십을 할 수 있어야 한다

동료와 네트워크 구축

내부 뿐 아니라 외부 네트워크도 가지고 있어야 한다.

임원을 대상으로 하는 프레젠테이션

<효울적인 의사소통 방법>

첫 문단에서 SCQA 형식을 따르자

  • 현 상황: 관련된 문잭이 무엇인가
  • 문제점: 현 상황이 왜 문제가 되는가?
  • 의문점: 문제를 해결하기 위한 핵심 의문 사항은 무엇인가?
  • 해결법: 이 의문점에 대한 최선의 해결책은 무엇인가?

<피해야할 실수>

  • 피드백에 발끈하지 말자
  • 문제나 책임을 회피하지 말자
  • 해결책이 없이 문제를 제시하지 말자
  • 학술적인 프로젠테이션은 하지 말자
  • 본인이 선호하는 결과를 고집하지 말자



개인 의견


회사에서 스태프 트랙을 가져가려고 하고 있고, 모든 개발자가 팀장(매니저) 직책을 갖을 수는 없기 때문에..  개발자로서 앞으로 Next 레벨을 생각해볼 필요가 있음.

스태프엔지니어는 종류가 어떻게 되는지 그리고 어떤 역할을 하는지에 대해서 알고 앞으로 미래를 그림을 그려보면 좋을 것 같습니다.

또, 정리는 하지 않았지만 앞으로 미래를 그려볼 때 4장 5장 책은 많은 도움이 되는 부분 중 하나가 될 수 있습니다. 

 - 4장 이직 결정하기 

 - 5장 인터뷰 → 실제로 해외 기업에서 스태프 엔지니어로 일하시는 분들에 인터뷰 내용이 담겨 있습니다. 실제 스태프 엔지니어가 기술리드/아키텍트/해결사/오른팔 의 역할을 어떻게 수행하고 있는지를 알 수 있습니다.

정리 - 코드리뷰 가이드

 

원문 사이트

https://github.com/thoughtbot/guides/tree/main/code-review


공통사항

  • 많은 프로그래밍 결정이 의견임을 인정하세요. 선호하는 장단점을 논의하고 신속하게 해결책을 도출하세요.
  • 좋은 질문을 하되 요구하지 마세요. ("이 이름을 :user_id로 짓는 것은 어떨까요?")
  • 좋은 질문은 판단을 피하고 작성자의 관점에 대한 가정을 피합니다.
  • 설명을 요청하세요. ("이해가 안 되는데 설명해 주시겠어요?")
  • 코드의 선택적 소유권을 피하세요. ("내 것", "내 것이 아니다", "당신 것")
  • 개인적 특성을 지칭하는 것으로 보일 수 있는 용어는 사용하지 마세요. ("dumb", "stupid"). 모든 사람이 지적이고 선의가 있다고 가정합니다.
  • 명확하게 표현하세요. 온라인에서 사람들이 항상 내 의도를 이해하는 것은 아니라는 점을 기억하세요.
  • 겸손하게 행동하세요. ("잘 모르겠습니다 - 찾아보겠습니다.")
  • 과장된 표현을 사용하지 마세요. ("항상", "절대", "끝없이", "아무것도")
  • 비꼬는 표현을 사용하지 마세요.
  • 진실을 유지하세요. 이모티콘, 움직이는 GIF 또는 유머가 본인에게 맞지 않는다면 억지로 사용하지 마세요. 이모티콘을 사용해야 한다면, 유머러스하게 사용하세요.
  • "이해하지 못했습니다" 또는 "다른 해결책:"이라는 댓글이 너무 많으면 채팅, 화면 공유, 직접 대면 등의 방식으로 동시에 대화하세요. 토론 내용을 요약하는 후속 댓글을 게시합니다.
  • 새로운 것을 배웠다면 감사의 마음을 전하세요. ("몰랐던 사실인데 공유해 주셔서 감사합니다.")


코드 리뷰 요청자

  • 검토자의 제안에 감사하는 마음을 표현하세요. ("좋은 지적입니다. 변경해 보겠습니다.")
  • 온라인에서 감정과 의도를 전달하기는 어려울 수 있다는 점에 유의하세요(https://thoughtbot.com/blog/empathy-online).
  • 코드가 존재하는 이유를 설명합니다. ("이런 이유 때문에 그런 것입니다. 이 클래스/파일/메서드/변수의 이름을 바꾸면 더 명확해질까요?")
  • 일부 변경 사항과 리팩터링을 추출하여 향후 티켓/스토리에 추가합니다.
  • 티켓/스토리에서 코드 리뷰로 연결합니다. ("검토 준비 완료: https://github.com/organization/project/pull/1")
  • 이전 피드백을 기반으로 한 커밋을 브랜치에 격리된 커밋으로 푸시합니다. 브랜치를 병합할 준비가 될 때까지 스쿼시하지 마세요. 리뷰어는 이전 피드백을 기반으로 개별 업데이트를 읽을 수 있어야 합니다.
  • 리뷰어의 관점을 이해하려고 노력하세요.
  • 모든 댓글에 응답하려고 노력하세요.
  • 지속적 통합(TDDium, Travis CI, CircleCI 등)에서 브랜치에서 테스트 스위트가 초록색으로 표시될 때까지 브랜치 병합을 기다린다.
  • 코드와 코드가 프로젝트에 미치는 영향에 대해 확신이 들면 병합하세요.
  • 최종 편집 권한은 풀리퀘스트 작성자에게 있습니다.


코드 리뷰어

변경이 필요한 이유를 이해합니다(버그 수정, 사용자 경험 개선, 기존 코드 리팩터링). 그런 다음

  • 어떤 아이디어가 마음에 드는지, 어떤 아이디어가 마음에 들지 않는지 소통하세요.
  • 문제를 해결하면서 코드를 간소화할 수 있는 방법을 찾아보세요.
  • 토론이 너무 철학적이거나 학문적으로 변하면 금요일 오후의 정기적인 기술 토론으로 오프라인 토론을 전환하세요. 그 동안에는 작성자가 대체 구현에 대한 최종 결정을 내리도록 하세요.
  • 대체 구현 방법을 제시하되, 작성자가 이미 고려하고 있다고 가정합니다. ("여기에 사용자 지정 유효성 검사기를 사용하는 것에 대해 어떻게 생각하세요?")
  • 작성자의 관점을 이해하려고 노력하세요.
  • 풀 리퀘스트에 👍 또는 "병합 준비 완료" 댓글로 서명하세요.
  • 게이트키퍼가 아니라 피드백을 제공하기 위해 여기에 있다는 것을 기억하세요.
  • '제안 추가' 기능을 사용하여 변경 사항을 제안할 때:
    • 어떤 줄을 추가/제거할 것을 제안하는지 명확하게 전달하세요.
    • 가능한 경우 제안한 변경 사항을 테스트하여 제대로 작동하는지 확인합니다.
    • 테스트할 수 없는 경우에는 풀 리퀘스트 작성자에게 제안을 테스트하지 않았다는 사실을 알립니다.
    • 작성자에게 변경을 제안하는 이유를 알릴 수 있는 컨텍스트를 제공하세요.


스타일 코멘트

검토자는 누락된 스타일 가이드라인에 대해 코멘트를 달아야 합니다. 코멘트 예시:

→ 유용한 경로를 이름별로 알파벳순으로 정렬하세요.

스타일 댓글에 대한 응답 예시:

→ 이런. 잘 발견했습니다, 감사합니다. a4994ec에서 수정되었습니다.

가이드라인에 동의하지 않는 경우 코드 리뷰 내에서 토론하지 말고 가이드 리포지토리에 이슈를 개설하세요. 그 동안 가이드라인을 적용하세요. 표준과 같은 lint를 설정하여 코드 형식을 자동으로 지정하는 것이 도움이 되는 경우가 많습니다. 이렇게 하면 개인적인 스타일 선호도에 대한 논쟁보다는 PR에 대해 더 의미 있는 대화를 나눌 수 있습니다.

도움이 되는 다른 글

구글 코드 리뷰 가이드 :

https://google.github.io/eng-practices/

https://soojin.ro/review/

클린코드 13장 동시성

 “객체는 처리의 추상화다. 스레드는 일정의 추상화다.” - 제임스 O. 코플리

동시성과 깔끔한 코드는 양립하기 어렵다. 스레드를 하나만 실행 하는 코드는 짜기가 쉽다.

겉으로 보기에는 멀쩡해 보이는 다중 스레드코드도 짜기 쉽다. 이런코드는 시스템이 부하를 받기 전까지 멀쩡 하게 돌아간다.

이 장에서는 여러 스레드를 동시에 돌리는 이유를 논하고 여러 스레드를 동시에 돌리는 어려움도 논한다. 이런 어려움에 대처하고 깨끗한 코드를 작성하는 방법도 몇 가지 제안한다. 마지막으로, 동시성을 테스트하는 방법과 문제점을 논한다.

동시성이 필요한 이유?

동시성은 결합(coupling)을 없애는 전략이다. 즉, 무엇(what)과 언제(when)를 분리하는 전략이다.

스레드가 하나인 프로그램은 무엇과 언제가 서로 밀접하다. 그래서 호출 스택을 살펴보면 프로그램 상태가 곧바로 드러난다.

무엇(what)과 언제(when)를 분리하면 애플리케이션 구조와 효율이 극적으로 나아진다. 구조적인 관점에서 프로그램은 거대한 루프 하나가 아니라 작은 협력 프로그램 여럿으로 보인다. 따라서 시스템을 이해하기가 쉽고 문제를 분리하기도 쉽다.

구조적 개선만을 위해 동시성을 채택하는 건 아니다. 어떤 시스템은 응답 시간과 작업 처리량 개선이라는 요구사항으로 인해 직접적인 동시성 구현이 불가피하다. (예를 들면 웹 사이트 정보 수집기, 사용자 처리 시스템, 대량 정보 분석하는 시스템 등등)

미신과 오해

  • 동시성은 항상 성능을 높여준다.

    대기 시간이 아주 길어 여러 스레드가 프로세서를 공유할 수 있거나 여러 프로세서가 동시에 처리할 독립적인 계산이 충분히 많은 경우에만 성능이 높아진다.

  • 동시성을 구현해도 설계는 변하지 않는다.

    단일 스레드 시스템과 다중 스레드 시스템은 설계가 판이하게 다르다. 일반적으로 무엇과 언제를 분리하면 시스템 구조가 크게 달라진다.

  • 웹 또는 EJB 컨테이너를 사용하면 동시성을 이해할 필요가 없다.

    실제로는 컨테이너가 어떻게 동작하는지, 어떻게 동시 수정, 데드락 등과 같은 문제를 피할 수 있는지를 알아야만 한다.

동시성과 관련된 타당한 생각 몇 가지

  • 동시성은 다소 부하를 유발한다. 성능 측면에서 부하가 걸리며 코드도 더 짜야한다.
  • 동시성은 복잡하다. 간단한 문제라도 동시성은 복잡하다.
  • 일반적으로 동시성 버그는 재현하기 어렵다. 그래서 진짜 결함으로 간주되지 않고 일회성 문제로 여겨 무시하기 쉽다.
  • 동시성을 구현하려면 흔히 근본적인 설계 전략을 재고해야 한다.

난관

동시에 다른 스레드가 같은 객체를 사용하게 될 때 원하는 값을 못받을 수 있다. 대다수는 올바른 결과를 내지만, 문제는 잘못된 결과를 내놓는 일부가 존재한다는 것이다.

동시성 방어 원칙

단일 책임 원칙(Single Responsibility Principle, SRP)

SRP는 주어진 메서드/클래스/컴포넌트를 변경할 이유가 하나여야 한다는 원칙이다.

동시성은 복잡성 하나만으로도 따로 분리할 이유가 충분하다. 즉, 동시성 관련 코드는 다른 코드와 분리해야 한다는 뜻이다.

동시성 구현시 고려 사항

  • 동시성 코드는 독자적인 개발, 변경, 조율 주기가 있다.
  • 동시성 코드에는 독자적인 난관이 있다. 다른 코드에서 겪는 난관과 다르며 훨씬 어렵다.
  • 잘못 구현한 동시성 코드는 별의별 방식으로 실패한다. 주변에 있는 다른 코드가 발목을 잡지 않더라도 동시성 하나만으로도 충분히 어렵다.

권장사항: 동시성 코드는 다른 코드와 분리하라.

따름 정리(corollary): 자료 범위를 제한하라

객체 하나를 공유한 후 동일 필드를 수정하던 두 스레드가 서로 간섭하므로 예상치 못한 결과를 내놓는다.

공유 객체를 시용하는 코드 내 임계영역(critical section)을 synchronized 키워드로 보호하라고 권장한다. 이런 임계영역의 수를 줄이는 기술이 중요하다.

공유자료를 수정하는 위치가 많을수록 커지는 문제

  • 보호할 임계영역을 빼먹는다. 그래서 공유 자료를 수정하는 모든 코드를 망가뜨린다.
  • 임계영역을 올바르게 보호했는지 확인하느라 똑같은 노력과 수고를 반복한다.
  • 찾기 어려운 버그가 더 찾기 어렵게 된다.

권장사항: 자료를 캡슐화하라. 공유 자료를 최대한 줄여라.

따름 정리: 자료 사본을 사용하라

공유 자료를 줄이려면 처음부터 공유하지 않는 방법이 제일 좋다. 어떤 경우에는 객체를 복사해 읽기 전용으로 사용하는 방법이 가능하다. 어떤 경우에는 각 스레드가 객체를 복사해 사용한 후 한 스레드가 해당 사본에서 결과를 가져오는 방법도 가능하다.

공유자료를 피하는 방법이 있다면 코드가 문제를 일으킬 가능성도 아주 낮아진다. 물론 객체를 복사하는 시간과 부하가 걱정스러울지 모르겠으나 복사 비용으 진짜 문제인지 실측해 볼 필요가 있다. (하지만 사본으로 동기화를 피할 수 있다면 내부 잠금을 없애 절약한 수행시간이 사본 생성과 가비지 컬렉션에 드는 부하를 상쇄할 가능성이 크다)

따름정리: 스레드는 가능한 독립적으로 구현하라

자신만의 세상에 존재하는 스레드를 구현한다. 즉, 다른 스레드와 자료를 공유 하지 않는다. 각 스레드는 클라이언트 요청 하나를 처리한다.모든 정보는 비공유 출처에서 가져오며 로컬 변수에 저정한다. 그러면 각 스레드는 세상에서 자신만 있듯이 돌아간다.

권장사항: 독자적인 스레드로, 가능하면 다른 프로세서에서, 돌려도 괜찮도록 자료를 독립적인 단위로 분할하라.

라이브러리를 이해하라

최신 자바 라이브러리를 검색해서 이해할 필요성이 있음. (자바5 기준으로 정리 되어 있어서 혼란을 줄 수 있기 때문에 따로 정리 하지 않음)

실행 모델을 이해하라

  • 한정된 자원 (Bound Resource)
    • 다중 스레드 환경에서 사용하는 자원으로, 크기나 숫자가 제한적이다. 대이터베이스 연결, 길이가 일정한 읽기/쓰기 버퍼 등이 예다.
  • 상호 배제 (Mutual Exclusion)
    • 한 번에 한 스레드만 공유 자료나 공유 자원을 사용할 수 있는 경우를 가리킨다.
  • 기아 (Starvation)
    • 특정 스레드가 굉장히 오랫동안 또는 영원히 자원을 기다리는 경우오랫동안 혹은 영원히 자원을 기다린다. 예를 들어, 항상 짧은 스레드에게 우선순위를 준다면, 짧은 스레드가 지속적으로 이어질 경우, 긴 스레드가 기아 상태에 빠진다.
  • 데드락 (Deadlock)
    • 여러 스레드가 서로가 끝나기를 기다린다. 모든 스레드가 각기 필요한 지원을 다른 스레드가 점유하는 바람에 어느 쪽도 더 이상 진행하지 못한다.
  • 라이브락 (Livelock)
    • 락을 거는 단계에서 각 스레드가 서로를 방해한다. 스레드는 계속해서 진행하려 하지만, 공명(resonance)으로 인해, 굉장히 오랫동안 혹은 영원히 진행하지 못한다.

생산자-소비자

하나 이상 생산자 스레드가 정보를 생성해 빈 공간이 있으면 (없으면 대기) 버퍼나 대기열에 넣는다. 하나 이상 소비자 스레드가 대기열에서 정보가 있으면 (없으면 대기) 정보를 가져와 사용한다. 생산자 - 소비자 스레드가 사용하는 대기열은 한정된 자원이다

생산자 스레드는 대기열에 정보를 채운 다음 소비자 스레드에게 시그널을 보낸다. 소비자 스레드는 대기열에서 정보를 읽어들인 후 생산자에게 시그널을 보낸다. 잘못하면 생성자 스레드와 소비자 스레드가 둘 다 진행 가능함에도 불구하고 동시에 서로에게서 시그널을 기다릴 가능성이 존재한다.

읽기-쓰기

읽기 스레드를 위한 주된 정보원으로 공유 자원을 사용하지만, 쓰기 스레드가 이 공유 자원을 이따금 갱신한다고 하자. 이런 경우 처리률이 문제의 핵심이다. 처리율을 강조하면 기아 현상이 생기거나 오래된 정보가 쌓인다. 갱신을 허용하면 처리율에 영향을 미친다.

따라서 읽기 스레드의 요구와 쓰릭 스레드의 요구를 적절히 만족시켜 처리율도 적당히 높이고 기아도 방지하는 해법이 필요하다.

식사하는 철학자들

두근 식타에 철학자 한 무리가 둘러앉았다. 각 철학자 왼쪽에는 포크가 놓였다. 식탁 가운데는 커다란 스파게티 한 접시가 놓였다. 철학자들은 배가 고프지 않으면 생각하며 시간을 보낸다. 배가 고프면 양손에 포크를 집어들고 스파게티를 먹는다. 양손에 포크를 쥐지 않으면 먹지 못한다. 왼쪽 철학자나 오른쪽 첡하자가 포크를 사용한 중이라면 그쪽 철학자가 먹고 나서 포크를 내려놓고 배가 고플 때까지 다시 생각에 잠긴다.

여기에서 철학자를 스레드로, 포크를 자원으로 바꿔 생각하면 많은 기업 애플리케이션이 겪는 문제다. 기업 애플리케이션은 여러 프로세스가 자원을 얻으려 경쟁한다. 주의해서 설계하지 않으면 데드락, 라이브락, 처리율 저하, 효율성 저하등의 상황을 겪는다.

권장사항: 위에서 설명한 기본 알고리즘과 각 해법을 이해하라

동기화하는 메서드 사이에 존재하는 의존성을 이해하라

동기화하는 메서드 사이에 의존성이 존재하면 동시성 코드에 찾아내기 어려운 버그가 생긴다. 자바 언어는 개별 메서드를 보호하는 synchronized라는 개념을 지원한다. (하지만 공유 클래스 하나에 동기화된 메서드가 여럿이라면 구현이 올바른지를 다시 한 번 확인하기 바란다.)

권장사항: 공유 객체 하나에는 메서드 하나만 사용하라

공유객체 하나에 여러 메서드가 필요한 경우

  • 클라이언트에서 잠금 : 클라이언트에서 첫 번째 메서드를 호출하기 전에 서버를 잠근다.
  • 서버에서 잠금 : 서버를 잠그고 모든 메서드를 호출한 후 잠금을 해제하는 메서드를 구현한다.
  • 연결 서버 : 잠금을 수행하는중간단계 를 생성한다.

동기화하는 부분을 작게 만들어라

자바에서 synchronized 키워드를 사용하면 락을 설정한다. 같은 락으로 감싼 모든 코드 영역은 한 번에 한 스레드만 실행이 가능하다. 락은 스레드를 지연시키고 부하를 가증시킨다. 그러므로 synchronized 문을 남발하는 코드는 바람직하지 않다.

하지만 임계영역은 반드시 보호해야 한다. 따라서 코드를 짤때는 임계영역수를 최대한 줄여야 한다. 그렇다고 임계영역 크기를 키우면 스레드 간에 경쟁이 늘어나고 프로그램 성능이 떨어진다.

권장사항: 동기화하는 부분을 최대한 작게 만들어라

올바른 종료 코드는 구현하기 어렵다

영구적으로 돌아가는 시스템을 구현하는 방법과 잠시 돌다 깔끔하게 종료하는 시스템을 구현하는 방법은 다르다. 깔끔하게 종료하는 코드는 올바로 구현하기 어렵다. 가장 흔히 발생하는 문제가 데드락이다. 즉, 스레드가 절대 오지 않을 시그널을 기다린다. 그러므로 깔끔하게 종료하는 다중 스레드 코드를 짜야 한다면 시간을 투자해 올바로 구현하기 바란다.

권장사항: 종료 코드를 개발 초기부터 고민하고 동작하게 초기부터 구현하라. 생각보다 오래 걸린다. 생각보다 어려우므로 이미 나온 알고리즘을 검토하라.

스레드 코드 테스트하기

코드가 올바르다고 증명하기는 현실적으로 불가능하다, 테스트가 정확성을 보장하지는 않는다. 그럼에도 충분한 테스트는 위험을 낮춘다. 스레드가 하나일때는 이 말이 옳지만 스레드가 둘 이상으로 늘어나면 상황은 급격하게 복잡해진다.

권장사항: 문제를 노출하는 테스트 케이스를 작성하라. 프로그램 설정과 시스템 설정과 부하를 바꿔가며 자주 돌려라. 테스트가 실패하면 원인을 추적하라. 다시 돌렸더니 통과하더라는 이유로 그냥 넘어가면 절대로 안 된다.

구체적인 여러 지침

  • 말이 안 되는 실패는 잠정적인 스레드 문제로 취급하라
  • 다중 스레드를 고려하지 않은 순차 코드부터 제대로 돌게 만들자
  • 다중 스레드를 쓰는 코드 부분을 다양한 환경에 쉽게 끼워 넣을 수 있게 스레드 코드를 구현하라
  • 다중 스레드를 쓰는 코드 부분을 상황에 맞게 조율할 수 있게 작성하라
  • 프로세서 수보다 많은 스레드를 돌려보라
  • 다른 플랫폼에서 돌려보라
  • 코드에 보조 코드(instrument)를 넣어 돌려라. 강제로 실패를 일으키게 해보라

말이 안 되는 실패는 잠정적인 스레드 문제로 취급하라

다중 스레드 코드는 때때로 말이 안 되는 오류를 일으킨다. 대다수의 개발자는 스레드가 다른 코드와 교류하는 방식을 직관적으로 이해하지 못한다. 그래서 많은 개발자가 하드웨어 문제, 단순한 ‘일회성’ 문제로 치부하고 무시한다.

일회성 문제란 존재하지 않는다고 가정하는 편이 안전하다. 일회성 문제를 계속 무시한다면 잘못된 코드 위에 코드가 계속 쌓인다.

권장사항: 시스템 실패를 ‘일회성’이라 치부하지 마라.

다중 스레드를 고려하지 않은 순차 코드부터 제대로 돌게 만들자

당연한 소리지만 다시 한 번 강조한다. 스레드 환경 밖에서 코드가 제대로 도는지 반드시 확인한다. 일반적인 방법으로, 스레드가 호출하는 POJO를 만든다. POJO는 스레드를 모른다. 따라서 스레드 환경 밖에서 테스트가 가능하다. POJO에 넣는 코드는 많을수록 더 좋다.

권장사항: 스레드 환경 밖에서 생기는 버그와 스레드 환경에서 생기는 버그를 동시에 디버깅하지 마라. 먼저 스레드 환경 밖에서 코드를 올바로 돌려라.

다중 스레드를 쓰는 코드 부분을 다양한 환경에 쉽게 끼워 넣을 수 있게 스레드 코드를 구현하라

다중 스레드를 쓰는 코드를 다양한 설정으로 실행하기 쉽게 구현하라.

  • 한 스레드로 실행하거나, 여러 스레드로 실행하거나, 실행 중 스레드 수를 바꿔본다.
  • 스레드 코드를 실제 환경이나 테스트 환경에서 돌려본다.
  • 테스트 코드를 빨리, 천천히, 다양한 속도로 돌려본다.
  • 반복 테스트가 가능하도록 테스트 케이스를 작성한다.

권장사항: 다양한 설정에서 실행할 목적으로 다른 환경에 쉽게 끼워 넣을 수 있게 코드를 구현하라.

다중 스레드를 쓰는 코드 부분을 상황에 맞게 조율할 수 있게 작성하라

적절한 스레드 개수를 파악하려면 상당한 시행착오가 필요하다. 처음부터 다양한 설정으로 프로그램의 성능 측정 방법을 강구한다.

스레드 개수를 조율하기 쉽게 코드를 구현한다. 프로그램이 돌아가는 도중에 스레드 개수를 변경하는 방법도 고려한다. 프로그램 처리율과 효율에 따라 스스로 스레드개수를 조율하는 코드도 고민한다.

프로세서 수보다 많은 스레드를 돌려보라

시스템이 스레드를 스와핑(swapping)할 때도 문제가 발생한다. 스와핑을 일으키려면 프로세서 수보다 많은 스레드를 돌린다. 스와핑이 잦을수록 임계영역을 빼먹은 코드나 데드락을 일으키는 코드를 찾기 쉬워진다.

다른 플랫폼에서 돌려보라

다중 스레드 코드는 플랫폼에 따라 다르게 돌아간다. 따라서 코드가 돌아갈 가능성이 있는 플랫폼 전부에서 테스트를 수행해야 마땅하다.

권장사항: 처음부터 그리고 자주 모든 목표 플랫폼에서 코드를 돌려라.

코드에 보조 코드(instrument)를 넣어 돌려라. 강제로 실패를 일으키게 해보라

스레드 버그가 산발적이고 우발적이고 재현이 어려운 이유는 코드가 실행되는 수천 가지 경로 중에 아주 소수만 실패하기 때문이다. 보조코드를 추가해 코드가 실행되는 순서를 바꿔주어 오류를 좀 더 자주 일으킬수 있도록 할 수 있다.

결론

다중 스레드 코드는 올바로 구현하기 어렵다. 다중 스레드 코드를 작성한다면 각별히 깨끗하게 코드를 짜야 한다. 주의하지 않으면 희귀하고 오묘한 오류에 직면하게 된다.

무엇보다 먼저 SRP를 준수한다. POJO를 사용하 스레드를 아는 코드와 스레드를 모르는 코드를 분리한다. 스레드 코드를 테스트할 때는 전적으로 스레드만 테스트한다. 즉, 스레드 코드는 최대한 집약되고 작아야 한다는 의미이다.

동시성 오류를 일으키는 잠정적인 원인을 철저히 이해한다.

사용하는 라이브러리와 기본 알고리즘을 이해한다.

보호할 코드 영역을 찾아내는 방법과 특정 코드 영역을 잠그는 방법을 이해한다.

어떻게든 문제는 생긴다. 초반에 드러나지 않는 문제는 일회성으로 치부해 무시하기 십상이다. 소위 일회성 문제는 대개 시스템에 부하가 걸릴 때나 아니면 뜬금없이 발생한다. 그러므로 스레드 코드는 많은 플랫폼에서 많은 설정으로 반복해서계속 테스트해야 한다.

테스트 용이성은 TDD 3대 규칙을 따르면 자연히 얻어진다.

  • 실패하는 단위테스트를 작성할 때까지 실제 코드를 작성하지 않는다.
  • 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위테스트를 작성한다.
  • 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.

시간을 들여 보조 코드를 추가하면 오류가 드러날 가능성이 크게 높아진다.

깔끔한 접근 방식을 취한다면 코드가 올바로 돌아갈 가능성이 극적으로 높아 진다.

클린코드 12장 창발성

 

창발적 설계로 깔끔한 코드를 구현하자

착실하게 따르기만 하면 우수한 설계가 나오는 간단한 규칙 네가지가 있다면? 네 가지 규칙을 따르면 코드 구조와 설계를 파악하기 쉬워진다면? 그래서 SRP나 DIP와 같은 원칙을 적용하기 숴우진다면? 네 가지 규칙이 우수한 설계의 찰발성을 촉진한다면?

우리들 대다수는 켄트 벡이 제시한 단순한 설계 규칙 네 가지가 소프트웨어 품질을 크게 높여준다고 믿는다. (중요도 순)

  • 모든 테스트를 실행한다.
  • 중복을 없앤다.
  • 프로그래머 의도를 표현한다.
  • 클래스와 메서드 수를 최소로 줄인다.

단순한 설계 규칙 1: 모든 테스트를 실행하라

설계는의도한 대로 돌아가는 시스템을 내놓아야 한다. 문서로는 시스템을 완벽하게 설계했지만, 시스템이 의도한 대로 돌아가는지 검증할 간단한 방법이 없다면, 문서 작ㄱ성을 위해 투자한 노력에 대한 가치는 인정받기 힘들다.

테스트를 철저히 거쳐 모든 테스트 케이스를 항상 통과하는 시스템은 ‘테스트 가능한 시스템’이다. 당연하지만 중요한 말이다. 테스트가 불가능한 시스템은 검증도 불가능하다. 논란의 여지가 있지만, 검증이 불가능한 시스템은 절대 출시하면 안 된다.

테스트가 가능한 시스템을 만들려고 애쓰면 설계 품질이 더불어 높아진다. 크기가 작고 목적 하나만 수행하는 클래스가 나온다. (SRP를 준수하는 클래스는 테스트가 훨씬 더 쉽다)

테스트 케이스가 많을 수록 개발자는 테스트가 쉽게 코드를 작성한다. 따라서 철저한 테스트 가능한 시스템을 만들면 더 나은 설계가 얻어진다.

결합도가 높으면 테스트 케이스를 작성하기 어렵다. 테스트 케이스를 많이 작성할수록 개발자는 DIP와 같은 원칙을 적용하고 의존성 주입(Dependency Injection), 인터페이스, 추상화 등과 같은 도구를 사용해 결합도를 낮춘다. 따라서 설계 품질은 더 높아진다.

단순한 설계 규칙 2~4: 리팩터링

테스트 케이스를 모ㅓ두 작성했다면 이제 코드와 클래스를 정리해도 괜찮다. 구체적으로는 코드를 점진적으로 리팩토링 해나간다. 코드 몇 줄을 추가할 때마다 잠시 멎추고 설계를 조감한다. 새로 추가하는 코드가 설계 품질을 낮추는가? 그러다면 깔끔히 정리한 후 테스트 케이스를 돌려 기존 기능을 깨뜨리지 않았다는 사실을 확인한다. 코드를 정리하면서 시스템이 깨질까 걱정할 필요가 없다. 테스트 케이스가 있으니까!

응집도를 높이고, 결합도를 낮추고, 관심사를 분리하고, 시스템 관심사를 모듈로 나누고, 함수와 클래스 크기를 줄이고, 더 나은 이름을 선택하는 다양한 기법들이 동원한다.

또한 이 단계는 단순한 설계 규칙 중 나머지 3개를 적용해 중복을 제거하고, 프로그래머 의도를 표현하고, 클래스와 메서드 수를 최소로 줄이는 단게이기도 하다.

중복을 없애라

우수한 설계에서 중복은 커다란 적이다. 중복은 추가 작업, 추가 위험, 불필요한 복잡도를 뜻하기 때문이다. 같은 코드는 당연히 중복이다. 비슷한 코드는 더 비슷하게 고쳐주면 리팩터링이 쉬워진다. 깔끔한 시스템을 만들려면 단 몇 줄이라도 중복을 제거하겠다는 의지가 필요하다.

표현하라

자신이 이해하는 코드를 짜기는 쉽다. 코드를 짜는 동안에는 문제에 푹 빠져 코드를 구석구석 이해하니까. 하지만 나중에 코드를 유지보수할 사람이 코드를 짜는 사람만큼이나 문제를 깊이 이해할 가능성은 희박하다.

소프트웨어 프로젝트 비용 중 대다수는 장기적인 유지보수에 들어간다. 시스템이 점차 복잡해지면서 유지보수 개발자가 시스템을 이해하느라 보내는 시간은 점점 늘어나고 동시에 코드를 오해할 가능성도 점점 커진다. 그러므로 코드는 개발자의 의도를 분명히 표현해야 한다.

개발자가 코드를 명백하게 짤수록 다른 사람이 그 코드를 이해하기 쉬워진다. 그래야 결함이 줄어들고 유지보수 비용이 적게 든다.

  1. 좋은 이름을 선택한다. 이름과 기능이 완전히 딴판인 클래스나 함수로 개발자를 놀라게 해서는 안 된다.
  2. 함수와 클래스 크기를 가능한 한 줄인다. 작은 클래스와 작은 함수는 이름 짓기도 쉽고, 구현하기도 쉽고, 이해하기도 쉽다.
  3. 표준 명칭을 사용한다. 예를 들어, 디자인 패턴은 의사소통과 표현력 강화가 주요 목적이다.
  4. 단위 테스트 케이스를 꼼꼼히 작성한다.

하지만 표현력을 높이는 가장 중요한 방법은 노력이다. 나중에 읽을 사람을 고려해 조금이라도 읽기 쉽게 만드려는 충분한 고민은 거의 찾기 어렵다. 하지만 나중에 코드를 읽을 사람은 바로 자신일 가능성이 높다는 사실을 명심하자.

그러므로 자신의 작품을 조금 더 자랑하자. 함수와 클래스에 조금 더 시간을 투자하자. 더 나은 이름을 선택하고, 큰 함수를 작은 함수 여럿으로 나누고, 자신의 작품에 조금만 더 주의를 기울이자. 주의는 대단한 재능이다.

클래스와 메서드 수를 최소로 줄여라

중복을 제거하고, 의도를 표현하고, SRP를 준수한다는 기본적인 개념도 극단으로 치달으면 득보다 실이 많아진다.

클래스와 메서드 크기를 줄이자고 조그만 클래스와 메서드를 수없이 만드는 사례도 없지 않다. 그래서 이 규칙은 함수와 클래스 수를 가능한 줄이라고 제안한다.

때로는 무의미하고 독단적인 정책 탓에 클래스 수와 메서드 수가 늘어나기도 한다.

  • 클래스마다 무조건 인터페이스를 생성하라고 요구하는 구현 표준
  • 자료 클래스(자료구조)와 동작 클래스(객체)는 무조건 분리해야 한다고 주장하는 개발자
  • 가능한 독단적인 견해는 멀리하고 실용적인 방식을 택해야 한다.

목표는 함수와 클래스 크기를 작게 유지하면서 동시에 시스템 크기도 작게 유지하는 데 있다. 하지만 이 규칙은 간단한 설계 규칙 네 개 중 우선순위가 가장 낮다. 다시 말해, 클래스와 함수 수를 줄이는 작업도 중요하지만 그보다 테스트 케이스를 만들고 중복을 제거하고 의도를 표현하는 작업이 더 중요하다는 뜻이다.

결론

경험을 대신할 단순한 개발 기법이 있을까? 당연히 없다. 하지만 이 장, 아니 이 책에서 소개하는 기법은 저자들이 수십 년 동안 쌓은 경험의 정수다. 단순한 설계 규칙을 따른다면 (오랜 경험 후에야 익힐) 우수한 기법과 원칙을 단번에 활용할 수 있다.

AI Coding Assistant 개인 프로젝트 그 이후 업무에 적용하기 위한 고민

  최근 사이드 프로젝트로 앱을 만들고 출시하면서 AI Agent 기반 개발을 여러 방식으로 실험해봤습니다. 개인 프로젝트에서 이것저것 부딪혀보고 나서, 실제 업무에 적용해보기 위해 회사에서 사용하던 스프린트 방식을 이 흐름에 적용해보고 싶어졌습니다....