-
Notifications
You must be signed in to change notification settings - Fork 26
[권민영] Sprint4 #88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[권민영] Sprint4 #88
The head ref may contain hidden characters: "Basic-\uAD8C\uBBFC\uC601-sprint4"
Conversation
|
스프리트 미션 하시느라 수고 많으셨어요. |
기능별로 함수를 나눠서 작성해보려고 했는데 어느 정도 단위로 나눠야 할 지 잘 모르겠습니다.크으 ~ 좋은 시도예요 벌써부터 "재사용성"을 고려하시다니... 🥺 다음 아티클을 보면 도움이 되실 것 같아요 !: Functions should do one thing함수는 한 가지 작업을 수행해야 합니다. 이것은 소프트웨어 엔지니어링에서 단연코 가장 중요한 규칙입니다. 함수가 한 가지 이상을 수행할 때 구성, 테스트 및 추론하기가 더 어렵습니다. 함수를 하나의 작업으로 분리할 수 있으면 쉽게 리팩토링할 수 있고 코드가 훨씬 더 깔끔하게 읽힙니다. 이 가이드에서 이것 외에 다른 것을 빼지 않는다면 당신은 많은 개발자들보다 앞서게 될 것입니다. Bad: function emailClients(clients: Client[]) {
clients.forEach((client) => {
const clientRecord = database.lookup(client);
if (clientRecord.isActive()) {
email(client);
}
});
}Good: function emailClients(clients: Client[]) {
clients.filter(isActiveClient).forEach(email);
}
function isActiveClient(client: Client) {
const clientRecord = database.lookup(client);
return clientRecord.isActive();
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오호 ! 유효성 검사 코드를 따로 분리하셨군요 ?
"재사용이 가능한가?"를 염두하고 설계하신거로 보여요. 훌륭합니다 👍
또한, 파일명을 유효성 검사 "함수들"을 모아놓은 js 코드임을 암시할 수 있도록 validations.js로 작명하셔도 될 것 같아요 !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(심화) 언제 코드를 어떤 단위로 분리해야 할까?
민영님께서 질문도 주시고 코드를 보니 "더 나은 코드"에 대해서 관심이 많으신 것 같아요. 😊
정말 긍정적인 신호입니다 !
자. 여러 페이지에서 비슷한 기능을 하는 코드들이 반복되고 있다면?
로그인, 회원가입 등 페이지마다 공통적인 유효성 검사나 동작이 존재하는 경우가 많습니다.
이러한 로직을 각 JS 파일에 그때그때 작성하게 되면 아래와 같은 문제가 생길 수 있어요:
- 로직 수정 시, 모든 파일을 수정해야 해요.
- 서로 약간씩 다른 방식으로 유사한 로직을 구현하게 되면 버그 발생 가능성이 증가합니다.
- 공통 로직의 변화가 전체 페이지에 ripple effect(연쇄 영향)를 줄 수 있어요.
이처럼 중복된 코드가 많아질수록, 전체 프로젝트의 유지보수 비용은 계속 높아지게 됩니다.
언제 분리 해야할까 ?
사실 이건 “경험”으로 익혀가는 부분이지만, 아래와 같은 신호가 있다면 분리를 고려해볼 수 있어요:
- "어? 이 함수 다른 데서도 쓸 것 같은데?"
- "이거 수정하려면 다른 JS 파일에도 가서 고쳐야 하네?"
- "이 기능이 특정 페이지에만 종속되지 않아!"
어떻게 하면 더 나은 설계를 할 수 있을까?”를 고민하는 건 아주 중요한 개발자의 태도예요.
정답은 없지만, 재사용성과 유지보수성이라는 기준을 계속 떠올리면서 코드를 분리하는 연습을 하다 보면,
더욱 확장성 있는 구조를 만들 수 있게 됩니다.
| function validateInput(el, label) { | ||
| const { validity } = el; | ||
| if (!validity.valid) { | ||
| if (validity.valueMissing) return `${label}을 입력해주세요`; | ||
| if (validity.typeMismatch) return "잘못된 이메일 형식입니다"; | ||
| if (validity.tooShort) return "비밀번호를 8자 이상 입력해주세요"; | ||
| if (validity.customError) return el.validationMessage; | ||
| } | ||
| return ""; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
크으~ 파라메터로 엘리먼트도 받고 있군요 !
외부 환경에 영향을 끼치지 않으면서 받은 파라메터로만 처리를 하고 있어요. 훌륭합니다.
해당 함수는 입력값이 같으면 언제나 같은 결과를 반환하고 외부 상태에 영향을 주거나 의존하지도 않아요.
이런 함수를 “순수 함수(Pure Function)” 라고 부릅니다.
이러한 구조는 테스트하기도 쉽고, 예측 가능한 코드 작성에 도움이 되는 좋은 패턴입니다.
지금처럼 유틸리티 함수를 순수하게 분리해 작성하는 습관, 정말 잘 하고 계세요! 🔥
추가로 민영님께서 만드신 이러한 함수를 "순수 함수"라고 칭합니다 😉
| const parentEl = inputEl.parentElement; | ||
| const targetLabel = parentEl.firstElementChild.textContent; | ||
|
|
||
| let p = parentEl.querySelector("p"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
p 태그는 모두 가져오고 있군요 ?
현재 설계된 대로라면 동작상 문제는 없을 거로 보이지만, 만약 형제 중에 p 태그가 추가되면(이를 테면 만약 새로운 기능 중 안내 문구 같은게 추가가 된다던지) 버그가 발생할 수도 있겠어요.
에러 메시지에 고유한 식별자를 넣어도 될 것 같아요. id나 class와 같이요 😉
| } | ||
| p.textContent = errMsg; | ||
| } else { | ||
| p && p.remove(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
크으 ~ 조건문을 단축해서 사용하시다니 😇
편의상 많이 사용되는 패턴이죠 👍
| if (errMsg) { | ||
| if (!p) { | ||
| p = document.createElement("p"); | ||
| p.classList.add("invalid-input"); | ||
| inputEl.after(p); | ||
| } | ||
| p.textContent = errMsg; | ||
| } else { | ||
| p && p.remove(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard Clause 패턴을 사용해볼 수도 있겠어요 😉:
| if (errMsg) { | |
| if (!p) { | |
| p = document.createElement("p"); | |
| p.classList.add("invalid-input"); | |
| inputEl.after(p); | |
| } | |
| p.textContent = errMsg; | |
| } else { | |
| p && p.remove(); | |
| } | |
| if (!errMsg) { | |
| p && p.remove(); | |
| return; | |
| } | |
| if (!p) { | |
| p = document.createElement("p"); | |
| p.classList.add("invalid-input"); | |
| inputEl.after(p); | |
| } | |
| p.textContent = errMsg; |
Guard Clause을 사용하게 되면 조건부를 조기에 처리할 수 있게 되어 핵심 로직을 구분할 수 있다는 장점이 있습니다. 따라서 가독성을 향상시킬 수 있어요.
또한, 미리 조건에 따라서 데이터의 범위를 좁힐 수 있기에 핵심 로직에서는 보장받은 데이터를 편리하게 사용할 수 있다는 장점도 있어요 😊
Guard Clause ?
다음과 같이 조기에 함수를 끝내는 기법을 의미합니다:
function calculateDiscount(price, discountRate) {
// Guard Clause: 가격이나 할인율이 유효하지 않으면 함수 종료
if (price <= 0 || discountRate <= 0 || discountRate > 1) {
console.error("Invalid price or discount rate");
return;
}
// 할인된 가격 계산
const discountedPrice = price * (1 - discountRate);
return discountedPrice;
}|
수고하셨습니다 민영님 ! 미션 수행하시느라 정말 수고 많으셨어요 ! |
요구사항
배포 링크
basic-my-pandamarket.netlify.app
기본
로그인
회원가입
심화
주요 변경사항
스크린샷
멘토에게