원티드 프리온보딩 챌린지 강의를 듣고 2

김형석·2022년 8월 10일
0

React

목록 보기
16/17

예시 라이브 리팩토링

Feedback 1) 맥락을 이해하기 힘든 변수명

구현 방식 대신 무엇인지를 나타내는 변수명(How vs What)을 선택하여 개발자의 의도를 드러내야 한다.

함수를 새로 만들고 목적을 잘 드러내는 이름을 붙여야한다.('어떻게'가 아닌 '무엇을' 하는지가 드러나야 한다.)

변수명이 중요한가?에 대해서는 공부를 하다보면 많이 듣게 되지만 막상 코드를 치게 되면 대충 이름을 짓게 되는 경우가 대부분이다. 이름을 지을 때 세부 구현사항을 손으로 가린 채 변수명만 보고 so what? 어쩌라고?라고 반문하면 도움이 된다하는데 리팩토링할 때 써봐야겠다.

타입별 변수명

  • boolean : is-, has-, can-,...
  • function : get-, handle-, submit-,...
  • array : -s(ex. users.map(user ⇒ user.id)), …

피해야 할 변수명

  • data, info, foo, user1, mdhms,...

피해야 할 변수명에는 왜 내가 쓰는 것만 들어있는 걸까?!

Feedback 2) 명령형 프로그래밍

명령형 프로그래밍과 선언형 프로그래밍에 대해서는 정확히 뭐고 어떻게 사용하는가에 대해서는 모르고 있었다. 챌린지를 통해서 선언적인 코드가 대부분의 상황에서 깔끔하고 그 둘 사이의 차이를 이해하는 계기가 되었다.
내 코드에도 적용해보면서 확실하게 익혀보겠다.

명령형과 선언형의 차이는 간단히 표현해보자면 명령형은 특정한 동작을 어떻게(How) 달성할 것인지에 집중하고, 선언형은 무엇을(What) 할지에 집중한다. how와 what이라니, 아까 변수명을 지을 때와 비슷한 맥락처럼 보인다.

예시를 보자.

명령형 프로그래밍의 패러다임으로 출근길을 표현해보면 다음과 같다.

“집에서 나와 오른쪽으로 10m, 다시 왼쪽으로 10m, 언덕을 따라 30m 내려간 뒤 왼편에 보이는 지하철역에서 강남역 방향 지하철을 타고 7정거장을 이동하여 하차한다.” (How)

반면 선언형 프로그래밍에 가깝게 표현하면 아래와 같다.

“나는 강남역으로 이동한다” (What)

'어떻게'에 대해서는 단 한마디도 없이 무엇을 하고 싶은지에 대해 서술만 있어 간결하게 느껴진다.

:: React(JSX) vs Vanilla JavaScript

[선언형]

React는 상호작용이 많은 UI를 만들 때 생기는 어려움을 줄여줍니다. 애플리케이션의 각 상태에 대한 간단한 뷰만 설계하세요. 그럼 React는 데이터가 변경됨에 따라 적절한 컴포넌트만 효율적으로 갱신하고 렌더링합니다.
선언형 뷰는 코드를 예측 가능하고 디버그하기 쉽게 만들어 줍니다.

  • React 공식문서
// #1
const App = () => <div>Hello, Declarative!</div>

// #2
const hello = document.createElement("div")
hello.innerText = "Hello, Declarative!"
body.appendChild(hello)

이 외에도 HTML, CSS SQL, YAML 등등의 문법들은 모두 무엇을 하고 싶은지만을 표현한 선언형의 대표적인 예시라고 볼 수 있다.

선언형 프로그래밍은 코드와 문법이 위와 같은 느낌으로 읽힐 수 있도록 이름을 짓고, 추상화하고, 인터페이스를 설계하는 방식이다. 특정한 부분은 명령형으로 작성할 수도 있겠지만, 사용자 측에서 가급적 무엇을 하고 싶은지만 신경쓸 수 있도록 하면 보다 직관적인 코드를 작성할 수 있다.

이것과 관련하여 좋은 동영상을 추천해 주셔서 직접 보고 가져왔다.

Feedback 3) 적절히 추상화 되지 않은 함수와 컴포넌트

프로그래밍에는 DRY(Don’t Repeat Yourself)라는 원칙이 있다고 한다. 중복 코드를 만들지 말라는 뜻이다. 코드의 중복을 줄이면 타이핑하는 코드가 줄어든다는 직관적인 장점 뿐만 아니라, 로직의 관리 포인트가 줄어들어 유지 보수 측면에서의 장점도 있다.

로직의 관리 포인트가 줄어든다는 말은 하나의 수정사항을 반영하기 위해 여러 코드를 반복적으로 수정하지 않아도 된다는 뜻! 그렇게 되면 개발자가 코드를 보다 쉽고 안전하게 수정, 추가할 수 있다.

setLoading(true)
fetch("http://localhost:3000", {
	method: "POST",
	body: JSON.stringify({
    id: "jt",
    pw: "1q2w3e4r!"
  })
})
	.then(res => res.json())
	.then(res => {
		setUser(res)
	})
	.catch(err => alert(err))
	.finally(() => {
		setLoading(false)
	})

음 위 코드는 내가 짠 코드같다.

// https://use-http.com/#/?id=managed-state-usage
const { get, post, response, loading, error } = useFetch('https://example.com')

const addTodo = async () => {
  const newTodo = await post('/todos', { title: 'my new todo' })
  if (response.ok) {
		setTodos([...todos, newTodo])
	}
}

단일 책임 원칙 하나의 함수가 한 가지 일을 하도록 코드를 작성하라는 것이다.

// 적용 전 - 1) 수정하는 사용자, 2) 등록하는 사용자가 하나의 함수를 사용한다
const getInitialData = (type: 'edit' | 'register') => {
  if (type ==== 'edit') {
    // 수정 시에 필요한 초기 데이터를 불러오는 로직
  } else {
    // 등록 시에 필요한 초기 데이터를 불러오는 로직
  }
};
// 적용 후 - 1) 수정하는 사용자, 2) 등록하는 사용자가 서로 다른 함수를 사용한다
const getInitialDataForEdit = () => {
  // 수정 시에 필요한 초기 데이터를 불러오는 로직
};
const getInitialDataForRegister = () => {
  // 등록 시에 필요한 초기 데이터를 불러오는 로직
};

동일한 코드를 서로 다른 두 액터가 유사한 코드를 구현할 경우는 억지로 합칠 필요는 없다고 한다. 비록 지금은 두 코드가 유사해보일지라도 두 코드는 서로 다른 액터에 의해 다른 방향으로 발전해나갈 것이기 때문이다.

우리의 코드가 어떤 형태의 인터페이스를 가지며 추출되어야 할지, 이 중복은 우발적인지 의도된 중복인지를 잘 생각해보면 나눈다 는 행위와, 어떠한 나누기, 어떠한 정도의 나누기가 좋은지에 대해서도 다시 생각해보면 좋을 것 같다고 했다.

아직은 모든 피드백을 이해하고 직접 사용하기에는 어렵지만 느낌은 파악했다. 앞으로는 위에서 이야기했던 것들을 꼭 적용시켜보는 코드를 작성하자

profile
블로그 이사 : https://hengxi.tistory.com

0개의 댓글