คู่มือแนวปฏิบัติที่ดี
ภาพรวม
คู่มือนี้สรุปแนวปฏิบัติที่ดีหลักที่แสดงให้เห็นในโค้ดเบสของ claude-code-leaked
แนวปฏิบัติที่ดีทางสถาปัตยกรรม
1. การออกแบบ Tool แบบโมดูลาร์
แนวปฏิบัติ: ทุกความสามารถถูกเปิดเผยเป็น tool ที่แยกออกมาเป็นอิสระ
เหตุผล: ทำให้ระบบสามารถขยายได้ง่ายและดูแลรักษาง่าย
ตัวอย่าง:
// แต่ละ tool มีไดเรกทอรีของตัวเองพร้อมตรรกะ, UI, และ prompt
src/tools/BashTool/
├── BashTool.ts - การดำเนินการของ tool
├── UI.tsx - ส่วนประกอบ UI
├── prompt.ts - การมีส่วนร่วมใน system prompt
2. สถาปัตยกรรมที่ใช้ Feature Flags
แนวปฏิบัติ: ใช้ bun:bundle feature flags สำหรับการตัดโค้ดที่ตาย
เหตุผล: ลดการใช้หน่วยความจำและเพิ่มประสิทธิภาพ
ตัวอย่าง:
const module = feature('FLAG_NAME')
? require('./module.js')
: null;
3. การเริ่มต้นระบบแบบขนาน
แนวปฏิบัติ: เริ่ม MDM, Keychain, และ API preconnect พร้อมกัน
เหตุผล: ลดเวลาเริ่มต้นระบบโดยการดำเนินการอิสระแบบขนาน
ตัวอย่าง:
await Promise.all([
ensureMdmSettingsLoaded(),
ensureKeychainPrefetchCompleted(),
fetchBootstrapData()
]);
4. การแยกชั้นบริการ (Service Layer)
แนวปฏิบัติ: แยกการเชื่อมต่อภายนอกเป็นชั้นบริการที่ชัดเจน
เหตุผล: การแยกหน้าที่ที่ชัดเจน, การทดสอบและการดูแลรักษาง่ายขึ้น
ตัวอย่าง:
src/services/
├── api/ - SDK ของ Anthropic
├── mcp/ - ระบบ MCP
├── oauth/ - การยืนยันตัวตน
├── lsp/ - เซิร์ฟเวอร์ภาษา
├── analytics/ - Feature Flags
5. ระบบ Permission
แนวปฏิบัติ: ควบคุมการดำเนินการของ tool ตามโหมด permission ที่ปรับแต่งได้
เหตุผล: ให้การควบคุมละเอียดเกี่ยวกับการเข้าถึง tool
ตัวอย่าง:
async checkPermissions(input, context) {
// ตรวจสอบข้อจำกัดของไดเรกทอรีการทำงาน
// ตรวจสอบกฎเฉพาะ tool
return { result: true };
}
แนวปฏิบัติที่ดีด้านคุณภาพโค้ด
1. TypeScript แบบ Strict
แนวปฏิบัติ: ใช้ Strict TypeScript ทั่วทั้งโค้ดเบส
เหตุผล: รับประกันความปลอดภัยของ type และลดข้อผิดพลาดขณะรัน
ตัวอย่าง:
interface ToolInputJSONSchema {
[x: string]: unknown;
type: 'object';
properties?: { [x: string]: unknown };
}
2. Schemas ของ Zod
แนวปฏิบัติ: ใช้ Zod สำหรับการตรวจสอบ schema แบบ runtime
เหตุผล: ให้การตรวจสอบ input ที่ชัดเจนและข้อความข้อผิดพลาด
ตัวอย่าง:
inputSchema: z.object({
command: z.string(),
timeout: z.number().optional(),
workdir: z.string().optional(),
})
3. Lazy Loading
แนวปฏิบัติ: โหลดโมดูลหนักเฉพาะเมื่อต้องการ
เหตุผล: ลดการใช้หน่วยความจำเริ่มต้นและเพิ่มเวลาเริ่มต้นระบบ
ตัวอย่าง:
const messageSelector = (): typeof import('src/components/MessageSelector.js') =>
require('src/components/MessageSelector.js')
4. การจัดการข้อผิดพลาด
แนวปฏิบัติ: ดำเนินการการลดผลกระทบจากข้อผิดพลาดอย่างนุ่มนวล
เหตุผล: ป้องกันการหยุดทำงานและรักษาเสถียรภาพของระบบ
ตัวอย่าง:
try {
await serviceOperation();
} catch (error) {
if (isRetryableError(error)) {
await retryOperation(error);
}
logEvent('service_error', { service: 'api', error: error.message });
}
5. กลยุทธ์ Caching
แนวปฏิบัติ: Cache การดำเนินการที่หนักเพื่อเพิ่มประสิทธิภาพ
เหตุผล: หลีกเลี่ยงการคำนวณและ I/O ซ้ำซ้อน
ตัวอย่าง:
export function clearPluginCache(reason: string): void {
// ล้าง cache เมื่อการตั้งค่าหรือไฟล์เปลี่ยนแปลง
}
แนวปฏิบัติที่ดีด้านประสิทธิภาพ
1. การดำเนินการแบบขนาน
แนวปฏิบัติ: ดำเนินการอิสระพร้อมกัน
เหตุผล: เพิ่มการใช้งาน CPU และ I/O ให้สูงสุด
ตัวอย่าง:
void Promise.all([
initUser(),
getUserContext(),
prefetchSystemContextIfSafe(),
getRelevantTips(),
prefetchOfficialMcpUrls()
]);
2. การตรวจสอบ Event Loop
แนวปฏิบัติ: ตรวจจับการหยุดชะงักของ event loop สำหรับปัญหาประสิทธิภาพ
เหตุผล: ระบุเมื่อ main thread ถูก block
ตัวอย่าง:
void import('./utils/eventLoopStallDetector.js')
.then(m => m.startEventLoopStallDetector());
3. การตัดโค้ดที่ตาย
แนวปฏิบัติ: ใช้ feature flags เพื่อตัดโค้ดที่ไม่ได้ใช้จากการ build
เหตุผล: ลดขนาด binary และการใช้หน่วยความจำ
ตัวอย่าง:
const module = feature('FLAG') ? require('./module.js') : null;
4. กลยุทธ์การโหลดล่วงหน้า
แนวปฏิบัติ: โหลดข้อมูลล่วงหน้าก่อนที่จำเป็น
เหตุผล: ลดเวลาแฝงเมื่อข้อมูลถูกต้องการจริง
ตัวอย่าง:
void prefetchOfficialMcpUrls();
void prefetchAwsCredentialsAndBedRockInfoIfSafe();
แนวปฏิบัติที่ดีด้านความปลอดภัย
1. โหมด Permission
แนวปฏิบัติ: ดำเนินการโหมด permission ที่ปรับแต่งได้ (default, plan, auto, bypass)
เหตุผล: ให้การควบคุมละเอียดเกี่ยวกับการเข้าถึง tool
2. ข้อจำกัดของไดเรกทอรีการทำงาน
แนวปฏิบัติ: จำกัดการดำเนินการในไดเรกทอรีการทำงานที่ได้รับอนุญาต
เหตุผล: ป้องกันการเข้าถึงไฟล์ที่ไม่ได้รับอนุญาต
3. ความปลอดภัยที่ควบคุมด้วย Feature
แนวปฏิบัติ: ควบคุมฟีเจอร์ความปลอดภัยด้วย feature flags
เหตุผล: อนุญาตการเปิดใช้งานฟีเจอร์ความปลอดภัยแบบเลือกได้
4. ขอบเขตข้อผิดพลาด
แนวปฏิบัติ: แยกข้อผิดพลาดเพื่อป้องกันระบบล้มเหลวทั้งระบบ
เหตุผล: รักษาเสถียรภาพของระบบเมื่อเกิดข้อผิดพลาด
แนวปฏิบัติที่ดีด้านการพัฒนา
1. แนวปฏิบัติการตั้งชื่อที่สม่ำเสมอ
แนวปฏิบัติ: ใช้แพทเทิร์นการตั้งชื่อที่คาดเดาได้
เหตุผล: ทำให้โค้ดเบสง่ายต่อการค้นหา
ตัวอย่าง:
- ไฟล์ Tool:
<ToolName>Tool.ts - ไฟล์ UI:
UI.tsx - ไฟล์ Prompt:
prompt.ts
2. โครงสร้างไดเรกทอรีที่ชัดเจน
แนวปฏิบัติ: จัดระเบียบโค้ดตามฟังก์ชัน
เหตุผล: ทำให้หาง่ายสำหรับโค้ดที่เกี่ยวข้อง
ตัวอย่าง:
src/
├── tools/ - การดำเนินการของ tools ทั้งหมด
├── commands/ - คำสั่ง slash ทั้งหมด
├── services/ - การเชื่อมต่อภายนอก
├── components/ - ส่วนประกอบ UI
├── utils/ - ฟังก์ชันช่วย
3. เอกสารในตัว
แนวปฏิบัติ: เพิ่มคอมเมนต์ JSDoc สำหรับความชัดเจน
เหตุผล: ทำให้โค้ดอธิบายตัวเองได้
ตัวอย่าง:
/**
* findGitRoot - ค้นหา root ของ repository Git
*
* @param cwd - ไดเรกทอรีการทำงานปัจจุบัน
* @returns เส้นทาง root ของ Git หรือ null ถ้าไม่พบ
*/
export function findGitRoot(cwd: string): string | null {
// การดำเนินการ
}
4. ระบบ Migration
แนวปฏิบัติ: ดำเนินการ migrations ที่มีเวอร์ชันสำหรับการตั้งค่า
เหตุผล: รับประกันความเข้ากันได้หลังการเปลี่ยนแปลง
ตัวอย่าง:
const CURRENT_MIGRATION_VERSION = 11;
if (getGlobalConfig().migrationVersion !== CURRENT_MIGRATION_VERSION) {
migrateSonnet1mToSonnet45();
migrateLegacyOpusToCurrent();
saveGlobalConfig(prev => ({
...prev,
migrationVersion: CURRENT_MIGRATION_VERSION
}));
}
จุดผิดพลาดที่พบบ่อยที่ควรหลีกเลี่ยง
- การขึ้นต่อกันแบบวงกลม: อาจทำให้เกิด import cycles และทำให้การเริ่มต้นระบบช้าลง
- การใช้ออกแบบ Feature Flags มากเกินไป: Flags ที่มากเกินไปอาจทำให้การตั้งค่า build ซับซ้อน
- ไฟล์โมโนลิธิกขนาดใหญ่: ไฟล์ที่มี 29K-46K บรรทัดอาจทำให้ยากต่อการเข้าใจ
- ความซับซ้อนของระบบ Permission: หลาย handlers อาจทำให้สับสนสำหรับผู้มาใหม่
- ภาระเอกสาร: ผู้มาใหม่ต้องเข้าใจเอกสารหลายไฟล์
คำแนะนำสำหรับโค้ดเบสใหม่
เมื่อสร้างโค้ดเบสใหม่แบบเดียวกัน ให้เน้นที่:
- ระบบ Tool: ดำเนินการรูปแบบโรงงานของ tool อย่างสม่ำเสมอ
- ชั้นบริการ: รักษาระบบการเชื่อมต่อภายนอกแยกจากตรรกะหลัก
- Feature Flags: ใช้สำหรับการตัดโค้ดที่ตาย
- การเริ่มต้นระบบแบบขนาน: เริ่มต้นระบบอิสระพร้อมกัน
- การควบคุมด้วย Permission: ดำเนินการโหมด permission ที่ปรับแต่งได้
- Lazy Loading: โหลดโมดูลหนักเมื่อต้องการ
- กลยุทธ์ Caching: Cache การดำเนินการที่หนัก
- การจัดการข้อผิดพลาด: ดำเนินการการลดผลกระทบจากข้อผิดพลาดอย่างนุ่มนวล