[{"data":1,"prerenderedAt":1965},["ShallowReactive",2],{"navigation_docs":3,"-tu-hoc-oop-solid":420,"-tu-hoc-oop-solid-surround":1960},[4,153],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":26},"Phỏng vấn .NET","i-lucide-briefcase","\u002Fphong-van","1.phong-van",[10,27,66,111,128],{"title":11,"icon":12,"path":13,"stem":14,"children":15,"page":26},"Tổng quan","i-lucide-compass","\u002Fphong-van\u002Ftong-quan","1.phong-van\u002F1.tong-quan",[16,21],{"title":17,"path":18,"stem":19,"icon":20},"Thị trường HCM","\u002Fphong-van\u002Ftong-quan\u002Fthi-truong","1.phong-van\u002F1.tong-quan\u002F1.thi-truong","i-lucide-trending-up",{"title":22,"path":23,"stem":24,"icon":25},"Lộ trình 7 ngày","\u002Fphong-van\u002Ftong-quan\u002Flo-trinh","1.phong-van\u002F1.tong-quan\u002F2.lo-trinh","i-lucide-calendar-days",false,{"title":22,"icon":25,"path":28,"stem":29,"children":30,"page":26},"\u002Fphong-van\u002Flo-trinh","1.phong-van\u002F2.lo-trinh",[31,36,41,46,51,56,61],{"title":32,"path":33,"stem":34,"icon":35},"Ngày 1 — C# cơ bản","\u002Fphong-van\u002Flo-trinh\u002Fngay-1-csharp-co-ban","1.phong-van\u002F2.lo-trinh\u002F1.ngay-1-csharp-co-ban","i-lucide-1",{"title":37,"path":38,"stem":39,"icon":40},"Ngày 2 — OOP và SOLID","\u002Fphong-van\u002Flo-trinh\u002Fngay-2-oop-solid","1.phong-van\u002F2.lo-trinh\u002F2.ngay-2-oop-solid","i-lucide-2",{"title":42,"path":43,"stem":44,"icon":45},"Ngày 3 — C# nâng cao","\u002Fphong-van\u002Flo-trinh\u002Fngay-3-csharp-nang-cao","1.phong-van\u002F2.lo-trinh\u002F3.ngay-3-csharp-nang-cao","i-lucide-3",{"title":47,"path":48,"stem":49,"icon":50},"Ngày 4 — Database và SQL","\u002Fphong-van\u002Flo-trinh\u002Fngay-4-database-sql","1.phong-van\u002F2.lo-trinh\u002F4.ngay-4-database-sql","i-lucide-4",{"title":52,"path":53,"stem":54,"icon":55},"Ngày 5 — ASP.NET Core và EF Core","\u002Fphong-van\u002Flo-trinh\u002Fngay-5-aspnet-efcore","1.phong-van\u002F2.lo-trinh\u002F5.ngay-5-aspnet-efcore","i-lucide-5",{"title":57,"path":58,"stem":59,"icon":60},"Ngày 6 — DSA coding","\u002Fphong-van\u002Flo-trinh\u002Fngay-6-dsa","1.phong-van\u002F2.lo-trinh\u002F6.ngay-6-dsa","i-lucide-6",{"title":62,"path":63,"stem":64,"icon":65},"Ngày 7 — Mock và HR","\u002Fphong-van\u002Flo-trinh\u002Fngay-7-mock-interview","1.phong-van\u002F2.lo-trinh\u002F7.ngay-7-mock-interview","i-lucide-7",{"title":67,"icon":68,"path":69,"stem":70,"children":71,"page":26},"Ngân hàng câu hỏi","i-lucide-database","\u002Fphong-van\u002Fngan-hang-cau-hoi","1.phong-van\u002F3.ngan-hang-cau-hoi",[72,77,82,87,92,97,102,107],{"title":73,"path":74,"stem":75,"icon":76},"C# (60+ câu)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fcsharp","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F1.csharp","i-lucide-hash",{"title":78,"path":79,"stem":80,"icon":81},"OOP và SOLID (40+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Foop","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F2.oop","i-lucide-shapes",{"title":83,"path":84,"stem":85,"icon":86},"SQL (40+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fsql","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F3.sql","i-lucide-database-zap",{"title":88,"path":89,"stem":90,"icon":91},"ASP.NET và EF (50+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Faspnet-ef","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F4.aspnet-ef","i-lucide-server",{"title":93,"path":94,"stem":95,"icon":96},"DSA và Coding (30+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fdsa-coding","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F5.dsa-coding","i-lucide-binary",{"title":98,"path":99,"stem":100,"icon":101},"HR và Soft skill (25+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fhr-behavior","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F6.hr-behavior","i-lucide-users",{"title":103,"path":104,"stem":105,"icon":106},"Design Pattern (55+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fdesign-pattern","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F7.design-pattern","i-lucide-puzzle",{"title":108,"path":109,"stem":110,"icon":91},"ASP.NET MVC và Web API","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Faspnet-mvc-webapi","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F8.aspnet-mvc-webapi",{"title":112,"itle":113,"icon":114,"path":115,"stem":116,"children":117,"page":26},"Tai Lieu","Tài liệu và Cheat sheet","i-lucide-book-marked","\u002Fphong-van\u002Ftai-lieu","1.phong-van\u002F4.tai-lieu",[118,123],{"title":119,"path":120,"stem":121,"icon":122},"Cheat Sheet","\u002Fphong-van\u002Ftai-lieu\u002Fcheatsheet","1.phong-van\u002F4.tai-lieu\u002F1.cheatsheet","i-lucide-clipboard-list",{"title":124,"path":125,"stem":126,"icon":127},"Nguồn tham khảo","\u002Fphong-van\u002Ftai-lieu\u002Fnguon","1.phong-van\u002F4.tai-lieu\u002F2.nguon","i-lucide-link",{"title":129,"icon":130,"path":131,"stem":132,"children":133,"page":26},"Phỏng vấn English","i-lucide-globe","\u002Fphong-van\u002Fenglish-interview","1.phong-van\u002F5.english-interview",[134,138,143,148],{"title":135,"path":136,"stem":137,"icon":130},"Tổng quan English","\u002Fphong-van\u002Fenglish-interview\u002Ftong-quan","1.phong-van\u002F5.english-interview\u002F1.tong-quan",{"title":139,"path":140,"stem":141,"icon":142},"Vocabulary","\u002Fphong-van\u002Fenglish-interview\u002Fvocabulary","1.phong-van\u002F5.english-interview\u002F2.vocabulary","i-lucide-book-a",{"title":144,"path":145,"stem":146,"icon":147},"Technical Q và A (EN)","\u002Fphong-van\u002Fenglish-interview\u002Ftechnical-en","1.phong-van\u002F5.english-interview\u002F3.technical-en","i-lucide-code",{"title":149,"path":150,"stem":151,"icon":152},"Behavioral (EN)","\u002Fphong-van\u002Fenglish-interview\u002Fbehavioral-en","1.phong-van\u002F5.english-interview\u002F4.behavioral-en","i-lucide-message-square-text",{"title":154,"icon":155,"path":156,"stem":157,"children":158},"Tự học","i-lucide-graduation-cap","\u002Ftu-hoc","2.tu-hoc",[159,161,287,310,333,357,384],{"title":154,"path":156,"stem":160,"icon":155},"2.tu-hoc\u002Findex",{"title":162,"icon":68,"path":163,"stem":164,"children":165},"Database","\u002Ftu-hoc\u002Fdatabase","2.tu-hoc\u002F1.database\u002Findex",[166,167,197,222,243,248],{"title":162,"path":163,"stem":164,"icon":68},{"title":168,"icon":91,"path":169,"stem":170,"children":171,"page":26},"SQL Server","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server","2.tu-hoc\u002F1.database\u002F2.sql-server",[172,177,182,187,192],{"title":173,"path":174,"stem":175,"icon":176},"1. Giới thiệu và Cài đặt","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F1.gioi-thieu-cai-dat","i-lucide-play-circle",{"title":178,"path":179,"stem":180,"icon":181},"2. Cú pháp cơ bản","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F2.cu-phap-co-ban","i-lucide-code-2",{"title":183,"path":184,"stem":185,"icon":186},"3. Truy vấn nâng cao","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F3.truy-van-nang-cao","i-lucide-git-merge",{"title":188,"path":189,"stem":190,"icon":191},"4. Đặc thù và Performance","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F4.dac-thu-performance","i-lucide-gauge",{"title":193,"path":194,"stem":195,"icon":196},"5. Q và A phỏng vấn","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F5.cau-hoi-phong-van","i-lucide-message-circle-question",{"title":198,"icon":199,"path":200,"stem":201,"children":202,"page":26},"PostgreSQL","i-simple-icons-postgresql","\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql","2.tu-hoc\u002F1.database\u002F3.postgresql",[203,206,209,212,215,218],{"title":173,"path":204,"stem":205,"icon":176},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F1.gioi-thieu-cai-dat",{"title":178,"path":207,"stem":208,"icon":181},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F2.cu-phap-co-ban",{"title":183,"path":210,"stem":211,"icon":186},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F3.truy-van-nang-cao",{"title":188,"path":213,"stem":214,"icon":191},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F4.dac-thu-performance",{"title":193,"path":216,"stem":217,"icon":196},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F5.cau-hoi-phong-van",{"title":219,"path":220,"stem":221,"icon":96},"6. Tích hợp C# và Postgres","\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Ftich-hop-csharp","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F6.tich-hop-csharp",{"title":223,"icon":224,"path":225,"stem":226,"children":227,"page":26},"MySQL","i-simple-icons-mysql","\u002Ftu-hoc\u002Fdatabase\u002Fmysql","2.tu-hoc\u002F1.database\u002F4.mysql",[228,231,234,237,240],{"title":173,"path":229,"stem":230,"icon":176},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F4.mysql\u002F1.gioi-thieu-cai-dat",{"title":178,"path":232,"stem":233,"icon":181},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F4.mysql\u002F2.cu-phap-co-ban",{"title":183,"path":235,"stem":236,"icon":186},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F4.mysql\u002F3.truy-van-nang-cao",{"title":188,"path":238,"stem":239,"icon":191},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F4.mysql\u002F4.dac-thu-performance",{"title":193,"path":241,"stem":242,"icon":196},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F4.mysql\u002F5.cau-hoi-phong-van",{"title":244,"path":245,"stem":246,"icon":247},"So sánh 3 RDBMS","\u002Ftu-hoc\u002Fdatabase\u002Fso-sanh","2.tu-hoc\u002F1.database\u002F5.so-sanh","i-lucide-columns-3",{"title":249,"path":250,"stem":251,"children":252,"icon":254},"Supabase (BaaS)","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase","2.tu-hoc\u002F1.database\u002F6.supabase\u002Findex",[253,255,259,264,269,274,278,283],{"title":249,"path":250,"stem":251,"icon":254},"i-simple-icons-supabase",{"title":256,"path":257,"stem":258,"icon":68},"1. Database","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fdatabase","2.tu-hoc\u002F1.database\u002F6.supabase\u002F1.database",{"title":260,"path":261,"stem":262,"icon":263},"2. Authentication","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fauthentication","2.tu-hoc\u002F1.database\u002F6.supabase\u002F2.authentication","i-lucide-key",{"title":265,"path":266,"stem":267,"icon":268},"3. Storage & Realtime","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fstorage-realtime","2.tu-hoc\u002F1.database\u002F6.supabase\u002F3.storage-realtime","i-lucide-zap",{"title":270,"path":271,"stem":272,"icon":273},"4. Edge Functions & AI","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Ffunctions-ai","2.tu-hoc\u002F1.database\u002F6.supabase\u002F4.functions-ai","i-lucide-brain",{"title":275,"path":276,"stem":277,"icon":181},"5. API & SDKs","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fapi-sdk","2.tu-hoc\u002F1.database\u002F6.supabase\u002F5.api-sdk",{"title":279,"path":280,"stem":281,"icon":282},"6. Platform & Deploy","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fplatform-deploy","2.tu-hoc\u002F1.database\u002F6.supabase\u002F6.platform-deploy","i-lucide-cloud",{"title":284,"path":285,"stem":286,"icon":196},"7. Interview & Q&A","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Finterview","2.tu-hoc\u002F1.database\u002F6.supabase\u002F7.interview",{"title":288,"icon":289,"path":290,"stem":291,"children":292},"TypeScript","i-simple-icons-typescript","\u002Ftu-hoc\u002Ftypescript","2.tu-hoc\u002F2.typescript\u002Findex",[293,294,297,301,306],{"title":288,"path":290,"stem":291,"icon":289},{"title":173,"path":295,"stem":296,"icon":176},"\u002Ftu-hoc\u002Ftypescript\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F2.typescript\u002F1.gioi-thieu-cai-dat",{"title":298,"path":299,"stem":300,"icon":81},"2. Type System","\u002Ftu-hoc\u002Ftypescript\u002Ftype-system","2.tu-hoc\u002F2.typescript\u002F2.type-system",{"title":302,"path":303,"stem":304,"icon":305},"3. Advanced types","\u002Ftu-hoc\u002Ftypescript\u002Fadvanced-types","2.tu-hoc\u002F2.typescript\u002F3.advanced-types","i-lucide-braces",{"title":307,"path":308,"stem":309,"icon":196},"4. Q và A phỏng vấn","\u002Ftu-hoc\u002Ftypescript\u002Fcau-hoi-phong-van","2.tu-hoc\u002F2.typescript\u002F4.cau-hoi-phong-van",{"title":311,"icon":81,"path":312,"stem":313,"children":314},"OOP","\u002Ftu-hoc\u002Foop","2.tu-hoc\u002F3.oop\u002Findex",[315,316,321,326,330],{"title":311,"path":312,"stem":313,"icon":81},{"title":317,"path":318,"stem":319,"icon":320},"1. Bốn tính chất","\u002Ftu-hoc\u002Foop\u002F4-tinh-chat","2.tu-hoc\u002F3.oop\u002F1.4-tinh-chat","i-lucide-circle-dot",{"title":322,"path":323,"stem":324,"icon":325},"2. SOLID","\u002Ftu-hoc\u002Foop\u002Fsolid","2.tu-hoc\u002F3.oop\u002F2.solid","i-lucide-shield",{"title":327,"path":328,"stem":329,"icon":106},"3. Design Pattern","\u002Ftu-hoc\u002Foop\u002Fdesign-pattern","2.tu-hoc\u002F3.oop\u002F3.design-pattern",{"title":307,"path":331,"stem":332,"icon":196},"\u002Ftu-hoc\u002Foop\u002Fcau-hoi-phong-van","2.tu-hoc\u002F3.oop\u002F4.cau-hoi-phong-van",{"title":334,"icon":305,"path":335,"stem":336,"children":337},"Generic","\u002Ftu-hoc\u002Fgeneric","2.tu-hoc\u002F4.generic\u002Findex",[338,339,344,349,354],{"title":334,"path":335,"stem":336,"icon":305},{"title":340,"path":341,"stem":342,"icon":343},"1. Khái niệm và cú pháp","\u002Ftu-hoc\u002Fgeneric\u002Fkhai-niem","2.tu-hoc\u002F4.generic\u002F1.khai-niem","i-lucide-book",{"title":345,"path":346,"stem":347,"icon":348},"2. Constraint và Variance","\u002Ftu-hoc\u002Fgeneric\u002Fconstraint-variance","2.tu-hoc\u002F4.generic\u002F2.constraint-variance","i-lucide-filter",{"title":350,"path":351,"stem":352,"icon":353},"3. C# vs TS","\u002Ftu-hoc\u002Fgeneric\u002Fso-sanh","2.tu-hoc\u002F4.generic\u002F3.so-sanh","i-lucide-git-compare",{"title":307,"path":355,"stem":356,"icon":196},"\u002Ftu-hoc\u002Fgeneric\u002Fcau-hoi-phong-van","2.tu-hoc\u002F4.generic\u002F4.cau-hoi-phong-van",{"title":358,"icon":359,"path":360,"stem":361,"children":362},"Nuxt 4","i-simple-icons-nuxt","\u002Ftu-hoc\u002Fnuxt-4","2.tu-hoc\u002F5.nuxt-4\u002Findex",[363,364,367,372,376,379],{"title":358,"path":360,"stem":361,"icon":359},{"title":173,"path":365,"stem":366,"icon":176},"\u002Ftu-hoc\u002Fnuxt-4\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F5.nuxt-4\u002F1.gioi-thieu-cai-dat",{"title":368,"path":369,"stem":370,"icon":371},"2. Routing và Rendering","\u002Ftu-hoc\u002Fnuxt-4\u002Frouting-rendering","2.tu-hoc\u002F5.nuxt-4\u002F2.routing-rendering","i-lucide-route",{"title":373,"path":374,"stem":375,"icon":91},"3. Data và Server","\u002Ftu-hoc\u002Fnuxt-4\u002Fdata-server","2.tu-hoc\u002F5.nuxt-4\u002F3.data-server",{"title":307,"path":377,"stem":378,"icon":196},"\u002Ftu-hoc\u002Fnuxt-4\u002Fcau-hoi-phong-van","2.tu-hoc\u002F5.nuxt-4\u002F4.cau-hoi-phong-van",{"title":380,"path":381,"stem":382,"icon":383},"5. Practical Todo App","\u002Ftu-hoc\u002Fnuxt-4\u002Fpractical-todo-app","2.tu-hoc\u002F5.nuxt-4\u002F5.practical-todo-app","i-lucide-check-square",{"title":385,"path":386,"stem":387,"children":388,"icon":390},"Tailwind CSS","\u002Ftu-hoc\u002Ftailwindcss","2.tu-hoc\u002F6.tailwindcss\u002Findex",[389,391,396,401,406,411,416],{"title":385,"path":386,"stem":387,"icon":390},"i-simple-icons-tailwindcss",{"title":392,"path":393,"stem":394,"icon":395},"1. Layout & Spacing","\u002Ftu-hoc\u002Ftailwindcss\u002Flayout-spacing","2.tu-hoc\u002F6.tailwindcss\u002F1.layout-spacing","i-lucide-layout",{"title":397,"path":398,"stem":399,"icon":400},"2. Typography & Colors","\u002Ftu-hoc\u002Ftailwindcss\u002Ftypography-colors","2.tu-hoc\u002F6.tailwindcss\u002F2.typography-colors","i-lucide-type",{"title":402,"path":403,"stem":404,"icon":405},"3. Interactive & Effects","\u002Ftu-hoc\u002Ftailwindcss\u002Finteractive-effects","2.tu-hoc\u002F6.tailwindcss\u002F3.interactive-effects","i-lucide-sparkles",{"title":407,"path":408,"stem":409,"icon":410},"4. Responsive & Dark Mode","\u002Ftu-hoc\u002Ftailwindcss\u002Fresponsive-darkmode","2.tu-hoc\u002F6.tailwindcss\u002F4.responsive-darkmode","i-lucide-monitor-smartphone",{"title":412,"path":413,"stem":414,"icon":415},"5. Customization & Theme","\u002Ftu-hoc\u002Ftailwindcss\u002Fcustomization","2.tu-hoc\u002F6.tailwindcss\u002F5.customization","i-lucide-settings-2",{"title":417,"path":418,"stem":419,"icon":181},"6. Practical Projects","\u002Ftu-hoc\u002Ftailwindcss\u002Fpractical-projects","2.tu-hoc\u002F6.tailwindcss\u002F6.practical-projects",{"id":421,"title":422,"body":423,"description":1953,"extension":1954,"links":1955,"meta":1956,"navigation":1957,"path":323,"seo":1958,"stem":324,"__hash__":1959},"docs\u002F2.tu-hoc\u002F3.oop\u002F2.solid.md","SOLID — 5 nguyên lý thiết kế",{"type":424,"value":425,"toc":1926},"minimark",[426,431,440,469,479,483,491,496,640,646,650,808,820,824,831,838,842,885,899,903,1013,1023,1027,1034,1041,1045,1118,1132,1136,1228,1232,1329,1334,1340,1347,1351,1358,1361,1365,1437,1441,1484,1491,1495,1650,1654,1661,1665,1725,1732,1736,1844,1848,1884,1888,1914,1922],[427,428,430],"h2",{"id":429},"solid-là-gì","SOLID là gì?",[432,433,434,435,439],"p",{},"SOLID = 5 nguyên lý OOP của ",[436,437,438],"strong",{},"Robert C. Martin (Uncle Bob)",":",[441,442,443,449,454,459,464],"field-group",{},[444,445,448],"field",{"name":446,"type":447},"S","Single Responsibility","Một class chỉ một lý do để thay đổi.",[444,450,453],{"name":451,"type":452},"O","Open\u002FClosed","Mở để mở rộng, đóng để sửa đổi.",[444,455,458],{"name":456,"type":457},"L","Liskov Substitution","Subclass dùng được thay cho base class.",[444,460,463],{"name":461,"type":462},"I","Interface Segregation","Nhiều interface nhỏ tốt hơn một interface to.",[444,465,468],{"name":466,"type":467},"D","Dependency Inversion","Depend abstraction, không depend concrete.",[470,471,474,475,478],"callout",{"color":472,"icon":473},"warning","i-lucide-star","⭐ ",[436,476,477],{},"PV gần như chắc chắn hỏi SOLID."," Học hiểu — đừng học thuộc.",[427,480,482],{"id":481},"s-single-responsibility-principle","S — Single Responsibility Principle",[484,485,486],"blockquote",{},[432,487,488],{},[436,489,490],{},"A class should have one, and only one, reason to change.",[492,493,495],"h3",{"id":494},"vi-phạm-srp-class-ôm-nhiều-việc","❌ Vi phạm SRP — Class ôm nhiều việc",[497,498,503],"pre",{"className":499,"code":500,"language":501,"meta":502,"style":502},"language-csharp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","public class Order {\n    public int Id { get; set; }\n    public decimal Total { get; set; }\n    public List\u003COrderItem> Items { get; set; }\n    \n    public decimal CalculateTotal() {           \u002F\u002F tính toán\n        return Items.Sum(i => i.Price * i.Quantity);\n    }\n    \n    public void SaveToDatabase() {              \u002F\u002F persistence\n        using var conn = new SqlConnection(...);\n        \u002F\u002F INSERT INTO Orders ...\n    }\n    \n    public string FormatForInvoice() {          \u002F\u002F formatting\n        return $\"Order #{Id}: ${Total}\\n\" + \n               string.Join(\"\\n\", Items.Select(i => $\"- {i.Name}\"));\n    }\n    \n    public void SendEmail(string to) {          \u002F\u002F communication\n        new SmtpClient().Send(to, \"Your order\", FormatForInvoice());\n    }\n}\n","csharp","",[504,505,506,514,520,526,532,538,544,550,556,561,567,573,579,584,589,595,601,607,612,617,623,629,634],"code",{"__ignoreMap":502},[507,508,511],"span",{"class":509,"line":510},"line",1,[507,512,513],{},"public class Order {\n",[507,515,517],{"class":509,"line":516},2,[507,518,519],{},"    public int Id { get; set; }\n",[507,521,523],{"class":509,"line":522},3,[507,524,525],{},"    public decimal Total { get; set; }\n",[507,527,529],{"class":509,"line":528},4,[507,530,531],{},"    public List\u003COrderItem> Items { get; set; }\n",[507,533,535],{"class":509,"line":534},5,[507,536,537],{},"    \n",[507,539,541],{"class":509,"line":540},6,[507,542,543],{},"    public decimal CalculateTotal() {           \u002F\u002F tính toán\n",[507,545,547],{"class":509,"line":546},7,[507,548,549],{},"        return Items.Sum(i => i.Price * i.Quantity);\n",[507,551,553],{"class":509,"line":552},8,[507,554,555],{},"    }\n",[507,557,559],{"class":509,"line":558},9,[507,560,537],{},[507,562,564],{"class":509,"line":563},10,[507,565,566],{},"    public void SaveToDatabase() {              \u002F\u002F persistence\n",[507,568,570],{"class":509,"line":569},11,[507,571,572],{},"        using var conn = new SqlConnection(...);\n",[507,574,576],{"class":509,"line":575},12,[507,577,578],{},"        \u002F\u002F INSERT INTO Orders ...\n",[507,580,582],{"class":509,"line":581},13,[507,583,555],{},[507,585,587],{"class":509,"line":586},14,[507,588,537],{},[507,590,592],{"class":509,"line":591},15,[507,593,594],{},"    public string FormatForInvoice() {          \u002F\u002F formatting\n",[507,596,598],{"class":509,"line":597},16,[507,599,600],{},"        return $\"Order #{Id}: ${Total}\\n\" + \n",[507,602,604],{"class":509,"line":603},17,[507,605,606],{},"               string.Join(\"\\n\", Items.Select(i => $\"- {i.Name}\"));\n",[507,608,610],{"class":509,"line":609},18,[507,611,555],{},[507,613,615],{"class":509,"line":614},19,[507,616,537],{},[507,618,620],{"class":509,"line":619},20,[507,621,622],{},"    public void SendEmail(string to) {          \u002F\u002F communication\n",[507,624,626],{"class":509,"line":625},21,[507,627,628],{},"        new SmtpClient().Send(to, \"Your order\", FormatForInvoice());\n",[507,630,632],{"class":509,"line":631},22,[507,633,555],{},[507,635,637],{"class":509,"line":636},23,[507,638,639],{},"}\n",[432,641,642,643],{},"3 lý do thay đổi: đổi DB → sửa class. Đổi format invoice → sửa class. Đổi cách gửi mail → sửa class. ",[436,644,645],{},"Vi phạm SRP.",[492,647,649],{"id":648},"tuân-thủ-srp-tách-thành-nhóm-có-trách-nhiệm-rõ","✅ Tuân thủ SRP — tách thành nhóm có trách nhiệm rõ",[497,651,653],{"className":499,"code":652,"language":501,"meta":502,"style":502},"\u002F\u002F Entity — chỉ chứa state\npublic class Order {\n    public int Id { get; set; }\n    public decimal Total { get; set; }\n    public List\u003COrderItem> Items { get; set; } = new();\n}\n\n\u002F\u002F Business logic — tính toán\npublic class OrderCalculator {\n    public decimal CalculateTotal(Order order) =>\n        order.Items.Sum(i => i.Price * i.Quantity);\n}\n\n\u002F\u002F Persistence — lưu trữ\npublic class OrderRepository {\n    private readonly DbContext _ctx;\n    public OrderRepository(DbContext ctx) => _ctx = ctx;\n    public async Task SaveAsync(Order order) { \u002F* ... *\u002F }\n}\n\n\u002F\u002F Formatting\npublic class OrderInvoiceFormatter {\n    public string Format(Order order) =>\n        $\"Order #{order.Id}: ${order.Total}\\n\" + \n        string.Join(\"\\n\", order.Items.Select(i => $\"- {i.Name}\"));\n}\n\n\u002F\u002F Communication\npublic class OrderEmailService {\n    public async Task SendInvoiceAsync(Order order, string to) { \u002F* ... *\u002F }\n}\n",[504,654,655,660,664,668,672,677,681,687,692,697,702,707,711,715,720,725,730,735,740,744,748,753,758,763,769,775,780,785,791,797,803],{"__ignoreMap":502},[507,656,657],{"class":509,"line":510},[507,658,659],{},"\u002F\u002F Entity — chỉ chứa state\n",[507,661,662],{"class":509,"line":516},[507,663,513],{},[507,665,666],{"class":509,"line":522},[507,667,519],{},[507,669,670],{"class":509,"line":528},[507,671,525],{},[507,673,674],{"class":509,"line":534},[507,675,676],{},"    public List\u003COrderItem> Items { get; set; } = new();\n",[507,678,679],{"class":509,"line":540},[507,680,639],{},[507,682,683],{"class":509,"line":546},[507,684,686],{"emptyLinePlaceholder":685},true,"\n",[507,688,689],{"class":509,"line":552},[507,690,691],{},"\u002F\u002F Business logic — tính toán\n",[507,693,694],{"class":509,"line":558},[507,695,696],{},"public class OrderCalculator {\n",[507,698,699],{"class":509,"line":563},[507,700,701],{},"    public decimal CalculateTotal(Order order) =>\n",[507,703,704],{"class":509,"line":569},[507,705,706],{},"        order.Items.Sum(i => i.Price * i.Quantity);\n",[507,708,709],{"class":509,"line":575},[507,710,639],{},[507,712,713],{"class":509,"line":581},[507,714,686],{"emptyLinePlaceholder":685},[507,716,717],{"class":509,"line":586},[507,718,719],{},"\u002F\u002F Persistence — lưu trữ\n",[507,721,722],{"class":509,"line":591},[507,723,724],{},"public class OrderRepository {\n",[507,726,727],{"class":509,"line":597},[507,728,729],{},"    private readonly DbContext _ctx;\n",[507,731,732],{"class":509,"line":603},[507,733,734],{},"    public OrderRepository(DbContext ctx) => _ctx = ctx;\n",[507,736,737],{"class":509,"line":609},[507,738,739],{},"    public async Task SaveAsync(Order order) { \u002F* ... *\u002F }\n",[507,741,742],{"class":509,"line":614},[507,743,639],{},[507,745,746],{"class":509,"line":619},[507,747,686],{"emptyLinePlaceholder":685},[507,749,750],{"class":509,"line":625},[507,751,752],{},"\u002F\u002F Formatting\n",[507,754,755],{"class":509,"line":631},[507,756,757],{},"public class OrderInvoiceFormatter {\n",[507,759,760],{"class":509,"line":636},[507,761,762],{},"    public string Format(Order order) =>\n",[507,764,766],{"class":509,"line":765},24,[507,767,768],{},"        $\"Order #{order.Id}: ${order.Total}\\n\" + \n",[507,770,772],{"class":509,"line":771},25,[507,773,774],{},"        string.Join(\"\\n\", order.Items.Select(i => $\"- {i.Name}\"));\n",[507,776,778],{"class":509,"line":777},26,[507,779,639],{},[507,781,783],{"class":509,"line":782},27,[507,784,686],{"emptyLinePlaceholder":685},[507,786,788],{"class":509,"line":787},28,[507,789,790],{},"\u002F\u002F Communication\n",[507,792,794],{"class":509,"line":793},29,[507,795,796],{},"public class OrderEmailService {\n",[507,798,800],{"class":509,"line":799},30,[507,801,802],{},"    public async Task SendInvoiceAsync(Order order, string to) { \u002F* ... *\u002F }\n",[507,804,806],{"class":509,"line":805},31,[507,807,639],{},[470,809,812,815,816,819],{"color":810,"icon":811},"primary","i-lucide-info",[436,813,814],{},"\"Reason to change\" là gì?"," Robert C. Martin sau này refine: \"should have one reason to change\" = \"should be responsible to one ",[436,817,818],{},"actor","\" (1 nhóm người dùng\u002Fstakeholder). Tính toán = team accounting; Format = team marketing; Save = team infra. Đổi cho 1 actor không nên ảnh hưởng actor khác.",[427,821,823],{"id":822},"o-openclosed-principle","O — Open\u002FClosed Principle",[484,825,826],{},[432,827,828],{},[436,829,830],{},"Open for extension, closed for modification.",[432,832,833,834,837],{},"Thêm tính năng mới = thêm code mới, ",[436,835,836],{},"không sửa code cũ",".",[492,839,841],{"id":840},"vi-phạm-ocp","❌ Vi phạm OCP",[497,843,845],{"className":499,"code":844,"language":501,"meta":502,"style":502},"public class AreaCalculator {\n    public double Calculate(object shape) {\n        if (shape is Rectangle r) return r.Width * r.Height;\n        if (shape is Circle c) return Math.PI * c.Radius * c.Radius;\n        \u002F\u002F Mỗi khi thêm shape — phải sửa method này\n        throw new ArgumentException();\n    }\n}\n",[504,846,847,852,857,862,867,872,877,881],{"__ignoreMap":502},[507,848,849],{"class":509,"line":510},[507,850,851],{},"public class AreaCalculator {\n",[507,853,854],{"class":509,"line":516},[507,855,856],{},"    public double Calculate(object shape) {\n",[507,858,859],{"class":509,"line":522},[507,860,861],{},"        if (shape is Rectangle r) return r.Width * r.Height;\n",[507,863,864],{"class":509,"line":528},[507,865,866],{},"        if (shape is Circle c) return Math.PI * c.Radius * c.Radius;\n",[507,868,869],{"class":509,"line":534},[507,870,871],{},"        \u002F\u002F Mỗi khi thêm shape — phải sửa method này\n",[507,873,874],{"class":509,"line":540},[507,875,876],{},"        throw new ArgumentException();\n",[507,878,879],{"class":509,"line":546},[507,880,555],{},[507,882,883],{"class":509,"line":552},[507,884,639],{},[432,886,887,888,891,892,895,896],{},"Thêm ",[504,889,890],{},"Triangle"," → mở file → thêm ",[504,893,894],{},"if"," → có thể vỡ test cho Rectangle\u002FCircle. ",[436,897,898],{},"Fragile.",[492,900,902],{"id":901},"tuân-thủ-ocp-polymorphism","✅ Tuân thủ OCP — Polymorphism",[497,904,906],{"className":499,"code":905,"language":501,"meta":502,"style":502},"public abstract class Shape {\n    public abstract double Area();\n}\n\npublic class Rectangle : Shape {\n    public double Width, Height;\n    public override double Area() => Width * Height;\n}\n\npublic class Circle : Shape {\n    public double Radius;\n    public override double Area() => Math.PI * Radius * Radius;\n}\n\npublic class Triangle : Shape {           \u002F\u002F ⭐ Thêm class, KHÔNG động code cũ\n    public double Base, Height;\n    public override double Area() => 0.5 * Base * Height;\n}\n\npublic class AreaCalculator {\n    public double Total(IEnumerable\u003CShape> shapes) =>\n        shapes.Sum(s => s.Area());\n}\n",[504,907,908,913,918,922,926,931,936,941,945,949,954,959,964,968,972,977,982,987,991,995,999,1004,1009],{"__ignoreMap":502},[507,909,910],{"class":509,"line":510},[507,911,912],{},"public abstract class Shape {\n",[507,914,915],{"class":509,"line":516},[507,916,917],{},"    public abstract double Area();\n",[507,919,920],{"class":509,"line":522},[507,921,639],{},[507,923,924],{"class":509,"line":528},[507,925,686],{"emptyLinePlaceholder":685},[507,927,928],{"class":509,"line":534},[507,929,930],{},"public class Rectangle : Shape {\n",[507,932,933],{"class":509,"line":540},[507,934,935],{},"    public double Width, Height;\n",[507,937,938],{"class":509,"line":546},[507,939,940],{},"    public override double Area() => Width * Height;\n",[507,942,943],{"class":509,"line":552},[507,944,639],{},[507,946,947],{"class":509,"line":558},[507,948,686],{"emptyLinePlaceholder":685},[507,950,951],{"class":509,"line":563},[507,952,953],{},"public class Circle : Shape {\n",[507,955,956],{"class":509,"line":569},[507,957,958],{},"    public double Radius;\n",[507,960,961],{"class":509,"line":575},[507,962,963],{},"    public override double Area() => Math.PI * Radius * Radius;\n",[507,965,966],{"class":509,"line":581},[507,967,639],{},[507,969,970],{"class":509,"line":586},[507,971,686],{"emptyLinePlaceholder":685},[507,973,974],{"class":509,"line":591},[507,975,976],{},"public class Triangle : Shape {           \u002F\u002F ⭐ Thêm class, KHÔNG động code cũ\n",[507,978,979],{"class":509,"line":597},[507,980,981],{},"    public double Base, Height;\n",[507,983,984],{"class":509,"line":603},[507,985,986],{},"    public override double Area() => 0.5 * Base * Height;\n",[507,988,989],{"class":509,"line":609},[507,990,639],{},[507,992,993],{"class":509,"line":614},[507,994,686],{"emptyLinePlaceholder":685},[507,996,997],{"class":509,"line":619},[507,998,851],{},[507,1000,1001],{"class":509,"line":625},[507,1002,1003],{},"    public double Total(IEnumerable\u003CShape> shapes) =>\n",[507,1005,1006],{"class":509,"line":631},[507,1007,1008],{},"        shapes.Sum(s => s.Area());\n",[507,1010,1011],{"class":509,"line":636},[507,1012,639],{},[470,1014,474,1015,1018,1019,1022],{"color":472,"icon":473},[436,1016,1017],{},"OCP thực dụng:"," không cần \"đóng\" mọi thứ. Đóng những điểm ",[436,1020,1021],{},"có khả năng thay đổi cao"," (thêm shape, thêm payment method, thêm export format). Còn lại sửa cũng không sao.",[427,1024,1026],{"id":1025},"l-liskov-substitution-principle","L — Liskov Substitution Principle",[484,1028,1029],{},[432,1030,1031],{},[436,1032,1033],{},"If S is a subtype of T, then objects of T may be replaced with objects of S without altering desirable properties.",[432,1035,1036,1037,1040],{},"Nói cách khác: ",[436,1038,1039],{},"subclass dùng được mọi nơi base class dùng được",", không gây bất ngờ.",[492,1042,1044],{"id":1043},"vi-phạm-lsp-kinh-điển-penguin","❌ Vi phạm LSP kinh điển — Penguin",[497,1046,1048],{"className":499,"code":1047,"language":501,"meta":502,"style":502},"public class Bird {\n    public virtual void Fly() => Console.WriteLine(\"Flying\");\n}\n\npublic class Sparrow : Bird {}\n\npublic class Penguin : Bird {\n    public override void Fly() {\n        throw new NotSupportedException(\"Penguins can't fly!\");\n    }\n}\n\nvoid MakeBirdsFly(List\u003CBird> birds) {\n    foreach (var b in birds) b.Fly();    \u002F\u002F Penguin trong list → CRASH\n}\n",[504,1049,1050,1055,1060,1064,1068,1073,1077,1082,1087,1092,1096,1100,1104,1109,1114],{"__ignoreMap":502},[507,1051,1052],{"class":509,"line":510},[507,1053,1054],{},"public class Bird {\n",[507,1056,1057],{"class":509,"line":516},[507,1058,1059],{},"    public virtual void Fly() => Console.WriteLine(\"Flying\");\n",[507,1061,1062],{"class":509,"line":522},[507,1063,639],{},[507,1065,1066],{"class":509,"line":528},[507,1067,686],{"emptyLinePlaceholder":685},[507,1069,1070],{"class":509,"line":534},[507,1071,1072],{},"public class Sparrow : Bird {}\n",[507,1074,1075],{"class":509,"line":540},[507,1076,686],{"emptyLinePlaceholder":685},[507,1078,1079],{"class":509,"line":546},[507,1080,1081],{},"public class Penguin : Bird {\n",[507,1083,1084],{"class":509,"line":552},[507,1085,1086],{},"    public override void Fly() {\n",[507,1088,1089],{"class":509,"line":558},[507,1090,1091],{},"        throw new NotSupportedException(\"Penguins can't fly!\");\n",[507,1093,1094],{"class":509,"line":563},[507,1095,555],{},[507,1097,1098],{"class":509,"line":569},[507,1099,639],{},[507,1101,1102],{"class":509,"line":575},[507,1103,686],{"emptyLinePlaceholder":685},[507,1105,1106],{"class":509,"line":581},[507,1107,1108],{},"void MakeBirdsFly(List\u003CBird> birds) {\n",[507,1110,1111],{"class":509,"line":586},[507,1112,1113],{},"    foreach (var b in birds) b.Fly();    \u002F\u002F Penguin trong list → CRASH\n",[507,1115,1116],{"class":509,"line":591},[507,1117,639],{},[432,1119,1120,1121,1124,1125,1128,1129],{},"Caller có signature ",[504,1122,1123],{},"List\u003CBird>"," → kỳ vọng mọi Bird ",[504,1126,1127],{},"Fly()"," được. Penguin throw → phá expectation. ",[436,1130,1131],{},"Vi phạm LSP.",[492,1133,1135],{"id":1134},"fix-tách-hierarchy","✅ Fix — Tách hierarchy",[497,1137,1139],{"className":499,"code":1138,"language":501,"meta":502,"style":502},"public abstract class Bird {\n    public abstract string Eat();\n}\n\npublic interface IFlyable {\n    void Fly();\n}\n\npublic class Sparrow : Bird, IFlyable {\n    public override string Eat() => \"Seeds\";\n    public void Fly() => Console.WriteLine(\"Sparrow flying\");\n}\n\npublic class Penguin : Bird {     \u002F\u002F không implement IFlyable\n    public override string Eat() => \"Fish\";\n}\n\n\u002F\u002F Caller nhận IFlyable — không có Penguin → không crash\nvoid MakeFly(List\u003CIFlyable> birds) { ... }\n",[504,1140,1141,1146,1151,1155,1159,1164,1169,1173,1177,1182,1187,1192,1196,1200,1205,1210,1214,1218,1223],{"__ignoreMap":502},[507,1142,1143],{"class":509,"line":510},[507,1144,1145],{},"public abstract class Bird {\n",[507,1147,1148],{"class":509,"line":516},[507,1149,1150],{},"    public abstract string Eat();\n",[507,1152,1153],{"class":509,"line":522},[507,1154,639],{},[507,1156,1157],{"class":509,"line":528},[507,1158,686],{"emptyLinePlaceholder":685},[507,1160,1161],{"class":509,"line":534},[507,1162,1163],{},"public interface IFlyable {\n",[507,1165,1166],{"class":509,"line":540},[507,1167,1168],{},"    void Fly();\n",[507,1170,1171],{"class":509,"line":546},[507,1172,639],{},[507,1174,1175],{"class":509,"line":552},[507,1176,686],{"emptyLinePlaceholder":685},[507,1178,1179],{"class":509,"line":558},[507,1180,1181],{},"public class Sparrow : Bird, IFlyable {\n",[507,1183,1184],{"class":509,"line":563},[507,1185,1186],{},"    public override string Eat() => \"Seeds\";\n",[507,1188,1189],{"class":509,"line":569},[507,1190,1191],{},"    public void Fly() => Console.WriteLine(\"Sparrow flying\");\n",[507,1193,1194],{"class":509,"line":575},[507,1195,639],{},[507,1197,1198],{"class":509,"line":581},[507,1199,686],{"emptyLinePlaceholder":685},[507,1201,1202],{"class":509,"line":586},[507,1203,1204],{},"public class Penguin : Bird {     \u002F\u002F không implement IFlyable\n",[507,1206,1207],{"class":509,"line":591},[507,1208,1209],{},"    public override string Eat() => \"Fish\";\n",[507,1211,1212],{"class":509,"line":597},[507,1213,639],{},[507,1215,1216],{"class":509,"line":603},[507,1217,686],{"emptyLinePlaceholder":685},[507,1219,1220],{"class":509,"line":609},[507,1221,1222],{},"\u002F\u002F Caller nhận IFlyable — không có Penguin → không crash\n",[507,1224,1225],{"class":509,"line":614},[507,1226,1227],{},"void MakeFly(List\u003CIFlyable> birds) { ... }\n",[492,1229,1231],{"id":1230},"vi-phạm-lsp-tinh-tế-hơn-square-rectangle","Vi phạm LSP tinh tế hơn — Square : Rectangle",[497,1233,1235],{"className":499,"code":1234,"language":501,"meta":502,"style":502},"public class Rectangle {\n    public virtual int Width { get; set; }\n    public virtual int Height { get; set; }\n}\n\npublic class Square : Rectangle {\n    \u002F\u002F Square = Rect đặc biệt — width = height\n    public override int Width {\n        set { base.Width = value; base.Height = value; }\n    }\n    public override int Height {\n        set { base.Width = value; base.Height = value; }\n    }\n}\n\nvoid TestArea(Rectangle r) {\n    r.Width = 5;\n    r.Height = 4;\n    Debug.Assert(r.Width * r.Height == 20);  \u002F\u002F FAIL với Square (= 16)\n}\n",[504,1236,1237,1242,1247,1252,1256,1260,1265,1270,1275,1280,1284,1289,1293,1297,1301,1305,1310,1315,1320,1325],{"__ignoreMap":502},[507,1238,1239],{"class":509,"line":510},[507,1240,1241],{},"public class Rectangle {\n",[507,1243,1244],{"class":509,"line":516},[507,1245,1246],{},"    public virtual int Width { get; set; }\n",[507,1248,1249],{"class":509,"line":522},[507,1250,1251],{},"    public virtual int Height { get; set; }\n",[507,1253,1254],{"class":509,"line":528},[507,1255,639],{},[507,1257,1258],{"class":509,"line":534},[507,1259,686],{"emptyLinePlaceholder":685},[507,1261,1262],{"class":509,"line":540},[507,1263,1264],{},"public class Square : Rectangle {\n",[507,1266,1267],{"class":509,"line":546},[507,1268,1269],{},"    \u002F\u002F Square = Rect đặc biệt — width = height\n",[507,1271,1272],{"class":509,"line":552},[507,1273,1274],{},"    public override int Width {\n",[507,1276,1277],{"class":509,"line":558},[507,1278,1279],{},"        set { base.Width = value; base.Height = value; }\n",[507,1281,1282],{"class":509,"line":563},[507,1283,555],{},[507,1285,1286],{"class":509,"line":569},[507,1287,1288],{},"    public override int Height {\n",[507,1290,1291],{"class":509,"line":575},[507,1292,1279],{},[507,1294,1295],{"class":509,"line":581},[507,1296,555],{},[507,1298,1299],{"class":509,"line":586},[507,1300,639],{},[507,1302,1303],{"class":509,"line":591},[507,1304,686],{"emptyLinePlaceholder":685},[507,1306,1307],{"class":509,"line":597},[507,1308,1309],{},"void TestArea(Rectangle r) {\n",[507,1311,1312],{"class":509,"line":603},[507,1313,1314],{},"    r.Width = 5;\n",[507,1316,1317],{"class":509,"line":609},[507,1318,1319],{},"    r.Height = 4;\n",[507,1321,1322],{"class":509,"line":614},[507,1323,1324],{},"    Debug.Assert(r.Width * r.Height == 20);  \u002F\u002F FAIL với Square (= 16)\n",[507,1326,1327],{"class":509,"line":619},[507,1328,639],{},[432,1330,1331,1332],{},"Caller có Rectangle → set width, height độc lập, tính area = w*h. Square phá assumption. ",[436,1333,1131],{},[432,1335,1336,1339],{},[436,1337,1338],{},"Fix:"," Square và Rectangle không nên kế thừa nhau — cả 2 có thể inherit Shape, hoặc immutable + factory.",[470,1341,1342,1343,1346],{"color":810,"icon":811},"LSP là lý do mạnh nhất cho ",[436,1344,1345],{},"\"Favor composition over inheritance\""," — composition không có ràng buộc behavior này.",[427,1348,1350],{"id":1349},"i-interface-segregation-principle","I — Interface Segregation Principle",[484,1352,1353],{},[432,1354,1355],{},[436,1356,1357],{},"Clients should not be forced to depend on methods they do not use.",[432,1359,1360],{},"Nhiều interface nhỏ, chuyên biệt > 1 interface to.",[492,1362,1364],{"id":1363},"vi-phạm-fat-interface","❌ Vi phạm — Fat interface",[497,1366,1368],{"className":499,"code":1367,"language":501,"meta":502,"style":502},"public interface IWorker {\n    void Work();\n    void Eat();\n    void Sleep();\n    void Pay();\n}\n\n\u002F\u002F Robot phải implement Eat, Sleep — không hợp logic\npublic class Robot : IWorker {\n    public void Work() { \u002F* OK *\u002F }\n    public void Eat() => throw new NotSupportedException();\n    public void Sleep() => throw new NotSupportedException();\n    public void Pay() { \u002F* OK *\u002F }\n}\n",[504,1369,1370,1375,1380,1385,1390,1395,1399,1403,1408,1413,1418,1423,1428,1433],{"__ignoreMap":502},[507,1371,1372],{"class":509,"line":510},[507,1373,1374],{},"public interface IWorker {\n",[507,1376,1377],{"class":509,"line":516},[507,1378,1379],{},"    void Work();\n",[507,1381,1382],{"class":509,"line":522},[507,1383,1384],{},"    void Eat();\n",[507,1386,1387],{"class":509,"line":528},[507,1388,1389],{},"    void Sleep();\n",[507,1391,1392],{"class":509,"line":534},[507,1393,1394],{},"    void Pay();\n",[507,1396,1397],{"class":509,"line":540},[507,1398,639],{},[507,1400,1401],{"class":509,"line":546},[507,1402,686],{"emptyLinePlaceholder":685},[507,1404,1405],{"class":509,"line":552},[507,1406,1407],{},"\u002F\u002F Robot phải implement Eat, Sleep — không hợp logic\n",[507,1409,1410],{"class":509,"line":558},[507,1411,1412],{},"public class Robot : IWorker {\n",[507,1414,1415],{"class":509,"line":563},[507,1416,1417],{},"    public void Work() { \u002F* OK *\u002F }\n",[507,1419,1420],{"class":509,"line":569},[507,1421,1422],{},"    public void Eat() => throw new NotSupportedException();\n",[507,1424,1425],{"class":509,"line":575},[507,1426,1427],{},"    public void Sleep() => throw new NotSupportedException();\n",[507,1429,1430],{"class":509,"line":581},[507,1431,1432],{},"    public void Pay() { \u002F* OK *\u002F }\n",[507,1434,1435],{"class":509,"line":586},[507,1436,639],{},[492,1438,1440],{"id":1439},"fix-tách-nhỏ","✅ Fix — Tách nhỏ",[497,1442,1444],{"className":499,"code":1443,"language":501,"meta":502,"style":502},"public interface IWorkable { void Work(); }\npublic interface IFeedable { void Eat(); }\npublic interface IRestable { void Sleep(); }\npublic interface IPayable  { void Pay(); }\n\npublic class Human : IWorkable, IFeedable, IRestable, IPayable { ... }\n\npublic class Robot : IWorkable, IPayable { ... }   \u002F\u002F chỉ implement cần thiết\n",[504,1445,1446,1451,1456,1461,1466,1470,1475,1479],{"__ignoreMap":502},[507,1447,1448],{"class":509,"line":510},[507,1449,1450],{},"public interface IWorkable { void Work(); }\n",[507,1452,1453],{"class":509,"line":516},[507,1454,1455],{},"public interface IFeedable { void Eat(); }\n",[507,1457,1458],{"class":509,"line":522},[507,1459,1460],{},"public interface IRestable { void Sleep(); }\n",[507,1462,1463],{"class":509,"line":528},[507,1464,1465],{},"public interface IPayable  { void Pay(); }\n",[507,1467,1468],{"class":509,"line":534},[507,1469,686],{"emptyLinePlaceholder":685},[507,1471,1472],{"class":509,"line":540},[507,1473,1474],{},"public class Human : IWorkable, IFeedable, IRestable, IPayable { ... }\n",[507,1476,1477],{"class":509,"line":546},[507,1478,686],{"emptyLinePlaceholder":685},[507,1480,1481],{"class":509,"line":552},[507,1482,1483],{},"public class Robot : IWorkable, IPayable { ... }   \u002F\u002F chỉ implement cần thiết\n",[470,1485,1486,1487,1490],{"color":810,"icon":473},"⭐ ISP là ",[436,1488,1489],{},"liên hệ với LSP"," — nếu interface fat → subtype có method không dùng được → throw → vi phạm LSP.",[492,1492,1494],{"id":1493},"trong-typescript-interface-composition","Trong TypeScript — interface composition",[497,1496,1500],{"className":1497,"code":1498,"language":1499,"meta":502,"style":502},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","interface Workable { work(): void; }\ninterface Feedable { eat(): void; }\ninterface Restable { sleep(): void; }\n\nclass Human implements Workable, Feedable, Restable {\n    work() {} eat() {} sleep() {}\n}\n\nclass Robot implements Workable {\n    work() {}\n}\n","typescript",[504,1501,1502,1532,1552,1572,1576,1601,1616,1620,1624,1637,1646],{"__ignoreMap":502},[507,1503,1504,1508,1512,1516,1520,1523,1526,1529],{"class":509,"line":510},[507,1505,1507],{"class":1506},"spNyl","interface",[507,1509,1511],{"class":1510},"sBMFI"," Workable",[507,1513,1515],{"class":1514},"sMK4o"," {",[507,1517,1519],{"class":1518},"swJcz"," work",[507,1521,1522],{"class":1514},"():",[507,1524,1525],{"class":1510}," void",[507,1527,1528],{"class":1514},";",[507,1530,1531],{"class":1514}," }\n",[507,1533,1534,1536,1539,1541,1544,1546,1548,1550],{"class":509,"line":516},[507,1535,1507],{"class":1506},[507,1537,1538],{"class":1510}," Feedable",[507,1540,1515],{"class":1514},[507,1542,1543],{"class":1518}," eat",[507,1545,1522],{"class":1514},[507,1547,1525],{"class":1510},[507,1549,1528],{"class":1514},[507,1551,1531],{"class":1514},[507,1553,1554,1556,1559,1561,1564,1566,1568,1570],{"class":509,"line":522},[507,1555,1507],{"class":1506},[507,1557,1558],{"class":1510}," Restable",[507,1560,1515],{"class":1514},[507,1562,1563],{"class":1518}," sleep",[507,1565,1522],{"class":1514},[507,1567,1525],{"class":1510},[507,1569,1528],{"class":1514},[507,1571,1531],{"class":1514},[507,1573,1574],{"class":509,"line":528},[507,1575,686],{"emptyLinePlaceholder":685},[507,1577,1578,1581,1584,1587,1589,1592,1594,1596,1598],{"class":509,"line":534},[507,1579,1580],{"class":1506},"class",[507,1582,1583],{"class":1510}," Human",[507,1585,1586],{"class":1506}," implements",[507,1588,1511],{"class":1510},[507,1590,1591],{"class":1514},",",[507,1593,1538],{"class":1510},[507,1595,1591],{"class":1514},[507,1597,1558],{"class":1510},[507,1599,1600],{"class":1514}," {\n",[507,1602,1603,1606,1609,1612],{"class":509,"line":540},[507,1604,1605],{"class":1518},"    work",[507,1607,1608],{"class":1514},"()",[507,1610,1611],{"class":1514}," {}",[507,1613,1615],{"class":1614},"sTEyZ"," eat() {} sleep() {}\n",[507,1617,1618],{"class":509,"line":546},[507,1619,639],{"class":1514},[507,1621,1622],{"class":509,"line":552},[507,1623,686],{"emptyLinePlaceholder":685},[507,1625,1626,1628,1631,1633,1635],{"class":509,"line":558},[507,1627,1580],{"class":1506},[507,1629,1630],{"class":1510}," Robot",[507,1632,1586],{"class":1506},[507,1634,1511],{"class":1510},[507,1636,1600],{"class":1514},[507,1638,1639,1641,1643],{"class":509,"line":563},[507,1640,1605],{"class":1518},[507,1642,1608],{"class":1514},[507,1644,1645],{"class":1514}," {}\n",[507,1647,1648],{"class":509,"line":569},[507,1649,639],{"class":1514},[427,1651,1653],{"id":1652},"d-dependency-inversion-principle","D — Dependency Inversion Principle",[484,1655,1656],{},[432,1657,1658],{},[436,1659,1660],{},"High-level modules should not depend on low-level modules. Both should depend on abstractions.",[492,1662,1664],{"id":1663},"vi-phạm-dip","❌ Vi phạm DIP",[497,1666,1668],{"className":499,"code":1667,"language":501,"meta":502,"style":502},"public class EmailService {\n    public void Send(string to, string subject) { \u002F* SMTP code *\u002F }\n}\n\npublic class OrderService {\n    private readonly EmailService _email = new();    \u002F\u002F gắn cứng concrete\n    \n    public void PlaceOrder(Order order) {\n        \u002F\u002F ...\n        _email.Send(order.UserEmail, \"Order placed\");\n    }\n}\n",[504,1669,1670,1675,1680,1684,1688,1693,1698,1702,1707,1712,1717,1721],{"__ignoreMap":502},[507,1671,1672],{"class":509,"line":510},[507,1673,1674],{},"public class EmailService {\n",[507,1676,1677],{"class":509,"line":516},[507,1678,1679],{},"    public void Send(string to, string subject) { \u002F* SMTP code *\u002F }\n",[507,1681,1682],{"class":509,"line":522},[507,1683,639],{},[507,1685,1686],{"class":509,"line":528},[507,1687,686],{"emptyLinePlaceholder":685},[507,1689,1690],{"class":509,"line":534},[507,1691,1692],{},"public class OrderService {\n",[507,1694,1695],{"class":509,"line":540},[507,1696,1697],{},"    private readonly EmailService _email = new();    \u002F\u002F gắn cứng concrete\n",[507,1699,1700],{"class":509,"line":546},[507,1701,537],{},[507,1703,1704],{"class":509,"line":552},[507,1705,1706],{},"    public void PlaceOrder(Order order) {\n",[507,1708,1709],{"class":509,"line":558},[507,1710,1711],{},"        \u002F\u002F ...\n",[507,1713,1714],{"class":509,"line":563},[507,1715,1716],{},"        _email.Send(order.UserEmail, \"Order placed\");\n",[507,1718,1719],{"class":509,"line":569},[507,1720,555],{},[507,1722,1723],{"class":509,"line":575},[507,1724,639],{},[432,1726,1727,1728,1731],{},"OrderService ",[436,1729,1730],{},"không thể test"," — chạy là gửi email thật. Đổi sang SMS = sửa OrderService.",[492,1733,1735],{"id":1734},"fix-depend-abstraction","✅ Fix — Depend abstraction",[497,1737,1739],{"className":499,"code":1738,"language":501,"meta":502,"style":502},"public interface INotificationService {\n    Task SendAsync(string to, string subject, string body);\n}\n\npublic class EmailNotificationService : INotificationService {\n    public async Task SendAsync(string to, string subject, string body) { \u002F* SMTP *\u002F }\n}\n\npublic class SmsNotificationService : INotificationService {\n    public async Task SendAsync(string to, string subject, string body) { \u002F* Twilio *\u002F }\n}\n\npublic class OrderService {\n    private readonly INotificationService _notifier;\n    \n    \u002F\u002F Depend abstraction — inject via constructor\n    public OrderService(INotificationService notifier) => _notifier = notifier;\n    \n    public async Task PlaceOrderAsync(Order order) {\n        \u002F\u002F ...\n        await _notifier.SendAsync(order.UserEmail, \"Order placed\", \"...\");\n    }\n}\n",[504,1740,1741,1746,1751,1755,1759,1764,1769,1773,1777,1782,1787,1791,1795,1799,1804,1808,1813,1818,1822,1827,1831,1836,1840],{"__ignoreMap":502},[507,1742,1743],{"class":509,"line":510},[507,1744,1745],{},"public interface INotificationService {\n",[507,1747,1748],{"class":509,"line":516},[507,1749,1750],{},"    Task SendAsync(string to, string subject, string body);\n",[507,1752,1753],{"class":509,"line":522},[507,1754,639],{},[507,1756,1757],{"class":509,"line":528},[507,1758,686],{"emptyLinePlaceholder":685},[507,1760,1761],{"class":509,"line":534},[507,1762,1763],{},"public class EmailNotificationService : INotificationService {\n",[507,1765,1766],{"class":509,"line":540},[507,1767,1768],{},"    public async Task SendAsync(string to, string subject, string body) { \u002F* SMTP *\u002F }\n",[507,1770,1771],{"class":509,"line":546},[507,1772,639],{},[507,1774,1775],{"class":509,"line":552},[507,1776,686],{"emptyLinePlaceholder":685},[507,1778,1779],{"class":509,"line":558},[507,1780,1781],{},"public class SmsNotificationService : INotificationService {\n",[507,1783,1784],{"class":509,"line":563},[507,1785,1786],{},"    public async Task SendAsync(string to, string subject, string body) { \u002F* Twilio *\u002F }\n",[507,1788,1789],{"class":509,"line":569},[507,1790,639],{},[507,1792,1793],{"class":509,"line":575},[507,1794,686],{"emptyLinePlaceholder":685},[507,1796,1797],{"class":509,"line":581},[507,1798,1692],{},[507,1800,1801],{"class":509,"line":586},[507,1802,1803],{},"    private readonly INotificationService _notifier;\n",[507,1805,1806],{"class":509,"line":591},[507,1807,537],{},[507,1809,1810],{"class":509,"line":597},[507,1811,1812],{},"    \u002F\u002F Depend abstraction — inject via constructor\n",[507,1814,1815],{"class":509,"line":603},[507,1816,1817],{},"    public OrderService(INotificationService notifier) => _notifier = notifier;\n",[507,1819,1820],{"class":509,"line":609},[507,1821,537],{},[507,1823,1824],{"class":509,"line":614},[507,1825,1826],{},"    public async Task PlaceOrderAsync(Order order) {\n",[507,1828,1829],{"class":509,"line":619},[507,1830,1711],{},[507,1832,1833],{"class":509,"line":625},[507,1834,1835],{},"        await _notifier.SendAsync(order.UserEmail, \"Order placed\", \"...\");\n",[507,1837,1838],{"class":509,"line":631},[507,1839,555],{},[507,1841,1842],{"class":509,"line":636},[507,1843,639],{},[492,1845,1847],{"id":1846},"dip-vs-di-vs-ioc","DIP vs DI vs IoC",[470,1849,1850,1855,1881],{"color":472,"icon":268},[432,1851,474,1852],{},[436,1853,1854],{},"Câu PV cực hay:",[1856,1857,1858,1865,1871],"ul",{},[1859,1860,1861,1864],"li",{},[436,1862,1863],{},"DIP",": nguyên lý \"depend abstraction\".",[1859,1866,1867,1870],{},[436,1868,1869],{},"IoC"," (Inversion of Control): nguyên lý lớn hơn — \"đảo control flow\", framework gọi code bạn (Hollywood principle).",[1859,1872,1873,1876,1877,1880],{},[436,1874,1875],{},"DI"," (Dependency Injection): ",[436,1878,1879],{},"kỹ thuật"," thực thi DIP\u002FIoC — constructor \u002F setter \u002F framework container.",[432,1882,1883],{},"Trong ASP.NET Core, NestJS, Spring → DI container tự build dependency graph.",[427,1885,1887],{"id":1886},"bonus-solid-khi-nào-không-áp-dụng","Bonus — SOLID khi nào không áp dụng",[470,1889,1891,1897,1908],{"color":472,"icon":1890},"i-lucide-alert-triangle",[432,1892,1893,1896],{},[436,1894,1895],{},"SOLID là guideline, không phải luật."," Lạm dụng → over-engineering:",[1856,1898,1899,1902,1905],{},[1859,1900,1901],{},"Script nhỏ 100 dòng — đừng tách 5 class.",[1859,1903,1904],{},"Prototype, throwaway code — code nhanh > clean.",[1859,1906,1907],{},"\"1 implementation, 1 interface\" cho mọi class → noise — chỉ tạo interface khi có ≥ 2 impl thật hoặc cần test mock.",[432,1909,1910,1913],{},[436,1911,1912],{},"Quy tắc thực dụng:"," áp dụng khi code grow và cảm thấy đau. Đừng áp dụng \"preemptive\".",[470,1915,1917,1918],{"color":810,"icon":1916},"i-lucide-arrow-right","Tiếp theo: ",[1919,1920,1921],"a",{"href":328},"Design Pattern",[1923,1924,1925],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}",{"title":502,"searchDepth":516,"depth":516,"links":1927},[1928,1929,1933,1937,1942,1947,1952],{"id":429,"depth":516,"text":430},{"id":481,"depth":516,"text":482,"children":1930},[1931,1932],{"id":494,"depth":522,"text":495},{"id":648,"depth":522,"text":649},{"id":822,"depth":516,"text":823,"children":1934},[1935,1936],{"id":840,"depth":522,"text":841},{"id":901,"depth":522,"text":902},{"id":1025,"depth":516,"text":1026,"children":1938},[1939,1940,1941],{"id":1043,"depth":522,"text":1044},{"id":1134,"depth":522,"text":1135},{"id":1230,"depth":522,"text":1231},{"id":1349,"depth":516,"text":1350,"children":1943},[1944,1945,1946],{"id":1363,"depth":522,"text":1364},{"id":1439,"depth":522,"text":1440},{"id":1493,"depth":522,"text":1494},{"id":1652,"depth":516,"text":1653,"children":1948},[1949,1950,1951],{"id":1663,"depth":522,"text":1664},{"id":1734,"depth":522,"text":1735},{"id":1846,"depth":522,"text":1847},{"id":1886,"depth":516,"text":1887},"SRP, OCP, LSP, ISP, DIP — case study refactor mỗi nguyên lý. Ví dụ C# + TypeScript.","md",null,{},{"title":322,"icon":325},{"title":422,"description":1953},"K1WmVVXySWg6PnJ7Z6GHb0cAmL-F4FfVGn0YSW7CeZw",[1961,1963],{"title":317,"path":318,"stem":319,"description":1962,"icon":320,"children":-1},"Encapsulation, Abstraction, Inheritance, Polymorphism — định nghĩa, ví dụ song song C# \u002F TypeScript, biến thể nâng cao.",{"title":327,"path":328,"stem":329,"description":1964,"icon":106,"children":-1},"Creational (Singleton, Factory, Builder), Structural (Adapter, Decorator, Facade), Behavioral (Strategy, Observer, Command...). Ví dụ C# + TS.",1783490358505]