1. ð ã¯ããã«
ååãŸã§ãåäœã»ããžãã¯ã»å¯èªæ§ã»ããã©ãŒãã³ã¹ã»ã»ãã¥ãªãã£ãã®èŠç¹ãåŠã³ãŸããã
æçµåã¯äžçªå¥¥æ·±ãããŒãã§ãã
èšèšã»ã¢ãŒããã¯ãã£ã®èŠç¹ïŒ
ãä»åããã ãã§ãªããå幎åŸã»1幎åŸãç¡çãªã倿Žã»æ¡åŒµã§ãããã
AIãæãèŠæãšããé åã§ãããªããªãèšèšã®è¯ãæªãã¯ããããžã§ã¯ãã®æèã»ããŒã ã®ç¶æ³ã»å°æ¥ã®æ¹åæ§ãç¥ããªããšå€æã§ããªãããã§ãã
2. ð€ ãªãèšèšã¯AIãèŠæãªã®ã
è¯ãèšèšã«ã¯ãAIãæã£ãŠããªããæèããå¿ èŠã§ãã
| å¿ èŠãªãã® | å ·äœçãªå 容 |
|---|---|
| ð ãããžã§ã¯ãã®æè | ããžãã¹èŠä»¶ã»éæ©èœèŠä»¶ïŒé床ã»å¯çšæ§ãªã©ïŒ |
| ð¥ ããŒã ã®ç¶æ³ | ã¡ã³ããŒã®ã¹ãã«ã»äººæ°ã»éçºã®æ £ç¿ |
| ð® å°æ¥ã®æ¹åæ§ | æ¡åŒµäºå®ã»å€æŽãå€ãéšåã»é·æããŒãããã |
| âïž ãã¬ãŒããªãã®å€æ | éã vs å®å šã»ã·ã³ãã« vs æè»ã»ã³ã¹ã vs å質 |
AIã¯ã³ãŒãããæžããã®ã¯åŸæã§ããã
ãããã®æèãæã£ãŠããªããã
ããã®å Žã§ã¯åãããå°æ¥å°ãèšèšããçæããããšããããŸãã
3. ð§© èŠç¹â¥ïŒè²¬ä»»ã®åé¢
1ã€ã®ãã®ã1ã€ã®ããšããã
責任ã®åé¢ïŒSeparation of ConcernsïŒãšã¯ïŒ
ãããããã®ã³ãŒãã1ã€ã®ããšã ããæ åœããããšããèãæ¹ã§ãã
æçã§äŸãããšã調çã»çãä»ãã»çä»ãããå¥ã ã®äººãæ åœããã€ã¡ãŒãžã§ããð å°éçšèªã§ã¯ãåäžè²¬ä»»ã®ååïŒSingle Responsibility PrincipleïŒããšåŒã³ãŸãã
ããã¯ãœãããŠã§ã¢èšèšã®éèŠãªæéããŸãšãããSOLIDååãã®1ã€ç®ã«ããããŸãã
äžçŽè ãç®æã人ã¯ãã²èª¿ã¹ãŠã¿ãŠãã ããïŒ
äžèšã®èšäºãåèãŸã§ã«ã芧ãã ããã
AIã¯ããšããããåããããšãåªå ããããã1ã€ã®é¢æ°ã»ã¯ã©ã¹ã«è€æ°ã®è²¬ä»»ãæãããŠããŸãããšããããŸãã
| è²¬ä»»ãæ··åšããŠããã³ãŒã | äœãåé¡ã |
|---|---|
| ããŒã¿ååŸã»å å·¥ã»è¡šç€ºã1ã€ã®é¢æ°ã§ãã£ãŠãã | ä¿®æ£ãããšã圱é¿ç¯å²ã倧ãã |
| ããžãã¹ããžãã¯ãšããŒã¿ããŒã¹æäœãæ··åš | ãã¹ããæžãã«ãã |
| UIã®åŠçãšAPIã®åŒã³åºããåããã¡ã€ã« | åå©çšãã«ãã |
â AIããããã¡ãªã³ãŒãïŒè²¬ä»»ãæ··åšïŒ
// ãŠãŒã¶ãŒæ
å ±ãååŸã»å å·¥ã»ã¡ãŒã«éä¿¡ã1ã€ã®é¢æ°ã§ãã£ãŠãã
async function processUser(userId: string) {
const user = await db.user.findUnique({ where: { id: userId } });
const formattedName = user?.name.toUpperCase() ?? "ååãªã";
await sendEmail(user?.email, `ããã«ã¡ã¯ã${formattedName}ãã`);
await db.user.update({
where: { id: userId },
data: { lastContactedAt: new Date() }
});
return { success: true };
}
â 人éãã¬ãã¥ãŒããŠä¿®æ£ããã³ãŒãïŒè²¬ä»»ãåé¢ïŒ
// 責任â ïŒããŒã¿ååŸã ããæ
åœãã颿°
async function getUser(userId: string) {
return await db.user.findUnique({ where: { id: userId } });
}
// 責任â¡ïŒããŒã¿ã®å å·¥ïŒãã©ãŒãããïŒã ããæ
åœãã颿°
// â DBãã¡ãŒã«ãšã¯ç¡é¢ä¿ãçŽç²ã«æååã®å€æã ã
function formatUserName(name: string | null | undefined): string {
return name?.toUpperCase() ?? "ååãªã";
}
// 責任â¢ïŒã¡ãŒã«éä¿¡ã ããæ
åœãã颿°
// â ãŠãŒã¶ãŒã®ååŸãDBæŽæ°ã¯ç¥ããªã
async function sendWelcomeEmail(email: string, name: string) {
await sendEmail(email, `ããã«ã¡ã¯ã${name}ãã`);
}
// 責任â£ïŒDBæŽæ°ã ããæ
åœãã颿°
// â ã¡ãŒã«éä¿¡ãååã®ãã©ãŒãããã¯ç¥ããªã
async function updateLastContacted(userId: string) {
await db.user.update({
where: { id: userId },
data: { lastContactedAt: new Date() }
});
}
// 責任â€ïŒå
šäœã®æµããå¶åŸ¡ããã ãã®é¢æ°
// â 现ããåŠçã¯å颿°ã«ä»»ãããäœãã©ã®é çªã§ããããã ããç¥ã£ãŠãã
async function processUser(userId: string) {
const user = await getUser(userId); // â ããŒã¿ååŸ
if (!user) throw new Error("ãŠãŒã¶ãŒãèŠã€ãããŸãã");
const name = formatUserName(user.name); // â¡ååããã©ãŒããã
await sendWelcomeEmail(user.email, name); // â¢ã¡ãŒã«éä¿¡
await updateLastContacted(userId); // â£æçµé£çµ¡æ¥ãæŽæ°
return { success: true };
}
ãã§ãã¯ã®ãã€ã³ãïŒ
颿°ãã¯ã©ã¹ã®èª¬æãããããŠããããŠããããããšè€æ°ã®åè©ã§èª¬æããªããã°ãªããªããªããåå²ãæ€èšããŸãããã
1ã€ã®é¢æ°ã¯ãããããã®1åè©ã§èª¬æã§ããã®ãçæ³ã§ãã
4. ð èŠç¹âŠïŒäŸåé¢ä¿
äŸåé¢ä¿ãæèãã
äŸåé¢ä¿ïŒdependencyïŒãšã¯ïŒ
ãAã¯Bããªããšåããªãããšããé¢ä¿ã®ããšã§ãã
äŸåé¢ä¿ãè€éã«ãªããšã1ãæã倿Žããã ãã§å¥ã®å Žæãå£ããããšããããŸãã
AIã¯ãä»åããã³ãŒããæžããããäŸåé¢ä¿ãæŽçããã«å®è£ ããããšããããŸãã
| åé¡ã®ããäŸåé¢ä¿ | ãªã¹ã¯ |
|---|---|
| å ·äœçãªå®è£ ã«çŽæ¥äŸåããŠãã | å®è£ ãå€ãããšå šäœãå£ãã |
| 埪ç°äŸåïŒAãBã«äŸåã»BãAã«äŸåïŒ | ã©ã¡ãããå€ãããšç¡éã«ãŒãã«ãªã |
| å€éšãµãŒãã¹ã«çŽæ¥äŸåããŠãã | ãã¹ããé£ãããªã |
â AIããããã¡ãªã³ãŒãïŒå ·äœçãªå®è£ ã«çŽæ¥äŸåïŒ
// ã¡ãŒã«éä¿¡ã®å®è£
ãçŽæ¥äœ¿ã£ãŠãã
import { sendgrid } from "@sendgrid/mail";
async function notifyUser(email: string, message: string) {
await sendgrid.send({ to: email, subject: "éç¥", text: message });
// SendGridãå¥ã®ãµãŒãã¹ã«å€ããããšãããã®é¢æ°ãå€ããå¿
èŠããã
}
â 人éãã¬ãã¥ãŒããŠä¿®æ£ããã³ãŒãïŒã€ã³ã¿ãŒãã§ãŒã¹ã«äŸåïŒ
// ã¡ãŒã«éä¿¡ã®ãã€ã³ã¿ãŒãã§ãŒã¹ïŒçŽæäºïŒããå®çŸ©
interface EmailSender {
send(to: string, subject: string, body: string): Promise<void>;
}
// å®è£
ã¯ã©ããªãµãŒãã¹ã§ãå·®ãæ¿ãããã
async function notifyUser(
emailSender: EmailSender, // å
·äœçãªå®è£
ã§ã¯ãªãçŽæäºã«äŸå
email: string,
message: string
) {
await emailSender.send(email, "éç¥", message);
}
ããããŠã€ã³ã¿ãŒãã§ãŒã¹ïŒçŽæäºïŒã«äŸåãããŠãããšãå®åã§å€§ããªã¡ãªãããçãŸããŸãã
- æ¬çªç°å¢ïŒ
SendGridEmailSenderãæž¡ããŠã¡ãŒã«ãå®éã«éä¿¡- ããŒã«ã«ã»ãã¹ãç°å¢ïŒ
ConsoleEmailSenderïŒã³ã³ãœãŒã«ã«ãã°ãåºãã ãã®ãããŒïŒã«1è¡ã§å·®ãæ¿ãSupabaseã®ãããªå€éšãµãŒãã¹ãåæ§ã§ã
ã€ã³ã¿ãŒãã§ãŒã¹ãæãã§ãããšãæ¬çªã¯Supabaseã»ãã¹ãã¯ã¢ãã¯ïŒåœç©ïŒããšããåãæ¿ããé©ãã»ã©ç°¡åã«ãªããŸãã
ãã¹ãã®ãã³ã«å®éã®DBã«ã¢ã¯ã»ã¹ããªããŠæžããããéçºé床ãäžãããŸãã
ããã®ã³ãŒãã®äžéšãå¥ã®å®è£ ã«å€ããããªã£ãããã©ãã ãä¿®æ£ãå¿ èŠãïŒã
ãã®åããããäŸåé¢ä¿ã®åé¡ãçºèŠãããã³ãã«ãªããŸãã
5. ð èŠç¹â§ïŒæ¡åŒµæ§
倿Žã«åŒ·ãã³ãŒããäœã
æ¡åŒµæ§ïŒextensibilityïŒãšã¯ïŒ
ãæ°ããæ©èœã远å ãããšããæ¢åã®ã³ãŒããããŸãå€ããªããŠããããšããæ§è³ªã§ãã
æ¡åŒµæ§ãäœãã³ãŒãã¯ã1ãæå€ãããšå¥ã®å Žæãå£ãããããšãå€ãã§ãã
AIã¯ãä»ã®èŠä»¶ãã«åãããã³ãŒããæžããŸããããå°æ¥ã®å€æŽããèæ ®ããªãããšãå€ãã§ãã
| æ¡åŒµæ§ã®åé¡ | å ·äœäŸ | äœãèµ·ããã |
|---|---|---|
| æ¡ä»¶åå²ãå¢ãç¶ãã | æ±ºæžæ¹æ³ãå¢ãããã³ã« if/else ãå¢ãã |
ã³ãŒããè€éã«ãªãä¿®æ£ãæããªã |
| ããŒãã³ãŒããããèšå® | æ¶è²»çšçã 0.1 ãšçŽæžããããŠãã |
çšç倿Žã®ãã³ã«å šãã¡ã€ã«ãä¿®æ£ |
| åãã³ãŒããè€æ°ã®å Žæã«ãã | ããªããŒã·ã§ã³ãåæã«ã³ãããããŠãã | ä¿®æ£æŒããèµ·ãããã |
â AIããããã¡ãªã³ãŒãïŒæ¡ä»¶åå²ãå¢ãç¶ããïŒ
// æ±ºæžæ¹æ³ãå¢ãããã³ã«if/elseãå¢ãã
async function processPayment(method: string, amount: number) {
if (method === "credit_card") {
await processCreditCard(amount);
} else if (method === "paypal") {
await processPaypal(amount);
} else if (method === "apple_pay") {
await processApplePay(amount);
}
// æ°ããæ±ºæžæ¹æ³ãå¢ãããã³ã«ããã«è¿œå ããªããã°ãããªã
}
â 人éãã¬ãã¥ãŒããŠä¿®æ£ããã³ãŒãïŒæ°ããæ±ºæžæ¹æ³ã远å ããããïŒ
// 決æžåŠçã®ãçŽæäºããå®çŸ©
interface PaymentProcessor {
process(amount: number): Promise<void>;
}
// åæ±ºæžæ¹æ³ãç¬ç«ããŠå®è£
class CreditCardProcessor implements PaymentProcessor {
async process(amount: number) { /* ... */ }
}
class PaypalProcessor implements PaymentProcessor {
async process(amount: number) { /* ... */ }
}
// æ°ããæ±ºæžæ¹æ³ã¯ã¯ã©ã¹ã远å ããã ãã»æ¢åã³ãŒããå€ããªããŠãã
async function processPayment(
processor: PaymentProcessor,
amount: number
) {
await processor.process(amount);
}
ãæ°ããããã远å ããããšããäœãæä¿®æ£ãå¿ èŠãïŒã
ãã®åãããã§æ¡åŒµæ§ã®åé¡ãçºèŠã§ããŸãã
çæ³ã¯ ãæ°ããã¯ã©ã¹ã1ã€è¿œå ããã ãã ã§ããð ããã¯ããªãŒãã³ã»ã¯ããŒãºãã®ååïŒOpen-Closed PrincipleïŒããšããèšèšã®åºæ¬åœ¢ã§ãã
ãæ¡åŒµã«å¯ŸããŠéããŠããïŒæ°ãããã®ã远å ããããïŒãä¿®æ£ã«å¯ŸããŠéããŠããïŒæ¢åã³ãŒããå€ããªããŠããïŒããšããæå³ã§ãSOLIDååã®2ã€ç®ã«ããããŸãã
Before/Afterã®ã³ãŒãã§ããŸãã«ãã®ååãäœçŸãããŠããŸãïŒ
äžèšã®èšäºãæ¯éã芧ãã ããã
6. ð€ èŠç¹âšïŒAIãšååããã¬ãã¥ãŒ
AIãã¬ãã¥ãŒã®çžæ£ã«ãã
èšèšã®åé¡ãçºèŠããããã«ãAIã«é質åããã®ã广çã§ãã
以äžã¯ãã®ãŸãŸCursorã»ChatGPTã»Claudeã«ã³ããããŠäœ¿ãããéæ³ã®ããã³ãããã§ã ðª
ð è²¬ä»»ã®æ··åšãçºèŠããããã³ãã
ãã®ã³ãŒãã®è²¬ä»»ïŒåœ¹å²ïŒãæ¥æ¬èªã§èª¬æããŠãã ããã
ããããããŠããããŠããããããšè€æ°ã®åè©ãå¿ èŠãªããåå²ã®ææ¡ãããŠãã ããã
𧪠ãã¹ããã«ããèšèšãçºèŠããããã³ãã
ãã®ã³ãŒãã«å¯ŸããŠãŠããããã¹ããæžããŠãã ããã
ãã¹ããæžãã®ãé£ããå Žåã¯ããã®çç±ãšèšèšã®æ¹åæ¡ãæããŠãã ããã
ð æ¡åŒµæ§ã®åé¡ãçºèŠããããã³ãã
æ°ãããããïŒæ©èœåïŒãã远å ãããå Žåããã®ã³ãŒãã®äœãã»äœãæä¿®æ£ããå¿ èŠããããŸããïŒ
ä¿®æ£ãå€ãå Žåã¯ãããæ¡åŒµããããèšèšãææ¡ããŠãã ããã
ð äŸåé¢ä¿ã®åé¡ãçºèŠããããã³ãã
ãã®ã³ãŒãã®äŸåé¢ä¿ãæŽçããŠãã ããã
å€éšãµãŒãã¹ãå ·äœçãªå®è£ ã«çŽæ¥äŸåããŠããéšåãããã°ãã€ã³ã¿ãŒãã§ãŒã¹ã䜿ã£ãæ¹åæ¡ãææ¡ããŠãã ããã
ðŽ ä¿å®æ§ã確èªããããã³ãã
ãã®ã³ãŒãã6ã¶æåŸã«åããŠèªãã éçºè ããããšããŠã
ããããã«ããã»ãªãããæžãããããããªãããšæããéšåã¯ã©ãã§ããïŒ
æ¹åæ¡ãåãããŠææ¡ããŠãã ããã
AIã¯ãæžããã ãã§ãªããæ¹è©ãããããšãã§ããŸãã
èªåãæžããã³ãŒãã»AIãæžããã³ãŒããå¥ã®AIã»ãã·ã§ã³ã§æ¹è©ãããã®ã广çã§ãã
AIã®éçãè£ãïŒæèã®èšé²
AIã¯æ¯åæèããŒãããå§ãããããèšèšã®æææ±ºå®ãèšé²ããŠããããšãéèŠã§ãïŒç¬¬äºã·ãªãŒãºã§è§ŠããŸãããïŒã
| èšé²ãã¹ãå 容 | æ®ãå Žæ |
|---|---|
| ãªããã®èšèšãéžãã ã | ADRïŒArchitecture Decision RecordsïŒ |
| æ€èšãããéžã°ãªãã£ãéžæè¢ | ADR |
| ãã®ã³ãŒãã®å¶çŽã»æ³šæç¹ | docstringã»ã³ã¡ã³ã |
| å°æ¥å€æŽãäºæ³ãããéšå | ã³ã¡ã³ãã« TODO: ãšããŠæ®ã |
7. ð ã¬ãã¥ãŒãã§ãã¯ãªã¹ãïŒç¬¬äžåãŸãšãïŒ
𧩠責任ã®åé¢
- 1ã€ã®é¢æ°ã»ã¯ã©ã¹ã1ã€ã®ããšã ããæ åœããŠãã
- ããããŠããããŠããããããšè€æ°ã®ããšãããŠããªã
- ããŒã¿ååŸã»å å·¥ã»è¡šç€ºãåé¢ãããŠãã
ð äŸåé¢ä¿
- å ·äœçãªå®è£ ã§ã¯ãªããçŽæäºïŒã€ã³ã¿ãŒãã§ãŒã¹ïŒãã«äŸåããŠãã
- 埪ç°äŸåïŒAãBã«äŸåã»BãAã«äŸåïŒãçºçããŠããªã
- å€éšãµãŒãã¹ãžã®äŸåãé©åã«æœè±¡åãããŠãã
ð æ¡åŒµæ§
- æ°ããæ©èœã远å ãããšããæ¢åã³ãŒããã»ãšãã©å€ããªããŠãã
- æ¡ä»¶åå²ãå¢ãç¶ããèšèšã«ãªã£ãŠããªã
- èšå®å€ãããŒãã³ãŒããããŠããªãïŒå®æ°ã»ç°å¢å€æ°ã䜿ã£ãŠããïŒ
- åãã³ãŒããè€æ°ã®å Žæã«ã³ããŒãããŠããªã
ð€ AIãšã®åå
- èšèšã®æææ±ºå®ãADRãã³ã¡ã³ãã«èšé²ãã
- AIã«é質åããŠèšèšã®åé¡ãçºèŠãã
-
å°æ¥å€æŽãäºæ³ãããéšåã«
TODO:ã³ã¡ã³ããæ®ãã
8. ð¯ ã·ãªãŒãºç·ãŸãšã
ðïž AIã³ãŒãã¬ãã¥ãŒã®6ã€ã®èŠç¹
| å | èŠç¹ | äžèšã§èšããš |
|---|---|---|
| 第äžå | â åäœã®æ£ãã | å®éã«åãããŠã»æ¥µç«¯ãªã±ãŒã¹ã詊ããïŒ |
| 第äžå | ð§ ããžãã¯ã®åŠ¥åœæ§ | èŠä»¶éãã«åããŠããïŒæ¡ä»¶ã¯æ£ããïŒ |
| 第äžå | ð å¯èªæ§ã»ä¿å®æ§ | å幎åŸã®èªåãèªãã§ãçè§£ã§ããïŒ |
| 第äºå | â¡ ããã©ãŒãã³ã¹ | N+1ã»äºéã«ãŒãã»å šä»¶ååŸã«æ°ãã€ããïŒ |
| 第äºå | ð ã»ãã¥ãªã㣠| å ¥åæ€èšŒã»èªå¯ã»ã·ãŒã¯ã¬ãã管çã¯å€§äžå€«ïŒ |
| 第äžå | ðïž èšèšã»ã¢ãŒããã¯ã㣠| é·ã䜿ããã³ãŒãã«ãªã£ãŠããïŒ |
9. ð æåŸã«ïŒå¯©çŸçŒã磚ãç¶ããã
AIã¯ã³ãŒãããéãã»å€§éã«ãçæã§ããŸãã
ã§ããè¯ãã³ãŒãããã©ããã倿ããã®ã¯ãããªãèªèº«ã§ãã
3åã«ããã£ãŠåŠãã ã¬ãã¥ãŒã®èŠç¹ã¯ãäžåºŠã«å šéšã§ããªããŠãæ§ããŸããã
ãŸã㯠第äžåã®ãã§ãã¯ãªã¹ã ããå§ããŠãæ £ããŠããã ããã©ãŒãã³ã¹ã»ã»ãã¥ãªã㣠ã®èŠç¹ãå ããæçµçã« èšèšã»ã¢ãŒããã¯ã㣠ãŸã§èŠãããããã«ãªãã
ãã®ç©ã¿éãããAIã³ãŒãã®å¯©çŸçŒããè²ãŠãŸãðª
| ã¹ããã | ç®æš | ææã®ç®å® |
|---|---|---|
| ð± ã¯ããã®äžæ© | åäœç¢ºèªã»ãšããžã±ãŒã¹ãå¿ ã詊ã | 仿¥ãã |
| ð¿ æ £ããŠããã | N+1ã»ããªããŒã·ã§ã³ã»ããžãã¯ãã³ããŒãèŠã | 1ã2é±éåŸ |
| ð³ ããã«äžãç®æã | 責任ã®åé¢ã»æ¡åŒµæ§ãæèããèšèšã¬ãã¥ãŒ | 1ã2ã¶æåŸ |
AIã䜿ãããªããšã³ãžãã¢ãšã¯ã
AIã®åºåãæ£ããè©äŸ¡ã»ä¿®æ£ã»æ¹åã§ãã人ã®ããšã§ãã仿¥ããã¬ãã¥ãŒã®ç¿æ £ãå§ããŠã¿ãŸãããð
ð¬ 質åãææ³ãããã°ãã³ã¡ã³ãæ¬ã§ãæ°è»œã«ã©ãã!
ð 圹ã«ç«ã£ãããããã&ã¹ããã¯ããé¡ãããŸã!
ð ãããŸã§èªãã§ãã ãã£ãŠãæ¬åœã«ããããšãããããŸãã!
ð ã·ãªãŒãºèšäº
- ã第äžåãåäœã»ããžãã¯ã»å¯èªæ§ã®èŠç¹
- ã第äºåãããã©ãŒãã³ã¹ã»ã»ãã¥ãªãã£ã®èŠç¹
- ã第äžåãèšèšã»ã¢ãŒããã¯ãã£ã®èŠç¹ïŒãã®èšäºïŒ