2017-11-06 13 views
0

다른 질문은 "데이터베이스에서 오는 데이터 유형을 내 REST 끝점에서 요청할 때 간단하고 원시로 유지해야합니까?"데이터베이스에서 검색된 데이터의 유효성을 얼마나 신뢰할 수 있습니까?

데이터베이스에 저장하려는이 사례 클래스를 상상해보십시오. 행으로 :

case class Product(id: UUID,name: String, price: BigInt) 

그것은 분명히 아니고, nameprice의 유형 서명 거짓말 때문에 그것이 말하는해서는 안됩니다. 그래서 지금의 과정을 (간단히하기 위해 우리의 유일한 관심사는 price 데이터 형식 상상)

case class Price(value: BigInt) { 
    require(value > BigInt(0)) 
} 

object Price { 
    def validate(amount: BigInt): Either[String,Price] = 
    Try(Price(amount)).toOption.toRight("invalid.price") 
} 

//As a result my Product class is now: 
case class Product(id: UUID,name: String,price: Price) 

:

그래서 우리가하는 일은 사용자 정의 데이터보다 같은 어떤 것을 표현 유형을 만들 수있다 제품 데이터에 대한 사용자 입력을 복용하는 것은 같을 것이다 : 트리플 물음표 (???)에서

//this class would be parsed from i.e a form: 
case class ProductInputData(name: String, price: BigInt) 

def create(input: ProductInputData) = { 
    for { 
    validPrice <- Price.validate(input.price) 
    } yield productsRepo.insert(
     Product(id = UUID.randomUUID,name = input.name,price = ???) 
    ) 
} 

보세요. 이것이 전체 애플리케이션 아키텍처 측면에서 우려 할 사항입니다. 데이터베이스에 Price이라는 열을 저장할 수있는 능력이 있다면 (예 : slick은 이러한 사용자 지정 데이터 형식을 지원합니다) 그러면 가격을 price : BigInt = validPrice.value 또는 price: Price = validPrice으로 저장할 수 있습니다.

나는이 결정들 모두에서 많은 찬반 양론들을 보았고 나는 결정할 수 없다. 간단한 데이터베이스 유형과 같은

저장 데이터 (즉, BigInt) 이유는 다음과 같습니다 :

  • 성능 : Price의 창조에 x > 0의 단순한 주장 는 여기에 내가 각 선택을 지원하는 참조 인수입니다 간단하지만 복잡한 정규 표현식을 사용하는 유형의 사용자 정의를 확인하려고한다고 가정 해보십시오. 그것은

  • 공차 부패에 대해 컬렉션의 검색시 유해 할 것 : BigInt가 음의 값으로 삽입되어있는 경우는 당신의 얼굴에서 응용 프로그램은 단순히 열을 읽고에 그것을 밖으로 던져하려고 할 때마다 폭발 would't 사용자 인터페이스 그러나 검색된 다음 구입과 같은 일부 도메인 계층 처리에 관여하면 문제가 발생할 수 있습니다.

데이터 저장이 때문에 도메인 풍부한 유형 (즉, Price)입니다 같이

  • 없음 암시 적 추론하지 않고 신뢰 : 다른 방법으로 가격을 필요가 시스템의 다른 어떤 장소를 유효한.예를 들면 :
//two terrible variations of a calculateDiscount method: 

//this version simply trusts that price is already valid and came from db: 
def calculateDiscount(price: BigInt): BigInt = { 
    //apply some positive coefficient to price and hopefully get a positive 
    //number from it and if it's not positive because price is not positive then 
    //it'll explode in your face. 
} 

//this version is even worse. It does retain function totality and purity 
//but the unforgivable culture it encourages is the kind of defensive and 
//pranoid programming that causes every developer to write some guard 
//expressions performing duplicated validation All over! 
def calculateDiscount(price: BigInt): Option[BigInt] = { 
    if (price <= BigInt(0)) 
    None 
    else 
    Some{ 
    //Do safe processing 
    } 
} 

//ideally you want it to look like this: 
def calculateDiscount(price: Price): Price 
  • 정수를 단순한 형식으로 도메인 형식 변환 및 그 반대 : 표시, 저장 영역 층과 같은 대; 당신은 단순히 그것들 모두를 지배하는 하나의 표현을 시스템에 가지고 있습니다.

내가보기에이 모든 혼란의 근원은 데이터베이스입니다. 사용자가 데이터를 가져 오는 것이 쉬운 일일 경우 : 을 신뢰할 수 없도록하는 것입니다. 당신은 단순한 데이터 타입을 유효성 검사를 통해 도메인 타입으로 캐스팅하고 진행하도록 요청합니다. 하지만 DB는 아니야. 현대의 계층화 된 아키텍처가이 문제를 확실하게 또는 최소한 완화 방법으로 해결합니까?

+0

사용자 입력에 대한 신뢰도를 말할 것입니다. 소스 데이터베이스의 이상 변이에 대한 변환 규칙을 가지고 있거나 원본 데이터베이스를 먼저 정규화 할 수 있습니다. –

+0

@plalx @RobertUdah 그러면 도메인을 처리하기 위해 가져온 값을'''BigInt'''로 저장한다고 가정합니다. 나는'''Price.validate (fetchedBigInt)''''''Price.apply (fetchedBigint)''두 가지 옵션을 가지고 있습니다. 전자는 예외를 던지지 않을 것이지만 편집증 프로그래밍의 범주에 넣습니다. 검색시 그것을 검증함으로써 당신은 거기에 놓인'''productService class''를 신뢰하지 않는다고 말하고 있습니다. 후자의 문제는 아무도 요즘 좋아하지 않는 예외를 던질 수 있다는 것입니다. 어느 쪽을 선택 하시겠습니까? – shayan

+0

@shayan DB의 값이 매핑하려고하는 유형에 맞지 않으면 스토리지 라이브러리가 항상 던져 버리지 않습니까? 아니면 놓친 것이 있습니까? – guillaume31

답변

2
  1. 데이터베이스의 무결성을 보호하십시오. 개체의 내부 상태의 무결성을 보호하는 것처럼 말입니다.
  2. 데이터베이스를 트러스트하십시오. 이미 체크인 한 항목을 확인하고 다시 확인하는 것은 의미가 없습니다.
  3. 가능한 한 오랫동안 도메인 개체를 사용하십시오. 마지막 순간까지 기다리십시오 (원시 JDBC 코드 또는 데이터가 렌더링되기 직전).
  4. 손상된 데이터를 허용하지 마십시오. 데이터가 손상되면 응용 프로그램이 중단됩니다. 그렇지 않으면 더 많은 데이터가 손상 될 수 있습니다.

DB에서 검색 할 때 require 호출의 오버 헤드는 무시할 수 있습니다. 실제로 그것이 문제라고 생각되면 사용자로부터 오는 데이터 (유효성 검사 수행)와 데이터가 양호하다고 가정하는 (데이터베이스 코드에서 사용하기위한) 생성자 두 가지를 제공하십시오.

나는 버그를 지적 할 때 예외를 좋아한다. (유효성이 불충분하기 때문에 데이터가 손상된다.)

그렇긴하지만 더 복잡한 유효성 검사에서 버그를 잡는 데 도움이되는 코드에 requires을 정기적으로 남겨 둡니다 (여러 테이블의 데이터가 잘못된 방법으로 결합되었을 수 있음). 시스템은 여전히 ​​충돌합니다 (그래야 함). 그러나 더 나은 오류 메시지가 나타납니다.

+0

나는 모든 점을 특히 좋아한다. # 4 – shayan