단일 책임 원칙이란 무엇입니까?
함수형 프로그래밍의 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.)