Files
document-haness/.agents/skills/rewriting-technical-prose-naturally/references/regression-examples.md
T

23 KiB

Regression Examples

Use these examples to calibrate decisions, not as sentence templates. The acceptable rewrites are intentionally plain. Reusing their sentence frames across a corpus would create another AI pattern.

한국 기술 블로그가 각 자리에서 실제로 쓰는 표현은 korean-tech-blog-register.md에 있다. 이 파일은 그 규범을 어겼을 때 어떤 문장이 나오는지를 모은 것이다.

1. 수치를 추세 표현으로 바꾸지 않는다

원문:

Page는 N=10, 100, 1,000에서 추가 쿼리가 각각 10번, 100번, 1,000번 발생했다. User는 3번, 20번, 20번 발생했다. 여러 Feed Item이 같은 User를 참조했고, 한 번 조회한 User는 1차 캐시에 남아 있었다.

잘못 고친 예:

데이터가 증가하면서 Page 조회 비용은 선형적으로 증가한 반면 User는 캐시 효과로 일정하게 유지됐다.

허용하는 예:

Page는 N=10, 100, 1,000에서 각각 10번, 100번, 1,000번의 추가 쿼리가 발생했다. User 같은 경우는 여러 Feed Item에서 같은 사용자를 참조하고 있어서 추가 쿼리가 3번, 20번, 20번 발생했다. 한 번 조회한 User는 1차 캐시에 남아 있었다.

실패 이유: 잘못 고친 문장은 수치를 삭제하고 조회 비용, 선형적, 캐시 효과, 일정하게 유지라는 더 넓은 해석으로 바꿨다. User의 3, 20, 20도 일정한 값이 아니다.

2. 제목에 대비를 만들지 않는다

원문에서 확인한 내용:

PageUser는 모두 @ManyToOne(EAGER)였다. 두 연관 관계에서 발생한 추가 쿼리 수가 달랐다.

잘못 고친 제목:

같은 EAGER가 정반대 곡선을 그린다

허용하는 제목:

EAGER 연관 관계에서 발생한 추가 조회

실패 이유: 정반대 곡선은 원문에 없는 모양과 대비를 만든다.

3. 추상적인 결정 요인으로 압축하지 않는다

원문:

이미 조회한 User는 1차 캐시에 남아 있어서 다시 조회하지 않았다.

잘못 고친 예:

Persistence Context의 재사용 여부가 비용을 결정했다.

허용하는 예:

한 번 조회한 User는 1차 캐시에 남아 있어서 다시 조회하지 않았다.

실패 이유: 비용을 결정했다는 측정 대상과 범위를 넓힌다.

4. 구체적인 변화는 그대로 적는다

원문:

Feed Item을 100개에서 1,000개로 늘리자 Page 추가 쿼리도 100번에서 1,000번으로 늘었다.

잘못 고친 예:

조회 비용이 데이터셋의 카디널리티에 비례했다.

허용하는 예:

Feed Item을 100개에서 1,000개로 늘리자 Page 추가 쿼리도 100번에서 1,000번으로 늘었다.

실패 이유: 구체적인 대상과 수치가 사라지고, 원문보다 넓은 비례 관계가 생겼다.

5. 비용을 다른 곳으로 이동시켰다고 포장하지 않는다

원문:

fetch join을 적용한 뒤 쿼리 수는 줄었다. 조인으로 조회되는 행 수와 메모리 사용량은 늘었다.

잘못 고친 예:

비용이 네트워크와 메모리로 이동했다.

허용하는 예:

쿼리 수는 줄었지만 조인으로 조회되는 행 수와 메모리 사용량은 늘었다.

실패 이유: 원문에 없는 네트워크를 추가했고, 서로 다른 관측값을 하나의 비용으로 일반화했다.

6. 내부 측정 용어는 정확한 뜻이 있을 때만 푼다

원문:

PreparedStatement에서 collection fetch를 제외한 뒤에도 추가 쿼리가 남았다.

잘못 고친 예:

ORM 내부 실행 비용을 제거한 뒤에도 숨은 부하가 존재했다.

허용하는 예:

컬렉션을 조회하는 쿼리를 제외하고도 추가 쿼리가 남았다.

실패 이유: PreparedStatement실행 비용으로, 추가 쿼리를 숨은 부하로 바꿔 의미를 넓혔다. 허용 예는 이 문서에서 collection fetch가 컬렉션 조회 쿼리를 뜻한다고 앞 문맥이 확인해 준 경우에만 사용할 수 있다.

7. 문장을 짧게 압축하기보다 설명 흐름을 남긴다

원문:

여러 Feed Item이 같은 User를 참조하고 있었다. 한 번 조회한 User는 1차 캐시에 남았다.

잘못 고친 예:

동일 User 참조가 Persistence Context에서 재사용됐다.

허용하는 예:

User 같은 경우는 여러 Feed Item에서 같은 사용자를 참조하고 있어서, 한 번 조회한 User는 1차 캐시에 남았다.

실패 이유: 잘못 고친 문장은 무엇을 다시 사용했는지와 실제 조회 동작을 압축했다.

8. 원문에 없는 교훈을 붙이지 않는다

원문:

N=100에서 Page 추가 쿼리가 100번 발생했다. 각 Feed Item이 서로 다른 Page를 참조하고 있었기 때문이다.

잘못 고친 예:

N=100에서 Page 추가 쿼리가 100번 발생했다. 따라서 EAGER 연관 관계는 반드시 피해야 한다.

허용하는 예:

N=100에서 Page 추가 쿼리가 100번 발생했다. 각 Feed Item이 서로 다른 Page를 참조하고 있었기 때문이다.

실패 이유: 측정 결과만으로 일반적인 설계 권고를 만들었다.

9. 확인하지 않은 결과를 확정하지 않는다

원문:

같은 refresh token의 두 번째 사용은 rotation 정책 때문에 거부될 가능성이 있다. 실제 응답과 session 영향은 아직 재현하지 않았다.

잘못 고친 예:

rotation이 적용되므로 두 번째 refresh token 사용은 거부된다.

허용하는 예:

같은 refresh token을 두 번째로 사용했을 때 거부될 가능성이 있다. 실제 응답과 session에 미치는 영향은 아직 확인하지 않았다.

실패 이유: 가능성을 확정된 결과로 바꾸고 미검증 범위를 삭제했다.

10. 대상을 기준선이라고 부르지 않는다

원문:

피드 아이템을 엔티티로 조회한 뒤 Stream으로 DTO에 옮기는 구현을 기준선으로 삼았다.

잘못 고친 예:

같은 기준선에 두 가지 위반이 함께 있었다.

허용하는 예:

피드 아이템을 엔티티로 조회한 뒤 Stream으로 DTO에 옮기는 코드를 그대로 두고 측정했다.

하이라이트가 아무리 많아도 조회량이 그에 비례해 늘지 않아야 한다는 요구가 두 가지 방식으로 깨졌다.

실패 이유: 기준선은 그 코드가 무엇인지 말하지 않고 비교 대상이라는 역할만 붙인다. 뒤에서 같은 기준선에로 되풀이되면 무엇을 가리키는지 더 흐려진다. 위반도 무엇을 어긴 것인지 말하지 않는다. 어긴 요구를 문장에 적는다.

11. API·지표 이름은 남기고 뜻을 옆에 적는다

원문:

| N | 초기화 Highlight 컬렉션 | 총 PreparedStatement |

N=1,000에서 총 PreparedStatement는 2,022개였다.

잘못 고친 예:

N=1,000에서 총 쿼리가 2,022개 실행됐다.

허용하는 예:

총 PreparedStatement는 Hibernate가 SQL 한 건을 실행하려고 JDBC에서 얻은 문장 객체 수다. 이 요청이 SQL 문장을 몇 건 준비했는지를 뜻한다.

N=1,000에서 총 PreparedStatement는 2,022개였다.

실패 이유: 잘못 고친 문장은 이름을 지우면서 뜻까지 바꿨다. 원문은 이 값이 SQL 실행 수와 항상 같지는 않다고 적었다. 이름은 그대로 두고, 처음 나오는 자리에 그것이 무엇인지 한 문장으로 적는다. 평문 칸처럼 이름을 그대로 쓰기 어려운 자리에서는 준비된 SQL 문장(PreparedStatement)처럼 뜻을 앞에 두고 이름을 괄호에 남긴다.

12. 지표를 지키려다 문장을 비틀지 않는다

원문(측정값):

초기화 Highlight 컬렉션 : N=10에서 10, N=100에서 100, N=1,000에서 1,000 총 PreparedStatement : 25, 222, 2,022 본문에 적힌 조건 : batch나 subselect가 없어 컬렉션 하나를 초기화할 때 SQL 하나가 나간다

잘못 고친 예:

매핑이 getHighlights()에 접근할 때마다 비워 뒀던 하이라이트 목록이 하나씩 채워졌고, 채워진 목록 수가 반환 아이템 수 N과 정확히 같았다. N=1,000에서 이 요청 하나가 준비한 SQL 문장은 2,022건이었다.

허용하는 예:

매핑이 getHighlights()에 접근하는 시점에 N개의 쿼리가 추가로 나갔다. N=1,000이라면 추가 쿼리를 포함해 총 2,022개가 나갔다.

실패 이유: 잘못 고친 문장은 초기화된 컬렉션 수는 SELECT 수가 아니다라는 주의를 요약 칸에서까지 지키려다 사건을 명사구(채워진 목록 수, 준비한 SQL 문장)로 바꿨다. 정확하지만 아무도 그렇게 말하지 않는다. 문서가 조건(batch 없음)을 이미 밝혔으므로 요약과 결론에서는 일어난 일을 동사로 적고, 지표 이름과 주의는 본문 표 옆에 남긴다.

13. 준비하거나 되풀이하는 문장은 지운다

원문:

반복되는 하이라이트 조회 하나의 실행계획

반복되는 하이라이트 조회 하나를 실행계획으로 확인했다.

Index Scan using ...

허용하는 예:

반복되는 하이라이트 조회 하나의 실행계획

Index Scan using ...

실패 이유: 제목이 이미 말한 것을 문장이 한 번 더 말한다. 코드에 반복문은 없다, 이 관찰은 두 위반을 드러낸다처럼 다음 문장을 준비하기만 하는 문장도 같다. 측정한 사실과 자료에 있는 이유만 남긴다.

14. 예시는 한 규모로 고정한다

잘못 고친 예:

N=10에서 10개, N=100에서 100개, N=1,000에서 1,000개였다. 총 쿼리는 25개, 222개, 2,022개였다. N=1,000에서 피드 한 번 로딩은 194 ms였다.

허용하는 예:

N=100이면 100번이고, 추가 쿼리를 포함한 총 쿼리는 222개였다. 피드 한 번 로딩의 지연 중앙값은 85.9 ms였다.

실패 이유: 세 규모를 문장마다 늘어놓으면 읽는 사람이 매번 어느 규모의 이야기인지 다시 맞춰야 한다. 어떻게 늘어나는지는 표가 이미 보여 준다. 설명은 한 규모에서 하고, 그 규모의 수치만 문장에 남긴다. 가장 큰 N을 고르는 것은 설명이 아니라 과장이다.

15. 문장을 그림으로 옮기지 않는다

본문에 있던 그림의 <text>:

loadFeed(0, N) → FeedItem N개 · Highlight 컬렉션 초기화 N회 · Highlight SELECT N회

바로 옆 문단:

매핑이 getHighlights()에 접근하는 시점에 아이템마다 쿼리가 한 번씩 나갔다.

실패 이유: 그림이 문단을 다시 그렸을 뿐이라 읽는 사람이 그림에서 새로 얻는 것이 없다. alt까지 같은 말을 세 번째로 반복한다. 그림은 순서·구조·측정값·실제 산출물(로그, 실행계획, 화면)처럼 문장이 담지 못하는 것을 담을 때만 남긴다.

16. 없는 관용구를 만들어 쓰지 않는다

원문(측정값):

returned : N=10에서 10, N=100에서 20, N=1,000에서 20 feedItemLoaded : 10, 100, 1,000

잘못 고친 예:

returned는 페이지 크기에 고정되었지만 feedItemLoaded는 N을 따라 늘었다. 조회 수는 아이템 수 100을 따라갔다.

허용하는 예:

returned는 페이지 크기인 20에 그대로 머물렀지만, feedItemLoaded는 N이 커지는 만큼 같이 늘어 N=1,000에서 1,000이 되었다.

실패 이유: 한국어에서 따라가다의 목적어는 사람, 길, 기준 같은 것이지 개수가 아니다. 100을 따라갔다는 한국어 문장이 아니다. 앞의 규칙(캐시 효과처럼 뭉뚱그리지 말 것)을 지키려다 아무도 쓰지 않는 관용구를 새로 만든 경우다. 금지 표현을 피한 자리에 들어가는 대체 표현도 똑같이 검사한다. 수가 같이 늘어난다는 말은 ~에 비례해, ~가 커지는 만큼, ~와 같은 수로, 또는 그냥 값을 적어 아이템이 100개면 조회도 100번 나갔다로 쓴다.

17. 논증 속 역할로 부르지 않는다 — 비교 대상, 최소한의 선, 관계

잘못 고친 예:

초기화 컬렉션 수와 PreparedStatement 수는 비교 대상이 아니다. 이 구현도 최소한의 선은 지켰다. 두 엔티티의 관계 때문에 추가 쿼리가 생겼다.

허용하는 예:

두 값은 세는 것이 다르다. 초기화 컬렉션 수는 지연 로딩이 채운 컬렉션 개수이고, PreparedStatement 수는 JDBC에서 얻은 문장 객체 수다. 이 구현도 공개 범위 판정은 요구대로 적용했다. FeedItem.page에 걸린 @ManyToOne(EAGER) 매핑 때문에 아이템마다 Page 조회가 한 번씩 더 나갔다.

실패 이유: 비교 대상이 아니다는 두 값이 왜 다른지를 말하지 않고 독자에게 비교하지 말라는 지시만 남긴다. 최소한의 선은 무엇을 지켰는지 말하지 않는다. 관계는 어느 매핑인지 말하지 않는다. 세 낱말 모두 글쓴이의 머릿속에 있는 논증 구조를 가리킬 뿐 코드나 측정값을 가리키지 않는다. 관계연관 관계, @ManyToOne 관계처럼 이름의 일부일 때만 쓴다.

18. 설명 앞에 상황 서술을 덧대지 않는다

잘못 고친 예:

이 코드는 반복문 없이 목록을 매핑하는 상황이다. 그런데도 매핑이 getHighlights()에 접근하는 시점에 아이템마다 쿼리가 한 번씩 나갔다.

허용하는 예:

매핑 코드에 반복문은 없지만, getHighlights()에 접근하는 시점에 아이템마다 쿼리가 한 번씩 나갔다.

실패 이유: 첫 문장이 말한 내용을 두 번째 문장이 그대로 다시 말한다. ~한 상황이다, 여기서는 ~를 다룬다, 이 절은 ~에 관한 내용이다는 설명을 미루기만 한다. 조건이 정말 필요하면 설명 문장 안에 ~지만, ~인데로 넣는다. 앞으로 어떤 각도에서 볼지 알려 주는 예고 문장(이번에는 ~를 ~ 중심으로 살펴보겠습니다)은 새 정보를 주므로 다르다.

19. 이유를 문장 밖으로 밀어내지 않는다

잘못 고친 예:

폴리곤 데이터는 실시간으로 변경되지 않는다. 그래서 메모리에 올렸다. 메모리에 올려도 문제가 없었다.

허용하는 예:

폴리곤 데이터는 실시간으로 변경되는 데이터가 아니기 때문에 메모리에 올려놓고 사용해도 무방했다.

실패 이유: 한 문장에 사실 하나라는 규칙을 기계적으로 적용하면 주어가 같은 문장이 셋으로 쪼개지고, 그래서가 접착제로 붙는다. 한국어 기술 문장은 이유를 ~기 때문에, ~다 보니, ~어서로 문장 안에 넣는다. 문장을 끊는 자리는 두 번째 절이 아니라 주어가 바뀌는 지점이다.

20. 처음 쓰는 말은 그 자리에서 정의한다

잘못 고친 예:

MDC에 진입점 정보를 넣고 스레드가 바뀔 때 복사했다.

허용하는 예:

MDC(Mapped Diagnostic Context)는 slf4j 같은 자바 로깅 프레임워크가 제공하는, 실행 중인 스레드 단위로 메타 정보를 담아 두는 공간이다. 여기에 진입점 정보를 넣고, 스레드가 바뀔 때 새 스레드로 복사했다.

실패 이유: 잘못 고친 문장은 독자가 MDC를 이미 안다고 가정한다. TechLog 기록은 짧아도 되지만, 핵심 내용을 이해하는 데 필요한 선수 지식은 글 안에 있어야 한다. 처음 나오는 API·지표·도메인 용어는 그것이 무엇이고 무엇을 하는지 한 문장으로 적고 이름은 그대로 둔다. 약어는 처음 나올 때 괄호로 편다. 이렇게 붙이는 정의는 자료에 없는 내용 추가가 아니다. 금지되는 것은 이 시스템·이 측정·이 결정에 대한 새 주장이다.

21. 코드와 측정의 시제를 섞지 않는다

잘못 고친 예:

RedisCommandGuard는 요청받은 명령을 catalog에서 찾았고, 등록되지 않은 명령이면 거절한다.

허용하는 예:

RedisCommandGuard는 요청받은 명령을 catalog에서 찾고, 등록되지 않은 명령이면 거절한다. 테스트에서 EVAL을 보내자 이 guard가 거절했고, 응답에는 command not allowed가 담겼다.

실패 이유: 코드가 늘 하는 일은 현재형(~한다, ~합니다)으로, 실제로 재거나 겪은 일은 과거형(~했다, ~했습니다)으로 쓴다. 한 문장 안에서 섞이면 독자가 지금 읽는 것이 코드 동작인지 측정 결과인지 알 수 없다.

22. 이름만 보고 지표의 뜻을 지어내지 않는다

원문:

deniedCommandCountrejectedRequestCount는 비교 대상이 아니다. deniedCommandCount는 1이었고 rejectedRequestCount는 200이었다.

잘못 고친 예:

deniedCommandCountrejectedRequestCount는 세는 것이 다르다. deniedCommandCount는 거절된 명령의 수이고, rejectedRequestCount는 거절된 요청의 수다.

허용하는 예:

deniedCommandCount는 1이었고 rejectedRequestCount는 200이었다. 두 값은 세는 단위가 달라서 함께 놓고 크기를 견주면 안 되는데, 각각이 정확히 무엇을 세는지는 이 문서에서 확인하지 않았다.

실패 이유: 원문은 두 값이 다르다고만 적었고 각각이 무엇을 세는지는 적지 않았다. 잘못 고친 문장은 비교 대상이 아니다(규칙 17)를 고치고 지표에 뜻을 붙이라는 규칙(규칙 11, 20)을 따르다가, 식별자 이름에서 뜻을 추론해 확정 사실로 적었다. 그럴듯해 보이지만 이것은 측정 대상에 대한 새 주장이다.

정의를 가져올 수 있는 곳은 셋뿐이다. 원문, 코드, 그 프레임워크의 공식 문서. 셋 다 답을 주지 않으면 이름을 그대로 두고, 원문이 말한 것까지만 적고, 확인하지 않았다고 밝힌다. 규칙 17을 지키려고 규칙 11을 넘겨 쓰지 않는다. 두 규칙이 부딪히면 원문 보존이 이긴다.

23. 영어 일반명사를 한국어로 쓴다

원문:

RedisCacheRegionAdapter는 단일 key invalidation에서 GETDEL을 호출해 INVALIDATEDALREADY_ABSENT를 구분합니다.

잘못 고친 예:

단일 key invalidation은 값을 읽으면서 그 자리에서 지우는 GETDEL을 호출하기 때문에, 지워진 값이 있었으면 INVALIDATED를, 처음부터 없었으면 ALREADY_ABSENT를 돌려줍니다.

허용하는 예:

키 하나를 무효화할 때는 값을 읽으면서 그 자리에서 지우는 GETDEL을 부릅니다. 지워진 값이 있었으면 INVALIDATED를, 처음부터 없었으면 ALREADY_ABSENT를 돌려줍니다.

실패 이유: 잘못 고친 문장은 규칙을 다 지켰다. 정의를 앞에 뒀고, 이유를 문장 안에서 이었고, 금지어도 없다. 그런데도 기계가 쓴 것처럼 읽힌다. keyinvalidation이 라틴 문자로 남아 있기 때문이다. 둘 다 식별자가 아니다. GETDEL, INVALIDATED, ALREADY_ABSENT는 식별자라 그대로 두고, key, invalidation무효화로 적는다.

우아한형제들 5편과 이 저장소 9개 절을 재보면 이렇다.

우아한형제들 이 저장소
문장당 맨몸 영문 낱말 1.4 4.4
글자 중 한글 비율 0.58 0.34
쿼리 / query 66 / 5 5 / 4
캐시 / cache 2 / 0 0 / 19
상태 / status 48 / 0 6 / 7

기술 블로그는 쿼리, 캐시, 인덱스, 라이브러리, 컴포넌트, 스레드, 플러그인처럼 자리잡은 외래어를 한글로 적는다. 라틴 문자는 진짜 식별자에만 쓴다. 이것을 고치면 사실은 하나도 바뀌지 않는다. 맨몸 일반명사는 애초에 보호 구간이 아니기 때문이다.

첫 등장 뒤에는 한국어로 받는다. optional contributor는 … optional contributor가 …… 이 항목이 …로 받는다. 매 문장에 영어 이름을 되풀이하는 것이 문장당 영문 낱말을 넷까지 끌어올린다.

24. 확인한 것을 끝에서 목록으로 다시 포장하지 않는다

잘못 고친 예:

현재 구현 공백과 잘못 읽기 쉬운 지점

  • semantic Redis 조립은 … 4/5입니다.
  • CacheRegionPort 빈은 있지만 …
  • CacheRefreshCoordinationPort 운영 구현은 없습니다.
  • … (여덟 개)

허용하는 예:

(각 한계를 그것이 제한하는 대상 옆에 둔다. 갱신 조정자를 설명한 문단 끝에 운영 구현은 아직 없고 테스트용 가짜 구현만 있습니다를 붙이는 식이다.)

실패 이유: 여덟 항목 모두 본문이 이미 설명한 것이다. 끝에 모아 놓으면 사람이 쓴 글이 아니라 에이전트가 분석을 마치고 Findings를 정리한 출력처럼 읽힌다. 문장은 자연스러운데 문서가 기계다. 한계는 그것이 제한하는 대상 바로 옆에 있을 때 독자에게 쓸모가 있다.

같은 이유로 아래도 하지 않는다.

  • 다음에 열어볼 source 순서 — 글쓴이가 자기한테 남기는 작업 메모다. 독자는 묻지 않았다.
  • 잘못 읽기 쉬운 지점 — AI 기술 문서에 반복해서 나오는 분류다. 잘못 읽기 쉬운 대목이 있으면 그 대목에서 바로 적는다.
  • 확인한 사실을 빠짐없이 절로 승격하기. 코드를 읽으면 참인 관찰이 수십 개 나온다. 글의 중심 질문에 필요한 것만 넣고 나머지는 버린다. 확인한 것을 다 넣고 싶은 마음이 가장 확실한 기계 신호다.

25. 독자에게 사고를 지시하지 않는다

잘못 고친 예:

먼저 결론을 구분해야 합니다. 여기서 typed label과 end-to-end 동작을 구분해야 합니다.

허용하는 예:

RedisCacheRegionAdapter는 운영 빈으로 조립됩니다. 그런데 CacheAsideExecutor와 묶어 쓰는 운영 유스케이스는 찾지 못했습니다.

CacheAsideExecutor까지 따라가면 동작이 달라집니다.

실패 이유: 구분해야 합니다는 독자에게 사고 절차를 지시할 뿐 아무 사건도 말하지 않는다. 사람이 작업 기록을 쓰면 바로 사건으로 들어간다. 방향을 알려 주는 문장은 글 전체에 한둘이면 충분하고, 절마다 붙으면 자기 분석 과정을 중계하는 글이 된다.

제목 회귀 목록

피할 제목 사실을 적은 제목
같은 EAGER가 정반대 곡선을 그린다 EAGER 연관 관계에서 발생한 추가 조회
쿼리 하나에 숨어 있던 비용 한 컬렉션을 fetch join했을 때 조회되는 행 수
페이지가 아닌 데이터셋에 비례한다 Feed Item 수에 따라 늘어난 Page 추가 쿼리
비용은 사라지지 않고 이동한다 쿼리 수는 줄었지만 추가 조회는 남았다
fetch join의 회계 항등식 fetch join 적용 전후의 쿼리 수와 조회 행 수
기준선 구현 측정한 loadFeed 구현
각 쿼리는 빠른데 느리다 반복되는 하이라이트 조회 하나의 실행계획
두 지표를 같은 것으로 읽지 않는다 초기화 컬렉션 수와 PreparedStatement 수가 뜻하는 것