2017-05-19 3 views
0

많은 Go 프로그래밍 서적에서 저자는 대개 비즈니스 논리를 처리하는 동일한 함수 내에 데이터 액세스 논리를 배치합니다. 이것이 교육 목적으로 만 쓰일 수 있음을 이해하지만 실제로 사람들이 실제 개발에서 BLL과 DAL을 실제로 분리하는지 궁금합니다.Go Web App에 DAL과 BLL이 있어야합니까?

나는 Go 프로젝트에 계층화 된 디자인을 적용하려했지만 그로부터 어떤 이점도 느껴 보지 못했습니다.

func GetCustomerAccountInfo (accountID int) (*sql.Rows, error) { 
    sql := `SELECT * FROM CUSTOMER_ACCOUNT WHERE ID = $1` 
    return GLOBAL_PSQL.Query(sql, accountID) 
} 

그리고 내 일반적인 BLL 기능은 다음과 같이 될 것이다 : 예를 들어, 내 DAL 기능 (appdal 패키지)과 같이 전형적으로

func NewCustomerAccountBLL (accountID int) (* CustomerAccountBLL) { 
    rows, err := appdal.GetCustomerAccountInfo(accountID) 
    // create an instance of CustomerAccountBLL (bll) and scan rows.... 
    return &bll 
} 

가 종종 내 BLL가 본질적으로 연결되어 있음을 발견 스캐닝 때문에 필자가 내 쿼리에서 읽은 열을 알아야하므로 일부 DAL 함수를 BLL에 병합하는 것이 좋지 않은 것으로 나타났습니다 (대신 BLL에 쿼리를 병합하는 것이 좋음). 또한 DAL을 보유하면 유지해야하는 코드 양도 증가합니다.

그러나 많은 소프트웨어 설계자는 계층화 된 디자인을 권장하며 BLL 및 DAL을 사용하고 각 계층에 명확한 책임을 할당하는 것이 좋습니다.

디자인과 패턴이 프로그래밍 언어에 반드시 의존하지는 않지만 필자는 프로젝트에서 BLL과 DAL을 거의 사용하지 않는 것으로 나타났습니다. 내가 디자인에서 중요한 것을 놓치고 있습니까, 아니면 가야합니까? 감사!

+0

이 정보가 도움이되는지 확인하십시오. http://stackoverflow.com/q/42791536/5779732, http://stackoverflow.com/a/42500771/5779732, http://stackoverflow.com/a/4/424700/5779732 –

답변

3

귀하가 언급 한대로이 질문은 특정 언어가 아니며 모든 언어에 적용될 수 있습니다.

다른 디자인 문제와 마찬가지로,이 일을 더 올바른 방법이 없습니다
  • 하지만 일반적인 관행이 실제로 별도의 비즈니스 로직입니다 : 여기

    난 당신이에 대해 생각해야한다고 생각 몇 가지 포인트입니다 데이터 액세스.

  • 비즈니스 로직을 실제 데이터 액세스 구현에 연결해서는 안되므로 SQL에서 멀리 이동하여 일반 파일 또는 No-SQL 저장소에 개체를 저장하려는 경우 반드시 변경하지 않아도됩니다. 비즈니스 로직 계층.

  • 귀하의 경우 GetCustomerAccountInfosql.Rows을 반환합니다. 이것은 실제 비즈니스 로직을 특정 구현과 결합시킵니다. 일반적으로 실제 모델 객체 (예 : CustomerAccount)를 반환합니다.

  • 예제가 매우 간단하므로 분리해도 많은 이점을 얻지 못할 수도 있습니다. 그러나 때로는 상황이 그렇게 간단하지 않습니다.

    • 데이터 액세스 논리에는 테이블을 조인하는 복잡한 쿼리가 포함될 수도 있고 데이터베이스 트랜잭션 내에서 별도의 쿼리를 만들 수도 있습니다. 이를 분리함으로써 이러한 낮은 수준의 세부 사항으로 비즈니스 로직을 오염시키지 않습니다. 또한 비즈니스 로직 계층을 변경하지 않고 데이터 액세스 계층 만 변경하여 기본 테이블 구조를 변경할 수 있습니다.

    • Business Logic은 다른 개체의 병합, 기본값 적용 및 도메인 유효성 검사 수행과 같은 복잡한 계산으로 구성 될 수도 있습니다.이 논리 (사용중인 저장 영역과 독립적 임)를 분리하면 데이터 액세스 논리를 변경하지 않고도 비즈니스 로직을 변경할 수 있습니다.

는 기본적으로,이를 분리함으로써, 당신은 개발 (또한 중요한 : 테스트) 할 수있는 비즈니스 및 데이터 액세스 로직을 각각 분리하고보다 모듈 형 설계가 있습니다.

도움이 되었기를 바랍니다.

+0

매우 감사. 그러나 계층화 된 디자인에 따르면 DAL은 BLL의 모델에 의존하지 않아야합니다. BLL 모델을 반환하는 DAL 함수가 있으면 종속성주기 문제가 발생할 수도 있습니다. BLL은 BLL 개체를 반환하는 DAL 함수를 호출합니다. 이것이 문제가 될까요? 아니면이 경우 DAO를 구현해야합니까? –

+0

DAL이 BLL 개체와 별도로 DAO를 반환하도록 할 수 있습니다. 필자는 BLL 객체가 DAL에서 DAL 계층을 BLL 논리에 연결하기에 충분히 복잡 할 경우에만 그렇게 할 것입니다. 그렇지 않으면 BLL 객체가 간단하다면 DAO에서 BLL 로의 매핑은 간단하지만 불필요한 단계가되며,이 경우 DAL에서 BLL 객체를 반환하는 것이 문제가되어서는 안됩니다. 이는 실제 사용 사례에 따라 크게 달라집니다. – eugenioy

1

실용적인 대답을 찾고 있다면 여기 내 생각 중 하나입니다.

고객 계정을 가져 와서 API의 입력에 맞게 수정하려고한다고 가정 해 보겠습니다.

그래서 다음과 같이 보일 것입니다 데이터 층 또는 쿼리를 작성 :

type CustomerAccount struct{ 
    id string // this data type will differ depends on your database. 
    Name string 
    Address string 
    Age int 
    // and any other attribute. this is just for example. 
} 


func (ca *CustomerAccount)GetCustomerAccount (id int) (CustomerAccount,error) { 
    var ca CostumerAccount 
    // write your query using any databases. 
    // return an error if error happens when you do query to the database. 

    return ca,nil 
} 

func (ca *CustomerAccount)SaveCustomerAccount(ca CustomerAccount) error { 
    // find and update the data from given CustomerAccount 
    return nil 
} 

저장 코드를 customer_account.go 명명 위.

이제 비즈니스 로직 또는이 경우 BLL을 사용하는 DAL에서 데이터베이스 쿼리를 분리하려고한다고 가정 해 보겠습니다. 당신은 그 인터페이스를 사용할 수 있습니다. customer_account_interface.go로 저장

type CustomerAccountInterface interface { 
    GetCustomerAccount (id int) (CustomerAccount,error) 
    SaveCustomerAccount(ca CustomerAccount) error 
} 

: 인터페이스이 같은 위의 모델 쿼리 방법을 마녀 일치 유형을 만들기.

이제 우리는 데이터 수정에 대한 책임이있는 비즈니스 로직을 작성하고자하며, CusomerAccountInterface을 비즈니스 로직으로 호출 할 것입니다. 데이터 액세스 또는 우리가 단위를 만들 수 있도록 쿼리 데이터베이스와 비즈니스 로직 우리가 핸들러를 분리 한 위의 접근 방식에서

func EditCustomerAccount(ca CustomerAccountInterface) http.Handler { 

    return http.HandleFunc(func(w http.ResponseWritter, r *http.Request){ 
    // get all the input from user using *http.Request like id and other input. 

    // get our CustomerAccount Data to modify it 
    customerAccount,err := ca.GetAccountCustomer(id) 

    // modify customerAccount Accordingly from the input data, for example 
     customerAccount.Name = inputName // you can change what ever you want with the data here. In this case we change the name only for example purpose. 

    // save your customerAccount to your database 
    err := ca.SaveCustomerAccount(customerAccount) 

    // send the response 200 ok resonse if no error happens 
    w.WriteHeader(http.StatusOk) 
    resp := response{} // you can create your response struct in other places. 
    resp.Message = "success update data" 
    json.NewEncoder(w).Encode(resp) 

    }) 

} 

: 우리가 혹 있도록 API를 만드는 때문에 우리는이에 대한 핸들러를 사용

type CustomerAccountMock struct { 
    err error 
    Data CutstomerAccount 
} 

func (ca *CustomerAccountMock)GetCustomerAccount (id int) (CustomerAccount,error) { 
    return ca.Data,nil 
} 

func (ca *CustomerAccountMock)SaveCustomerAccount(ca CustomerAccount) error { 
    return ca.err 
} 

이제 우리는이 같은 테스트 뭔가를 쓸 수 있습니다 :

데이터 액세스의 결과 쿼리를 조롱하는

CustomerAccountMock 만들기 :이 같은 핸들러 뭔가 비즈니스 로직에 대한 시험

func TestEditCustomerAccount(t *testing.T){ 
    testObjects := []struct{ 
    CMock CutomerAccountMock 
    }{ 
    { 
     CMock : CustomerAccountMock{ 
     err : errors.New("Test error") 
     Data : CustomerAccount{} // return an empty data 
     }, 
    }, 
    } 

    for _, testObject := range testObjects { 
    actualResponse := createRequestToHandler(testObject.CMock) 
    // here you can check your response from calling your request testing to your handler. 

    } 

} 

위의 아이디어를 얻는 것 이상으로 데이터 계층과 비즈니스 로직 계층을 분리하여 어떻게 접근해야합니까? 내 완전 source code here을 참조 할 수 있습니다. 이 코드는 드라이버 데이터를 업데이트하는 것과 같은 또 다른 테스트 케이스를 나타내지 만 동일한 접근법입니다.

하지만이 접근법에는 몇 가지 단점이 있습니다. 테스트에서는 수천 건의 기사 작성과 비슷합니다. 인내심을 가져야합니다.

그래서 귀하의 질문에

오는 그것은 이동 Web App에서 DAL 및 BLL이 필요하다?

예. 데이터 액세스를 비즈니스 로직 레이어와 분리하면 단위 테스트가 가능해집니다.

위의 예제에서 로직은 매우 간단하지만 데이터를 조작하는 복잡한 로직이 있고 DAL과 BLL을 분리하지 않는다고 상상해보십시오. 로직이나 쿼리를 변경하면 미래의 개발자와 다른 개발자에게 해를 입힐 것입니다.

뭔가 잘못되었을 때 변경하고 좌절감을 느끼는 것은 분명히 직업 생활에서 일어나는 것을 피하기를 원합니다.

관련 문제