Review checklist
นี่คือ checklist ที่ต้องไล่ตรวจ — ด้วยตา บน diff ไหนก็ได้ ของคุณเองหรือของ AI — หลังจากเครื่องมือใน Verification Tools รันเสร็จและผ่านสะอาดแล้ว มันตั้งใจให้อยู่ในกระดาษหน้าเดียวพอดี: checklist ที่ไม่มีใครเปิดดูจริงระหว่างรีวิวก็ไร้ค่า ทุกบรรทัดลิงก์ไปยัง catalog entry ที่อธิบาย ทำไม เพื่อให้หน้านี้ยังเป็นแค่รายการ ไม่ใช่การรันคอร์สซ้ำ กลุ่มต่าง ๆ เรียงตามลำดับเดียวกับ How to read Flutter code you did not write บวกกลุ่ม Tooling สุดท้ายที่ครอบคลุมว่าอีกแปดกลุ่มถูกตรวจสอบจริงได้อย่างไร
flowchart LR A["State & lifecycle"] --> R["Needs a real dispose/rebuild sequence<br/>to surface at all"] W["Widget tree & keys"] --> T["Mostly human review<br/>(renders correctly either way)"] L["Layout"] --> T2["Framework catches it loudly --<br/>but only the exact arrangement that overflows"] As["Async & isolates"] --> R N["Navigation"] --> T P["Platform"] --> D["Needs the actual platform/runtime --<br/>compiles and analyzes clean otherwise"] Pf["Performance"] --> M["Silent cost, not a crash --<br/>needs reading RenderObject properties directly"] Tl["Tooling & release"] --> M2["Analyzer/lint catches SOME --<br/>only if the rule is actually enabled"]
pubspec & ข้อจำกัดของ SDK
หัวข้อที่มีชื่อว่า “pubspec & ข้อจำกัดของ SDK”environment: sdk:ในpubspec.yamlรองรับ Dart/Flutter เวอร์ชันที่โปรเจกต์นี้เล็งเป้าไว้จริงหรือเปล่า ไม่ใช่ก็อปมาจาก tutorial เก่า?- โค้ด Riverpod ไหนเรียก
StateProvider/StateNotifierProvider/ChangeNotifierProviderผ่าน import หลักflutter_riverpod.dartแทนที่จะเป็น importlegacy.dartที่จำเป็นใน Riverpod 3 หรือเปล่า? ดู AI Bug Catalog entry 5 พิสูจน์ด้วย diagnostic จริงundefined_function - ถ้า
custom_lint/riverpod_lintถูก pin ไว้ทั้งคู่ พวกมัน resolve คู่กันได้จริงที่เวอร์ชันเหล่านั้นหรือเปล่า? ดู Verification Tools สำหรับข้อค้นพบ version-conflict จริงและเป็นปัจจุบัน
State & lifecycle
หัวข้อที่มีชื่อว่า “State & lifecycle”- มี
ProviderScopeอยู่เหนือConsumerWidget/ref.watchตัวแรกหรือเปล่า? ดู AI Bug Catalog entry 1 พิสูจน์ด้วยBad state: No ProviderScope foundจริง - ทุก
setStateที่เข้าถึงได้จาก.then(), การทำงานต่อหลังawait,Timer, หรือStreamlistener เช็คmountedก่อนหรือเปล่า? ดู entry 2 พิสูจน์ด้วยsetState() called after dispose()จริง build()ของ widget ไหนเรียกsetStateบน widget อื่น ที่ยังกลาง build แบบ synchronous หรือเปล่า? ดู entry 3 พิสูจน์ด้วยsetState() or markNeedsBuild() called during buildจริง- field แบบ
lateเคยถูกอ่านบน path ที่ method ซึ่งกำหนดค่าให้มันอาจยังไม่ทำงานหรือเปล่า? ดู entry 4 พิสูจน์ด้วยLateInitializationErrorจริง
Widget tree & keys
หัวข้อที่มีชื่อว่า “Widget tree & keys”- list ของ stateful widget ที่สร้างด้วย
for/.map()มีkeyหรือเปล่า ในเมื่อลำดับของมันเปลี่ยนได้? ดู AI Bug Catalog entry 6 พิสูจน์ด้วย test การเรียงใหม่จริง GlobalKeyตัวเดียวกันถูกใช้ซ้ำข้าม sibling widget แทนที่จะใช้UniqueKey()/ValueKeyต่อรายการหรือเปล่า? ดู entry 7 พิสูจน์ด้วยDuplicate keys foundจริงScaffold.of(context)เคยถูกเรียกด้วยcontextตัวเดียวกันเป๊ะกับที่Scaffoldที่ล้อมรอบถูก build ด้วย แทนที่จะเป็น context จาก descendant ของBuilderหรือเปล่า? ดู entry 8 พิสูจน์ด้วยScaffold.of() called with a context that does not contain a Scaffoldจริง
ListView/GridView/scrollable อื่นถูกวางตรง ๆ ในColumn/Rowโดยไม่มีอะไรจำกัดขนาดแกนหลักของมันหรือเปล่า? ดู AI Bug Catalog entry 9 พิสูจน์ด้วยVertical viewport was given unbounded heightจริง — และยืนยันว่ากรณีย้อนกลับ (Columnข้างในListView) ไม่ถูก “แก้” โดยไม่จำเป็นExpanded/Flexibleเคยถูกใช้เป็นลูกของสิ่งที่ไม่ใช่Row/Column/Flexหรือเปล่า? ดู entry 10 พิสูจน์ด้วยIncorrect use of ParentDataWidgetจริงRow/Columnของ children ขนาดคงที่ไม่มีExpanded/Flexible/scrolling เป็นทางออกสำหรับเนื้อหาที่อาจเกิน viewport หรือเปล่า? ดู entry 11 พิสูจน์ด้วยRenderFlex overflowedจริง
Async & isolate
หัวข้อที่มีชื่อว่า “Async & isolate”- async function ถูกเรียกตรง ๆ ข้างใน
build()แทนที่จะเรียกครั้งเดียวในState(initState/field แบบlate final) หรือเปล่า? ดู AI Bug Catalog entry 12 พิสูจน์ด้วยการนับจำนวนการ rebuild-refetch จริง - closure ของ
compute()captureBuildContext,Zone, หรืออะไรก็ตามที่เข้าถึงได้จาก binding ของ isolate นี้เองหรือเปล่า? ดู entry 13 พิสูจน์ด้วยIllegal argument in isolate message: object is unsendableจริง StreamControllerถูกปล่อยไว้ที่ default แบบ single-subscription ในขณะที่มีการเรียก.listen()อิสระมากกว่าหนึ่งครั้งบนมันหรือเปล่า? ดู entry 14 พิสูจน์ด้วยBad state: Stream has already been listened toจริง
Navigation
หัวข้อที่มีชื่อว่า “Navigation”- route ของ
go_routerที่มีพารามิเตอร์ (/pets/:id) ถูกประกาศ ก่อน route แบบ static ที่เฉพาะเจาะจงกว่าในระดับ segment เดียวกัน (/pets/new) หรือเปล่า? ดู AI Bug Catalog entry 15 พิสูจน์ด้วย test misroute จริง context.go()/router.go()ถูกใช้ในจุดที่ user ต้องกดย้อนกลับได้ (navigation แบบดำดิ่งลึก) แทนที่จะเป็นpush()หรือเปล่า? ดู entry 16 พิสูจน์ด้วยการเปรียบเทียบความลึกของ route stack จริง- callback
redirectอ่าน state ภายนอก (auth flag) โดยไม่ได้ชี้refreshListenableไปที่สิ่งที่แจ้งเตือนเมื่อ state นั้นเปลี่ยนหรือเปล่า? ดู entry 17 พิสูจน์ด้วย test ที่ค้างหน้า login จริง - โค้ดไหนยังใช้
WillPopScope(deprecated ไม่รองรับ predictive-back) หรืออ้างถึงPredictiveBackPageTransitionBuilder(ขาดตัว “s”) หรือเปล่า? ดู entry 18 พิสูจน์ด้วย deprecationinfoจริงและundefined_functionerror จริง
Platform
หัวข้อที่มีชื่อว่า “Platform”dart:io/Platform.isIOS/Fileถูกใช้แบบไม่มีเงื่อนไขในโค้ดที่ต้อง build สำหรับ web ด้วยหรือเปล่า? ดู AI Bug Catalog entry 19 พิสูจน์ด้วยflutter build web --releaseจริงที่สะอาดและซ่อนบั๊กไว้จนกว่าจะถึง runtime จริง- การเรียก
MethodChannel.invokeMethodสมมติว่ามี native handler ลงทะเบียนไว้ทุก platform ที่แอป ship ไปหรือเปล่า (และทุก test ที่ใช้มัน mock channel หรือเปล่า)? ดู entry 20 พิสูจน์ด้วยMissingPluginExceptionจริง FlutterError.onErrorถูกมองว่าครอบคลุม error ทั้งหมด โดยไม่มีrunZonedGuarded/PlatformDispatcher.onErrorสำหรับ error ที่ throw นอก build/layout/paint ของ framework เองหรือเปล่า? ดู entry 21 พิสูจน์ด้วย error จากFutureธรรมดาจริงที่มีแค่runZonedGuardedเท่านั้นที่จับได้
Performance
หัวข้อที่มีชื่อว่า “Performance”AnimationControllerทุกตัวที่สร้างด้วยSingleTickerProviderStateMixin/TickerProviderStateMixinถูก.dispose()ในdispose()ของStateเองหรือเปล่า? ดู AI Bug Catalog entry 22 พิสูจน์ด้วยwas disposed with an active TickerจริงOpacity(opacity: 1.0)ถูกใช้ในจุดที่ค่าไม่เคยเปลี่ยนแปลงจริง ๆ แทนที่จะคืนค่า child ตรง ๆ หรือเปล่า? ดู entry 23 พิสูจน์ด้วยการอ่าน propertyisRepaintBoundary/alwaysNeedsCompositingของRenderOpacityที่มีชีวิตจริง- โค้ดไหนยังส่งตัวเลขเปล่า ๆ ให้
cacheExtentแทนที่จะเป็นscrollCacheExtent: ScrollCacheExtent.pixels(...)หรือเปล่า? ดู entry 24 พิสูจน์ด้วย deprecationinfoจริงและคำแนะนำจริงจากdart fix --dry-run
Tooling & release
หัวข้อที่มีชื่อว่า “Tooling & release”constถูกสมมติว่าถูกบังคับใช้โดย “linter” ทั้งที่flutter_lints6.0.0 ที่คอร์สนี้ pin ไว้มีแค่prefer_const_constructors_in_immutablesไม่มี rule ทั่วไปหรือเปล่า? ดู AI Bug Catalog entry 25 พิสูจน์ด้วยการเทียบflutter analyzeก่อน/หลังจริง- การเรียก
print()ไหนถูกสมมติว่าถูกตัดออกจาก release build หรือเปล่า? ดู entry 26 พิสูจน์ด้วย string จริงที่พบคำต่อคำข้างในmain.dart.jsของ release switchบนsealed classข้าม subtype ไปโดยพึ่งความเคยชินแทนที่จะพึ่ง exhaustiveness check ของ analyzer เองหรือเปล่า? ดู entry 27 พิสูจน์ด้วยnon_exhaustive_switch_expressionerror จริง- named parameter หรือชื่อ method ไหนดูสมเหตุสมผลแต่ไม่มีอยู่จริงบน class ที่กำลังพูดถึงหรือเปล่า? ดู entry 28 พิสูจน์ด้วย
undefined_named_parameter/undefined_methoderror จริง — การเช็คที่ถูกที่สุดและใช้เครื่องจักรจับได้ง่ายที่สุดในทั้งหน้านี้ - CI รันทั้ง
flutter analyzeANDflutter test(ไม่ใช่แค่ตัวใดตัวหนึ่ง) โดยรู้ว่า analyze พิสูจน์แค่ type/syntax ไม่เคยพิสูจน์พฤติกรรมตอน runtime เลยหรือเปล่า? ดู Verification Tools flutter build web --wasmเคยถูกใช้เป็น portability gate หรือเปล่า หรือมีแค่ default build แบบ JS? ดู Verification Tools พิสูจน์ด้วย--wasmbuild จริงที่สะอาด- harness ของคอร์สนี้เอง (
npm run verify,--test <module>/<lesson>) รันกับทุก fence จริงหรือเปล่า ไม่ใช่แค่ human skim? ดู Verification Tools