7 สิ่งที่ได้เรียนรู้จากการสร้างเฟรมเวิร์ก TUI สมัยใหม่
(textualize.io)- ในกระบวนการพัฒนา Textual สามารถสร้าง แอนิเมชัน TUI ที่ลื่นไหล ได้แม้อยู่บนโปรโตคอลเทอร์มินัลแบบเก่า แต่ต้องจัดการวิธีรีเฟรชหน้าจอและการซิงก์เอาต์พุตอย่างรอบคอบ
- หากต้องการลดการกะพริบ สิ่งสำคัญคือไม่ล้างหน้าจอแล้วค่อยวาดใหม่ แต่ให้เขียนทับ, เขียนลง standard output ในครั้งเดียว, และใช้โปรโตคอล Synchronized Output
dict.items()view และ@lru_cacheของ Python มีประโยชน์ต่อการคำนวณส่วนต่างของการเรนเดอร์และการปรับแต่งฟังก์ชันขนาดเล็กที่ถูกเรียกถี่ ๆ โดยมี implementation แบบ C ของ CPython ช่วยรองรับ ประสิทธิภาพของแคช- อ็อบเจ็กต์ที่เกือบไม่เปลี่ยนแปลง, ไดอะแกรมอักขระกล่อง Unicode และ
fractions.Fractionต่างช่วยเพิ่ม ความแม่นยำ ในด้านการให้เหตุผล·การแคช·การทดสอบ, ความเข้าใจเอกสาร, และการคำนวณเลย์เอาต์ตามลำดับ - Emoji บนเทอร์มินัลคาดเดาได้ยากเพราะความต่างของเวอร์ชัน Unicode, ความกว้างอักขระ และการเรนเดอร์หลาย code point ดังนั้นในการใช้งานจริง Emoji แบบเรียบง่ายระดับ Unicode 9 จึงเสถียรกว่า
แอนิเมชันบนเทอร์มินัลและการควบคุมการกะพริบ
- เทอร์มินัลอีมูเลเตอร์สมัยใหม่ทำงานอยู่บนโปรโตคอลแบบเก่า แต่หลาย implementation ใช้เทคนิคกราฟิกที่พบได้ในวิดีโอเกมด้วย
- เอฟเฟกต์ภาพบนเทอร์มินัลเกิดอาการกะพริบหรือ tearing ได้ง่าย แต่ถ้ารักษาเงื่อนไขบางอย่างก็สามารถทำ แอนิเมชันที่ลื่นไหล ได้
- วิธีแรกในการลดการกะพริบคือไม่ใช้ “clear แล้ว draw” แต่เป็นการ เขียนทับเนื้อหาเดิม
- ถ้าล้างหน้าจอแล้วค่อยเพิ่มเนื้อหาใหม่ อาจเห็นเฟรมว่างหรือเฟรมที่วาดไม่ครบชั่วขณะ
- วิธีที่สองคือเขียนข้อมูลอัปเดตลง standard output ด้วย write เดียว
- หากเรียก
file.writeหลายครั้ง ผู้ใช้อาจเห็นสถานะอัปเดตเพียงบางส่วนได้
- หากเรียก
- วิธีที่สามคือใช้โปรโตคอล Synchronized Output
- หากแจ้งจุดเริ่มต้นและจุดสิ้นสุดของเฟรมให้เทอร์มินัลรู้ เทอร์มินัลก็สามารถใช้สิ่งนี้เพื่อช่วยอัปเดตแบบไม่กะพริบได้
- Textual ตั้งเป้าไว้ที่ 60fps และที่สูงกว่านั้นอาจไม่ได้ให้ความต่างที่สังเกตได้มากนัก
- ไม่ใช่ทุกแอนิเมชันจะมีคุณค่าเท่ากัน
- เอฟเฟกต์อย่างแถบด้านข้างที่เลื่อนเข้ามาจากซ้ายอาจดูดี แต่ไม่ได้เพิ่มประโยชน์ต่อประสบการณ์ผู้ใช้มากนัก
- การเลื่อนอย่างลื่นไหลช่วยให้รักษาตำแหน่งปัจจุบันในข้อความยาว ๆ ได้
- ด้วยเหตุนี้ Textual จึงมีแผนจะเพิ่มกลไกสำหรับปิดแอนิเมชันบางประเภท
หา diff ของการเรนเดอร์ด้วย DictView
keys()และitems()ของdictใน Python จะคืนค่าKeysViewและItemsViewตามลำดับ ซึ่งมีอินเทอร์เฟซคล้ายเซต- กระบวนการจัดเลย์เอาต์ของ Textual จะสร้าง render map ซึ่งเป็นการแมประหว่าง Widget กับตำแหน่งบนหน้าจอ
- วิธีเดิมทำให้แม้จะเปลี่ยนตำแหน่งของ Widget เพียงตัวเดียว ก็ยังรีเฟรชทั้งหน้าจออย่างสิ้นเปลือง
- หากใช้ symmetric difference ของ
ItemsViewสองชุด ก็จะหา item ที่เพิ่มใหม่หรือเปลี่ยนไปได้- การทำงานนี้ประมวลผลในระดับ C
- Textual ใช้สิ่งนี้เพื่อหา area บนหน้าจอที่เปลี่ยนไปเมื่อคุณสมบัติ CSS เปลี่ยน และนำไปสู่ การอัปเดตที่ปรับแต่งแล้ว
lru_cache และการปรับแต่งฟังก์ชันขนาดเล็ก
@lru_cacheใน standard libraryfunctoolsเป็น decorator สำหรับแคชค่าที่ฟังก์ชันคืนกลับ- การตั้ง
maxsizeช่วยจำกัดไม่ให้แคชโตแบบไร้ขีดจำกัด lru_cacheของ CPython ใช้ implementation แบบ C จึงทำงานได้เร็วทั้งกรณี cache hit และ miss- ใน Textual มีฟังก์ชันขนาดเล็กจำนวนมากที่ไม่ได้ช้าในตัวเอง แต่ถูกเรียกบ่อยมาก และหลายฟังก์ชันก็เหมาะกับการแคช
- โดยทั่วไปการตั้ง
maxsizeราว 1000~4000 ก็เพียงพอที่จะทำให้การเรียกส่วนใหญ่กลายเป็น cache hit - เมื่อใช้แคช ควรตรวจดู
cache_info()- หากแคชมีประสิทธิภาพ ก็ควรเห็นว่า
hitsเพิ่มเร็วกว่าmisses
- หากแคชมีประสิทธิภาพ ก็ควรเห็นว่า
- เมธอด
intersectionที่คำนวณส่วนทับซ้อนของพื้นที่สี่เหลี่ยมสองส่วน แม้งานต่อครั้งจะไม่มาก แต่เมื่อถูกเรียกหลายพันครั้งก็ได้ประโยชน์จากการแคช
ความเรียบง่ายที่ได้จากอ็อบเจ็กต์ไม่เปลี่ยนแปลง
- ใน Python ไม่มีอ็อบเจ็กต์ immutable อย่างแท้จริง แต่ tuple,
NamedTupleและ frozen dataclass ก็ให้ประโยชน์ได้มาก - ข้อจำกัดที่ว่าอ็อบเจ็กต์เปลี่ยนค่าไม่ได้อาจดูเหมือนเป็นการจำกัดโดยไม่จำเป็น แต่ในโค้ดจริงกลับช่วยได้บ่อยครั้ง
- โค้ดใน Textual ที่ใช้อ็อบเจ็กต์ immutable นั้น ให้เหตุผลง่าย, เหมาะกับการแคช และเอื้อต่อการทดสอบ
- เหตุผลสำคัญคือมันทำให้เขียนโค้ดที่ไม่มีผลข้างเคียงได้ง่ายขึ้น
- เมื่อส่งคลาสอินสแตนซ์เข้าไปในฟังก์ชัน จะหลีกเลี่ยงผลข้างเคียงในลักษณะเดียวกันได้ยากกว่า
Unicode art และการทำเอกสาร
- เมื่ออธิบายเรื่องเชิงเทคนิคด้วยคำพูดอย่างเดียวได้ยาก ไดอะแกรมที่ทำจากอักขระกล่อง Unicode จะช่วยให้เข้าใจเอกสารได้มาก
- ใน docstring ของ Textual มีการใช้ ไดอะแกรมอักขระกล่อง เพื่ออธิบายเมธอดที่แบ่งพื้นที่ออกเป็นสี่ sub-region
- ไดอะแกรมแบบนี้ไม่ได้แทนที่ docstring ที่เขียนดีอยู่แล้ว แต่เมื่อใช้ร่วมกันจะช่วยเพิ่มความเข้าใจได้
- ใช้ monodraw เป็นเครื่องมือวาดไดอะแกรม
- Monodraw ใช้ได้เฉพาะบน macOS
- อาจมีทางเลือกอื่นสำหรับแพลตฟอร์มอื่น
ลดความคลาดเคลื่อนของเลย์เอาต์ด้วย fractions.Fraction
- โมดูล
fractionsใน standard library ของ Python มีมาตั้งแต่ Python 2.6 Fractionเป็นอีกวิธีหนึ่งในการแทนตัวเลข และเมื่อสร้างแล้วก็สามารถใช้แทน float ได้- จำนวนทศนิยมแบบลอยตัวมีข้อจำกัดที่รู้จักกันดี
- ตัวอย่างเช่น
0.1 + 0.1 + 0.1 == 0.3ให้ค่าเป็นFalse
- ตัวอย่างเช่น
- ใน Textual ปัญหา ความคลาดเคลื่อนจากการปัดเศษของ floating point เกิดขึ้นในเลย์เอาต์ที่แบ่งหน้าจอตามสัดส่วนหลายระดับ
- เช่น เมื่อมีพาเนลกว้าง 1/3 ของหน้าจอ แล้วนำ 2/3 ที่เหลือไปแบ่งต่อ อาจเกิดช่องว่างขนาดหนึ่งตัวอักษรได้
- หากเปลี่ยนจาก float เป็น
Fractionก็จะหลีกเลี่ยงความคลาดเคลื่อนจากการปัดเศษแบบนี้ได้- ผลรวมของ
Fraction(1, 10)จำนวนสามตัว เท่ากับFraction(3, 10)
- ผลรวมของ
- ในตัวอย่างการแบ่งอักขระ 24 ตัวออกเป็น 7 ส่วน เวอร์ชัน float ขาดไปหนึ่งตัวอักษร แต่เวอร์ชัน Fraction เติมความยาวได้ครบ
ความยากของ Emoji บนเทอร์มินัล
- การรองรับ Emoji เป็นปัญหาต่อเนื่องมาตั้งแต่ยุคแรกของ Rich และ Textual ก็รับปัญหานี้ต่อมาเช่นกัน
- บนเทอร์มินัล อักขระมักกินพื้นที่หนึ่งช่องหรือสองช่อง และบางอักขระมีความกว้างเป็น 0
- อักขระ CJK ใช้พื้นที่มากกว่าตัวอักษรตะวันตกเป็นสองเท่า
- ถ้าต้องการจัดกึ่งกลางหรือวาดกรอบแบบพื้นฐาน ก็จำเป็นต้องรู้ความกว้างบนเทอร์มินัลของข้อความที่จะพิมพ์ออกมา
- ดังนั้น
len(text)เพียงอย่างเดียวจึงไม่บอกความกว้างที่ข้อความกินจริงบนเทอร์มินัล
- ในฐานข้อมูล Unicode มีการแมประหว่างอักขระความกว้างเดี่ยวและความกว้างคู่
- Rich และ Textual จะค้นฐานข้อมูลนี้สำหรับทุกอักขระที่ต้องแสดงผล
- งานนี้ไม่เบา แต่ด้วยการออกแบบวิศวกรรมและการแคชก็ทำให้เร็วพอได้
- แม้ Emoji จะอยู่ในฐานข้อมูล Unicode แต่เมื่อมี Emoji ใหม่เพิ่มเข้ามาในแต่ละรีลีสของ Unicode ผลลัพธ์ก็ยังคาดเดาได้ยาก
- เมื่อพิมพ์ Emoji ใหม่ลงเทอร์มินัล มันอาจแสดงผลเป็นหนึ่งช่องหรือสองช่องก็ได้
- หรืออาจเรนเดอร์ไม่ถูกต้องเลยก็ได้
- ไม่มีวิธีมาตรฐานที่เชื่อถือได้ในการตรวจจับเวอร์ชัน Unicode ที่เทอร์มินัลอีมูเลเตอร์ใช้อยู่
- ไม่มี environment variable มาตรฐานด้วย
- แม้จะมี heuristic ที่พิมพ์ sequence เฉพาะแล้วถามตำแหน่งเคอร์เซอร์ แต่ในการทดสอบ ต่อให้สมมติว่ารู้ฐานข้อมูล Unicode แล้ว เทอร์มินัลก็ยังเรนเดอร์ Emoji อย่างคาดเดาไม่ได้
- Emoji ที่ประกอบจากหลาย code point ทำให้ปัญหาซับซ้อนขึ้นอีก
- ตัวอย่างเช่น 👨🏻🦰 ประกอบด้วย 4 code point
- เทอร์มินัลบางตัวอาจเรนเดอร์มันเป็น 4 ตัวอักษร, 2 ตัวอักษร, 1 ตัวอักษร, กว้างหนึ่งช่องหรือสองช่อง, หรือเป็น
?4 ตัวก็ได้
- ในทางปฏิบัติ หากใช้ Emoji ระดับ Unicode 9 จะค่อนข้างเสถียรบนหลายแพลตฟอร์ม
- ต่อให้ Emoji ใหม่และอักขระหลาย code point จะแสดงได้ดีบนเทอร์มินัลปัจจุบัน ก็ควรหลีกเลี่ยงไว้ก่อน
Textualize กำลังรับสมัคร
- Textualize กำลังรับสมัครเพื่อสร้างเฟรมเวิร์ก TUI ที่สามารถเข้ามาแทนบทบาทบางส่วนของเบราว์เซอร์ได้
- ดูข้อมูลงานได้ที่ Jobs
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
น่าสนใจที่ นักพัฒนา TUI ทุกคนสุดท้ายก็ต้องเจอกับ Unicode และการจัดการตัวอักษรนานาชาติกับอีโมจิให้ถูกต้องก็กลายเป็นโปรเจกต์แยกอีกชิ้นหนึ่งที่ใหญ่พอ ๆ กับ หรือใหญ่กว่าโปรเจกต์ TUI เดิม
เรื่องเดียวกันนี้เคยเกิดกับ rivo/tview ด้วย และแพ็กเกจ rivo/uniseg ที่ทำขึ้นมาจากเรื่องนั้นก็ทำให้รู้ว่าผู้ดูแลไลบรารี TUI อื่น ๆ ก็เจอปัญหาเดียวกัน
ท้ายที่สุด เพราะความกว้างของตัวอักษรไม่ได้ถูกทำให้เป็นมาตรฐาน และเทอร์มินัลก็ซับซ้อน ทุกคนจึงต้องคิดวิธีแก้ของตัวเอง ผู้เขียนบทความรองรับแค่ Unicode 9 แต่ปัจจุบัน Unicode อยู่ที่ 15.1 จึงยากจะมั่นใจว่านี่เป็นทางออกที่ดีหรือไม่ เพราะสักวันหนึ่งคงมีคำบ่นว่าอีโมจิหรือตัวอักษรนานาชาติบางตัวแสดงผลผิด
กำลังดูแลไลบรารี TUI สองตัวที่ใช้เทคนิคนี้อยู่ และการรองรับอีโมจิก็แทบจะยอดเยี่ยมมาก หนึ่งในนั้นใช้ไลบรารี uniseg ด้วย
https://mitchellh.com/writing/grapheme-clusters-in-terminals
ความไม่พอใจใหญ่ที่สุดต่อ textual คือมัน พยายามจะเป็นเหมือน React เข้าใจได้ว่าทำไมถึงเป็นแบบนั้น เพราะเป็นเฟรมเวิร์กยอดนิยมที่หลายคนคุ้นเคย แต่ไม่คิดว่านั่นเป็นวิธีที่ดีในการสร้างส่วนติดต่อผู้ใช้
แนวทาง reactive design เองเป็นเส้นทางที่พิสูจน์มาแล้ว และการวางสถาปัตยกรรมระบบบนวิธีที่รู้กันว่าทำงานได้ดีก็เป็นวิธีที่ดีในการลดความเสี่ยงของโปรเจกต์
แต่การเอา CSS เวอร์ชันดัดแปลง มาใช้ด้วยนั้นดูจะเกินไป โมเดลของ React ชอบคอมโพเนนต์ที่เป็นมาตรฐาน ขณะเดียวกันก็ทำลายแนวคิดของ CSS ไปแล้วหลายด้าน และการที่นักพัฒนาปรับแต่งคอมโพเนนต์ด้วย CSS ดูเหมือนเป็นผลข้างเคียงจากวิวัฒนาการของ React มากกว่าจะเป็นสถาปัตยกรรมที่สมเหตุสมผล
ตอนที่ลองใช้ครั้งล่าสุดต้องใช้ CSS และไม่มีคอมโพเนนต์มาตรฐานดี ๆ เลย ต้องสร้างเอง แทนที่คอมโพเนนต์จะเป็นคลาส Python เดียวที่ encapsulate ได้อย่างสะอาด เอกสารทางการกลับเป็นแนวสร้างคอมโพเนนต์รายการแล้วตกแต่งด้วยสไตล์ชีตภายนอก
ใน Python ควรมีวิธีที่ชัดเจนหนึ่งวิธีในการทำสิ่งใดสิ่งหนึ่ง และถ้าเป็นไปได้ก็ควรมีแค่วิธีเดียว การตาม React ใกล้เกินไปทำให้ดูเหมือนกำลังตามเอานิสัยแย่ที่สุดของชุมชน JavaScript มาด้วย
เรื่องที่ว่าไม่มีคอมโพเนนต์มาตรฐานดี ๆ ก็ดูเหมือนจะไม่ได้เช็กมานานแล้ว: https://textual.textualize.io/widget_gallery/
ไม่จำเป็นต้องสร้างคอมโพเนนต์เองด้วย และ CSS ก็เป็นสิ่งที่รู้อยู่แล้ว กลับกัน ความแตกต่างเล็กน้อยเรื่อง เลย์เอาต์ และจุดที่เบี่ยงออกจาก CSS ต่างหากที่ทำให้สับสนเป็นบางครั้ง
ให้นึกภาพว่าในหน้าต่าง GUI ปกติมีคอมโพเนนต์หนึ่งเป็นหน้าต่างเทอร์มินัล อยากรู้ว่ามีของแบบนี้ไหม หรือควรใช้แค่ text view แบบฟอนต์ความกว้างคงที่
TUI นี้ดูสวย แต่ยากจะจินตนาการถึงสถานการณ์ที่ผมจะใช้จริงและถึงขั้นยอมจ่ายเงิน อาจเป็นเพราะผมไม่ได้อยู่ในสภาพแวดล้อมที่เหมาะก็ได้ แต่จากประสบการณ์ของผม ผู้คนมักพอใจกับเครื่องมือที่มินิมอลจริง ๆ หรือไม่ก็หันไปทำ GUI เพื่อให้ผู้ใช้พอใจทันที
ตัวอย่างเช่น ลิงก์ YouTube ในบทความแสดงตารางที่ไฮไลต์เซลล์ แต่ผมไม่เข้าใจว่าทำไมต้องทำสิ่งนั้นเป็น TUI ถ้าต้องย้ายเซลล์ที่กำลังแอ็กทีฟซึ่งถูกไฮไลต์อยู่ สุดท้ายก็ต้องมีฟีเจอร์อื่น ๆ อีกมาก และท้ายที่สุดน่าจะต้องมี GUI ที่เหมาะสม
อย่างไรก็ตาม ผมก็ไม่แน่ใจว่า “GUI ที่เหมาะสม” คืออะไร เทอร์มินัลมีมาตรฐานเปิดที่ใช้กันแพร่หลาย และโปรโตคอลเหล่านี้มีความเป็นมาตรฐานและทำงานร่วมกันได้มากกว่าเฟรมเวิร์ก GUI ใด ๆ อีก ทั้งยังรองรับในทุกระบบ
หากเพิ่มองค์ประกอบอย่างวิดีโอเข้าไปและอุดช่องว่างบางส่วนได้ การจะแข่งขันกับเบราว์เซอร์หรือพาประสบการณ์การใช้งานคอมพิวเตอร์ทั้งหมดมาไว้ในเทอร์มินัลก็ดูสมเหตุสมผล
แน่นอนว่าเมื่อเทอร์มินัลเพิ่มวิดีโอเข้าไป ก็เท่ากับลอกเลียน rendering pipeline ของ “GUI ที่เหมาะสม” แต่ก็เป็นการปรับปรุงประสบการณ์เทอร์มินัล และถ้าประสบความสำเร็จอย่างมาก ก็อาจมองได้ว่าเป็นการนำ ความเรียบง่ายแบบ UNIX มาสู่ GUI
พนักงานทำงานด้วยคีย์ลัดได้อย่างมีประสิทธิภาพมาก และทุกครั้งที่มีคนพยายามเปลี่ยน AS400 ให้เป็นเว็บแอปสมัยใหม่ ประสิทธิภาพการทำงานจะตกลง 100 เท่า
เป็นสถานการณ์เดียวกับความแตกต่างระหว่างเซียน Vim/Emacs กับ GUI ที่ดูเนี้ยบแต่ไม่มีคีย์ลัด
สามารถให้ผู้ใช้ SSH เข้าเซิร์ฟเวอร์แล้วใช้แอป TUI เหมือนเป็นเชลล์ได้ ซึ่งผมยอมรับว่าเป็นสถานการณ์ที่ค่อนข้างฝืน
โดยส่วนตัว Textual ใช้งานแล้วรู้สึกแปลก ๆ นิดหน่อย แต่ก็ดีกว่า ncurses อย่างไรก็ตาม มันไม่ได้ให้ผลลัพธ์ที่ผมต้องการ แอปพลิเคชัน TUI แบบเมนเฟรมยุคเก่า ให้ความรู้สึกว่ามีประสิทธิภาพมาก
บางครั้งมันทำงานได้ดี แต่ค่อนข้างจำกัด เช่น การใช้ X forwarding บนการเชื่อมต่อที่มีแบนด์วิดท์สูง กรณีอื่น ๆ GUI จะหน่วงไปหมด
GUI แบบข้อความดูเหมือนจะเก็บข้อดีของทั้งสองฝั่งได้
วิธี “เคล็ดลับแรกคืออย่าลบ แต่ให้เขียนทับ” เป็นแบบเดียวกับวิธีที่ใช้เขียน เกมยุคก่อน DirectX
เขียนลง framebuffer โดยตรง และแทนที่จะล้างทั้งหมดแล้ววาดใหม่ ก็วาดเฉพาะส่วนที่เปลี่ยนกับบริเวณรอบ ๆ/ด้านล่างใหม่ เพราะไม่มีเวลาพอที่จะอัปเดตทั้งหน้าจอให้ทัน
แบบแรกคือเขียนลงบัฟเฟอร์อื่น แล้วเมื่อจบเฟรมก็คัดลอกบัฟเฟอร์ทั้งหมดทีเดียว เพื่อให้แต่ละพิกเซลเปลี่ยนเพียงครั้งเดียว บัฟเฟอร์นี้โดยปกติอาจเป็น RAM ปกติ ไม่ใช่ video RAM
แบบที่สองคือเขียนลงบัฟเฟอร์อื่นใน video RAM แล้วเปลี่ยนรีจิสเตอร์ของฮาร์ดแวร์กราฟิก เพื่อให้พิกเซลที่แสดงบนจอภาพถูกสร้างจากบัฟเฟอร์นั้น
จุดแลกเปลี่ยนไม่เหมือนกัน การคัดลอกทั้งบัฟเฟอร์มีต้นทุนสูง ส่วนการเปลี่ยนรีจิสเตอร์ที่อยู่มีต้นทุนต่ำ แต่รายละเอียดของรีจิสเตอร์อาจขึ้นกับฮาร์ดแวร์ และตอนนั้นก็ยังไม่มีเฟรมเวิร์กไดรเวอร์กราฟิกที่เป็นเรื่องเป็นราว
ถ้าจะทำแค่ “buffer flipping” แม้ตอนเรนเดอร์ไปยังบัฟเฟอร์นอกจอ ก็ยังต้องส่งพิกเซลไปยัง video RAM ซึ่งเท่าที่จำได้ การเข้าถึง video RAM ช้ากว่า RAM ปกติ ในทางปฏิบัติมันเป็นโครงสร้างแบบ NUMA ดังนั้นขึ้นอยู่กับว่าพิกเซลถูกวาดทับบ่อยแค่ไหน การเรนเดอร์ใน RAM ปกติอาจเร็วกว่าโดยรวม แม้จะรวมการคัดลอกครั้งสุดท้ายแล้วก็ตาม
อย่างไรก็ตาม ผมมองว่าความสามารถในการบอกเทอร์มินัลถึงจุดเริ่มต้นและจุดสิ้นสุดของเฟรมนั้นทรงพลังกว่ามาก
ผมไม่เข้าใจจริง ๆ ว่าทำไมวิศวกรซอฟต์แวร์ถึงสนใจ TUI กันมากขนาดนั้น ผมชอบ โปรแกรมบรรทัดคำสั่ง ที่ดี แต่ TUI ไม่ดึงดูดผม
แถมยังมีกลิ่นอายแฮ็กเกอร์ด้วย สไตล์ไม่ได้ถูกแยกออกจากคอนเทนต์อย่างเข้มงวด และตัวเลือกสไตล์ที่ปรับได้ก็มีจำกัด แอป TUI จึงมักบรรจบไปที่สไตล์เดียวกัน สไตล์นั้นทำให้นึกถึงหนังแฮ็กเกอร์และไซไฟเท่ ๆ
มันไม่ใช่พื้นที่ที่ดีไซเนอร์องค์กรชอบ และบริษัทต่าง ๆ ก็ไม่ได้ใช้ TUI เป็นเหตุผลในการปิดการขายกับองค์กรหรือผู้บริโภค พอไม่มีแรงกดดันเชิงพาณิชย์แบบนั้น TUI จึงถูกออกแบบโดยนักพัฒนาเพื่อนักพัฒนา
ดังนั้นมีม TUI จึงเสริมแรงตัวเอง นักพัฒนาเห็นและใช้ TUI แล้วรู้สึกว่ามันเป็นเครื่องมือที่มักทำโดยคำนึงถึงนักพัฒนา จากนั้นก็อยากสร้าง TUI ของตัวเองขึ้นมาอีก
การข้ามแพลตฟอร์มแทบได้มาฟรี ๆ ไม่ต้องสร้าง GUI ที่สมบูรณ์แบบระดับพิกเซล และที่จริงก็ทำไม่ได้อยู่แล้ว อีกทั้งไม่ต้องมีไอคอนหรือกราฟิก เพราะแสดงกราฟิกไม่ได้
คุณยังใช้ terminal emulator พร้อมฟอนต์ที่ชอบต่อไปได้ ขณะเดียวกันก็มีอินเทอร์เฟซแบบ GUI
แอป TUI ทั้งหมดที่ผมเคยใช้จนถึงตอนนี้มีเวลาตอบสนองต่ำ แอป GUI ส่วนใหญ่ก็เร็วเช่นกัน แต่แอปที่ช้าจนน่าหงุดหงิดทั้งหมดที่เคยเจอล้วนเป็นแอป GUI
มี ascii-draw เป็นทางเลือกแทน Monodraw
https://github.com/Nokse22/ascii-draw
หลังจาก TurboVision แทบทุกอย่างที่ผมเห็นแม้จะได้รับแรงบันดาลใจมา แต่ในทางปฏิบัติกลับยังไม่สมบูรณ์พอ พอลองใช้ toolkit จริง ๆ ก็น่ารักดี แต่รู้สึกเหมือนยังทำไม่เสร็จ
พูดอีกอย่างได้ว่า TUI framework จำนวนมากที่ผมเห็นเป็นเฟรมเวิร์กแบบ “มีแนวทางชัดเจน”
บางทีผมอาจจะทึ่มและไม่ค่อยสร้างสรรค์ก็ได้ แต่ตั้งแต่ย้ายจาก DOS ไป Linux ในยุค 90 ผมก็ไม่เคยทำงานได้มีประสิทธิภาพเท่าตอนทำกับ B800 อีกเลย
เป็นไปได้ว่าผมใช้เวลานานกว่าจะเข้าใจความจำเป็นของ double buffering, ความต่างระหว่าง text mode แบบ local direct กับ terminal รวมถึง escape sequence แต่ถึงอย่างนั้น ทุกครั้งที่พยายามทำอะไรเองด้วย ncurses ก็แทบจะยอมแพ้เพราะความไม่พอใจที่ชัดเจน มันต่างกันสิ้นเชิงกับสิ่งที่ทำได้ด้วยอุดมคติอันเรียบง่ายของ B800
ไม่รู้ว่ามุมมองของผมถูกบดบังไปทั้งเมืองหรือเปล่า แต่ GUI framework หลังยุค message pump ทั้งหมดนี่เข้าใจยากเหลือเกิน
โดยเฉพาะผมไม่เข้าใจว่า framework เชิงวัตถุแก้ปัญหา UI แบบหลายเธรดให้จริง ๆ ได้อย่างไร ใน Win32 ผมใส่ renderer หลักไว้ในเธรด แล้วให้ renderer รอง ๆ สร้าง model อยู่ข้าง ๆ จากนั้นอัปเดตเฉพาะส่วนต่าง โค้ดก็ไม่ได้ใหญ่จนรับมือไม่ไหวแต่อย่างใด
ถ้าจะรัน kitty ก็ทำอะไรได้มากกว่านั้นอีกเยอะ: https://m.youtube.com/watch?v=ft1Q-DwGWIs
https://notcurses.com/
ทั้งสองตัวใช้ protocol เดียวกันเพื่อแสดงกราฟิกได้ ถ้าจำเป็นต้องใช้กราฟิกจริง ๆ terminal แทบจะไม่ใช่คำตอบที่ถูกต้องอยู่แล้ว แต่บางครั้งก็มีประโยชน์กับของเล็ก ๆ อย่างไอคอน
น่าสนใจตรงที่กำลังรับสมัครงานอยู่ อยากรู้ว่าจะวางแผนหาเงินจาก TUI framework อย่างไร
เผื่อเป็นข้อมูล ผมลองประเมินไลบรารี TUI แบบคอมไพล์ได้ราว 12 ตัว และ FTXUI ใช้ง่ายและเสถียรที่สุด
https://github.com/ArthurSonzogni/FTXUI
เป็นเครื่องมือที่ดีสำหรับทำ dashboard แบบ interactive ที่รองรับทั้งคีย์บอร์ดและเมาส์