여러가지 클래스를 종류별로 구분하는 기준이 궁급합니다.

안녕하세요. 프로젝트를 구성하면서 내가 하는 것이 맞는 것인가…? 싶은 생각이 들어서 질문하게 되었습니다.

  1. 여러분들은 보통 프로젝트를 구성하실 때 Helper, Manager, Utility, Service와 같은 클래스들을 어떤 기준으로 구분하여 생성하시나요??
  2. 닷넷 코드를 열어보면 프로젝트를 .Cores, .Essentials, .Controls과 같이 구분해 놓은 경우를 볼 수 있는데 이것은 어떤 기준인지 궁금합니다.

나의 생각

  • Helper : RelayCommand, Extension 등과 같이 내가 구성하는 기능을 말 그대로 도와주는 역할을 하는 클래스
  • Manager : ViewModelManger, LogManager, CrashManager, AlertManager 등과 같이 하나의 묶음으로 관리하고 싶은 클래스
  • Utility : DirectoryUtil 등과 같이 여러 함수를 경유해서 가야하는 경우 그 과정을 단축하기 위한 편의를 제공하는 클래스
  • Service : 사실 잘 모르겠음…

이렇게 생각이 되는데 다른 많은 분들의 이야기를 들어보고 싶어서 적게 되었습니다. 감사합니다.

5개의 좋아요
  • Helper, Utility - 특정한 목적의 유틸성 기능을 간편하게 사용하기 위한 목적으로 모아둔 클래스. 클래스의 각 멤버는 서로 어떠한 연관도 없이 동작해야 하며 언제 어떤 입력값을 넣든 결과값을 예상할 수 있어야 함. (ex. FileHelper.GetLastWriteTime()을 호출하면 파일의 최근 수정 시각을 반환하는 등.)

  • Manager - 특정한 클래스에서 공통적으로 사용되는 작업을 집중화해 관리함으로써 복잡성을 줄이는데 사용. 보통 싱글톤으로 선언

  • Service - 특정한 작업을 실제 서비스 계층에서 수행하는 역할(ex. MySqlService vs SqliteService)


저는 이렇게 이해하고 명명하고 있습니다. 아직까지 Manager는 써본 일이 거의 없어서 설명이 좀 그렇네요 ㅎ…

5개의 좋아요

저는 Util 이라는 단어를 쓰지 않습니다.


간혹 Helper라는 접미사를 붙여 클래스를 만들곤 하는데 AppDomain에 대해 전역으로 사용되는 클래스에 대해서 사용합니다.
전역이기 때문에 static class 입니다
또한 Helper에는 interface도 사용하지 않습니다.
다른 프로젝트에도 가져다 사용할 수 있을만큼 완전하게 격리되고 독립된 기능을 모아 Helper로 사용합니다.
대표적으로 확장메서드가 있을 것 같네요.
AppDomain 내에서 데이터를 공유하는 부분도 없고, 정말 딱 독립적으로 동작이 가능할 때 사용합니다.


Manager는 전역에서 '관리’의 개념을 갖고 있는 static class에 대해서 사용합니다.
Helper와 다른 것은 데이터을 캐싱, 저장한다는 개념이 있는 class 입니다.
따라서 thread safe에 대해서 상황을 고려해야 하는 클래스입니다.
여러 클래스에서 데이터를 가져다 쓸 때 동기화가 반드시 되어 있어야하는 클래스인 것입니다.


Service는 Data Model을 응용하는 클래스로 의미를 두어 사용합니다.
OOP 에서 Object인 Data Model은 각자의 데이터를 가지고 각자 스스로 일을 합니다.
그것 이외에 여러 Model들이 의존성 주입을 통해 엮여서 하나의 동작 캡슐화를 할 수 있을 때 Service라고 명명하고 있습니다.

5개의 좋아요

Controls: GUI 컨트롤
Helper, Util: 유틸 기능. 네이밍이 익숙한 대로 사용(StringHelper, AppUtils)
Manager: 객체 관리자
Service: 클라이언트와 통신하는 서비스 (WebService, DiscordBotService)
Core, Essentials: 안 씀.

4개의 좋아요

이름이야 붙이기 나름이고 각종 책이나 포스팅, 깃허브 소스, 유데미 강좌 등에서도 각 개발자마다 자기 스타일대로 이름을 붙입니다.

그 중에서 최근에 공통적으로 보이는 것이 하나 있다면, ASP.NET이나 Blazor 프로젝트들 강좌/영상/소스들에서 View 바로 아래단, 즉 DI되는 클래스들에 Service라는 이름을 주로 붙입니다.

예를 들면, ASP.NET Core MVC에서 cshtml->controller 까지는 xxx.Web 프로젝트에 정의되어 있고, xxx.Services 프로젝트에 AuthService, UserService, ProductService, LogService 등과 같이 Service 클래스를 만들고, 이 Service 클래스들을 services.AddScoped<ILogService, LogService>(); 와 같이 DI하는 패턴들이 많이 보입니다.

제 개인적인 의견이지만 매우 대규모 프로젝트가 아닌 이상, 생각보다 꼭 인터페이스로 정의해야 하는 경우가 의외로 많지 않을 수 있습니다. (물론 프로젝트 도메인과 성향에 따라 다릅니다.) 오히려 다형성을 완벽하게 하는 것보다는 레이어에 따른 관심의 분리를 잘 하는 편이 코드 유지보수가 매우 잘 될 수 있습니다.

예를 들면, 다음과 같이 관심사에 따라서 레이어를 나누고 각 레이어를 각 csproj로 생성하고 최상단 XXX.Web 프로젝트에서 다 참조하게 합니다. DB 처리는 DB 레이어에서만 하고, Service 레이어에서는 DB 레이어의 클래스들을 사용하되 XXX…Web에 직접 EF 모델 클래스를 노출하지 않고 Dto 클래스들만 노출시키는 겁니다.

XXX.Web
XXX.Service
XXX.Repository
XXX.Data (또는 XXX.Entity 등)
XXX.Shared

뭐 이런 식으로 말이죠. 이 때 실제 참조는 Shared를 제외하고는 바로 아래로?만 갑니다. XXX.Web 프로젝트에서 XXX.Repository의 클래스를 직접 사용하지 않아야 하고 XXX.Service의 클래스들만 사용합니다.

그러다보면 XXX.Service에는 YYYService라는 클래스가 많을 것이고, ZZZHelper라는 이름의 클래스는 XXX.Shared에 들어가게 될 겁니다.

이런 식으로 자기만의 규칙, 또는 팀의 규칙을 정하고 프로젝트를 설계하다보면 Service니, Manager니 Repository니, Helper니 하는 이름들을 해당 단어 뜻에 맞게 잘 사용해서 나도 다른 사람도 클래스이름만 보고도 얘가 뭐하는 녀석이겠구나 쉽게 알 수 있게 하면 되지 않을까 싶습니다.

쓰다보니 잡소리가 되었네요.

5개의 좋아요

유행은 돌고 돕니다~! ㅋ :rofl:

그리고 GPT에게 추천 받는 것도 한 방법입니다!

3개의 좋아요

… 저는 주로 네이밍룰 좋아하시는 분에게 맞춥니다. ㅋㅋㅋㅋㅋ
개발팀의 평화(?)를 위해서 ㅎㅎㅎ

  • 사내 프로젝트의 경우 주니어가 이해하기 쉬운 방향으로 하는 편입니다.
    그래야 설명하기가 편하더라구요.
5개의 좋아요

Helper, Utility 같은 경우에는 static 으로 많이 선언하겠죠…?

1개의 좋아요

Helper의 경우 완전하게 격리되고 독립된다는 것은 프로젝트 내부에 있는 그 어떤 데이터도 건드리지 않는다는 이야기죠?

  • 추가로 Manager와 같은 경우 Thread Safe와 같은 것들을 고려해야 한다는 점은 정말 귀한 의견이네요 감사합니다.
2개의 좋아요

정성스런 답변 너무 감사합니다.
방금 말씀하신 것처럼 각 프로젝트에 맞게 계층으로 구성하고, 바로 아래에 있는 것만 참조해서 사용을 한다고 하셨는데

예를 들어, XXX.Web 에서 XXX.Repository를 참조해야 하는 상황이 생긴다면 그것은 설계가 잘못된 것일까요? 아니면 어떻게든 XXX.Service를 통해서 할 수 있도록 방법을 찾아야 하는 것일까요?

1개의 좋아요

맞네요! ㅋㅋㅋ GPT 한테 추천받는 것도 좋은 방법이군요

1개의 좋아요

이런 방법도 있겠군요!!
원만한 관계와 평화로운 개발 분위기를 위해!

1개의 좋아요

감사합니다!

2개의 좋아요

글을 잘못 작성했습니다…

3개의 좋아요

수고하셨습니다! ㅎㅎ

2개의 좋아요

모든 객체는 문맥에 따른 관점이 투사되어 그 문맥 안에서만 의미 있는 이름을 갖습니다.

그런데, 특정 문맥에서 자주 나타나는 전형적인 이름들이 있습니다.

첫째로 소프트웨어 구조로 인해 명명되는 이름들입니다.

Asp.Net 코어 뿐만 아니라, 많은 웹 프레임워크 들이 채택하는 MVC 구조에서는 특정 부류의 요청을 처리하는 객체에 "***Controller"라는 이름을 붙입니다.

둘째로, UI 를 위한 프레임워크에서는 사용자와 상호 작용하는 시각적 객체를 "***Control"이라고 부릅니다. 버튼, 라벨, 텍스트 입력 등이 있습니다.

셋 째로, 프레임워크의 관점에 따른 객체가 있습니다.
닷넷에서는 의존성 주입기를 "서비스 컨테이너"라고 부릅니다. 그래서, 의존성 주입기에 의해 주입되는 객체를 "서비스"라고 부릅니다.

이 경우에는 객체의 이름에 Service라는 접미어를 잘 붙이지 않습니다.
만약, 의존성 주입기를 "디펜던시 인젝터"라고 불렀으면, 주입되는 객체를 "디펜던시"라고 불렀을 것입니다.

그런데, 서비스는 더 다양한 의미를 갖습니다.

"웹 서비스"를 줄여서 "서비스"라고 부르기도 하는데, 이 경우 보통 외부의 웹 API를 가리킵니다.

일반적인 개념으로는

첫 째, 객체의 외형에 따른 구분
객체는 보통 상태를 저장하는 필드와 행위를 담당하는 메서드로 구성됩니다.
상태를 저장하는 멤버 만으로 이뤄진 객체를 “데이터 모델” 혹은 "데이터 클래스"라고 부르고,
메서드만으로 구성된 객체를 보통 “서비스 객체” 혹은 "서비스 클래스"라고 부릅니다.

서비스 객체는 서비스 자체를 위한 상태를 포함할 수 있지만, 이를 데이터 모델의 멤버라고 보지는 않습니다.

둘 째, 핵심 임무에 관여 여부에 따른 구분입니다.
핵심 임무 실행에 필요한 간접적인 객체를 보통 서비스라고 부릅니다.
자료를 저장하는 게 핵심 임무인 프로젝트에서는 파일/DB 접근하는 임무가 핵심 임무이기 때문에 서비스가 아니지만, 뷰를 담당하는 프로젝트에서는 이 객체들이 서비스로 분류됩니다.

헬퍼는 보통 핵심 임무를 간단하게 처리해주는 혹은 기본 뼈대를 제공하는 객체를 가리킬 수 있습니다.
헬퍼의 범위는 상당히 넓습니다.

예를 들어, Asp.Net Core 프레임워크는 크게 거시적으로 보면 헬퍼입니다.
가장 협소하게는 ~~Builder, ~~~Manager 도 헬퍼입니다.
전자는 복잡한 객체의 설정을 도와주는, 후자는 특정 객체 혹은 상태를 관리해주는 도우미인 것이죠.

유틸리티는 말 그대로 도구입니다.
파일 도구, 그리기 도구 처럼 말이죠. 윈폼 프로젝트에서 폼 디자이너가 도구라고 할 수 있습니다.
유틸리티까지 정의가 필요하다면, 사실 복잡하고, 큰 규모의 프로젝트라고 할 수 있을 것입니다.

마지막으로 Core, Essential, Engine 등의 이름은 보통 도메인의 핵심 객체를 모아 놓은 프로젝트 모듈을 가리킵니다. 이러한 이름의 프로젝트가 존재한다면, 전체 솔루션이 레이어 구조를 갖도록 설계된 경우가 많습니다.

레이어드 아키텍쳐, 클린 아키텍쳐, 엔터프라이즈 아키텍쳐 등에서는 전체 솔루션을 적층적 레이어로 구성하는데, 각 레이어에는 하나 이상의 프로젝트가 존재합니다. 모든 레이어의 가장 아래, 혹은 가장 깊은 곳에 위치한 모듈을 코어 모듈, 도메인 모듈 등으로 부르는데, 보통 하나의 프로젝트입니다.

이러한 레이어 구조에서는 보통 UI를 담당하는 레이어를 가장 바깥 쪽에 두는데, C#에서는 윈폼, Asp.Net Core, WPF, Console 등의 프로젝트가 여기에 해당합니다.

7개의 좋아요