일정 VS 퀄리티
•
프로덕트 엔지니어는 일정이 중요하다고, 퀄리티를 모두 무시하는 행위도 반대로 퀄리티가 중요하다고 일정을 무시하는 행위도 해서는 안된다.
•
코드 커버리지의 타겟 퍼센티지를 지정하듯 최고는 아니지만 최선의 퀄리티를 균일하게 일정 내에 개발할 수 있어야 한다.
일정을 잘 지키는 사람들의 공통점
좋은 코드를 선택하는 방법을 잘 선택한다.
•
매번 최근에 본 개발 관련 서적이나 아티클등을 참고해서 좋은 코드를 선택하려 고민한다.
◦
클린 코드를 봤으면, 리팩토링을 봤으면, 오브젝트를 봤으면….하면서 자신이 최근 봤던 책들을 기반으로 고민을 하게 된다.
•
우리가 A코드와 B코드 중 무엇을 선택할지 고민할 때 그들은 그동안 해왔던 기준과 원칙으로 빠르게 결정하고, 더 중요한 것에 집중한다.
◦
기존의 기준이 100점짜리 코드에 부족한 80점~ 90점짜리 코드라는건 이미 감안하고 있다.
◦
하지만 나머지 80점~90점은 그동안 해왔고 성공해왔던 경험하에 쌓여진 기준으로 선택한다.
무엇이 옳을까? 적어도 회사및 내 시간을 생각하면 후자가 맞지 않을까?
제어할 수 없는 것에 의존하지 않기
Developer Area
현실 세계의 변화와 설계 사이의 결합도를 줄여야 한다.
전화번호를 식별자로 사용하는가?
자신의 힘으로 제어할 수 없는 속성에 의존하지 말라.
- 실용주의 프로그래머 중
불변이라 생각했지만 가변이였던
•
절대 변하지 않을 것이라 믿고 의존했던 속성(주민 등록 번호)이었지만, 변경이 발생해 대부분의 시스템의 주요키 변경이 발생했다.
그 이후…
•
외부에서 전달 받은 값은 절대 주요키로 선택하지 않는다.
•
애플리케이션의 중요한 키 혹은 식별자는 내가 직접 만들어 관리하는 키만 사용하겠다(Ex: 대리키)
그리고…
•
패스워드 발급시 단방향 암호화 등을 SQL에서 password등을 통해 암호화를 할 수 있다.
•
하지만, 이런 기능들은 성능을 끌어올리거나 분산환경에서 동일한 규칙으로 만들기 어렵다.
•
결국, 성능이나 환경등 제어할 수 없는 것에 의존할수록 변화에 쉽게 흔들리는 소프트웨어가 만들어진다.
코드로 살펴보는 제어할 수 없는 코드
public class Order {
private double amount;
public void discount() {
LocalDateTime now = LocalDateTime.now();
if (now.getDayOfWeek() == DayOfWeek.SUNDAY) {
this.amount = this.amount * 0.9;
}
}
}
Java
복사
일요일이면 할인되는 코드
이 코드는 내가 제어할 수 없는 코드이다.
어째서일까?
@Test
void discountTest() {
ProductOrder order = new ProductOrder(1_000);
order.discount();
assertThat(order.getAmount()).isEqualTo(900);
}
Java
복사
위와 같은 테스트 코드를 실행하면 성공할까? 일요일에만 성공하는 테스트코드다.
LocalDateTime.now() 메서드 호출은 개발자가 제어할 수 없는 코드다.
그래서 모킹을 이용해 무조건 now() 메서드가 일요일을 반환하도록 할 수 있긴 하다.
@Test
public void testDiscountOnSunday() {
// 가짜 시간 생성
LocalDateTime sunday = LocalDateTime.parse("2023-04-09T00:00:00");
Clock clock = Clock.fixed(sunday.atZone(ZoneId.systemDefault()).toInstant(), ZoneId.systemDefault());
LocalDateTime.now(clock); // 현재 시간을 가짜 시간으로 설정
}
Java
복사
그런데, 날짜 라이브러리나 테스트 프레임워크가 바뀐다면?
⇒ 기존에 모킹하고 있던 모든 코드를 변경해줘야 한다.
제어할 수 있는 코드로 만들기
public class ProductOrder {
private double amount;
public ProductOrder(double amount) {
this.amount = amount;
}
public void discount() {
discount(LocalDateTime.now());
}
public void discount(LocalDateTime now) { // <----- 시간을 외부에서 주입받게 변경
if (now.getDayOfWeek() == DayOfWeek.SUNDAY) {
this.amount = this.amount * 0.9;
}
}
public double getAmount() {
return amount;
}
}
@Test
void discountTestForSunday() {
ProductOrder order = new ProductOrder(1_000);
order.discount(LocalDateTime.of(2023, 4, 9);
assertThat(order.getAmount()).isEqualTo(900);
}
@Test
void discountTestForElse() {
ProductOrder order = new ProductOrder(1_000);
order.discount(LocalDateTime.of(2023, 4, 8);
assertThat(order.getAmount()).isEqualTo(1_000);
}
Java
복사
•
제어할 수 없는 값을 제어할 수 있는 값으로 만들어 줬다.
•
일요일이 아닐 경우에 대한 에지 케이스도 테스트할 수 있다.
전염되는 제어할 수 없는 코드
제어할 수 없는 코드만 살펴보는게 아닌 좀 더 확장해서 제어할 수 없는 코드에 의존하는 메서드들이 늘어남에 따라 제어할 수 없는 범위가 전염되는 것을 볼 수도 있다.
Base Code
•
requestPg(course.title, payAmount); 메서드는 외부 API요청이다.
이 메서드를 메서드로 분리해서 리팩토링을 진행해보자.
Refactoring Code
•
pay, payAll이라는 두 개의 메서드로 기능을 분리해줬다.
◦
여러 개의 강의에 대해 결제를 순회하면 진행하는 payAll
◦
하나의 강의에 대한 결제를 진행하는 pay
•
두 메서드들을 호출하며 로직 오케스트레이션을 하는 payCourses
•
async/await 키워드가 모든 메서드에 접두사로 붙어있다.
◦
모든 메서드가 외부 API를 모킹해야지만 테스트할 수 있는 메서드들이 되었다
◦
분명 리팩토링하며 메서드를 순수함수로 만들었는데 의존성이 생긴걸까?
제어할 수 없는 함수에 의존하는 모든 코드가 제어할 수 없는 코드가 된다.
pay 메서드의 외부 API(requestPg)
제어할 수 있는 것과 없는 것
•
여기서 제어할 수 있는 것을 제어할 수 없는 것과 분리를 할 필요가 있다.
제어할 수 있는 것과 없는 것을 분리
•
강의의 할인을 적용해 반환하는 기능과, 결과 요금을 필터링해서 유효한 코스들을 추출해내는 메서드를 분리해 냈다.
•
async/await을 사용해 외부 API를 호출하는 메서드는 payAll하나의 반복문 내로 좁혀졌다.
제어할 수 없는 코드란?
•
내가 만들지 않은, 외부에서 사용하는 내가 핸들링하기 힘든 함수 혹은 객체들을 제어할 수 없는 코드라 지칭한다.
이제 우리가 해야할 일은?
UI
•
Back: Json결과물이나 HTML Template
•
Front: View layer
Business Logic
•
back, front: business logic…
Data
•
Back: ORM, Respository, …
•
Front: fecth, axios, …
제어 불가능한 영역을 최대한 밀어넣어 격리하자.
제어 가능한 영역을 최대한 늘려나가자
제어할 수 없는 것에 의존하지 않기
Company Communication Area
어떻게 좋은 개발자를 영입하고, 안나가게 할 수 있을까?
돈으로 다 해결하면 좋겠지만…
•
코로나 시즌 해외 투자가 정체되며 국내 투자로 돈이 흘러들어오며 스타트업들의 자금규모가 극적으로 커지면서, 개발자에 대한 대우도 드라마틱하게 올라갔다.
•
그래서 이런 흐름에 발맞춰 마냥 페이를 올려주기엔 부담이 크다.
그 여파로 인한 현재 winter is comming
•
요즘 투자금액이나 개발자에 대한 급여 대비 이익이 안나오면서 전체적인 구조조정 시즌
•
시니어 개발자들은 이런 상황에서 이직을 결심하기 더 힘들어져 영입이 더 힘들어진 상황
제어할 수 있는 것과 없는 것
•
내가 회사의 매출, 투자, 연봉, 생태계의 권고사직 분위기를 제어할 순 없다.
좋은 개발자 채용도 내가 제어할 수 없는 부분일 수 있다.
회사의 CTO가 100이라는 노력을 하면 100만큼의 인재가 들어온다는 보장이 있을까?
가비지 컬렉터의 destroy와 같이 어느정도 권유는 할 수 있지만 제어는 할 수 없다.
인프랩에서의 행보
1.
좋은 시니어 개발자 채용이 아닌 사내 강연
정기적인 외부 시니어 강연에 긍정적 피드백 사이클이 돌기 시작한 인프랩 직원들
2.
잦은 피드백을 줄 수 있는 환경 구성
→ 누가 코드 리뷰를 (여러 사정으로 인해) 못하는 환경에서도 피드백을 제공하기 위해 PR시
•
소나 큐브에 의한 정적 분석
•
테스트 코드
•
Lint
등의 도구를 이용해 피드백을 제공할 수 있는 환경을 제공한다.
다시 보는 제어할 수 없는 것과 있는 것
•
회사 내의 개발환경은 제어할 수 있는 범위에 있기에 이 부분을 집중한다.
•
할 수 있는 것에 집중하고 긍정적으로 상황을 판단하기
행복회로? No
우리 팀의 팀원이 이번에 네카라쿠배로 이직을 했네. 나도 해야하나?
여기 계속 남아 있어도 되는건가? 가야지 성장할 수 있는거 아닐까?
•
반대로 생각하면 네카라쿠배급의 회사에서도 우리의 개발방법, 개발자에 대해 긍정한다는 것이다.
•
개발문화나 프로세스가 잘못된게 아니다.