단일 책임 원칙이란 무엇입니까?
함수형 프로그래밍의 SRP
SRP는 하나의 클래스 또는 하나의 기능이 한 가지만 담당해야 한다고 말합니다. 예를 들어 데이터를 읽고 다른 데이터를 변경하는 기능이 있는 경우 변경해야 할 두 가지 이유가 있습니다. 그 이유는 데이터베이스에서 데이터를 읽거나 데이터를 변경하는 구현이 변경되면 전체 기능을 수정해야 하기 때문입니다.
이런 경우에 객체 지향 프로그래밍 언어에는
interface
가 있습니다. 그러나 함수형 프로그래밍의 경우 일반적으로 함수형 프로그래밍 언어(FPL)에서 클래스를 사용하지 않기 때문에 이와 같은 구현이 없습니다.Note: There is interface implementation in Typescript, so if you
use Typescript for FPL, you can create an interface for
SRP.
아래 예에서 SRP를 위반하는 함수의 잘못된 구현을 볼 수 있습니다.
Note: I'll use the React library to demonstrate the concept.
// bad example
let handleFetching = async () => {
// 1. read data from somewhere
let res = await fetch("some.url").then(res => res.json())
if(res != null)
{
//2. mutate the state
setData(res.data);
}
}
handleFetching
함수에서 볼 수 있듯이 두 가지 책임이 있습니다. 첫 번째는 어딘가에서 데이터를 읽는 것이고 두 번째는 일부 상태 또는 데이터를 변경하는 것입니다. 따라서 이 두 가지 다른 책임에 대한 구현이 변경되면 handleFetching
기능을 변경해야 합니다. 또한 이 두 가지 책임을 테스트해야 하는 곳에서 이 기능을 테스트하기가 어렵습니다.// good example
let handleFetching = async () => {
// 1. read data from somewhere
let res = await getData();
return res
}
let getData = async () => {
// get data implementation goes here
}
useEffect(() => {
let res = handleFetching()
if(res != null)
{
//2. mutate the state
setData(res.data);
}
}, [])
좋은 예에서 볼 수 있듯이 모든 기능이 한 가지만 담당하도록 만들었습니다.
handleFetching
함수는 이제 데이터 가져오기만 담당하고 일부 상태는 변경하지 않습니다. getData
는 어딘가에서 데이터를 가져오는 등의 역할을 합니다. 따라서 우리는 모든 책임을 다른 기능으로 분리하여 개별적으로 테스트할 수 있습니다.OOP의 SRP
함수형 프로그래밍과 유사하게, 우리는 함수가 한 가지를 담당하는지 여부를 결정하기 위해 함수를 분석할 수 있습니다. 기능이나 서비스에 대한 책임이 여러 개인 경우 해당 책임을 분리해야 합니다.
아래 코드에서 나쁜 예를 볼 수 있습니다.
Note: I'll use c# programming language to demonstrate the concept.
//bad example
public async Task<Something> GetSomethingById(int id)
{
var something = await _somethingRepo.GetOneAsync(x => x.id == id);
// violates the SRP
var url = "google.com";
var client = new WebClient();
var reply = client.DownloadString(url);
something.reply = reply;
}
보시다시피
GetSomethingById
메서드에서는 저장소에서 데이터를 가져오고 DownloadString
메서드를 사용하여 응답 속성을 업데이트합니다. 따라서 이 기능에는 두 가지 다른 책임이 있습니다. 하나는 데이터를 가져오는 것이고 다른 하나는 속성을 변경하는 것입니다.// bad example
class FoodDelivery
{
private List<Food> foods;
public Food MakeFood(string name)
{
}
public Food GetFood(int id, int price)
{
}
public void DeliverFood(string path)
{
}
}
이 예에서 우리는
FoodDelivery
클래스에 세 가지 다른 메서드가 있고 모두 다른 논리에서 책임지는 것을 볼 수 있습니다. 구현을 변경하면 다른 기능에 영향을 미칠 수 있습니다. 예를 들어 MakeFood
메서드를 변경하면 DeliverFood
메서드 내부의 일부 로직을 업데이트해야 할 수 있습니다. 또한 MakeFood
및 GetFood
기능은 음식 배달 사업과 관련이 없습니다. 이제 논리를 다른 서비스로 분리하여 이 나쁜 예를 좋은 예로 바꾸는 방법을 살펴보겠습니다.//good example
public interface IFoodGetter{
Food GetFood(int id, int price);
}
public interface IFoodMaker{
Food MakeFood(string name);
}
public class FoodGetter : IFoodGetter {
public Food GetFood(int id, int price){
//implementation goes here
}
}
public class FoodMaker : IFoodMaker {
public Food MakeFood(string name){
//implementation goes here
}
}
class FoodDelivery
{
private List<Food> foods;
private readonly IFoodGetter _foodGetter;
private readonly IFoodMaker _foodMaker;
public FoodDelivery(IFoodGetter foodGetter, IFoodMaker foodMaker){
foodGetter = _foodGetter;
foodMaker = _foodMaker;
}
public void DeliverFood(string path)
{
var food = _foodGetter.GetFood(1,20);
if(food == null){
food = _foodMaker.MakeFood("food_name");
}
//delivery implementation goes here
}
}
위의 예에서 비즈니스 로직을 분리하기 위해
FoodGetter
, FoodMaker
와 같은 두 가지 다른 서비스를 생성했습니다. 그리고 FoodDelivery
클래스는 음식 배달만 담당합니다. FoodGetter
서비스에서 일부 구현을 변경해야 하는 경우 해당 서비스 내에서 변경할 수 있습니다. 또한 인터페이스를 사용하여 이러한 서비스의 모의 구현을 생성할 수 있으므로 실제 데이터베이스 등에 연결하지 않고도 테스트할 수 있습니다.
Reference
이 문제에 관하여(단일 책임 원칙이란 무엇입니까?), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/eminvergil/what-is-single-responsibility-principle--bmi텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)