클래스로 묶는 것은 항상 좋은 코드인가?

2024년 5월 30일 목요일

Today I Learned

날짜

2024년 5월 30일 목요일

내용

클래스로 묶는 목적

리스트 디자이너 고도화 작업중에 고민이 생겼다. 이번에 추가해야할 기능은 상품 자동진열 방식에 따라 자동으로 상품 목록을 업데이트 해주는 것이다. 위젯의 자동진열 기준이 판매량 순이라면, 매일 특정한 시간에 그 샵의 판매량 순서를 확인하고 변경이 있다면 위젯에 등록될 상품도 변경해줘야 한다. 기능 자체는 어찌어찌 만들었는데, 코드를 어디에 어떻게 배치해야 할지에 대해 나름 고민이 생겼다.

이 기능의 로직을 조금 더 작은 단위로 구별해보면 다음 순서로 이루어진다.

  1. 기준을 확인한다(판매량, 신상품, 리뷰작성수).
  2. 1번에서 확인한 기준으로 스토어에서 상위 15개 상품을 확인한다.
  3. 현재 위젯에 표시되도록 등록된 상품들과 순서를 비교해본다.
  4. 변경점이 있으면 업데이트한다.

각 기능들을 더욱 잘게 쪼개서 여러가지 함수로 구현했더니 나름 괜찮은 코드가 나왔다고 생각한다. 문제는 이것을 crud.py 안에 함수로 정의해 둘지, 리스트 디자이너와 관련된 클래스들이 모여있는 파일에 클래스로 묶어둘지가 고민된다.

함수로 정의한 지금 코드는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
def get_top_selling_products():
	"""
	판매량이 높은 상위 상품 반환
	"""
	return products
	
def get_newly_released_products():
	"""
	최근에 출시된 신상품 반환
	"""
	return products
	
def get_most_reviewed_products():
  """
  작성된 리뷰가 많은 상품 반환
  """
  return products
  
def delete_list_designer_product_by_id():
	"""
	위젯에 등록된 상품 데이터를 삭제
	"""
	return
	
def create_list_designer_product_from_product():
	"""
	상품 데이터를 리스트디자이너 위젯에서 사용할 데이터로 바꾸어 저장
	"""
	return
  
def compare_and_update_list_designer_products_in_widget():
    """
    위젯의 기존 상품과 새로 가져온 상품을 하나씩 비교하여 업데이트하는 함수
    """
    if (기존상품) == (새상품):
	    continue
	  else:
		  # 삭제 후 새 상품데이터 생성
		  delete_list_designer_product_by_id()
		  create_list_designer_product_from_product()
    return product_platform_ids

def update_list_designer_products_in_widgets():
    """
    모든 List Designer 위젯에 연결된 상품들을 정해진 preset에 따라 업데이트하는 크론 함수
    """
    
    1) 모든 위젯 조회
    ...
    2)  위젯별로 현재 위젯  상품 목록 조회
    ...
    3) 위젯의 기준에 맞는 상품 조회하는 함수 호출
	    a) get_top_selling_products()
	    b) get_newly_released_products()
	    c) get_most_refviewed_products()
	  ...
	  4) compare_and_update_list_designer_products_in_widget() 호출

각 함수들이 한 가지 책임만 지도록, 이름에서 어떤 함수인지 최대한 알 수 있도록 작성했다. 이 함수가 쓰이는 곳은 위젯을 생성하거나 수정할 때도 있지만 매일 자동으로 업데이트되야 하므로 크론으로도 호출되야 한다.

이 함수들을 클래스로 구성할 수도 있지 않을까? 업데이트 하기위해 상품을 가져올 기준만 다를뿐, 상품을 가져온 이후에는 update_list_designer_products_in_widgets(), compare_and_update_list_designer_products_in_widget(), craete_list-designer_product_from_product(), delete_list_designer_product_by_id() 함수는

언제나 동일하게 쓰인다. 따라서

  1. 상속클래스로 만들고 공통적인 메서드를 정의한다.
  2. 상품을 가져오는 부분만 달라지므로 하위 클래스는 각각 상품을 가져오는 추상 메서드를 가진다.
  3. 그외의 메서드는 모두 상속받은 메서드를 그대로 사용한다.

로 작성하면 될 수도 있겠다고 생각했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class UpdateItem(ABC):
def __init__():
	...

# 기준에 맞게 상품 가져오는 메서드만 하위 클래스에서 구현
@abstractmethod
def get_products():
	pass
	
@abstactmethod
def update_list_designer_products_in_widgets():
	...
	
@abstractmethod
def compare_and_update_list_designer_products_in_widget()
  ...
  
@abstractmethod
def create_list_designer_product_from_product()
  ...
  
@abstractmethod
def delete_list_designer_product_by_id()
	...

	
class TopSellingUpdateItem(UpdateItem):
def __init__():
	super().init()
	
def get_products():
	# 판매량 높은 상품들을 탐색하는 로직 작성
	
# 이후는 공통된 로직이므로 상위 메서드 호출
def update_list_designer_products_in_widgets():
  super().update_list_designer_products_in_widgets()
  
def compare_and_update_list_designer_products_in_widget()
	super().compare_and_update_list_designer_products_in_widget()

... 

class NewReleasedUpdateItem(UpdateItem):
...

class MostReviewedUpdateItem(UpdateItem):
...

이런 느낌으로..? 근데 묶어놨는데 오히려 가독성이 떨어지는 느낌이 너무 강하게 들었다. 언제 클래스로 묶고, 언제 별개의 함수로 둬야할지 아직 감이 덜잡혔다. 단지 비슷한 로직, 비슷한 기능이라고 묶는건 아니지 않을까. 동일한 인스턴스의 상태변화를 다룰 때 같은 클래스로 묶여야 한다는 생각이 들어 이번에는 묶지 않았다.

슈퍼어드민

서비스를 이용하는 스토어들에 대한 정보를 볼 수 있는 관리자 페이지를 슈퍼어드민으로 부른다. 이 페이지에선 그 스토어에 대한 정보를 볼 수 있고, 그 스토어의 어드민페이지도 볼 수 있(었)다. 해당 스토어의 어드민 페이지로 이동하는 기능이 고장나서 해결해야 했다.

서비스에 로그인을 하면 서버는 프론트에게 계정 정보와 연관된 샵들을 제공한다. 슈퍼어드민을 통해 어떤 스토어의 어드민페이지로 접근하는 방식도 동일하다. 단, 우리가 계정 정보(비밀번호)를 알 방법이 없으니, 슈퍼관리자 계정으로 로그인시키고 접근하려는 샵이 연관되있는 것처럼 묶어서 프론트에게 전달한다. 쉽게 말하면, 슈퍼관리자 계정이 임시로 그 스토어의 관리자가 되는 셈이다.

이번에 새로운 앱이 서버에 추가되면서 로그인 떄 보내는 데이터 형식이 변경됐는데 슈퍼어드민에는 반영이 안되면서 생기는 문제였다. 기존 로그인이 바뀐것처럼 바꾸어주었더니 잘된다.

회고

어떻게 작성해야 기가 막히게 해냈다고 소문이 날까