프로세스

1. 프로세스의 개념

Untitled

  • 프로세스의 문맥 : 프로세스의 현재 상태를 나타내는데 필요한 모든 요소
    • CPU 수행 상태를 나타내는 하드웨어 문맥 - Program Counter, 각종 register
    • 프로세스의 주소 공간 : code, data,stack
    • 프로세스 관련 커널 자료 구조 : PCB(Process Control Block), Kernel stack
  • 프로세스가 번갈아가며 실행되기 때문에 다음번 CPU를 점유했을 때 작업을 이어서 실행하기 위해서는 프로세스 문맥이 필요하다

프로세스의 상태

Untitled

프로세스는 상태가 변경되며 수행된다.

  • Running : CPU를 잡고 instruction을 수행중인 상태
  • Ready : 메모리 등 다른 조건을 만족하고 CPU를 기다리는 상태
  • Blocked(wait, sleep) : CPU를 주어도 당장 instruction을 수행할 수 없는 상태, Process 자신이 요청한 event(I/O)가 즉시 만족되지 않아 이를 기다리를 상태 ex) 디스크에서 file을 읽어와야 하는 경우
  • New : 프로세스가 생성중인 상태
  • Terminated : 수행이 끝난 상태

Untitled

하나의 프로세스만 CPU에서 수행됨. timer interrupt가 들어오면 다음 프로세스가 CPU 점유.

Queue!!

Process Control Block(PCB)

운영체제가 각 프로세스를 관리하기 위해 프로세스 당 유지하는 정보.

Untitled

1) OS가 관리상 사용하는 정보

  • Process state, Process ID
  • schekduling information, priority

2) CPU 수행 관련 하드웨어 값

  • Program counter, registers

3) 메모리 관련

  • code, stack, data의 위치정보

4) 파일 관련

  • open file descriptors

문맥 교환(Context Switch)

  • CPU를 한 프로세스에서 다른 프로세스로 넘겨주는 과정
  • CPU가 다른 프로세스에게 넘어갈 때 운영체제는 다음을 수행한다
    • CPU를 내어주는 프로세스의 상태를 그 프로세스의 PCB에 저장
    • CPU를 새롭게 얻는 프로세스의 PCB를 읽어옴

Untitled

  • system call이나 interrupt 발생시 반드시 context switch가 일어나는 것은 아니다

Untitled

사용자 프로세스 간에 CPU가 넘어갈 때 context switch가 일어남.

system call이나 interrupt가 발생하면 운영체제로 CPU로 넘어감 → 이건 context switch가 아님!

2. 프로세스 스케줄링

프로세스를 스케줄링하기 위한 큐

프로세스들은 각 큐들을 오가며 수행된다.

  • Job Queue : 현재 시스템 내에 있는 모든 프로세스의 집합
  • Ready Queue : 현재 메모리 내에 있으면서 CPU를 잡아서 실행되기를 기다리는 프로세스의 집합
  • Device Queues : I/O device의 처리를 기다리는 프로세스의 집합

스케줄러

  • CPU scheduler=Short-term scheduler : 프로세스에 CPU를 주는 문제, 어떤 프로세스를 다음번에 running 시킬지 결정,충분히 빨라야함
  • Job scheduler = Long-term scheduler : 프로세스에 메모리를 주는 문제, 프로세스시작(new)→ 메모리에 올라가면 ready 상태가 됨, 시작 프로세스 중 어떤 것들을 ready queue(메모리)로 보낼지 결정, degree of Multiprogramming(메모리에 올라가는 프로세스 수)을 제어. time sharing system에는 보통 장기 스케줄러가 없고 무조건 ready 상태임.
  • Swapper = Medium-term Scheduler : 요즘 시스템은 프로그램이 시작되자마자 메모리를 줌. 여유 공간 마련을 위해 프로세스를 통째로 메모리에서 디스크로 쫓아냄, 프로세스에게서 memory를 뺏는 문제, degree of Multiprogramming을 제어 → 프로세스를 Suspended 상태로 만듦!!!

Untitled

3. Thread 쓰레드

프로세스 내부의 CPU 수행단위. 프로세스하나에서 공유할 수 있는 건 최대한 공유(PCB, 메모리의 data,code), 별로도

Untitled

Untitled

  • 다중 스레드로 구성된 태스크 구조에서는 하나의 서버 스레드가 blocked 상태인 동안에도 동일한 태스크 내의다른 스레드가 실행(running)되어 빠른 처리를 할 수 있다.
  • 동일한 일을 수행하는 다중 스레드가 협력하여 높은 처리율과 성능 향상을 얻을 수 있다.
  • 스레드를 사용하면 병렬성을 높일 수 있다.

Thread의 구성

  • program counter
  • register set
  • stackspace

Thread가 동료 thread와 공유하는 부분(=task)

  • code section
  • data section
  • OS resources

스레드의 장점

  • 응답성 : 스레드를 여러개 가지고 있으면 하나의 스레드가 blocked 상태일 때 (예 - 네트워크 통신) 다른 스레드가 동작한다(예 - 화면 보여주기)
  • 자원 공유 : 같은 일을 하는 프로그램이 여러 개 있을 때 여러 프로세스를 쓰는 것보다는 하나의 프로세스를 만들고 CPU 수행단위를 여러개를 만들어 code, data, 프로세스 resource를 공유하면 자원을 더 효율적으로 사용할 수 있다.
  • 경제성 : 스레드의 create & CPU swithing이 프로세스의 그것보다 오버헤드가 적음
    프로세스를 하나 만드는 것이 프로세스 내부에서 스레드를 만드는 것 보다 오버헤드가 더 큼, 문맥교환(프로세스 간 cpu 점유 이동) 프로세스 내부에서 스레드 내 CPU swithing이 context switch보다 오버헤드가 작음

스레드 구현 방법

  • Kernerl Thread : kernel 방식 - 스레드가 여러개 있다는 사실을 운영체제 커널이 알고 있다. 스레드를 넘길 때 커널이 관여한다
  • User Thread : library 방식 - 운영체제는 스레드가 여러개라는 걸 모르고, 사용자 프로그램이 자체적으로 스레드를 관리함.

4. 프로세스 관리

프로세스 생성

  • 부모 프로세스(Parent process)가 자식 프로세스(children process) 생성 - 복제
    • Copy on Write(COW) : 효율적인 운영ㅊ제에서는 PCB 정도만 복제하고, 우선 자원을 공유한다. 내용이 바뀔 때만 복제를 함.
  • 프로세스의 트리(계층 구조) 형성
  • 프로세스가 실행되려면 자원(cpu, memory,..)이 필요하다
    • 운영 체제로부터 받는다
    • 부모와 공유한다
  • 주소 공간(Address space)
    • 자식은 부모의 공간을 복사함(binarhy and OS data - PCB,자원,..) - ex) unix fork()
    • 자식은 그 공간에 새로운 프로그램을 올림 ex] exec() 시스템 콜을 통해 새로운 프로그램을 메모리에 올림

프로세스 종료

  • 프로세스가 마지막 명령을 수행한 후 운영체제에게 이를 알려줌 ex] exit() system call - 자발적
    • 자식이 부모에게 output data를 보냄 ex] wait()
    • 프로세스의 각종 자원들이 운영체제에게 반납됨
  • 강제 종료 : 부모 프로세스가 자식의 수행을 종료시킴 ex] abort()
    • 자식이 할당 자원의 한계치를 넘어섬
    • 자식에게 할당된 태스크가 더 이상 필요하지 않음
    • 부모가 exit 하는 경우
      • 운영체제는 부모 프로세스가 종료하는 경우 자식이 더 이상 수햏ㅇ되도록 두지 않는다
      • 단계적인 종료

프로세스 관련 시스템 콜 정리

  • fork() : 프로세스 복제
  • exec() : 새로운 프로그램으로 덮어씌움.
  • wait() :
  • exit() : 자발적 프로세스 종료

프로세스 간 협력 - IPC(Interprocess Communication)

  • 독립적 프로세스 : 프로세스는 각자의 주소 공간을 가지고 수행되므로 원칙적으로 하나의 프로세스는 다른 프로세스의 수행에 영향을 미치지 못함

  • 협력 프로세스 : 프로세스 협력 메커니즘을 톨ㅇ해 하나의 프로세스가 다른 프로세스의 수행에 영향을 미칠 수 있음

  • 프로세스 간 협력 메커니즘 (IPC : Interprocess Communication)

    Untitled

    • message passing : 메시지를 전달하는 방법, 커널을 통해, 프로세스 사이에 공유 변수를 사용하지 않고 통신하는 시스템

      Untitled

      • Direct Communication : 통신하려는 프로세스의 이름을 명시적으로 표시
      • Indirect Communication : mailbox(또는 port)를 통해 메시지를 간접 전달
    • shared memory : 주소 공간을 공유하는 방법. 서로 다른 프로세스 간에도 일부 주소 공간을 공유하게 하는 shared memory 메커니즘이 있다.

  • 스레드는 사실상 하나의 프로세스이므로 프로세스 간 협력으로 보기는 어렵지만 동일한 프로세스를 구성하는 스레드들간에는 주소 공간을 공유하므로 협력이 가능

'CS > 운영체제' 카테고리의 다른 글

컴퓨터 시스템의 구조  (0) 2022.03.15
컴퓨터 내부의 언어체계  (0) 2022.01.18

Untitled

CPU

  • 메모리에 올라와있는 기계어를 처리
  • instruction set - 기계어 정의 집합, 보통 4byte, 0과 1의 조합
  • PC(Program counter)라는 레지스터가 가리키고 있는 메모리 주소를 실행시킴
  • CPU에서 instruction을 실행하면, 다음 위치의 메모리 주소가 PC에 올라옴.
  • 기본적으로는 순차적으로 프로그램을 실행
  • if, 반복문 등을 실행할 때는 memory jump를 함. jump instruction이 있음.

Interrupt

  • 인터럽트 다한 시점의 레지스터와 program counter를 save한 후 CPU의 제어를 인터럽트 처리 루틴에 넘긴다
  • 인터럽트 종류
    • Interrupt (하드웨어 인터럽트) : 하드웨어가 발생시킨 인터럽트, 디바이스 controller가 발생시킨 인터럽트. 일반적인 인터럽드라하면 하드웨어 인터럽트임
    • Trap(소프트웨어 인터럽트)
      • Exception : 프로그램이 오류를 범한 경우
      • System call : 프로그램이 커널 함수를 호출하는 경우
  • 인터럽트 종류마다 실행해야 할 함수가 미리 정의되어 있다.
  • 인터럽트 벡터 : 인터럽트 주소와 처리 루틴 주소를 가지고 있음
  • 인터럽트 처리 루틴(Interrupt Service Routine) : 해당 인터럽트를 처리하는 커널 함수

System call

  • 사용자 프로그램이 운영체제에게 I/O 작업을 해야할 때 system call을 이용해 요청함
  • CPU의 제어권이 사용자 프로그램에서 OS로 넘어감

Timer

  • timer가 인터럽트를 가지고 있음
  • OS가 사용자 프로그램으로 제어권을 넘겨줄 때 mode bit을 1로 바꿔서 넘겨줌
  • 사용자 프로그램이 CPU를 계속 사용할 때(ex- 무한루프) 타이머에 시간셋팅을 해 할당된 시간이 끝나면 타이머가 CPU에게 인터럽트를 걸어 제어권을 다시 OS에게 넘겨줌

I/O

  • device controller
  • local buffer : IO 디바이스의 데이터를 저장
  • CPU에 정보를 전달할 때 interrupt를 걸어서 이용해 호출

Untitled

동기식 입출력(Synchronous I/O)

  • I/O 요청 후 입출력 작업이 완료된 후에야 제어가 사용자 프로그램으로 넘어감

비동기식 입출력(Asynchronous I/O)

  • I/O가 시작된 후 입출력 작업이 끝나기를 기다리지 않고 제어가 사용자 프로그램에 즉시 넘어감
  • 두 경우 모두 I/O 완료는 인터럽트로 알려줌

DMA (Direct Memory Access) Controller

  • 빠른 입출력 장치를 메모리에 가까운 속도로 처리하기 위해 사용
  • CPU 중재 없이 device controller가 device의 buffer storage의 내용을 메모리에 block 단위로 직접 전송

저장장치 계층 구조

Untitled

Q. SSD???

프로그램의 실행(메모리 load)

Untitled

프로그램은 실행파일 형태로 하드디스크에 저장되어 있다. 실행파일을 실행시키면 메모리로 올라가 프로세스가 된다. 물리적인 메모리에 바로 올라가는 것이 아니도 virtual memory 단계를 거친다.

프로그램을 실행시키면 그 프로그램만의 독자적인 주소공간(Address space)가 만들어진다.

  • code : 프로그램 실행코드
  • data : 변수, 자료구조를 담고 있다
  • stack : 함수를 호출하거나 리턴할 때 쌓는 곳

컴퓨터를 켰을 때 커널은 항상 메모리에 올라가있다.

프로세스의 코드가 모두 물리적인 메모리에 올라가는 것이 아니고 진짜 실행되는 부분만 올라간다.

커널 주소 공간의 내용

Untitled

사용자 프로그램이 사용하는 함수

  • 사용자 정의 함수 : 자신의 프로그램에서 정의한 함수
  • 라이브러리 함수 : 자신의 프로그램에서 정의하지 않고, 갖자 쓴 함수, 자신의 프로그램의 실행 파일에 포함되어 있다
  • 커널 함수 : 운영체제 프로그램의 함수, 커널 함수의 호출 = 시스템 콜

'CS > 운영체제' 카테고리의 다른 글

프로세스  (0) 2022.03.15
컴퓨터 내부의 언어체계  (0) 2022.01.18

Feeling

정산봇

정산은 우리팀의 큰 아젠다다. 정산 자동화를 위해 4달째 개발을 하고 있고, 개선을 하고 있다. 전체 목표에서 80프로 정도 진행된 상태다. 지금까지는 스프린트를 다 같이 진행하면서 일감을 나누어 개발했는데, 어쩌다보니 내가 정산 담당자가 되었다. 🙄 공식적?으로 담당자가 되니까 프로덕트에 대한 오너쉽이 생기고, 더 애착이 생긴다. 그래서 정산 플로우나 백엔드 로직에 대해 더 이해하려고 하고, 스스로 기획, 개발, UX에 대해 더 적극적으로 의견을 내게 되었다. 코드나 UI/UX에 미흡한 부분도 더 잘 보이고, 일도 더 밀도있게 하고 있다. 쉬지않고 계속 개발을 하는 느낌이라 지치기도 하지만 또 성장할 수 있는 기회라고 생각한다. 화이팅

요즘 참 재밌네. 출퇴근은 힘들지만...

출퇴근이 힘든 건 적응을 못하고있지만 그래도 요즘 공부가 순조롭고 재밌다. 회사 생활도 참 재밌다. 팀데이도 진행했고, 한달에 한 번 비타민카드 쓰기라는 팀 문화도 만들었다. 아래는 팀원들의 메시지. 요즘은 문서화에 신경을 많이 쓰고 있다. 프로젝트, QA, 배포 관련 문서화나 프로세스가 없는 상태여서 부족하지만 하나씩 만들어가는 중이다.

네?! 주니어같지 않다고요!?

이번달 면담 시간에 팀장님한테 주니어 같지 않다는 얘기를 들었다. 저번달 면담하면서 ‘문제 해결능력이 부족하다’라는 피드백을 들었다고 남겼는데 사실 그 뒤에 시간을 더 드릴걸그랬다는 말씀을 하셨다. 사수님의 의도는 뒷 부분이었기때문에 그런 말을 제가 했나요?!라고 놀라셨지만 나는 앞부분에 충격을 받았고, 그게 좋은 자극이 되었다고 말씀드렸다. 그랬더니 내 행동이 주니어 같지는 않아서 마냥 주니어 대하듯 대하지 않고 있나보다 라고 하셨다.

연륜때문인가.


사수님도 칭찬으로 말씀하셨고 나에게도 지금 시점에서 가장 의미있는 칭찬이라 기대치 팍팍 올려서 팍팍 키워달라고 했다. 팍팍크자

연륜의

주니어

한 권으로 읽는 컴퓨터 구조와 프로그래밍

을 읽고있다. 해야할 건 언제나 많지만 CS 지식을 쌓고싶다는 욕구와 동작원리를 알아가면 재밌으니까! 이번달에 다 읽고 정리하는게 목표였는데.... 몹시 더디다. 챕터당 블로그 글 한개씩 쓰는게 목표였는데 중간에 이해를 못하는 것도 있고, 글로 어떻게 정리를 할지, 어떤 내용을 엮어야할지 몰라 이것도 더디게 더디게 하고 있다. 그래도 조금 더 기계적인 관점으로 컴퓨터를 생각할 수 있게 되었다. 책만 쭉 읽고 정리하는건 능동적이지 못한 공부 방법이라고 해 우선 내용을 넣고, 필요한 부분은 더 찾아보고, 면접질문도 같이 보면서 공부를 하고 있다.

그럼에도 공부를 많이 못해 아쉽다

퇴근하면 체력이 없다는 핑계로 몰입해서 공부를 한지가 꽤 된 것 같다. 그래서 우선 가볍게, 재미있는것부터 하자는 생각으로 저 책을 읽고 있다. 그리고 정리하는 방법을 조금 바꿨는데, 노션을 적극적으로 활용하고 있다. 가볍게 읽은 블로그 글이나 몰라서 찾아본 것들을 노션에 우선 아무렇게나 적고, 미완이면 미완인 상태로 남겨둔다. 부족한 내용은 더 보충하고, 까먹으면 그냥 넘어가기도 하고, 정리를 다한 완성된 글은 블로그에 올리는 식으로 하고 있다. 메모처럼 쉽게 접근할 수 있어 오히려 더 많은 것을 남길 수 있게 되었다. 도구를 바꾸니 공부하는 방식이나 효율이 달라지는게 신기하다.

하지만 역시 몰입이나 밀도가 부족하니까 어딘가 허하고 부족한 기분이다. 이런 기분은 해서 채우는 수 밖에 없지 뭐...

Fact

  • 하루 한개 회사 코드 개선하기
    • 순환참조 문제 발견 및 해결
    • 어떤 페이지의 어떤 테이블 칼럼 너비 조절
    • useColumnEdit hook 만들기 (테이블에서 수정할 때 수정/취소 모드를 바꾸는 훅)
    • 정산 spinner 개선 - cache 유지 때문에 스피너를 껐는데 그러니까 버벅거리게 느껴짐. 스피너를 돌릴 isLoading을 다르게 하기
  • 알고리즘 문제
    • 뉴스 클러스팅 - 합집합, 교집합은 set으로
  • 달달한 재택근무
  • 프로젝트 구조 변경type 정의 → api 정의 → container → page에서 조립만
    • 이렇게 하면 불필요한 코드가 없어지고, 복잡도가 줄어듦!
    • 진짜 그런지에 유의할 것
    • function에 //** 로 주석 작성하기 - description, 설명, input, output
  • 에 따라 작업 순서가 바뀌게 됨
  • graphQL 사용한다!
  • 버전관리
    • $ yarn version 하면 git에도 관리가 됨
    • 버전관리 방법 : 2.스프린트.핫픽스

Find

  • URL에 #등의 특수문자는 인코딩해주기! - # → %23
  • amplify 자동 배포가 안될 때 웹훅추가, reconnect
  • typescript static readonly - readonly를 붙인 class 내부 property나 interface 구현체는 값 변경을 못함-
  • https://www.tutorialsteacher.com/typescript/typescript-readonly
  • react-query refetch는 enabled와 상관없이 동작한다. useEffect에 있는 경우 주의
  • 같은 의미에는 같은 단어를 쓰기
  • npm과 npx의 차이?npx는 npm 레지스트리에 올라가있는 패키지를 쉽게 설치하고 관리할 수 있도록 도와줌. npm을 통해 설치하는 모든 종류의 Node.js 기반 파일을 간단하게 설치하고 실행할 수 있게 도와줌.npx를 사용하는 경우
  • 즉, npm = Package Manager(관리), npx = Pacakage Runner(실행)
  • npx는 npm의 npm을 좀 더 편하게 사용하기 위해서 5.2.0 버전부터 새로 추가된 도구!
  • useQuery의 결과값으로 useEffect 안에서 setState를 하면 무한루프를 돈다
    • 원인 ? setState ↔ useQuery 호출의 무한반복
    • 해결 ? useEffect array에 date가 아니라 isSuccess를 넣는다
  • 상수는 곳곳에서 쓰이는 값을 한번에 바꾸기 위해서 쓰는 것!
  • 타입 캐스트를 어디서 할지에 대해
  • antd popconfirm에서 form submit을 하고싶을 때?
    • _`okButtonProps_={{ htmlType: 'submit', form: formName }}`

'성장 > 월간 회고' 카테고리의 다른 글

2021년 회고  (0) 2022.01.18
2021년 12월 회고  (0) 2022.01.18
2021년 11월 회고  (0) 2021.11.29
2021년 10월 회고  (0) 2021.11.06
9월 회고  (0) 2021.10.14

컴퓨터는 내부적으로 ‘비트’를 사용한다. 1비트는 0 또는 1을 표현한다.

논리연산은 비트들이 표현하는 내용으로부터 새로운 동작을 만들어낸다. 불리언대수는 비트에 사용할 수 있는 연산 규칙의 집합이다. NOT, AND, OR, XOR, 드모르간의 법칙이 있다.

참고로 1byte는 8bit.

비트로 표현하기

숫자

  • 정수를 비트로 표현
    • 덧셈 : 두 비트를XOR, 올림은 AND한 값과 같다
    • 음수 표현은 부호 비트를 사용한다
  • 실수를 표현하는 방법
    • 고정 소수점 : 메모리가 많이 필요하다
    • 부동 소수점
      • ex) 0.0012 → 1.2 x 10^-3
  • 2진수를 다루는 쉬운 방법
    • 8진법 : 0으로 시작
    • 16진법 : 0X로 시작
    • 10진법 : 1~9로 시작

텍스트

  • ASCII 코드 : 키보드에 잇는 모든 기호에 대해 7비트 수를 할당(0~128)
  • 영어 이외의 표준 : ISO-646, ISO-8859, JISX, KSC5661등 → 비트가 비쌌기 때문에 7이나 8bit에 문자를 욱여 넣음
  • UNICODE : 비트 가격이 떨어지면서 문자에 16비트 코드를 부여한 것
  • 그래서 한 문자를 8비트(1byte)
  • 인코딩 : 다른 비트 패턴을 표현하기 위해 사용하는 비트 패턴
    • UTF-8(Unicode Transformation Format-8) : 8비트 시퀀스로 인코딩, 모든 아스키 문자를 8비트로 아스키가 아닌 문자의 경우 깨지지 않는 방법으로 인코딩한다.

  • 컴퓨터 그래픽스는 전자 모눈에 점을 찍어서 표현한다 - pixel
  • RGB 컬러
    • Red, Green, Blue의 색의 조합으로 나타낸 3채널 컬러 이미지 저장방식
    • 각 채널은 8bit 즉, 0~255 사이의 값
    • 컬러 영상에서는 각 8bit의 기본 컬러 3개를 조합해 256x256x256=16,777,216개의 컬러를 만들어 낼 수 있다. = 24bit 트루컬러
    • 1pixel = 8bit x 3 = 3byte (24bit 채널 이미지 기준)
  • Hex 코드
    • RGB 색상을 R,G,B 각각 두자리씩 16진수로 나타낸 표현법
    • ex] RGB(255,255,255) = #ffffff

이미지 - 비트맵과 벡터

비트맵 그래픽은 서로 다른 점(픽셀)의 조합으로 그려지는 이미지 표현방식이다. 비트맵 이미지는 정교하고 화려한 표현이 가능하며, 주로 사진 이미지에 사용된다. 비트맵 이미지는 크기를 늘리거나 줄이면 원본 이미지에 손상이 간다. 비트맵 이미지는 이미지를 표시하는 방식에서 컴퓨터에 부담을 덜 주는 구조를 갖고 있기 때문에 웹에서 이미지를 표시할 때는 주로 비트맵 이미지를 사용한다. JPG, JPEG, PNG, GIF가 모두 비트맵 방식이다.

벡터 이미지는 점과 점을 연결해 수학적 원리로 그림을 그려 표현하는 방식이다. 이미지를 늘리고 줄여도 손상이 되지 않지만, 사진과 같은 복잡한 그림을 표현하려면 컴퓨터에 부하가 걸린다.

PNG

Portable Network Graphics

무손실 압축 포맷을 채택했으며, 256색에 한정된 GIF의 한계를 극복해 32비트 트컬러(RGB 채널 + 알파채널 8bit)를 표현할 수 있게 되었다. 알파채널을 추가했기 때문에 불투명도를 지정할 수 있다.


reference

'CS > 운영체제' 카테고리의 다른 글

프로세스  (0) 2022.03.15
컴퓨터 시스템의 구조  (0) 2022.03.15

모든 것은 이직으로부터

올 2월 SI 프리랜서로 두 번째 프로젝트를 마치고 이직 준비를 시작했다. 이직을 결심한 이유는 역시 개발자로서의 성장이었다. 프로젝트를 진행하면서 내가 느낀 것은 ‘좋은 코드’를 짜기보다는 돌아가기만 하는 코드를 짜면 된다는 것이었다. 처음에는 내가 개발자라는 것 자체가 너무 좋았는데 점점 내가 그 정체성에 부끄러워지기 시작했다. 성장할 수 있는 많은 방법 중 내가 선택한 방법은 환경을 바꾸는 것이었고, 동료가 있고, 프로덕트의 지속적인 개선이 필요한 환경을 원했기 때문에 이직 준비를 시작했다.

이직을 위해 내가 필요한 것과 부족한 것, 채워야 할 것이 혼자서는 명확하지 않아 항해99 과정을 시작했고, 포트폴리오와 면접을 준비해 지금 우리 회사로 왔다. 지원한 회사중 가장 오고 싶었던 회사였기 때문에, 합격 연락이 오기 전에 다른 최종 합격한 다른 회사에 거절 의사를 전달도 했는데 다행히 곰이 그려진 명함을 받게 되었다.

우리팀은 올초부터 무에서 유를 창조하고 있는 중이었고, 프론트엔드 개발자로 그 과정을 함께하고 있다. GPM으로 시작해 파트너센터 스팩을 변경한 2.0을 오픈했고, 정산검수, 정산내역까지 쉬지않고 개발했다.

회사에서 개발자로 일하기

고미는 내 인생 첫 회사다. 그래서 개발자로서도 회사원으로서도 많은 것을 배우고 있다. 우선 개발자로서 회사의 도메인이나 프로덕트 구조나 구성에 대한 파악을 해야했고, 우리팀의 업무 흐름과 업무 방식(JIRA, 스프린트, slack,...)에 익숙해져야했다. 그리고 회사내의 개발팀으로서 우리가 해야할 일에 대한 고민을 함께 했고, 그 안에서 해야할 일을 찾고, 그것을 전달하고, 소통하는 방법도 배우고 있다.

지금까지는 막연하게 프로그래밍에 대해 많이 아는 사람이 실력 좋은 개발자라고 생각했는데, 지금은 회사에서 당면한 문제를 좋은 코드로 풀어 해결하는 사람이 좋은 개발자라고 생각한다. 일 잘하는 개발자에 대한 나름대로의 정의가 생겼고, lv1부터 한개씩 스테이지를 깨가고 있다고 생각한다.

좋은 동료

그 과정에서 동료들의 도움을 정말정말 많이 받고 있다. 그리고 같이 일하는 게 즐겁다. 같이 프로덕트를 만들어 가는 것도, 문제를 해결하는 것도, 좋은 코드를 위해 의견을 나누는 것도 다 즐겁다! 물음표로 이어지는 대화를 하고 퇴근을 할 때의 들뜸이란. 좋아하는 그들에게 나 역시 신뢰할 수 있고, 즐거운 동료가 되고 싶다. 그러기 위해 지금 부족한건 역시 실력일까..

뭘 공부해야하지?

항상 공부할게 명확했는데 올 4분기에는 길을 잃었다. 내가 뭘 알아야하는지, 어느 정도 알아야하는지를 몰라서 공부 방향을 잡기 위해 사수님에게도 물어보고, 유튜브도 보고, 블로그 글도 보고 했다. 해야할 게 많은데도 뭘 해야할지 모른다면 그건 모든 걸 한 번에 다 해야한다는 부담감때문인 것 같다. 나는 점을 찍는다는 말을 좋아한다. 한 번에 딥 다이브하는 것도 좋지만 그럼 맥락을 놓치기 쉽다. 간단히 훑고 지나가는 것만으로도 뇌에는 점이 찍히고, 그 점을 다른 상황에서 다시 만났을 때 다른 점과 엮이거나 더 잘 이해할 수 있다고 생각한다. 이론과 실전이 항상 상호작용해야한다는 것을 잊지말고, 당장 눈에 보이지 않는 지리멸렬한 시간을 인내심을 갖고 계속 쌓아가야하지 않을까. 우선 공부에 흥미를 붙이는게 우선인것 같아 내년에는 내가 제일 궁금한 걸 제일 보람있는 방식으로 시작할 예정이다. 1년치 목표를 월별, 분기별로 정해놓을까도 했는데, 언제든 바뀔 수 있기 때문에 처음 한 두달치만 정해서 시작!

'성장 > 월간 회고' 카테고리의 다른 글

2022년 1월 회고  (0) 2022.02.08
2021년 12월 회고  (0) 2022.01.18
2021년 11월 회고  (0) 2021.11.29
2021년 10월 회고  (0) 2021.11.06
9월 회고  (0) 2021.10.14

정산 검수 개발 완료 및 정산 내역 개발

정산 알파는 감마와 델타를 지나 ‘정산 검수’로 기획이 바뀌었고, 드디어 개발을 완료하고 배포를 했다. 파일 업로드와 파일 다운로드 기능을 구현하면서 polling 요청과 blob, 파일 다운로드 로직에 대해 공부도 했다. 그리고 현업 사용자에게 이런 피드백을 받았다. 이후로 계속 개선중이다.

스크린샷 2021-12-13 오후 5.31.34.png

그리고 이어서 정산 내역을 개발했다. 내가 담당한 페이지는 정산 과정상 복잡한 과정이 없어서 비교적 빨리 스프린트를 마칠 수 있었다. 개발하는 속도가 빨라졌다는 걸 느낀다. 개발이 순조롭게 끝나서 배포를 마치고, 현업 피드백을 받아 반영하고 있다.

그 와중에 부끄러운 일이 있었는데 파일 업로드 상태를 받아오는 로직에서 polling을 처리해야 했는데 react-query에 기능을 제공하는데도 불구하고 useEffect를 이용해 처리를 했다. 문서를 보고했는데 폴링 요청이 제대로 안들어가 나름대로는 해결한거였는데 연차와 주말이 지나고 돌아오니 다른 분이 다시 손 본 다음 머지가 되어있었다. 일을 두 번하게 하는 팀원이라니 ㅠㅠ 시간에 맞추기 위해 우선 하고 넘기자는 생각이었는데, 시간이 조금 더 들더라도 제대로 처리해야겠다고 다짐했다.

그리고 QA 과정에서 꼼꼼하지 못했던 것도 반성... 꺼진 커밋도 다시보자.

회사일을 잘하는 건 어떤건가요? 지금 저에게 부족한건 어떤건가요?

라고 사수님께 여쭤봤다. 코딩 실력도 회사 일을 처리하는 능력도 늘지 않는 것 같아서 계속 고민을 했기 때문이다. 사수님의 답변은 회사 프로덕트에 관심을 갖고 끊임없이 개선을 해야한다. 개선점을 알아보려면 결국 input이 많아야한다. 자바스크립트 코어를 잡고 가려는 지금의 공부방향도 좋지만, 그것과는 별개로 변두리의 것들도 챙겼으면 좋겠다고 하셨다. 그리고 문제 해결 능력이 조금 아쉽다고 했다. 우선 돌아가는 것도 중요하지만 Best practice가 뭔지 많이 찾아보고 적용해봤으면 좋겠다고 하셨다.

스스로를 돌아보니 나는 회사에서 일정이 널널할 때는 회사 프로젝트를 보기보다는 리액트나 CS의 이론들을 찾아본다. 코어도 중요하지만 당장 코드에 적용할 수 있는 무언가는 아닐 수도 있다. 진짜 문제는 회사 태도를 대하는 자세라고 생각했다. 그래서 하루에 한개씩 개발이외에 수정사항 찾기를 하기로했다.

그래서 하루 한개 회사 코드 개선하기

면담 이후 하루 한개씩 회사 코드를 수정하기로 하고 실천했다. 변수 이름 변경, 예외 케이스 찾아서 처리하기, 코드에서 중복되는 부분을 없애기 위해 컴포넌트를 수정하거나, hook 만들어서 처리하기, strict mode에서 warning 나던 코드 개선하기, 스택 변경하고 나서 손길이 닿지 않은 부분 코드 수정하기 등등을 했다.

물론 할당량을 못 채운 날도 있었지만 회사 프로덕트를 대하는 자세가 달라졌다. 개발이 완료된 소스를 안중에 없었는데(

반성

) 프로젝트 전체를 과거가 아닌 현재로 인식을 하게 되었고, 이게 정말 최선일까? 더 좋은 방법이 없을까를 계속 고민하고 찾고 있다. 그리고 실질적으로 적용하고 개선할 수 있는 것들을 공부하니 공부에 좀 더 재미가 붙었다. 지금까지 했던 공부들은 물론 다 필요한 것이지만 눈에 보이는 결과물이 없어 재미도 없고, 보람도 없었기 때문이다. 눈을 크게 뜨고 프로젝트를 대하니 전보다 더 애정도 생긴다. 이 태도가 사실은 당연한 건데 이제라도 배운 것을 다행으로 생각하고 앞으로도 계속 유지할 것이다.

  • 하루 한개 회사 코드 개선하기
    • settlement_index 없을 때 검증관련 버튼들 비활성화
    • 컴포넌트 내부에 있던 object 컴포넌트 밖으로 뺌 - 컴포넌트가 렌더링 될때마다 불필요한 객체 생성을 피하기위해
    • 업로드 취소 기능이 추가됐을 때, api에 반영되지 않은 예외케이스를 찾아서 추가했다
    • Layout의 Header 컴포넌트 extra 부분에 여러 컴포넌트가 들어갈 경우 간격 유지를 Row, Col 컴포넌트로 일일이 해줘야하는 것을 Header 내부에 Space 컴포넌트와 간격을 추가했다. → 모든 컴포넌트에서 헤더 내부 버튼 간격이 동일해지고, 레이아웃을 사용하는 곳에서 Row,Col을 줄필요가 없음
    • useTableData → useFetchPayload로 변경, keyword포함
    • React has detected a change in the order of Hooks called by VerificationTable. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: 에러 해결
      • 원인 : 조건문 안에서 hook을 쓰고 있었음. isLoading?:<Table column={tableCoumn(내부에서 useTranslation훅)}>
    • i18next로 변경하면서 관련 파일 수정
    • GPM table key 에러 수정
    • 권한 라우터 수정

조직 개편과 개발실 이사, 그리고 삶의 질 개선

회사가 시리즈B 투자를 받으면서 본격적으로 성장할 준비를 하고있다. C Level 임원진을 구성하고, 지금 업무를 좀 더 체계적으로 하기 위해 조직 개편도 했다. 채용도 더 많이 늘릴 예정이라고 한다. 개발실은 당장 개편의 영향을 받은 것은 아니라서 하는 일에서 달라진건 없다. 다만 사수팀이 팀장님!이 되셨고, 우리 파트너센터의 R&R을 선명하게 하고, 회사 안에서 해야할 일을 적극적으로 찾고 있다. 회사 입사할 때 해야할 일이 많아 보였고, 회사의 가능성이 너무 좋았는데 기대했던대로 회사가 성장하고 있다. 시스템을 잡아가는 과정, 조직이 성장하는 과정에서 많이 배우고, 그 안에서 내가 해야할 일도 적극적으로 찾아서 해야지.

인원이 늘어나면서 사무실이 좁아져 내년 초 이사전까지 개발실은 위워크로 이사를 했다. 회사 여기저기서 들리던 웃음소리가 사라져 적막한데 차분한 분위기나 시설은 좋다. 강남역으로 이사한 덕에 출퇴근 시간이 십분정도 줄었는데 아침저녁으로 큰 차이다. 퇴근 후에 조금 더 여유가 생겼다. 계속 여기 있으면 좋겠는데 과연...

'성장 > 월간 회고' 카테고리의 다른 글

2022년 1월 회고  (0) 2022.02.08
2021년 회고  (0) 2022.01.18
2021년 11월 회고  (0) 2021.11.29
2021년 10월 회고  (0) 2021.11.06
9월 회고  (0) 2021.10.14

깨끗한 코드는 한가지를 제대로 한다.

1. 깨끗한 코드

  • "깨끗한 코드는 단순하고 직접적이다 .깨끗한 코드는 잘 쓴 문장처럼 읽힌다. 깨끗한 코드는 결코 설계자의 의도를 숨기지 않는다. 오히려 명쾌한 추상화와 단순한 제어문으로 가득하다"
  • "기계가 실행할 정도로 상세학 요구사항을 명시하는 작업, 바로 이것이 프로그래밍이다. 이렇게 명시한 결과가 바로 코드다."
  • "나는 우아하고 효율적인 코드를 좋아한다. 논리가 간단해야 버그가 숨어들지 못한다. 의존서을 최대한 줄여야 유지보수가 쉬워진다. 오류는 명백한 전략에 의거해 철저히 추리한다. 성능을 최적으로 유지해야 사람들이 원칙없는 최적화로 코드를 망치려는 유혹에 빠지지 않는다. 깨끗한 코드는 한가지를 제대로 한다."
  • "함수는 한 가지를 해야한다. 그 한가지를 잘해야 한다. 그 한가지만을 해야한다"
  • "주석은 쉰들러 리스트가 아니다. 주석은 '순수하게 선하지' 못하다. 사실상 주석은 기껏해야 필요악이다.
    프로그래밍 언어 자체가 표현력이 풍부하다면, 아니 우리에게 프로그래밍 언어를 치밀하게 사용해 의도를 표현할 능력이 있다면,
    주석은 거의 필요하지 않으리라. 아니, 전혀 필요하지 않으리라"
  • "처음부터 올바르게 시스템을 만들 수 있다는 믿음은 미신이다.
    대신에 우리는 오늘 주어진 사용자 스토리에 맞춰 시스템을 구현해야 한다. 내일은 새로운 스토리에 맞춰 시스템을 조정하고 확장하면 된다. 이것이 반복적이고 점진적인 애자일 방식의 핵심이다.
    테스트 주도 개발, 리팩터링, 그로 얻어지는 깨끗한 코드는 코드 수준에서 시스템을 조정하고 확장하기 쉽게 만든다"
  • "소프트웨어 시스템은 물리적인 시스템과 다르다.
    관심사를 적절히 분리해 관리한다면 소프트웨어 아키텍처는 점진적으로 발전할 수 있다.
    ... 소프트웨어 시스템은 수명이 짧다는 본질로 인해 아키텍처의 점진적인 발전이 가능하다"

    2. 의미있는 이름

  • 의도를 분명히 밝혀라
  • 그릇된 정보를 피하라
  • 의미 있게 구분하라
  • 발음하기 쉬운 이름을 사용하라
  • 검색하기 쉬운 이름을 사용하라
  • 클래스 이름은 명사, 메서드 이름은 동사구
  • 한 개념에 한 단어

3. 함수

  • 작게 만들어라
  • 한가지만 해라
  • 함수당 추상화 수준은 하나로
  • 내려가기 규칙
  • 서술적인 이름을 사용하라
  • 함수 인수는 0~1. flag는 사용하지 말것
  • 부수 효과는 일으키지 마라
  • 명령과 조회를 분리하라
  • 오류코드보다 예외를 사용하라
  • 반복하지마라

4. 주석

  • 주석은 나쁜 코드를 보완하지 못한다
  • 코드로 의도를 표현하라
  • 좋은 주석 : 법적인 주석, 정보를 제공하는 주석, 의도를 설명하는 주석, 의도를 명료하게 밝히는 주석, 결과를 경고하는 주석, todo 주석
  • 나쁜 주석 : 주절거리는 주석, 같은 이야기를 중복하는 주석, 오해할 여지가 있는 주석

5. 형식 맞추기

  • 적절한 행 길이를 유지하라
  • 개념은 빈 행으로 분리하라
  • 밀접한 코드 행은 세로로 가까이
  • 변수는 사용하는 위치에 최대한 가까이 선언(인스턴스 변수는 클래스 맨 처음에 선언)
  • 공백을 넣으면 여러개의 개념으로 보인다, 승수사이에는 공백이 없다. 항 사이에는 공백

6. 객체와 자료구조

  • 자료 추상화 : 개발자는 객체가 포함하는 자료를 표현할 가장 좋은 방법을 심각하게 고민해야 한다. 아무 생각없이 조회/설정 함수를 추가하는 방법이 가장 나쁘다
  • 자료/객체 비대칭 : "객체 지향 코드에서 어려운 변경은 절차적 코드에서 쉬우며, 절차적인 코드에서 어려운 변경은 객체 지향 코드에서 쉽다."
  • 디미터 법칙 : 클래스 c의 메서드 f는 클래스c, f가 생성한 객체, f인수로 넘어온 객체, c인스턴스 변수에 저장된 객체만 호출
  • 자료전달객체 : 객체는 동작을 공개하고 자료를 숨긴다. 그래서 기존 동작을 변경하지 않으면서 새 객체 타입을 추가하기는 쉬운 반면, 기존 객체에 새 동작을 추가하기는 어렵다. 자료 구조는 별다른 동작 없이 자료를 노출한다. 그래서 기존 자료 구조에 새 동작을 추가하기는 쉬오나, 기존 함수에 새 자료구조를 추가하기는 어렵다. 어떤 시스템을 구현할 때, 새로운 자료 타입을 추가하는 유연성이 필요하면 객체가 더 적합하다. 새로운 동작을 추가하는 유연성이 필요하면 자료구조와 절차적인 코드가 더 적합하다. 우수한 소프트웨어 개발자는 편견없이 이 사실을 이해해 직면한 문제에 최적인 해결책을 찾는다.

7. 오류처리

  • 오류 코드보다 예외를 사용하라
  • unchecked 예외를 사용하라
  • 예외에 의미를 제공하라(=오류메시지에 정보를 담아 던진다)
  • 호출자를 고려해 예외 클래스를 정의하라 : 오류를 정의할 때 프로그래머에게 가장 중요한 관심사는 오류를 잡아내는 방법이 되어야한다
  • null을 전달/반환하지 마라

8. 경계

  • 외부코드 사용하기
  • 경계 살피고 익히기
  • log4j 익히기
  • 아직 존재하지 않는 코드를 사용하기

9.단위테스트

  • TDD(Test Driven Development - 테스트 주도 개발)
  • TDD 법칙 세가지
    • 실패하는 단위테스트를 작성할 때까지 실제 코드를 작성하지 않는다.
    • 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다
    • 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다
  • 깨끗한 테스트코드 유지하기
  • 테스트는 유연성, 유지보수성, 재사용성을 제공한다
  • 깨끗한 테스트코드 = 가독성(최소한의 표현으로 많은 것을 나타내야함)
  • 테스트당 assert하나 : 테스트랑 개념하나
  • Fast / Independent / Repeatable / Self-validating(테스트결과는 boolean, 자가 검증) / Timely(적시에)

10. 클래스

  • 클래스는 작아야 한다 : 클래스는 해당 클래스 책임을 기술해야 한다. 간결한 이름이 떠오르지 않는다면 클래스 크기가 너무 크거나 책임이 너무 많아서다
  • 변경하기 쉬운 클래스

11. 시스템 (??)

  • 관심사 분리
  • 확장
  • AOP(Aspect Oriented Programming, 관점지향프로그래밍) : 특정 관심사를 지원하려면 시스템에서 특정 지점들이 동작하는 방식을 일관성 있게 바꿔야 한다고 명시한다
  • 자바프록시, POJO
  • AspectJ관점 : 관심사를 관점으로 분리하는 강력한 도구, 언어 차원에서 관점을 모듈화 구성으로 지원하는 자바 언어 확장
  • 테스트주도 시스템 아키텍처 구축
  • 의사 결정을 최적화하라
  • 명백한 가치가 있을 때 표준을 현명하게 사용하라
  • 시스템은 도메인 특화 언어가 필요하다

12. 창발성

  • 단순한 설계규칙
    • 모든 테스트를 실행하라
    • 중복을 없애라
    • 표현하라 - 좋은 이름을 선택한다, 함수와 클래스 크기를 가능한 줄인다, 표준 명칭을 사용한다, 단위테스트케이스를 꼼꼼히 작성한다
    • 클래스와 메서드 수를 최소로 줄여라

13. 동시성

여러 스래드를 동시에 돌리는 이유, 어려움, 이런 어려움에 대처하고 깨끗한 코드를 작성하는 방법

  • 동시성이 필요한 이유? 동시성은 결합을 없애는 전략, 무엇과 언제를 분리하는 전략
  • 동시성 방어원칙 - 동시성 코드는 다른 코드와 분리하라, 자료를 캡슐화하라, 공유 자료를 최대한 줄여라
  • 라이브러리를 이해하라

14. 점진적인 개선

15. JUnit 들여다보기

16.Serial Date 리팩터링

17. 냄새와 휴리스틱

'' 카테고리의 다른 글

리팩터링 2판  (0) 2022.01.18


리팩터링 원칙

리팩터링이란 소프트웨어의 겉보기 동작은 그대로 유지한 채, 코드를 이해하고 수정하기 쉽도록 내부 구조를 변경하는 기법이다.

  • 좋은 설계, 쉬운 이해, 버그 찾기, 프로그래밍 속도 향상에 목적이 있다.
  • 언제 리팩터링 해야 할까?
    • 리팩터링 작업 대부분은 드러나지 않게, 기회가 될 때마 다해야한다
    • 비슷한 일을 세 번째 하게 되면 리팩터링 한다
    • 새로운 기능을 추가학 ㅣ전에 한다
    • 코드를 파악할 때 마다 코드의 의도가 더 명확하게 드러나도록 리팩토링 해야 한다
    • 코드 리뷰 할 때
  • 리팩터링하는 동안에는 코드가 항상 정상 작동하기 때문에 전체 작업이 끝나지 않았더라도 언제든 멈출 수 있다.

코드에서 나는 악취

1. 기이한 이름

함수, 모듈, 변수 , 클래스 등은 그 이름만 보고도 각각이 무슨 일을 하고 어떻게 사용해야 하는지 명확히 알 수 있도록 신경써서 이름을 지어야 한다.

2. 중복 코드

3. 긴 함수

  • 함수를 적극적으로!! 쪼개기
  • 주석을 달아야 할 만한 부분을 함수로 만들기
  • 조건문 반복문 처리 : 조건문 분해하기(10.1), 조건문 통합하기(10.2)

    4. 긴 매개변수 목록

  • 매개변수는 함수 동작에 변화를 줄 수 있는 일차적인 수단
  • 매개변수를 질의 함수로 바꾸기(11.5) : 피호출함수가 매개변수로 받지 않고 함수 내부에서 값을 얻을 수 있으면 이렇게 한다. 단, 매개변수를 제거했을 때 피호출 함수에 원치않는 의존성이 생기지 않는 경우에만!
  • 객체를 통째로 넘기기(11.4) : 하나의 레코드에서 값을 가져와 넘길 때에는 레코드를 통째로 넘긴다. 함수 내부에서 레코드를 사용하기 편리하고, 사용하는 값이 추가되거나 바뀔 때 매개변수를 수정하지 않아도 됨
  • 매개변수 객체 만들기(6.8)
  • 플래그 인수 제거하기(11.3)

    5. 전역 데이터

  • 전역 데이터는 코드베이스 어디서든 건드릴 수 있고, 값을 누가 바꿨는지 찾아낼 메커니즘이 없다
  • 6.6 함수 캡슐화하기 : 데이터로의 접근을 독점하는 함수를 만든다. → 데이터를 변경하고 사용하는 코드를 감시할 수 있다

    6. 가변 데이터

  • 데이터를 변경했더니 예상치 못한 결과가 나올 가능성이 있다.
  • 9.1 변수 쪼개기 : 하나의 변수에 값을 한 번만 할당한다. 두 번 이상 할당해야한다면 여러가지 역할을 하는 것이므로 쪼개야 한다. const로 선언할 것을 권장!
  • 8.6 문장 슬라이스 : 관련된 코드들을 모아놓기, 변수를 한 곳에서 선언하기 보다 처음 사용할 때 선언
  • 6.1 함수 추출
  • 11.1 질의함수와 변경함수 분리하기

    7. 뒤엉킨 변경

  • 하나의 모듈이 여러 가지 방식으로 변경되는 일이 많은 경우
  • 원인: 단일 책임 원칙(SRP) 지켜지지 않아서
  • 맥락별로 분리하기
  • 맥락이 다르면 독립된 모듈로 분리
  • 단계 쪼개기: 맥락끼리 특정한 데이터 구조를 담아 전달
  • 함수 옮기기: 맥락이 동일한 함수들을 모듈로 모으기

8. 산탄총 수술

  • 코드를 변경할 때마다 자잘하게 수정해야 하는 클래스가 많을 때
  • 함께 변경되는 대상을 한 모듈에 묶어두기 : 필드 옮기기(8.2), 함수 옮기기(8.1)
  • 비슷한 데이터를 다루는 함수 묶기 : 여러 함수를 클래스로 묶기(6.9), 여러 함수를 변환 함수로 묶기(6.10)
  • 인라인 리팩터링

기본적인 리팩터링

  • 가장 많이 하는 리팩터링은 함수 추출하기와 변수 추출하기 (리팩터링은 본래 코드를 변경하는 작업인 만큼 반대로 함수, 변수 인라인하기도 많이함)
  • 추출은 결국 이름 짓기
  • 자주 함께 뭉쳐다니는 인수는 매개변수 객체로 만들면 편리하다
  • 함수를 그룹으로 묶을 때는 클래스로 묶기

함수 추출하기

  • 이름만 봐도 무엇을 하는지 알 수 있게
  • 목적과 구현을 분리
  • 함수를 추출할 때 추출한 코드에서만 사용하는 변수가 추출한 함수 밖에 선언되어 있다면 추출한 함수 안에서 선언하도록 수정
  • 중첩 함수도 가능 (지원하는 언어에서만)
  • 코드를 독립된 함수로 묶는 시점
    • 길이가 한 화면 안 넘어가기
    • 재사용성
    • 두 번 이상 사용될 코드
  • 함수가 긴 것 보다 짧게 여러번 호출되는게 오히려 성능에 유리하다
  • 함수를 짧게 작성할때의 이점은 이름을 잘 지어야만 발휘된다

매개변수 객체 만들기

  • 데이터의 관계 명확해짐, 매개 변수 줄어듦, 데이터의 일관성이 높아짐
  • 데이터 구조를 활용하는 형태로 프로그램 동작을 재구성 할 수 있다 = 데이터 구조에 담긴 데이터에 공통으로 적용되는 동작을 추출

여러 함수를 클래스로 묶기

  • 같은 인수로 긴밀하게 엮여 작동하는 함수들은 클래스로 묶는다
  • 장점 : 함수들이 공유하는 공통 환경을 명확하게 표현할 수 있다, 함수 인수를 줄여서 객체 안에서 호출을 간결하게 할 수 있다

여러 함수를 변환 함수로 묶기

  • 원본 데이터를 입력받아서 필요한 정보를 모두 도출한 뒤 각각을 출력 데이터 필드에 넣어서 반환

캡슐화

  • 모듈을 분리하는 가장 중요한 기준은 자신을 제외한 다른 부분에 드러내지 않아야 할 비밀을 얼마나 잘 숨기고 있느냐
  • 레코드 캡슐화하기, 컬렉션 캡슐화하기로 숨길 수 있다.
  • 기본형 데이터는 기본형을 객체로 바꾸기로 캡슐화 할 수 있다.
  • 클래스는 본래 정보를 숨기는 용도로 설계되었다.
  • 클래스 추출하기, 인라인하기도 활용할 수 있다.

기본형을 객체로 바꾸기

  • 단순한 출력 이상의 기능이 필요해지는 순간 데이터를 표현하는 전용 클래스를 정의하는 편
  • 특별한 동작이 추가되거나 프로그램이 커질 수록 유용한 도구가 된다.
  • 절차
    • 데이터 값을 다루기 전 변수부터 캡슐화
    • 단순한 값 클래스를 만든다 (인수로 받아서 저장하는 생성자와 값을 반환하는 게터 추가)
    • 기존 클래스에서 게터를 통해 새로만든 클래스의 게터를 호출한 결과를 반환하도록 게터를 수정
    • 테스트

임시 변수를 질의 함수로 바꾸기

  • 함수에서 어떤 결과값을 다시 참조하는 목적으로 임시 변수를 쓴다
  • 임시 변수를 사용하면 값을 계산하는 코드 반복을 줄이고 설명할 수도 있어서 유용하다
  • 함수로 만들어 사용하는 편이 낫다.
  • 각각의 임시 변수들을 함수로 만들어 사용하면 변수를 따로 전달할 필요도 없고 함수의 경계가 더 분명해지고 부자연스러운 의존 관계나 부수효과를 찾는데 도움이된다
  • 다른 함수에서도 사용할 수 있어 도움이된다.
  • 스냅숏 용도로 쓰이는 변수에는 이 리펙터링을 하면 안된다

기능이동

  • 관련된 코드끼리 모이도록 코드 조각을 옮기기
  • ex. 변수를 첫머리에 모아두지 않고 처음 사용할 때 선언하기

함수 옮기기

필드 옮기기

  • 필요한 경우 : 함수에 어떤 레코드를 넘길 때마다 또 다른 레코드의 필드도 함께 넘기는 경우, 레코드를 변경할 때 다른 것도 변경해야 할 경우, 여러 개에 정의된 똑같은 필드를 갱신해야한다면 한 번만 갱신해도 되게끔

데이터 조직화

변수 쪼개기

  • 하나의 변수가 여러 역할을 가지지 않도록
  • 변수에 값이 두 번 이상 대입되면 역할이 두 개라는 신호 (수집 변수 제외)
  • 웬만하면 불변으로 선언

필드 이름 바꾸기

  • 우선 캡슐화 하기
  • 객체 안의 필드명과 메서드를 수정
  • 이후, 접근자 수정
  • 리팩터링 도중 테스트에 실패한다면 더 작은 단계로 나눠야 한다!

파생 변수를 질의 함수로 바꾸기

  • 질의 함수: 연산을 통해 값을 구하는 함수
  • 계산해 낼 수 있는 변수를 제거하여 함수로 분리하기

참조를 값으로 바꾸기

  • 객체 내부의 속성을 변경하는 경우, 참조를 이용하지 않고 값으로 기존 객체를 통째로 대체하기
  • 계산해 낼 수 있는 변수를 제거하여 함수로 분리하기

값을 참조로 바꾸기

  • 같은 데이터를 여러번 복제하여 사용할 때, 참조를 이용하기
  • 값을 복제하면 데이터를 갱신할 때 일관성이 깨지는 문제 발생
  • 같은 데이터를 참조할 수 있는 저장소 객체 생성하여 이용
  • 유일하게 접근할 수 있는 위치

매직 리터럴 바꾸기

  • 코드의 의미를 분명히 드러내는 이름의 상수로 바꾸기
  • 리터럴이 함수 하나에서 쓰이거나, 맥락 정보를 충분히 제공할 때에는 굳이 사용할 필요

조건부 로직 간소화

조건문 분해하기

  • 복잡한 조건부 로직은 프로그램을 복잡하게 만드는 흔한 원흉
  • 조건식을 먼저 함수로 추출하고 다음으로 조건절을 함수로 추출한다
  • 해당 리펙토링을 진행하면 조건식과 조건절이 좀 더 명확해진다.
  • 조건식과 그 조건식에 딸린 조건절 각각을 함수로 추출 → 조건이 무엇인지 강조하고, 무엇을 분기했는지 명확해짐

조건식 통합하기

  • 비교하는 조건은 다르지만 그 결과로 수행하는 동작은 같은 코드들을 통합시킨다.
  • OR 연산자를 통해 합친 조건식을 함수로 추출해서 사용한다.
  • 동작이 다른 독립적인 조건문은 리펙토링 해서는 안된다.

중첩된 조건문을 보호 구문으로 바꾸기

  • 모두 정상 동작으로 이어지는 형태의 조건문은 if else 절
  • 정상, 비정상이 나뉘어 진다면 보호 구문으로 바꾸기

특이 케이스 추가하기

  • 데이터 구조의 특정 값을 확인한 후 똑같은 동작을 수행 === 중복코드
  • 이처럼 특정 값에 대해 똑같이 반응하는 코드가 여러 곳이라면 그 반응들을 한 데로 모으는게 좋다.
  • 특수한 경우의 공통 동작을 요소 하나에 모아서 사용것을 특이 케이스 패턴이라 한다.
  • 해당 패턴을 사용하면 코드 대부분을 단순한 함수 호출로 변경할 수 있다.
  • Null을 특이 케이스로 보는 경우가 많아사 위 패턴을 널 객체 패턴이라고도 한다.
  • 절차
    • 컨테이너 (데이터구조, 클래스) 에서 특이 케이스를 검사하는 속성을 추가하고 false 값을 반환하게 한다.
    • 특이 케이스 객체를 만든다. 이 객체는 특이 케이스인지를 검사하는 속성만 포함하고 true를 반환한다.
    • 특이 케이스인지 검사하는 코드를 함수로 추출한다.
    • 특이 케이스를 검사하는 함수에서 특이 케이스 객체의 속성을 사용하게 변경한다.
    • 특이 케이스 검사 함수를 클래스로 묶거나 여러 함수를 변환함수로 묶기를 적용해서 공통 동작을 새로운 요소로 옮긴다.

'' 카테고리의 다른 글

클린코드  (0) 2022.01.18

+ Recent posts