


高速なデータベースのコードを、速さと互換性を落とさずに直す
Java・SQL・Rust・ネイティブコード・CIにまたがる、速さ重視のデータベースをAIに直させる時に使う。コードの書き方、NULLの扱いとメモリの後片付け、クエリのテスト、失敗の調べ方、プルリクエストとビルドの決まりを示し、完了と言う前の最終チェックで締める。
このAIルールを使うには
## モジュールの境目を保ち、メモリを確保しないデータの流れを守る
- storage engine、SQL engine、network protocol、utility、worker queue、logging、background task、benchmark、compatibility test、exampleのmodule boundaryを明示的に維持する。
- production codeをbenchmark、build utility、example、platform wrapperから分離する。
- 入れ子のclient repositoryまたはsubmoduleを、独自のcommitとcompatibility targetを持つ独立repositoryとして扱う。
- behaviorを変える前に、server startup、storage engine、SQL compiler、table reader、table writerのどれが正しいentry pointか特定する。
- query executionとingestion中のzero-allocation data pathを保護する。
- architectureが要求する場合はobject pool、reusable buffer、column-oriented storage、vectorized execution、native accelerationを優先する。
- projectがperformance-critical algorithmを内製する方針なら、third-party runtime dependencyを導入しない。
- memory、platform、failure riskに見合うoperationだけにnative codeを限定する。
## Javaのクラスメンバーを決まった順に並べ、古いJava向けクライアントとの互換性を守る
- class memberをstaticまたはinstanceの種別とvisibilityでまとめ、各group内でalphabetical orderを保つ。
- decorative section groupを作らず、新しいfieldとmethodを正しいsort位置へ挿入する。
- Javaのsection heading代わりとなるbanner commentを絶対に追加しない。
- main moduleが対応するmodern language featureを使う。enhanced switch、multiline string、pattern variableなどが該当する。
- compatibility moduleでは古いlanguage targetを守り、main moduleのsyntaxを旧Java release向けclientへ混入させない。
- boolean variable、field、methodには内容に応じて`is`または`has`prefixを付ける。
- logging pipelineがUnicode punctuationやsymbolを確実に表示できない場合、log messageを厳密にASCIIだけで書く。
- 既存cleanup utilityと連携する場合は、generic object arrayよりprojectのresource-aware collection typeを使う。
- 新しいabstractionを導入する前に、既存のnaming、ownership、allocation patternに従う。
## NULLの扱いを決め、エラーの時もメモリを必ず片付ける
- column data、expression result、SQL statement、intermediate stateのNULL behaviorを明示的に決める。
- 「まだ初期化されていない」を表すNULL sentinelと、実データのNULLを区別する。
- すべてのallocationとcloseable resourceをsuccess、error、cancellation、early returnの各pathで追跡する。
- listとcloseable elementにはrepository所定のcleanup helperを一貫して使う。
- leak preventionをtestだけの関心事ではなくdesign requirementとして扱う。
- native memoryをallocateするtestにはmemory-leak assertionを追加する。
- native memoryをallocateしないことを証明できる狭いunit testではleak harnessを省略してよい。
- success pathだけでなく、関連するすべてのerror pathでcleanupを検証する。
- 便利なcontainerやhelperの背後にownershipの曖昧さを隠さない。
## クエリのテストは、結果を読み直す厳しいチェックで書く
- 旧式のsingle-pass print-and-compare helperではなく、正規のfluent query assertion frameworkを優先する。
- deterministic queryでは、2回目のcursor pass、size cross-check、variable-column check、関連するfactory-property assertionを必須にする。
- 1回だけのassertionはprojectionが再読時に本当に不安定な場合だけ使い、その理由を明記する。
- 正当な不安定性にはseedなしrandom functionやtime-varying functionが含まれる。
- DDLなどのnon-query statementはnon-query execution pathで実行する。
- optimizer behaviorが契約の一部なら、frameworkのplan helperでexecution planをassertする。
- dialectが対応する場合、複数のtest rowを1つのINSERT statementで追加する。
- 長いSQLとmultiline expected resultにはmultiline stringを使う。
- SQL keywordは一貫して書き、原則としてuppercaseを使う。
- syntaxが対応する場合、5桁以上のliteralではunderscoreで桁を区切る。
## SQLの方言に合わせ、エラーの位置を問題の文字ぴったりに指す
- dimensionalityがcolumn typeに含まれる場合、multidimensional array typeを別々のtypeとして扱う。
- 同等のcast表現を混在させず、dialectが推奨するcast syntaxを一貫して使う。
- numeric separatorの対応をparser、implementation code、testの間で一致させる。
- standard SQL featureが存在すると決めつけず、未対応operationを文書化してtestする。
- 行単位の消去に対応しない場合は、application logicでsoft deletionを明示的にmodel化する。
- partition単位のdrop operationと行単位の消去は作用範囲と安全性が異なるため区別する。
- 報告するSQL error positionはexpressionの先頭ではなく、問題を起こした正確なcharacterを指すようにする。
- parser errorではmessageと正確なpositionの両方をtestする。
- syntax、semantic、type、executionのerrorを区別したまま保つ。
## 落ちたテストは、証拠がそろうまで本物のバグとして調べる
- red test、failed CI job、unexpected log entryを、evidenceが反証するまでlive defectとして扱う。
- 「pre-existing」「flaky」「unrelated」「known issue」は仮説であり、結論ではない。
- 関連baselineで再現し、version historyを調べ、timing constraintを測定し、authoritative upstream reportを確認する。
- evidenceが別の結論を強制した後に限り、そのfailureを対象外にする。
- 別のreviewerが検証できるよう、classificationの根拠となったevidenceを報告する。
- green rerunだけをfailureが無害だった唯一の証拠にしない。
- 複数のchangeが同じCI lineageを共有する場合はinteraction failureを調べる。
- diagnosisに必要なlog、failing input、最小のreliable reproductionを維持する。
- 証明されたcauseだけにfixを絞り、そのfixがなければ失敗するregression testを追加する。
## ブランチとプルリクエストを、マージの方式とCIの手間に合わせる
- branchとpull requestのstrategyをrepositoryのmerge modelとCI costに合わせる。
- squash-merge workflowでは、破棄されるbranch historyを整えるために時間を使わない。
- cosmetic historyだけのためにprior commitを書き換えたりforce pushしたりせず、明確なfix-up commitを追加する。
- 分割によって長いCI run、flake exposure、merge coordinationが増える場合は、関連fixをまとめる。
- userが要求した場合、またはchangeを独立してmergeもしくはrevertする必要がある場合にだけ分割する。
- 既存pull requestを更新する時はremote headと同期し、そのbranchへchangeを追加してmetadataを更新する。
- 同じchange lineageのvalidationを再実行するためだけに、2つ目のpull requestを開かない。
- repository policyが別branchをcanonical review stateとして定める場合、review用worktreeやcheckout branchを作らない。
- diffだけが必要ならbranchを切り替えずにpull request diffを取得する。
- nested repository内部を先にcommitしてから、parentのsubmodule pointerを記録する。
## プルリクエストとコミットに、良い点も悪い点も同じ重さで書く
- repository所定のpull request title conventionを使い、descriptionをend userに意味のある内容にする。
- positive effect、negative effect、regression、tradeoffを同じ強さで記述する。
- sales language、superlative、selective metric、decorative emphasisを避ける。
- 修正対象issueはpull request body冒頭で所定のclosing formを使って参照する。
- commit titleは短く、descriptiveにし、repository所定のstyleへ合わせる。
- titleの繰り返しではなく、changeを説明する実質的なcommit bodyを含める。
- checkboxやcheck markが禁止されている場合、test planにはplain bulletを使う。
- change domainとtitleに合うlabelを付ける。
- commit、pull request、code commentではactive voiceを使う。
- passive constructionに隠さず、動作主体であるclass、method、caller、componentを明記する。
## 環境を確かめてから、いちばん小さい範囲でビルドとテストをする
- build前に必要なlanguage runtime、build tool、architecture、environment variableを確認する。
- 現在のchangeを証明できる最小build profileを選び、webまたはnative artifactが影響を受ける時はより完全なprofileを使う。
- local artifact cacheに古いclientまたはlibraryが残る可能性がある場合はdependent moduleをrebuildする。
- parallel buildが干渉する場合、高costなtest invocationをsequentialに実行する。
- 最も狭い関連test classまたはmethodから始め、riskとrepository policyに応じて広げる。
- compilationだけをruntime behaviorの証明として扱わない。
- 対応するstartup pathでserverを検証し、直接影響するendpointまたはinterfaceを確認する。
- build artifactを指定されたmodule-owned locationへ置く。
- buildが止まった時は、失敗した正確なcommandと最初のactionable errorを記録する。
## Rustの警告をなくし、JNI越しのpanicでJVMが落ちないようにする
- Rust作業の完了前にcrate rootからformatting、all-target compilation、lint、library testを実行する。
- mandatory checkすべてでエラー0件・警告0件を必須にする。
- testを追加または変更した後はcoverageを測定する。
- uncovered lineごとにtestを追加するか、到達不能であることを証明してinvariantを明示的にmarkする。
- file由来またはexternal input由来のdataに`unwrap()`や`expect()`を絶対に使わない。
- recoverable failureは`Result`、`Option`、language標準のerror propagationで伝える。
- JNIをまたぐRust panicはrecoveryなしにJVM全体をabortさせる可能性があることを忘れない。
- repository所定のrelease configurationでnative C/C++ libraryをbuildし、expected artifactを確認する。
- FFI ownership、lifetime、alignment、error conversionを明示的な契約として扱う。
- changeが影響するsupported platformすべてでboundary failureをtestする。
## ヒープの確保を避け、速くなったかはベンチマークで測る
- zero-GC behaviorがarchitecture requirementであるdata pathではheap allocationを避ける。
- bufferとpooled objectを再利用し、ownership transferを明示する。
- compressionとvectorized operationがlayoutに依存する場合、analytical dataをcolumn単位で保存する。
- SIMD、memory management、platform-specific optimizationを狭いnative boundaryの内側に置く。
- storage、parsing、planning、code generation、execution、protocol handling、background workを分離する。
- allocationとcleanup behaviorを理解しtestしている場合にだけcustom collectionを使う。
- performance changeはintuitionではなくrepresentative benchmarkで測定する。
- optimizationにはcorrectness test、resource check、documented tradeoffを組み合わせる。
- 未測定のspeedupを得るためにcompatibilityやerror precisionを弱めない。
## 完了と言う前に、最後の差分を確かめて結果を報告する
- final diffでmember ordering、compatibility boundary、NULL behavior、resource ownership、logへの意図しないUnicode混入を確認する。
- changeが影響するJava、SQL、Rust、native、integrationのcheckを実行する。
- deterministic queryがstrong reread assertion pathを使っていることを確認する。
- external inputがunrecoverable native panicを引き起こせないことを確認する。
- 調査したfailureにevidence-backed classificationと報告済みreproductionがあることを確認する。
- pull request metadata、label、test plan、commit text、issue referenceがrepository policyに合うことを確認する。
- nested repositoryとparent pointerが正しい順序でcommitされていることを確認する。
- mandatory checkにerrorまたはwarningが残る間は完了を主張しない。
- 実行したcommand、observed result、remaining risk、意図的に未testとしたscopeを報告する。
