เหตุใดการพัฒนาแอปเนทีฟบน Windows ถึงเละเทะ
(domenic.me)- ระบบนิเวศการพัฒนาแอปเนทีฟบน Windows ยังคงไม่สามารถมอบประสิทธิภาพการพัฒนาที่ใช้งานได้จริงแม้ในปี 2025 เนื่องจาก ความไม่ต่อเนื่องของเฟรมเวิร์กและการออกแบบใหม่ซ้ำไปซ้ำมา ที่ยืดเยื้อมาหลายทศวรรษ
- แม้จะผ่านวิวัฒนาการของเฟรมเวิร์ก UI มา 7 ขั้นจาก Win32, MFC, WinForms, WPF, WinRT, UWP จนถึง WinUI 3 แต่ในหลายกรณีก็ยังไม่สามารถทำฟังก์ชันพื้นฐานได้ด้วย API รุ่นใหม่เพียงอย่างเดียว
- ความสามารถที่ใช้กันในชีวิตประจำวันอย่างไอคอนในถาดระบบหรือการดักจับคีย์ลัดแบบโกลบอล ยังคงต้องพึ่งพา การเรียก Win32 ผ่าน P/Invoke ซึ่งทำให้ความหมายของการนำเฟรมเวิร์กรุ่นใหม่มาใช้นั้นลดทอนลง
- แม้จะบิลด์แอปยูทิลิตีง่าย ๆ ด้วย .NET AOT compilation ก็ยังได้ไบนารีขนาดเกิน 9MiB และใบรับรองสำหรับเซ็นโค้ดเพื่อแจกจ่ายแบบ MSIX ก็เป็นอุปสรรคในทางปฏิบัติที่มีค่าใช้จ่ายราว $200–300 ต่อปี
- ข้อเท็จจริงที่ว่าแอปสำคัญของ Microsoft เองอย่าง VS Code, Outlook และ Start Menu ถูกสร้างด้วยเว็บเทคโนโลยี เป็นหลักฐานว่า การพัฒนาแบบเนทีฟบน Windows ไม่ได้เป็นลำดับความสำคัญภายใน Microsoft อีกต่อไป
เบื้องหลัง: สร้างอะไรขึ้นมา
- ระหว่างการพัฒนา แอปยูทิลิตีเฉพาะ Windows ชื่อ ‘Display Blackout’ ก็ได้เผยให้เห็นปัญหาของสภาพแวดล้อมการพัฒนาแอปเนทีฟในปัจจุบัน
- แอปนี้มีฟังก์ชัน ปิดหน้าจอด้านซ้ายและขวาด้วยโอเวอร์เลย์สีดำ ระหว่างเล่นเกมในสภาพแวดล้อมหลายจอ
- ฟังก์ชันที่ต้องใช้ได้แก่ การไล่รายการดิสเพลย์ การคำนวณขอบเขต การจัดการ คีย์ลัดแบบโกลบอล, การแสดง ไอคอนในถาดระบบ, การรันอัตโนมัติเมื่อเริ่มระบบ, การบันทึกการตั้งค่า เป็นต้น
- แม้จะมีทั้งสคริปต์ AutoHotkey และแอปใน Microsoft Store อยู่แล้ว แต่ก็ลองพัฒนาเองเพื่อการเรียนรู้และปรับปรุง UI
- สุดท้ายก็พบว่า สภาพแวดล้อมการพัฒนาแอปเนทีฟบน Windows นั้นซับซ้อนและไร้ประสิทธิภาพอย่างยิ่ง
ประวัติของการเขียนโปรแกรมบน Windows
- ในยุคแรก Win32 API ที่อิง C คือทางเลือกเดียว และ API นี้ก็ยังคงใช้งานได้มาจนถึงทุกวันนี้
- MFC ที่อิง C++ ได้เพิ่ม abstraction เชิงวัตถุอย่างคลาสและเทมเพลตไว้บน Win32
- เมื่อ .NET 1.0 (2002) ถูกนำมาใช้ ก็มีภาษา C#, VM สำหรับ JIT bytecode และการจัดการหน่วยความจำอัตโนมัติเกิดขึ้น โดย Windows Forms เป็น wrapper ของ API หน้าต่างและคอนโทรลใน Win32
- WPF ใน .NET 3.0 (2006) ได้นำภาษา markup อย่าง XAML มาใช้ และเป็นความพยายามครั้งแรกในการลดการพึ่งพา Win32 ด้วยการเรนเดอร์คอนโทรลบน GPU
- WinRT ของ Windows 8 (2012) นำโมเดลแอปแบบ sandbox มาใช้ โดยตั้งเป้ารวมเดสก์ท็อป แท็บเล็ต และมือถือเข้าด้วยกัน แต่โครงสร้าง XAML ก็แตกต่างจาก WPF แบบละเอียดอ่อนจนทำให้เกิดความสับสน
- UWP ของ Windows 10 (2015) ผ่อนคลายข้อจำกัดของ sandbox ลงบางส่วน แต่ก็ยังไม่ถึงระดับสิทธิ์บนเดสก์ท็อปแบบ WPF และฟีเจอร์บางอย่างของระบบปฏิบัติการ (push notification, live tile, การแจกจ่ายผ่าน Microsoft Store) ก็ยังถูกจำกัดให้ใช้ได้เฉพาะ WinRT/UWP
- จึงเป็นสาเหตุให้แอปเดิมอย่าง Chrome และ Microsoft Office ต้องใช้สถาปัตยกรรมที่กระอักกระอ่วน โดยเชื่อม bridge app แบบ WinRT/UWP ผ่าน IPC
- Windows App SDK ของ Windows 11 (2021) เปิดให้ใช้ฟีเจอร์ที่เคยจำกัดอยู่ใน WinRT/UWP กับทั้งแอป C++ มาตรฐานและแอป .NET และมีไลบรารีคอนโทรลแบบ XAML ใหม่ชื่อ WinUI 3 รวมอยู่ด้วย
- สรุปวิวัฒนาการของ UI framework:
> Win32 C APIs → MFC → WinForms → WPF → WinRT XAML → UWP XAML → WinUI 3
ภาวะกลืนไม่เข้าคายไม่ออกในการเลือกแนวทางพัฒนา
- การพัฒนาแอป WinUI 3 มี 3 เส้นทางให้เลือก:
- C++: ไบนารีขนาดเล็ก, อินเทอร์ออปกับ Win32 C API ได้ง่าย — แต่ไม่มี memory safety
- C#/XAML + การแจกจ่ายที่พึ่งพาเฟรมเวิร์ก: แม้แต่ Windows 11 รุ่นใหม่ก็ยังติดตั้งมาแค่ .NET 4.8.1 ล่วงหน้า ทำให้ประสบการณ์ผู้ใช้ย่ำแย่ เพราะตอนติดตั้งครั้งแรกจะมีไดอะล็อกให้ดาวน์โหลดไลบรารี .NET เพิ่ม
- C#/XAML + .NET AOT: รวมทั้ง .NET runtime (VM, GC, standard library) เข้าไปในไบนารี — แม้เป็นแอปง่าย ๆ ก็ยังได้ไบนารีเกิน 9MiB
- ความพยายามดูแล Rust binding อย่าง
windows-app-rsถูก เก็บเข้าคลัง (archived) ไปแล้ว - วิธีแจกจ่ายก็เต็มไปด้วยความลำบากในการเลือก:
- ฟอร์แมต MSIX ต้องใช้ใบรับรองเซ็นโค้ด และสำหรับผู้ที่อยู่นอกสหรัฐฯ มีค่าใช้จ่ายราว $200–300 ต่อปี
- การไซด์โหลดแบบไม่เซ็นต้องใช้คำสั่ง PowerShell ที่เข้าใจยากและใช้ได้เฉพาะในเทอร์มินัลสิทธิ์ผู้ดูแลระบบ
- การลงทะเบียนใน Microsoft Store ถูก ปฏิเสธ ด้วยเหตุผลว่าไม่ได้มอบ “คุณค่าที่มีเอกลักษณ์และต่อเนื่อง”
ฟังก์ชันที่ทำไม่ได้แม้ใน SDK รุ่นล่าสุด
| ฟังก์ชัน | การรองรับใน Windows App SDK |
|---|---|
| การไล่รายการดิสเพลย์ | รองรับบางส่วน (foreach loop ใช้ไม่ได้ และการตรวจจับการเปลี่ยนแปลงต้องใช้ P/Invoke) |
| การวางหน้าต่างสีดำแบบไม่แอ็กทีฟ | รองรับบางส่วน (ถ้าเป็น non-activating ต้องใช้ P/Invoke) |
| การดักจับคีย์ลัดคีย์บอร์ดระดับโกลบอล | ไม่ได้ — ต้องใช้ P/Invoke |
| การรันอัตโนมัติเมื่อเริ่มระบบ | ได้ (มี API สำหรับเชื่อมกับการตั้งค่าระบบ) |
| การบันทึกการตั้งค่าแบบถาวร | ได้ |
| ไอคอนในถาดระบบ + เมนู | ไม่ได้ — ต้องใช้ P/Invoke และสไตล์เมนูไม่เป็นมาตรฐาน |
- สไตล์เมนูของไอคอนถาดระบบแตกต่างกันไปในแต่ละแอป และ ไม่มีมาตรฐานที่สอดคล้องกัน ทั่วทั้ง OS
- ระหว่างการเปลี่ยนจาก WPF มาสู่ WinUI 3 นั้น แม้แต่ฟังก์ชันพื้นฐานอย่าง การปรับขนาดหน้าต่างอัตโนมัติ ก็หายไปด้วย
ข้อจำกัดเชิงโครงสร้างของ C# และ Win32 interop
- เครื่องมือ P/Invoke สมัยใหม่อย่าง CsWin32 มีบั๊กที่ไม่สามารถห่อหุ้มสตริงภายใน struct ได้อย่างถูกต้อง
- เอกสารของ CsWin32 ระบุว่า เนื่องจาก C# ไม่มีวิธีแสดงพารามิเตอร์พื้นฐานของ Win32 API อย่าง
[optional, out]ได้อย่างเป็นธรรมชาติ จึงต้องสร้างเมธอดเดียวกันออกมาสองเวอร์ชัน - แม้จะผ่านไป 20 ปีนับจากการเปิดตัว WPF (2006) แล้ว แต่ boilerplate สำหรับเขียนคลาสเพื่อทำ UI binding ก็แทบไม่ได้ดีขึ้นเลย
- ยังคงต้องเขียนโค้ดซ้ำ ๆ เช่น แปลงทุกพร็อพเพอร์ตีเป็นคู่ getter/setter, ตรวจค่าว่าซ้ำเดิมหรือไม่, เรียก event แจ้งการเปลี่ยนแปลง เป็นต้น
- ตลอด 20 ปีที่ผ่านมา C# ก็ยังไม่ได้เพิ่มทางออกในระดับภาษาแบบเดียวกับ decorator หรือ proxy ของ JavaScript เข้ามา
- CsWin32 มี changelog ที่ให้ข้อมูลน้อยและยังอยู่ต่ำกว่าเวอร์ชัน 1.0 จึงดูเหมือนว่า มีโอกาสที่โปรเจกต์จะถูกละทิ้งภายในไม่กี่ปี
บทสรุป: ทำไม Electron ถึงเป็นคำตอบ
- ตอนนี้ Microsoft ไม่ได้ให้ความสำคัญกับการพัฒนาแอปเนทีฟ
- ตัวติดตาม issue ที่เกี่ยวข้อง เต็มไปด้วยบั๊กและรายงาน แต่แทบไม่มีการตอบกลับจากวิศวกรของ Microsoft
- changelog ของ Windows App SDK ก็เน้นไปที่การเพิ่ม API ด้าน machine learning เป็นหลัก
- ข้อเท็จจริงที่ว่า แอปหลักของ Microsoft เอง อย่าง VS Code, Outlook และ Start Menu ถูกสร้างด้วย เว็บเทคโนโลยี ก็ยิ่งยืนยันเรื่องนี้
- ชุมชนกำลังย้ายไปใช้ เฟรมเวิร์ก UI ของ third party อย่าง Avalonia และ Uno Platform
- เฟรมเวิร์กเหล่านี้ สืบทอดแนวคิดของ WPF และ เสริมการรองรับข้ามแพลตฟอร์ม
- ในตอนนี้ เฟรมเวิร์กแบบเว็บอย่าง Electron หรือ Tauri จึงเป็นตัวเลือกที่สมจริงกว่า
- ชุด TypeScript/React/CSS มีประสิทธิภาพในการพัฒนามากกว่า C#/XAML
- และยัง เข้าถึง Win32 API ได้ด้วย
-
Tauriนั้นใช้ระบบ WebView จึงไม่จำเป็นต้องบันเดิล Chromium
- WebView2 runtime อัปเดตทุก 4 สัปดาห์ ขณะที่ .NET ของระบบถูกตรึงอยู่ที่ 4.8.1
- หาก Microsoft เดินหน้าปรับปรุง Windows App SDK และ ทำให้ระบบการแจกจ่ายง่ายขึ้น ก็อาจมีโอกาสฟื้นตัวได้
- แต่ในตอนนี้ นักพัฒนาส่วนใหญ่ไม่ได้คาดหวังเช่นนั้น
- สุดท้ายจึงลงเอยด้วยข้อสรุปว่า “จะเลือกใช้เว็บสแตก”
- ประกาศล่าสุดของ Microsoft เรื่อง ความมุ่งมั่นต่อคุณภาพของ Windows ระบุว่าจะใช้ WinUI 3 มากขึ้นทั่วทั้ง OS แต่ก็ยังไม่ชัดเจนว่าจะนำไปสู่การปรับปรุงที่เป็นรูปธรรมหรือไม่
3 ความคิดเห็น
ช่วยทำให้ทุกอย่างกลับมาเข้าที่ด้วย Electron สินะ...
หวังว่า WinUI 3 WYSIWYG จะออกมาสักทีเมื่อไหร่นะ
ความเห็นจาก Hacker News
ฉันก็คิดเหมือนคนอื่น ๆ ว่าการยึด Win32 ไว้นั้นถูกต้อง
ในฐานะคนที่พัฒนาด้วย Win32 มานาน ฟีเจอร์ที่ต้องการสามารถทำได้ครบด้วยไฟล์ executable แบบสแตนด์อโลนที่มีขนาดไม่ถึง 8KB
ทั้งการไล่รายการจอภาพ, การสร้างหน้าต่าง, การ hook คีย์ลัด, การลงทะเบียนให้รันตอนเริ่มระบบ, การบันทึกการตั้งค่า, การแสดงไอคอนใน system tray ล้วนทำได้ด้วยการเรียก API เพียงไม่กี่ร้อยไบต์
แต่การเขียนโปรเจ็กต์ใหม่ในปี 2026 ด้วย ภาษาที่ไม่ปลอดภัยด้านหน่วยความจำ (C++) ก็ถือว่าล้าสมัย
อย่างไรก็ตาม ถ้าเป็นแอปที่แทบไม่มีอินพุตที่ไม่น่าเชื่อถือ ก็ไม่จำเป็นต้องถูกชักจูงด้วยคำโฆษณาชวนเชื่อ (Propaganda)
_UNICODEก็สามารถทำแบบเดียวกันได้ด้วย .NET Framework ในเวลาครึ่งเดียวคิดว่าควรมีขบวนการ “NoFramework” กลับมา แล้วกลับไปสู่ยุค RAD
แต่ก็ควรคิดให้รอบคอบถ้าจะเลือก C++ สำหรับโปรเจ็กต์ใหม่
ใช้ Win32 จากภาษาแบบ memory-safe ก็ได้ — ตัวอย่างเช่น windows-rs
ตอนนั้น Borland Delphi เป็นเครื่องมือที่ได้รับความนิยมมากที่สุด
ถ้าไม่ใช่แอป WinRT, UAP หรือ UWP เดิมอยู่แล้ว ก็ควรหลีกเลี่ยง WinUI 3.0 และ WinAppSDK
ควรใช้เทคโนโลยีที่พิสูจน์ตัวเองแล้วอย่าง Win32, MFC, WinForms, WPF ต่อไปจะดีกว่า และถ้าอยู่นอก ecosystem ของ Microsoft ก็อาจพิจารณา Qt, VCL, Firemonkey, Avalonia, Uno, ImGUI
WinUI 3.0 ยุ่งเหยิงมากจนแม้แต่ Microsoft เองก็กำลังพยายามส่งต่อให้ชุมชนดูแลแบบโอเพนซอร์ส
หลังจากนั้น WinJS ก็เปลี่ยนไปเป็นเว็บเฟรมเวิร์กโอเพนซอร์ส และการสนับสนุนอย่างเป็นทางการก็สิ้นสุดลง
บล็อกโพสต์ที่เกี่ยวข้อง
ฉันเป็นนักพัฒนา embedded และการทำ โปรแกรม GUI แบบ Win32 ที่สื่อสารกับอุปกรณ์ก็ยังคงง่ายอยู่
โค้ดสมัย XP ยังทำงานได้เหมือนเดิมบน Windows 11 และแม้จะเปิดโปรเจ็กต์ VC6 ด้วย Visual Studio 2022 ก็ยัง build ผ่านได้ไม่มีปัญหา
ความเข้ากันได้ย้อนหลัง แบบนี้หาได้ยากมากบนแพลตฟอร์มอื่น
Cocoa ของ Apple แม้โครงสร้างจะดู “สง่างาม” แต่ในทางปฏิบัติกลับซับซ้อนและเอกสารก็ไม่เป็นมิตร
Win32 API แบบเพียว ๆ ยังเป็นตัวเลือกที่ใช้งานได้จริง
ถ้าทำ wrapper คล้าย MFC ขึ้นมาเองด้วย C++ ก็เสร็จได้ภายใน 2–3 สัปดาห์ และหลังจากนั้นก็จะมีอำนาจควบคุมได้เต็มที่
ด้วย ความเข้ากันได้ย้อนหลังอันแข็งแกร่ง ของ Microsoft แอปที่ใช้ Win32 จึงมีเสถียรภาพในระยะยาว
สามารถดูตัวอย่างที่อัปเดตต่อเนื่องมากว่า 10 ปีได้ ที่นี่
สีของระบบและคอนโทรลต่าง ๆ ถูก hardcode ไว้ จึงชนกับธีมมืด
มีเพียงบางส่วนของ UI เช่น เมนู, message box, file dialog เท่านั้นที่รองรับ dark mode ทำให้ความสม่ำเสมอพังไป
ดูการพูดคุยที่เกี่ยวข้องได้ในบทความนี้
ตอนนี้ยังคงดูแลต่อในรูปแบบโอเพนซอร์ส และออกมาถึงเวอร์ชัน 10 แล้ว
จากประสบการณ์ที่เคยทำแอป Windows มาหลายตัว
(1) Win32 API เก่าแล้วแต่เสถียรมาก และ
(2) UI toolkit ที่ Microsoft เป็นเจ้าของ ควรหลีกเลี่ยง — สุดท้ายแล้วก็มักต้องการการควบคุมในระดับ Win32 อยู่ดี
ตลอด 20 ปีที่ผ่านมา เทคโนโลยี UI ที่ Microsoft สร้างส่วนใหญ่ล้วนเป็นร่างแปลงของ WPF
ถ้า Microsoft พัฒนา WPF ต่อเนื่อง ป่านนี้มันคงกลายเป็น มาตรฐานของการพัฒนา UI ไปแล้ว
ในมุมผู้ใช้ แอปเนทีฟนั้นเร็วและดี แต่ฝั่งพัฒนานี่คือ ความโกลาหลที่ซับซ้อน จริง ๆ
นี่ก็เป็นเหตุผลที่แอปอย่าง Outlook และ Teams แย่ลงเรื่อย ๆ
มันยากที่จะเลียนแบบความรู้สึกแบบเนทีฟในเรื่องอย่างโฟกัสหรือการนำทางด้วยคีย์บอร์ด
ดูได้ที่ โปรเจ็กต์ Electrobun
ฉันไม่เห็นด้วยกับคำพูดที่ว่า “การทำโปรเจ็กต์ใหม่ด้วย C++ คืออาชญากรรม”
สำหรับ GUI นั้น ประสิทธิภาพและการควบคุม สำคัญกว่าความปลอดภัย และ C++ ก็ยังเป็นภาษาที่พิสูจน์ตัวเองแล้ว
Qt ก็ยังเป็นหนึ่งใน GUI framework ที่ดีที่สุดในปี 2026 และมีฟีเจอร์ด้าน memory safety ในตัว
สงสัยว่าทำไม .NET runtime รุ่นใหม่ ถึงไม่ถูกรวมมากับ Windows 11 เป็นค่าเริ่มต้น
เรื่องนี้ดูเหมือนเป็นอีกกรณีหนึ่งที่ Microsoft ยอมแพ้กับประสบการณ์ผู้ใช้ที่สม่ำเสมอ
การแจกทั้งหมดผ่าน Windows Update จึงไม่สมจริง
แต่สามารถแจกจ่ายเป็น ไฟล์ executable แบบ AOT สแตนด์อโลน ได้ (ประมาณ 9MiB)
เล็กและมีประสิทธิภาพกว่า Electron มาก
ทุกวันนี้การแพ็ก DLL ไปพร้อมกันกลับดีกว่า
จึงยากที่จะฝังไว้ใน OS
เลยแยกออกจากการอัปเดต OS เพื่อคงรอบการออกเวอร์ชันที่รวดเร็ว
หลังจากไม่ได้ใช้มานาน ฉันลองทำแอปสำหรับ Windows และ Mac ด้วย Tauri
การพัฒนาและการ build นั้นง่าย แต่เพื่อนร่วมงานกลับติดตั้งไม่ได้เพราะปัญหา code signing
บน Mac แก้ได้ด้วยคำสั่งในเทอร์มินัล แต่บน Windows ต้องปิด Smart App Control
และฟีเจอร์นี้ปิดแล้วจะเปิดกลับไม่ได้หากไม่ติดตั้งระบบใหม่
เข้าใจวัตถุประสงค์ด้านความปลอดภัย แต่ไม่คิดว่ากระบวนการติดตั้งจะยากขนาดนี้
คำตอบของคำถามที่ว่า “ทำไมไม่ใช้ Electron” นั้นง่ายมาก —
แอป Electron ให้ประสบการณ์ผู้ใช้ที่แย่
แม้การพัฒนาจะง่าย แต่ต้องแลกกับประสิทธิภาพและคุณภาพ
ถ้าอยากทำผลิตภัณฑ์ที่ดี ต่อให้ยากก็ต้องไปทาง native
ส่วนตัวฉันคิดว่า C# ดีกว่า TypeScript มาก