7 Hal yang Dipelajari dari Membangun Framework TUI Modern
(textualize.io)- Proses pengembangan Textual menunjukkan bahwa animasi TUI yang mulus bisa dibuat bahkan di atas protokol terminal lama, tetapi cara pembaruan layar dan sinkronisasi output harus ditangani dengan cermat
- Untuk mengurangi flicker, penting untuk menimpa layar tanpa menghapusnya, menulis ke standard output sekaligus, dan memanfaatkan protokol Synchronized Output
- View
dict.items()dan@lru_cachedi Python berguna untuk menghitung delta render dan mengoptimalkan fungsi kecil yang sering dipanggil, sementara implementasi C di CPython mendukung performa cache - Objek yang hampir immutable, diagram karakter kotak Unicode, dan
fractions.Fractionmasing-masing meningkatkan akurasi dalam penalaran, caching, dan pengujian; pemahaman dokumentasi; serta perhitungan layout - Emoji di terminal sulit diprediksi karena perbedaan versi Unicode, lebar karakter, dan rendering multi-codepoint, sehingga dalam praktiknya Emoji sederhana setingkat Unicode 9 lebih stabil
Animasi terminal dan pengendalian flicker
- Emulator terminal modern berjalan di atas protokol lama, tetapi banyak implementasinya menggunakan teknik grafis yang juga dipakai dalam video game
- Efek visual terminal rentan mengalami flicker atau tearing, tetapi animasi yang mulus bisa diwujudkan jika beberapa kondisi dipenuhi
- Cara pertama untuk mengurangi flicker adalah menimpa konten yang sudah ada, bukan “clear lalu draw”
- Jika layar dihapus lalu konten baru ditambahkan, frame kosong atau frame yang baru tergambar sebagian dapat terlihat sesaat
- Cara kedua adalah menulis pembaruan ke standard output dengan satu kali write
- Jika
file.writedipanggil berkali-kali, pembaruan parsial bisa terlihat oleh pengguna
- Jika
- Cara ketiga adalah menggunakan protokol Synchronized Output
- Dengan memberi tahu terminal kapan frame dimulai dan berakhir, terminal dapat memanfaatkannya untuk pembaruan tanpa flicker
- Textual menjadikan 60fps sebagai acuan, dan di atas itu perbedaannya mungkin tidak terlalu terlihat
- Tidak semua animasi memiliki nilai yang sama
- Efek seperti sidebar yang meluncur dari kiri memang terlihat bagus, tetapi mungkin tidak memberi manfaat nyata bagi pengalaman pengguna
- Scroll yang mulus membantu mempertahankan posisi saat ini pada teks panjang
- Karena alasan ini, Textual berencana menyediakan mekanisme untuk mematikan animasi tertentu
Mencari delta render dengan DictView
keys()danitems()padadictPython masing-masing mengembalikanKeysViewdanItemsView, serta menyediakan antarmuka yang mirip set- Proses layout Textual membuat render map, yaitu pemetaan antara Widget dan posisi layar
- Pada pendekatan sebelumnya, meski hanya posisi satu Widget yang berubah, seluruh layar diperbarui secara boros
- Dengan menggunakan symmetric difference dari dua
ItemsView, item yang baru muncul atau berubah dapat diperoleh- Operasi ini diproses di level C
- Saat properti CSS berubah, Textual menggunakannya untuk menemukan area layar yang berubah dan melakukan pembaruan yang dioptimalkan
lru_cache dan optimisasi fungsi kecil
@lru_cachedari pustaka standarfunctoolsadalah decorator untuk melakukan cache pada nilai kembalian fungsi- Dengan mengatur
maxsize, pertumbuhan cache tanpa batas dapat dibatasi lru_cachedi CPython menggunakan implementasi C sehingga cepat baik saat cache hit maupun miss- Textual memiliki fungsi-fungsi kecil yang tidak lambat tetapi dipanggil sangat sering, dan banyak di antaranya cocok untuk di-cache
- Biasanya,
maxsizesekitar 1000–4000 sudah cukup untuk membuat sebagian besar pemanggilan menjadi cache hit - Saat menggunakan cache,
cache_info()perlu diperiksa- Pada cache yang efektif,
hitsdiharapkan bertambah lebih cepat daripadamisses
- Pada cache yang efektif,
- Metode
intersectionyang menghitung area tumpang tindih dua persegi panjang tidak memiliki beban kerja besar, tetapi dipanggil ribuan kali sehingga mendapat manfaat dari caching
Kesederhanaan dari objek immutable
- Python tidak memiliki objek immutable dalam arti yang benar-benar ketat, tetapi tuple,
NamedTuple, dan frozen dataclass memberi banyak manfaat - Batasan bahwa objek tidak bisa diubah mungkin terlihat seperti pembatasan arbitrer, tetapi dalam kode nyata sering kali membantu
- Di Textual, kode yang menggunakan objek immutable lebih mudah dinalar, serta menguntungkan untuk cache dan pengujian
- Alasan utamanya adalah karena lebih mudah menulis kode tanpa efek samping
- Saat meneruskan instance class ke fungsi, lebih sulit menghindari efek samping dengan cara yang sama
Seni Unicode dan dokumentasi
- Ketika materi teknis sulit dijelaskan hanya dengan kata-kata, diagram yang dibuat dengan karakter kotak Unicode sangat membantu pemahaman dokumentasi
- Docstring Textual menggunakan diagram karakter kotak untuk menjelaskan metode yang membagi sebuah area menjadi empat sub-area
- Diagram seperti ini tidak menggantikan docstring yang ditulis dengan baik, tetapi jika digunakan bersama dapat meningkatkan pemahaman
- Untuk membuat diagram, digunakan monodraw
- Monodraw khusus untuk macOS
- Mungkin ada alternatif di platform lain
Mengurangi error layout dengan fractions.Fraction
- Modul
fractionsdi pustaka standar Python sudah ada sejak Python 2.6 Fractionadalah cara lain untuk merepresentasikan angka, dan setelah dibuat dapat digunakan sebagai pengganti float- Floating point memiliki keterbatasan yang sudah dikenal
- Misalnya,
0.1 + 0.1 + 0.1 == 0.3bernilaiFalse
- Misalnya,
- Di Textual, error pembulatan floating point menjadi masalah pada layout yang membagi layar ke beberapa rasio
- Dalam situasi panel selebar 1/3 layar dan sisa 2/3 dibagi lagi, bisa muncul celah selebar satu karakter
- Mengganti float dengan
Fractiondapat menghindari jenis error pembulatan seperti ini- Jumlah tiga
Fraction(1, 10)sama denganFraction(3, 10)
- Jumlah tiga
- Dalam contoh membagi 24 karakter menjadi 7 bagian, versi float kekurangan satu karakter, tetapi versi Fraction mengisi seluruh panjangnya
Sulitnya Emoji di terminal
- Dukungan Emoji sudah menjadi masalah sejak awal Rich, dan Textual mewarisi masalah yang sama
- Di terminal, karakter biasanya menempati satu atau dua kolom, sementara sebagian karakter memiliki lebar 0
- Karakter CJK menempati ruang dua kali lebih besar daripada alfabet Barat
- Untuk melakukan formatting dasar seperti perataan tengah atau menggambar kotak, lebar terminal dari teks yang akan dicetak harus diketahui
- Karena itu,
len(text)saja tidak cukup untuk mengetahui lebar yang ditempati di terminal
- Database Unicode memiliki pemetaan karakter lebar tunggal dan lebar ganda
- Rich dan Textual melakukan lookup ke database ini untuk setiap karakter yang dicetak
- Pekerjaan ini tidak ringan, tetapi dengan engineering dan caching dapat dibuat cukup cepat
- Meski Emoji termasuk dalam database Unicode, Emoji baru ditambahkan pada setiap rilis Unicode baru sehingga hasilnya sulit diprediksi
- Jika Emoji baru dicetak di terminal, ia bisa ditampilkan selebar satu atau dua kolom
- Bisa juga tidak dirender dengan benar
- Tidak ada cara standar untuk mendeteksi secara andal versi Unicode yang digunakan emulator terminal
- Tidak ada environment variable standar
- Ada heuristik yang mencetak sequence tertentu lalu menanyakan posisi kursor, tetapi dalam pengujian, meski merasa mengetahui database Unicode, terminal tetap merender Emoji secara tidak terprediksi
- Emoji multi-codepoint membuat masalah menjadi lebih rumit
- Misalnya 👨🏻🦰 terdiri dari 4 codepoint
- Sebuah terminal bisa merendernya sebagai 4 karakter, 2 karakter, 1 karakter, satu kolom atau dua kolom, atau 4 tanda
?
- Secara praktis, memakai Emoji dari Unicode 9 relatif stabil di berbagai platform
- Emoji baru dan karakter multi-codepoint sebaiknya dihindari meskipun tampak baik di terminal saat ini
Rekrutmen Textualize
- Textualize sedang merekrut untuk membangun framework TUI yang dapat menggantikan sebagian peran browser
- Informasi lowongan dapat dilihat di Jobs
1 komentar
Komentar Hacker News
Menarik bahwa semua pengembang TUI pada akhirnya terbentur Unicode, dan pekerjaan menangani karakter internasional serta emoji dengan benar menjadi proyek terpisah yang besarnya mirip atau bahkan lebih besar daripada proyek TUI aslinya
Hal yang sama terjadi di rivo/tview, dan lewat paket rivo/uniseg yang dibuat sebagai hasilnya, saya tahu bahwa para maintainer library TUI lain juga mengalami masalah yang sama
Pada akhirnya, karena lebar karakter tidak distandardisasi dan terminal itu kompleks, semua orang menciptakan solusinya masing-masing. Penulis artikel hanya mendukung Unicode 9, sementara Unicode saat ini sudah 15.1, jadi suatu saat pasti akan ada keluhan bahwa emoji atau karakter internasional tertentu dirender dengan keliru; sulit memastikan apakah ini solusi yang baik
Saya memelihara dua library TUI yang memakai teknik ini, dan dukungan emoji-nya nyaris sangat baik. Salah satunya juga memakai library uniseg
https://mitchellh.com/writing/grapheme-clusters-in-terminals
Keluhan terbesar saya terhadap textual adalah bahwa ia berusaha menjadi seperti React. Saya mengerti alasannya, karena React adalah framework populer yang akrab bagi banyak orang, tetapi saya tidak menganggapnya sebagai cara yang baik untuk membuat antarmuka pengguna
Desain reaktif itu sendiri adalah jalur yang sudah teruji, dan menyandarkan desain sistem pada pendekatan yang diketahui bekerja dengan baik memang cara yang bagus untuk mengurangi risiko proyek
Namun memakai sampai varian CSS di sana terasa berlebihan. Model React, yang lebih menyukai komponen terstandardisasi, dalam banyak hal sudah merusak konsep CSS, dan pengembang yang mengustomisasi komponen dengan CSS lebih terlihat seperti efek samping evolusi React daripada arsitektur yang benar-benar sah
Terakhir kali saya mencobanya, saya harus memakai CSS, dan karena tidak ada komponen standar yang bagus, saya harus membuatnya sendiri. Alih-alih komponen menjadi satu kelas Python yang terenkapsulasi rapi, dokumentasi resmi menunjukkan cara membuat komponen daftar lalu menghiasnya dengan stylesheet eksternal
Di Python, seharusnya ada satu cara yang jelas untuk melakukan sesuatu—dan kalau bisa, hanya satu. Dengan mengikuti React terlalu dekat, ini tampak seperti ikut meniru bahkan kebiasaan terburuk komunitas JavaScript
Sepertinya sudah cukup lama sejak Anda mengecek soal tidak adanya komponen standar yang bagus: https://textual.textualize.io/widget_gallery/
Saya juga tidak perlu membuat komponen sendiri, dan CSS sudah saya kenal. Justru sedikit perbedaan layout dan bagian-bagian yang menyimpang dari CSS kadang membingungkan
Bayangkan satu komponen di dalam jendela GUI biasa berupa jendela terminal. Saya penasaran apakah hal seperti ini ada, atau apakah harus memakai tampilan teks dengan font monospace saja
TUI ini memang cantik, tetapi sulit membayangkan situasi di mana saya benar-benar akan memakainya sampai membayar. Mungkin saja saya tidak berada di lingkungan yang tepat, tetapi berdasarkan pengalaman saya, orang-orang biasanya puas dengan alat yang benar-benar minimalis, atau langsung mencoba memuaskan pengguna dengan GUI
Misalnya, tautan YouTube di tulisan itu menampilkan tabel yang menyorot sel, tetapi saya tidak tahu mengapa itu harus dibuat sebagai TUI. Jika sel aktif yang disorot harus bisa dipindahkan, pada akhirnya akan dibutuhkan banyak fitur lain juga, dan tampaknya pada akhirnya akan perlu GUI yang layak
Namun saya tidak begitu tahu apa yang dimaksud dengan “GUI yang layak”. Terminal memiliki standar terbuka yang digunakan luas, dan protokol-protokol ini lebih standar dan lebih interoperabel daripada framework GUI mana pun, serta didukung di semua sistem
Jika elemen seperti video ditambahkan ke sini dan beberapa celah ditutup, bersaing dengan browser atau membawa seluruh pengalaman komputasi ke terminal juga tampak masuk akal
Tentu saja, jika terminal menambahkan video, itu berarti meniru pipeline rendering dari “GUI yang layak”, tetapi itu adalah upaya memperbaiki pengalaman terminal, dan jika sukses besar, bisa juga dilihat sebagai membawa kesederhanaan ala UNIX ke GUI
Para staf bekerja sangat efisien dengan pintasan keyboard, dan setiap kali ada yang mencoba mengganti AS400 dengan aplikasi web modern, produktivitas turun 100 kali lipat
Situasinya seperti perbedaan antara pengguna mahir Vim/Emacs dan GUI yang terlihat mulus tetapi tidak memiliki pintasan keyboard
Pengguna bisa masuk ke server lewat SSH dan memakai aplikasi TUI seperti shell, meski saya mengakui itu skenario yang agak dipaksakan
Secara pribadi, Textual terasa agak aneh dipakai, tetapi lebih baik daripada ncurses. Namun tetap tidak memberi hasil yang saya inginkan. Aplikasi TUI bergaya mainframe lama terasa sangat efisien
Kadang bisa berjalan baik, tetapi terbatas, misalnya saat memakai X forwarding pada koneksi berbandwidth besar. Dalam kasus lain, GUI menjadi benar-benar lamban
GUI berbasis teks tampaknya bisa mengambil kelebihan dari kedua sisi
Cara “trik pertama adalah menimpa, bukan menghapus” sama seperti cara game sebelum DirectX ditulis
Menulis langsung ke frame buffer, lalu alih-alih menghapus semuanya dan menggambar ulang, hanya menggambar ulang bagian yang berubah beserta area di sekitar dan di bawahnya. Itu karena tidak ada waktu untuk memperbarui seluruh layar tepat waktu
Pertama, menulis ke buffer lain, lalu saat frame selesai, menyalin seluruh buffer sekaligus agar setiap piksel hanya berubah satu kali. Buffer ini biasanya bisa berupa RAM biasa, bukan video RAM
Kedua, menulis ke buffer lain di dalam video RAM, lalu mengubah register hardware grafis agar piksel yang ditampilkan di monitor dihasilkan dari buffer tersebut
Trade-off-nya berbeda. Menyalin seluruh buffer itu mahal, sedangkan mengubah register alamat murah. Namun detail register bisa bergantung pada hardware, dan belum ada framework driver grafis yang layak
Untuk sekadar melakukan “buffer flipping”, saat merender ke buffer di luar layar pun piksel harus dikirim ke video RAM, dan seingat saya akses video RAM lebih lambat daripada RAM biasa. Karena pada dasarnya strukturnya seperti NUMA, tergantung seberapa sering piksel digambar ulang, merender di RAM biasa secara keseluruhan bisa lebih cepat, meski termasuk penyalinan terakhir
Namun saya melihat kemampuan untuk memberi tahu terminal awal dan akhir sebuah frame sebagai sesuatu yang jauh lebih kuat
Saya benar-benar tidak tahu mengapa software engineer begitu tertarik pada TUI. Saya suka program command line yang bagus, tetapi TUI tidak menarik bagi saya
Selain itu ada nuansa hacker. Gaya tidak terlalu dipisahkan dari konten, dan opsi gaya yang bisa disesuaikan juga terbatas, sehingga aplikasi TUI umumnya mengerucut ke satu gaya. Gaya itu mengingatkan pada film hacker dan fiksi ilmiah yang keren
Ini juga bukan ranah yang disukai desainer korporat, dan perusahaan tidak menutup penjualan ke enterprise atau konsumen dengan menjadikan TUI sebagai alasan. Karena tidak ada tekanan komersial semacam itu, TUI dirancang oleh developer untuk developer
Karena itu meme TUI memperkuat dirinya sendiri. Developer melihat dan memakai TUI, merasakan bahwa itu biasanya alat yang dibuat dengan developer sebagai target, lalu ingin membuat TUI mereka sendiri
Lintas platform hampir gratis, tidak perlu membuat GUI yang sempurna sampai tingkat piksel—dan sejak awal itu memang tidak mungkin—serta tidak perlu ikon atau grafik. Karena memang tidak bisa menampilkan grafik
Anda bisa tetap memakai emulator terminal dengan font pilihan Anda, sambil memiliki antarmuka seperti GUI
Semua aplikasi TUI yang pernah saya pakai sejauh ini memiliki waktu respons rendah. Aplikasi GUI umumnya juga cepat, tetapi semua aplikasi yang terasa sangat lambat dan membuat frustrasi adalah aplikasi GUI
Ada ascii-draw sebagai alternatif Monodraw
https://github.com/Nokse22/ascii-draw
Hampir semua yang saya lihat setelah TurboVision memang terinspirasi olehnya, tetapi pada praktiknya kurang matang. Saat benar-benar mencoba memakai toolkit-nya, rasanya lucu, tetapi seperti belum selesai
Dengan kata lain, bisa juga dibilang banyak framework TUI yang saya lihat adalah framework yang “sangat beropini”
Mungkin saya memang lamban dan kurang kreatif, tetapi sejak pindah dari DOS ke Linux pada era 90-an, saya belum pernah seproduktif saat bekerja dengan B800
Mungkin saya butuh waktu lama untuk memahami perlunya double buffering, perbedaan antara mode teks langsung lokal dan terminal, hingga escape sequence. Meski begitu, setiap kali mencoba membuat sesuatu sendiri dengan ncurses, rasa tidak puas yang jelas membuat saya hampir menyerah. Itu sama sekali berbeda dari apa yang bisa dilakukan dengan ideal sederhana B800
Entah pandangan saya tertutup sebesar satu kota atau bagaimana, tetapi semua framework GUI setelah message pump benar-benar sulit saya pahami
Khususnya, saya tidak mengerti bagaimana framework berorientasi objek benar-benar menyelesaikan masalah UI multi-threaded. Di Win32, saya menaruh renderer utama di sebuah thread, sementara renderer pendukung membuat model di samping lalu hanya memperbarui perbedaannya. Kodenya tidak sampai membengkak hingga tak tertangani
Kalau akan menjalankan kitty, Anda bisa melakukan jauh lebih banyak daripada itu: https://m.youtube.com/watch?v=ft1Q-DwGWIs
https://notcurses.com/
Keduanya bisa menampilkan grafis menggunakan protokol yang sama. Kalau benar-benar membutuhkan grafis, terminal hampir tidak pernah menjadi solusi yang tepat. Namun, kadang berguna untuk hal-hal kecil seperti ikon
Menarik bahwa mereka sedang merekrut. Saya penasaran bagaimana mereka berencana menghasilkan uang dengan framework TUI
Sebagai referensi, saya pernah mengevaluasi sekitar 12 library TUI yang bisa dikompilasi, dan FTXUI adalah yang paling mudah digunakan dan paling stabil
https://github.com/ArthurSonzogni/FTXUI
Ini alat yang bagus untuk membuat dashboard interaktif yang mendukung keyboard maupun mouse