작성
·
56
1
안녕하세요, 오랜만에 흥미로운 강의를 알게되어 주말동안 강의를 몰아보다보니 9강까지 듣게 되었네요.
23분 59초 정도에 setter를 지양하기 떄문에 custom setter를 잘 사용하지 않고, update함수를 만들어 사용한다 라는 내용에 예시가 있다면 알 수 있을까요?
java 프로젝트를 활용할 때 setter를 커스텀하게 수정해서 쓰는 경우가 아주 간혹 값이 업데이트 될 때 다른 필드를 함께 업데이트 해야하는 케이스들 때문에 사용했던 기억이 있는데, setter를 사용하지 않고 update를 사용한다는게 어떤 말씀이신지 조금 더 상세히 알려주시면 감사하겠습니다!
답변 1
1
안녕하세요 영욱님! 🙂 질문 감사합니다.
사실 이 부분은 글로는 설명이 어려워 예전에 영상을 만들어 둔 적이 있습니다.
아래 영상을 참고해주시면 감사드리겠습니다. 🙇
https://www.youtube.com/watch?v=5P7OZceQ69Q
감사합니다!
올려주신 유튜브 영상 정독해보았습니다.
여러가지 이유 다 와닿았는데, 한가지 조금 고민이 해갈되지 않는 지점이 있습니다.
updateSpeed와 같이 한개의 값만을 바꾸어주는 업데이트 함수를 만들어주는 부분이 생산성이 올라간다 라고 말씀 해주셨었는데, 이렇게 하는것과 커스텀 세터를 이용해서 사용하는것이 생산성에 차이가 있나요?
아직 제가 코틀린에 익숙하지 않아 자바 기준으로 생각해서 생기는 의문이 아닐까 싶은데..
예상되는 포인트가 애초에 java 진영에선 setXXX() 같은 형태로 단일 업데이트도 해당 행위를 위한 함수를 호출해 사용하기 때문에 해당 세터가 호출된곳을 찾으면 되는것에 반해,
코틀린 진영해서는 자바스크립트마냥 필드명을 그냥 적으면 되서(내부적으론 게터 세터를 호출한다고 하더라도), 이게 단순히 speed를 호출한건지, 아니면 speed에 값을 대입하기 위해 적어놓은곳인지 직관적으로 알 수 없어서 생산성에 차이가 있다라고 말씀하신걸까요?
좋은 포인트입니다! 🙂 "이게 단순히 speed를 호출한건지, 아니면 speed에 값을 대입하기 위해 적어놓은곳인지 직관적으로 알 수 없어서 생산성에 차이가 있다" 라고 말씀해주신 부분과도 아주 미세하게 영향이 있겠지만 사실 더 본질적으로 생산성이 올라가는 이유는 "변경 지점이 줄어든다" (= 요구사항 추가에 따른 비용이 감소한다) 입니다.
예를 들어 보겠습니다. 아래와 같은 클래스가 있습니다.
class Car(
var speed: Int,
var mode: CarMode, // 에코 모드, 스포츠 모드, 일반 주행 모드 등
)
우리는 이 클래스의 speed
를 여기저기서 setter를 통해 변경하고 있었습니다.
1년 동안 speed 제어 기능이 여기저기 들어가 한 10~15곳 정도에서 car.speed = 10
과 같은 setter를 사용하고 있다고 해보죠 🙂
당연히 제가 작업한 부분도 있고 ,다른 사람이 작업한 부분도 있어 모든 히스토리를 알고 있지 못합니다.
자 그런데 이 상황에서 자동차 모드에 따라 속도를 제한해야 한다고 해보죠.
만약 속도를 초과하면 각 모드에 따른 최대 속도로 고정될 수도 있고, 예외를 던질 수도 있고 아무튼 모드와 속도에 따른 어떠한 로직이 들어가야 합니다.
흐름 제어는 간단합니다. if - else if
구문을 사용하건 when
을 사용하건 mode에 따라 최대 속도를 고정해주면 되죠.
if (car.mode == CarMode.XXX) {
...
} else if ( ) {
...
} else if () {
...
}
문제는 이제 이 코드가 어디에 위치할 것인가 입니다. 🙂 만약 setter를 사용하고 있다면
car.speed = ??
라는 코드가 10~15곳의 XXXService
/ XXXController
등 온갖 곳에 퍼져 있을 텐데요, 이 경우 히스토리를 잘 모르는 상태에서 가장 안전한 접근은 위의 if - else if
코드를 10~15 곳에 모두 복사-붙여 넣기 하는 겁니다.
결국 우리는 그만큼 더 많은 코드를 수정해야 하고, 더 많은 버그 위험에 노출되며, 더 많은 작업 시간이 걸리고, 또 다시 요구사항이 변경되면 다시 10~15 곳의 코드가 모두 바뀌게 되죠 (악순환의 반복입니다)
반면, 애당초 setXXX가 아닌 적절한 도메인 레벨의 인터페이스를 사용하고 있었다면 훨씬 편합니다.
class Car(
var speed: Int,
var mode: CarMode
) {
fun update(speed: Int, mode: CarMode) {
// .. 여기서 사용
}
}
이런 코드에서 실제로 setter
를 외부에서 쓰고 있지는 않았다고 해보죠.
즉 update
함수가 10~15곳에서 쓰이고 있습니다. 이 경우 우리는 if - else if
로직을 update
라는 함수 안에 한 번만 넣어주면 됩니다. 변경 지점이 적으니 분석 시간도 줄고, 버그 위험도도 줄고, 작업 시간도 줄고, 다음 작업이 또 생겨도 더 적은 비용으로 유지보수가 가능하죠.
굉장히 간단한 예시이지만, 프로덕트가 커지고 수십만줄의 코드, 수천개의 클래스가 생기면 더 체감되는 포인트입니다. 🙂 적절한 위치에 적절한 코드가 있어야 생산성이 올라가는거죠.
결국 핵심은 "단순히 setter를 사용하면 안된다" 보다는 "도메인 로직은 도메인 계층으로 로직을 모아야 한다" 인데요! 이 얘기를 글로 말씀드리기엔 또 너무 길어지다 보니 여기서 끊겠습니다.. 다른 질문들도 올려주신 것 확인했습니다. 시간이 될 때 하나씩 답변 드릴 수 있도록 하겠습니다. 감사합니다. 🙏
아침부터 상세한 답변 너무 감사합니다!
애초에 세터 자체를 커스텀 해서 쓴다라는 개념 보다는 세터 자체의 사용을 지양하고 별개의 기능을 가진 동작을 구현한다 가 여러 측면에서 유리한 행동이 되는거군요🤔
제가 큰 서비스를 다뤄본적이 없어 체감하지 못하는 영역일 수 있겠네요..
세터는 이미 만들어진 객체의 널러블 필드의 초기값을 나중에 채워놓는 경우만 사용해보고 대입된 값 자체를 변경해야 하는 경우에는 업데이터를 만들어서 사용 해본다던가 나름의 기준점을 만들어야겠네요!!
친절한 답변 감사합니다 :)
넵넵 ㅎㅎㅎ "setter를 nullable 필드 초기값을 채우는 용도로만 사용한다"가 해당 클래스 안에서 setter를 사용한다 라면 같은 생각이 맞습니다!
물론 생성자를 여러개 만들거나 정적 팩토리 메소드 등을 활용해 객체를 초기화하여 nullable 필드 자체를 줄이는 것도 중요합니다. 🙂
감사합니다.
빠른 답변 감사합니다!
아마 이 유튜브가 오늘의 마지막 학습이 되겠네요 😂😂