DSL 단어와 모델 검사
팀만의 DSL 단어
ElastiCORE 는 모르는 단어를 오류로 보지 않고 보관만 합니다. 생성 코드에는 아무것도 나오지 않고, 규칙이 읽을 수 있습니다. 그래서 팀의 개념을 YAML 에 그대로 적게 할 수 있습니다.
model/entity.yml
Category:
meta: entity @root @editable @expose(20) @access(read=public) @nodelete # 엔티티 단어
Customer:
fields:
email: string(100) @email @pii # 필드 단어
PurchaseOrder:
meta: entity @root @expose(20) @event(Placed(total), Shipped, Cancelled) @topic(petstore.order) # 값이 있는 단어
| 어디에 | 있나 | 값 |
|---|---|---|
엔티티 meta: | e.hasMeta("nodelete") | e.metaValue("topic") → "petstore.order" |
| 필드 | f.hasDsl("pii") | f.dslValue("search") → "like" |
| 같은 단어 여러 번 | e.metaValues("x") | |
이름 붙은 속성 @x(a=1, b=2) | f.dslProperty("x", "a"), e.metaText("x") (원문) |
필드 단어는 대소문자를 가리지 않습니다(@PII 도 hasDsl("pii")).
지을 때:
- ElastiCORE 에 이미 있는지 먼저 -
@readonly,@restExclude,@example,@label처럼 이미 있는 기능을 다시 만들지 마세요. 규칙을 지워 보고 결과가 그대로면 이미 있는 것입니다. 목록: DSL 레퍼런스. - 이미 쓰는 단어와 겹치지 않게 -
@event,@search,@label… 걱정되면 팀 접두사(@psTopic). - 철자가 틀려도 조용합니다 -
@pi는 그냥 무시됩니다. 중요한 단어라면 아래처럼 검사 규칙을 두세요.
모델 검사 - ModelCheck
규칙은 코드를 쓰지 않고 모델만 검사할 수도 있습니다.
| 호출 | 결과 |
|---|---|
ModelCheck.warn(msg) | 경고만 출력. 같은 메시지는 한 번. 빌드는 계속 |
ModelCheck.fail(msg) | 생성은 끝까지 하고(모든 문제를 한 번에 보이도록) 마지막에 모아 보여 준 뒤 빌드 실패 |
@Rule("ps-model-check")
void check(EntitySpec e) {
if (!e.aggregateRoot()) return;
if (!e.commands().isEmpty() && e.events().isEmpty()) {
ModelCheck.warn(String.format(
"[ps] %s takes commands but declares no @event: nothing outside the aggregate hears what happened.",
e.getName()));
}
// A team setting in env.yml: elasticore.config.ps.maxPageSize
String max = e.config("ps.maxPageSize");
String expose = e.metaValue("expose");
if (max != null && expose != null && expose.trim().matches("\\d+")
&& Integer.parseInt(expose.trim()) > Integer.parseInt(max.trim())) {
ModelCheck.fail(String.format(
"[ps] %s pages %s rows at a time (@expose(%s)); the team maximum is ps.maxPageSize=%s.",
e.getName(), expose.trim(), expose.trim(), max.trim()));
}
}
팀 설정값 - config(...)
검사 기준처럼 프로젝트마다 다를 수 있는 값은 규칙에 박지 말고 env.yml 의 config: 아래에 둡니다.
blueprint/petstore/env.yml
elasticore:
config:
domainName: petstore
…
ps:
maxPageSize: 500 # team rule ps-model-check: no @expose(n) above this
| 코드 | 읽는 값 |
|---|---|
e.config("ps.maxPageSize") | 그 엔티티 도메인의 elasticore.config.ps.maxPageSize - 없으면 null |
d.config("…"), d.isOn("…") | 도메인 규칙에서 / "true" 인가 |
펫스토어의 Country 는 @expose(300) 입니다. maxPageSize 를 100 으로 내리면:
[elcore3] the model check failed (1) - fix these and build again:
[ps] Country pages 300 rows at a time (@expose(300)); the team maximum is ps.maxPageSize=100.
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':elcore3'.
> Process 'command '…\java.exe'' finished with non-zero exit value 1
500 으로 두면 통과합니다. 실패해도 생성은 끝까지 돌기 때문에, 여러 엔티티의 문제가 한 번에 보입니다. 이미 만들어진 파일 중 DSL 이 더 이상 만들지 않는 것은 검사가 통과할 때까지 지우지 않습니다.
예외를 던지지 마세요
규칙 안에서 예외가 나면 그 규칙이 쓰던 파일 하나만 실패(ERROR)로 남고 나머지는 생성된 뒤 종료 코드 1 로 끝납니다.
어느 파일이 왜 빠졌는지 찾기 어렵습니다. 모델의 문제는 ModelCheck.fail 로, 규칙이 다룰 수 없는 경우는 return 으로.
테스트에서
@Test
void aPageAboveTheTeamMaximumFails() {
EntitySpec country = new EntitySpec("Country").domain("petstore", "Petstore").meta("root", "")
.meta("expose", "300").config("ps.maxPageSize", "100")
.field("isoCode", "string(2) @id");
engine().run(country, "entity");
assertEquals(1, ModelCheck.failures().size());
}
@AfterEach
void forget() {
ModelCheck.reset(); // failures are kept per JVM: reset between tests
}
ModelCheck.failures() 는 실패만 모읍니다. 경고는 콘솔에 출력되므로, 경고를 테스트하려면 System.out 을 잡아서
봅니다. 자세한 것은 테스트.