kangoll
kangoll 23 year old college student.I like drawing and traveling.

[우테코] level-1 / mission3 회고

[우테코] level-1 / mission3 회고

요약 우테코 1단계 3주차 회고 글입니다. 미션을 진행하며 배운 점과 기억하고자 하는 점들을 담았습니다.




목차




미션 3단계

미션 3단계를 마치며

소프트 스킬의 중요성

미션 3단계를 진행하며 깨달은 점은 소프트스킬의 중요성이다.

페어로부터 “대화하기 편한 분위기를 만들어준다“라는 피드백을 받게 되었는데 당시엔 꽤나 신선한 충격으로 다가왔다. 그동안 이게 내 강점이라고 생각해본 적이 없었기 때문이다. 이 피드백을 통해 “소프트 스킬“이 협업에 있어 꽤나 중요한 역할을 한다는 것을 인지하게 되었다.

우테코에 와서 배운 것 중 가장 중요한 것을 꼽자면 소통이라고 생각한다. 내 의견을 상대방이 잘 이해할 수 있도록 설명해야 했고, 의견 충돌이 생겼을 때는 상대방의 기분이 나쁘지 않게 의견을 전달할 수 있어야 했다. 또한 근거를 가지고 설득하는 방법, 두괄식으로 핵심을 먼저 말하는 방법 등도 익히게 된 것 같다.

아쉬웠던 점

미션을 급하게 수행하다 보니 놓친 부분들이 있다. 매주 회고글을 작성하지 못했고, 여전히 기본적인 지식이 부족하다고 느꼈지만 이를 깊게 공부하지 못한 점이 아쉬움으로 남는다.

성장한 점

엘강오 스터디에 참여한 것이 큰 전환점이 되었다. 유강스(유연성 강화 스터디)를 통해 “익숙한 곳에 머무르지 않도록 나를 안전지대로부터 이끌어내기“라는 목표를 세우게 되었고, 그 첫 걸음으로 엘강오에 참여하게 되었다. 익숙함에서 벗어나기 위해 운동도 다시 시작하게 되었고 망설이던 교회 청년부도 들어가게 되면서 “새로운 환경에 적응하는 훈련”을 하게 되었다.

그 과정에서 깨달은 것은 “언젠가는 괜찮아진다“는 점이다. 공원이 해준 말이기도 하지만, “새로운 도전은 누구에게나 힘들다“는 것을 스스로 체감하며 받아들이게 된 것 같다.



공부 내용


📌 Q1) 응집성 응집성 응집성!! 결합성도!!

응집도

이번 1단계 미션을 진행하면서 가장 많이 받은 코멘트는 바로 응집성에 대한 피드백이다.

처음에는 ‘응집성’이라는 단어가 굉장히 추상적으로 느껴졌다. “그래서 응집성을 높이려면 어떻게 해야하는데?” 라는 의문이 머릿속을 맴돌기도 했다. 하지만 몇 번의 피드백을 주고받으며 조금씩 ‘응집성’에 대한 의미를 이해하게 되었다.

내가 이해한 ‘응집성’은 결국 유사한 기능들을 한 곳에서 관리할 수 있게 만들어라. 비슷한 기능들을 다룰 때애 시선이 멀리 떨어지지 않게 관리하라. 라는 의미로 전달이 되었다.

결합도

결합도에 대해서는 아직 완전히 와닿지 않는다. 다만 피드백을 통해 받은 멘트 중 “header는 언제나 iconButton컴포넌트와 함께 존재하고,iconButton은 언제나 click하면modalOpen`이 실행되는군요” 라는 말이 기억에 남는다.

위의 피드백을 통해 ‘결합도’에 대해 조금 이해하게 되었는데, “ headericonButtonmodalOpen함수에 의존한다. 즉 강결합 되어있다. 다른 형태로 쓰일 수 없다.” 라는 의미로 다가왔다.


📌 Q2) 나의 나쁜 습관들 : 변수명을 대충 짓는다.

사실 나의 습관을 가장 관통하는 피드백으로 기억에 남는다. 처음에 “변수명을 대충 짓는다”라는 피드백을 받게 되었을 때 나의 성격을 잘 파악하신 것 같아서 잠시 웃음이 나오기도 했다.

코드를 빠르게 읽을 때, 인터페이스만 보고 코드를 읽습니다. 즉, 함수명, 변수명, 인자명만 보죠. 그렇게만 봐도, 어떤 흐름으로 어플리케이션이 돌아가는지 이해할 수 있어야 합니다. 하지만 캉골의 코드는 읽을때 중간에 턱턱 막힙니다. 사실 대부분의 코드에서 읽다가 막혀서, 세부 구현 자체를 살펴보아야 했습니다.

그래서 캉골이 변수명을 대충 짓는 습관이 있다고 추론하게 되었어요.

가장 기억에 남는 피드백인만큼 “어떻게 하면 변수명을 잘 지을 수 있을까” 하는 고민이 이후 미션때마다 따라오기 시작했던 것 같다.

이때 도움이 되었던 이론 중에 하나가 엘강오에서 읽었던 내용 중 하나인데, 객체의 이름을 짓는 방법에 대한 규칙이였다.


객체(class)

  1. 객체는 살아있는 유기체로 대할 것.
  2. 객체의 이름을 지을 땐 -er, -or과 같이 어떠한 ‘역할’을 의미하는 것이 아닌 객체가 ‘무엇’인지에 초점을 둘것
  3. 객체의 내부 함수에서 어떠한 값을 return 하는 경우 명사 형식으로 작성한다.
  4. 객체의 내부 함수에서 어떠한 값을 props로 전달받아 상태를 변경시키는 경우 return 값은 존재하지 않아야 하며 동사형식으로 작성한다.

3,4번의 경우 Car의 class의 예시를 들어보자면 다음과 같다.

자동차의 위치를 반환하는 함수의 경우 const a = Car.position()

자동차에게 위치를 변경하는 함수의 경우 Car.movePosition(3)


일반함수(function)

  1. 함수의 이름에서 두가지 이상의 이름이 필요하다면 많은 기능이 들어간 것일 확률이 높다. 더 작게 역할을 분리하자
  2. 함수의 이름에서 알 수 있는 역할까지만 일을 수행하도록 할것.
  3. 개발자들이 자주 쓰는 관행어를 익히도록 한다.
    1. ex) fetch~ : 어떠한 데이터를 반환하는 함수일 가능성이 높다.
  4. 이름 짓는게 어렵다면 ai를 활용해보자.


📌 Q3) JavaScript에서 this 바인딩 오류

< 문제 코드 >

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//FoodInventory.js
  addFoodItem() {
    const foodInfo = this.#getFoodItem();
    if (!foodInfo) return;
    this.#updateFoodList(foodInfo);
    Modal.close();
  }

  //FoodForm.js
  Button({
    cssType: "primary",
    innerText: "추가하기",
    onClick: foodInventory.addFoodItem,
  })
  ..

위 코드에서는 foodInventory.addFoodItem을 직접 addEventListener에 전달하고 있습니다. 하지만 이렇게 하면 this가 foodInventory 인스턴스를 가리키지 않고 undefined가 되어 오류가 발생하게 된다.

위 상황을 해결할 수 있는 방법으로는

  1. bind 사용하기 (해결한 방법)

bind를 사용하여 this를 명확하게 바인딩할 수 있다. bind를 사용해서 내가 전달하고싶은 this가 무엇인지를 전달하는 과정이라고 생각하면 될 것 같다! 이렇게 하면 addFoodItem 내부에서 thisfoodInventory를 유지하게 됩니다.

1
onClick: foodInventory.addFoodItem.bind(foodInventory),
  1. 화살표 함수 사용하기 화살표 함수를 사용하면 this가 외부 스코프(foodInventory)의 this를 유지할 수 있다. 하지만 이 방법은 addFoodItem이 호출될 때마다 새로운 함수가 생성된다는 단점이 있습니다.
1
onClick: () => foodInventory.addFoodItem(),
  1. 클래스 메서드를 화살표 함수로 변경 다만 위 방식을 사용하게 된다면 클래스 내부에서 함수 작성 방식을 변경해야 하므로 사용하지 않았다!
1
2
3
4
addFoodItem = () => {
  const foodInfo = this.#getFoodItem();
  Modal.close();
};


📌 Q4) domain과 ui의 분리

특히나 component(UI)에 onClick 속성(domain)을 주어야 할 경우 어떻게 해야할까? 두가지 방법 정도를 예시로 들 수 있다.

  1. onClick 함수를 porps로 전달받아서 사용한다.
  2. 이벤트를 더 상위 부모에게 위임해서 사용한다.

domain과 ui를 분리하는 기준은 ui가 바뀌더라도 변경되지 않는 부분은 domain, 그렇지 않고 변경되는 부분은 ui라고 생각한다. (더 좋은 의견이 있을까요?)


📌 Q5) 상태를 관리하는 방법

이번 피드백에서 기억에 남는 부분 중 하나는 “상태 -> UI를 반영하는 구조가 되어야지 UI에서 상태를 가지고 와서는 안된다.” 라는 피드백이다.

여기서 상태의 원천이라는 용어를 배우게 되었는데 이는 가장 믿을 수 있는 상태의 출처, 즉 진짜 상태가 저장되어 있는 중심지를 의미한다.

이를 이번 피드백에서 적용해보자면 화면 UI가 상태의 원천이 되어서는 안된다는 것이다. UI에서 가져온 상태를 가지고 domain에 사용되는 상태를 변경했을 때 예상되는 몇가지 문제점이 있다.

  1. UI 변경 시 로직이 깨질 수 있다.
  2. DOM 에 의존하기 때문에 테스트 하기 어렵다.

결국 UI가 상태의 원천이 될 수 밖에 없었던 원인은 상태를 props로 계속해서 전달해주기가 불편했기 때문임을 알게 되었다. 그리고 이에 대한 나의 해결법은 싱글톤 패턴전역 상수를 도입하는 것이다.

  • 싱글톤 패턴

app 전체에서 하나의 인스턴스만 존재하도록 보장하는 디자인 패턴. 함수나 class를 바로 export 하는 것이 아니라 처음 실행된 인스턴스를 export 하는 방식으로 구현할 수 있다.

  • 전역 상수

app 전반에서 사용할 수 있도록 하나의 별도의 파일을 만들어서 관리하는 방법. 어디에서든 import 해서 사용가능하다.



이번주 키워드


🔑 K1 ) 응집도, 결합도

응집도는 하나의 모듈이나 내부의 구성요소들이 얼마나 밀접하게 관련되어 있는지를 수치적으로 평가한 것이다.

응집도가 높다 = 해당 모듈이 하나의 목적 또는 책임에 집중하고 있다. 응집도가 낮다 = 여러 목적을 섞어놓은 모듈일 가능성이 크다

  • 단일책임원칙(SRP)를 위반 가능성 있음

결합도는 하나의 모듈이 다른 모듈에 얼마나 의존하고 있는지 연결 정도를 평가한 것.

결합도가 높다 = 모듈 간 의존성이 높아져서 하나를 수정하면 다른 것도 같이 영향을 받음 결합도가 낮다 = 모듈이 서로 독집적으로 동작하며 변경 시 영향이 적다

높은 응집도와 낮은 결합도를 목표로 설계할 수 있도록 훈련하자.


🔑 K2 ) E2E 테스트란?

E2E 테스트는 최대한 실제 사용자가 앱을 사용하듯이 작성하여, 실제 사용할 때 생길 수 있는 문제를 사전에 검증할 수 있도록 하는 테스트를 의미한다.

  • 단위테스트 비지니스 로직이 올바르게 동작하는지 테스트 한다. domain 기능을 주로 테스트 한다.

  • e2e 테스트 단위테스트와는 달리 하나의 큰 흐름을 테스트한다는 점이 특징이다. UI부터 도메인, 외부 API까지의 하나의 ‘동작’을 테스트 한다.

e2e 테스트를 위해서 Cypress를 사용할 수 있다.


🔑 K3 ) TypeScript

[우테코] level-1 / TypeScript에 관하여 TypeScript에 대한 구체적인 내용은 위의 블로그 글에 업로드 했으니 참고해도 좋을 것 같다!

TypeScript를 왜 쓰냐고 한다면 JS는 동적 타입 시스템이기 때문에 런타임때 오류 검사를 하지만 TS는 정적 타입 시스템이기 때문에 컴파일때 오류 검사를 진행하기 때문인 것 같다.

따라서 TS는 컴파일 시간에 오류를 잡아내주기 때문에 안정적이게 코드를 작성할 수 있으며 타입이 일관성 있어지므로 유지보수가 쉬워진다. 또한 타입 시스텝 덕분에 개발자가 실수하지 않도록 도와주며, IDE 툴을 통한 자동완성을 도와주므로 개발 경험을 향상시켜준다는 장점이 있다.

그러나 TS는 컴파일 시 타입 검사만 수행하기 때문에 런타임 타입 안전성을 보장하지 않는다. 또한 유연성있는 JS의 특성을 그대로 유지하기 위해 구조적 타입 시스템을 사용한다.복잡한 타입 추론이 필요한 경우 완전한 타입 정합성보다 개발자의 편의성을 우선시하는 허용적인 설계를 택하는 경우도 있다.


🔑 K3 ) YAGNI (You aren’t gonna need it)

YAGNI는 프로그래머가 필요하다고 간주할 때까지 기능을 추가하지 않는 것이 좋다는 XP(익스트림 프로그래밍)의 원칙이다. XP의 창시자는 이를 두고 ‘실제로 필요할 때 무조건 구현하되, 그저 필요할 것이라고 예상할 때에는 절대 구현하지 말라’고 강조했다.


🔑 K4 ) 읽기 전용으로 만들기

  • Object.freeze

Object.freeze는 JavaScript의 Object 객체에 정의된 정적 메서드로, 객체를 동결(freeze)하여 속성을 추가, 제거, 변경할 수 없게 만든다. 런타임에 실행되며, 동결된 객체의 속성을 변경하려 할 때 use strict 모드에서는 TypeError를 발생시키지만, 일반 모드에서는 조용히 실패(silent fail)한다. (에러 발생시키지 않음)

Object.freezeTop-level 수준에서만 동결이 가능하기 때문에 객체 내부에 중첩된 객체가 있을 경우, 해당 내부 객체들도 동결하려면 재귀적으로 Object.freeze를 호출해야 한다.

1
2
3
4
5
6
7
8
const obj = Object.freeze({
  outer: {
    inner: "hello",
  },
});

obj.outer = {}; // ❌ 얘는 막힘 (Top level은 freeze 됐기 때문)
obj.outer.inner = "hi"; // ✅ 이건 바뀐다! (내부 객체는 freeze 안 됐음)

Object.freeze는 아래와 같이 실제로 obj의 속성을 writable: false로 바꿔주지만 런타임때 코드가 실행된다.

1
2
3
4
Object.defineProperty(obj, key, {
  writable: false,
  configurable: false,
});


  • as const

as const는 객체나 배열의 값을 리터럴 타입으로 고정하고, 전체를 읽기 전용(readonly)으로 만드는 TypeScript의 문법이다.

Object.freeze와 다른점은 2개가 있다.

  1. TypeScript의 문법이기 때문에 컴파일 타임에 type 오류를 잡을 수 있다.
  2. Object.freeze는 top-level에서만 type 검사를 실행하지만 as const는 중첩 객체의 경우에도 모든 속성을 readonly 속성으로 만들어준다.

as const는 Object.freeze처럼 실제로 obj의 속성을 바꿔주지는 않지만 컴파일 시점에 검사를 진행하기 때문에 빠른 피드백을 얻을 수 있다. 또한 아래 코드와 같이 object가 중첩되어 있는 상황에서도 내부까지 readonly 속성으로 설정한다.

1
2
3
4
5
6
7
8
9
10
11
12
const obj = {
  outer: {
    inner: "hello"
  }
} as const;

obj.outer = {};           // ❌ TS 에러: outer는 readonly
obj.outer.inner = "hi";   // ❌ TS 에러: inner도 readonly




  • readonly / Readonly<Type>

readonly는 객체의 속성을 읽기 전용으로 지정하는 키워드이며, 주로 인터페이스나 타입 정의에서 사용된다. 또한 Readonly<Type> 유틸리티 타입을 통해 객체 전체를 읽기 전용으로 만들 수도 있다.

주로 객체 안에 있는 props 대상으로 사용한다.

1
2
3
4
5
6
7
8
9
10
11
function foo(config: {
    readonly bar: number,
    readonly bas: number
}) {
    // ..
}

let config = { bar: 123, bas: 123 };
foo(config);
// `config`가 변경되지 않는다고 확신할 수 있음 🌹

comments powered by Disqus