Wall of Text #11: C Array and Fraps

น้องเค้ามีคำถามจากการบ้านว่า

จงเปรียบเทียบระหว่าง Array ในภาษาเก่าๆ กับ Python list

ผมชอบคำถามนี้นะ คำตอบที่เค้าเขียนคือ

ในภาษา C สมาชิกของ Array ทั้งหมดจะต้องเป็น data type เดียวกันทั้งหมด และขนาดของ Array จะตายตัว แต่ใน Python list สามารถคละ data type กันได้ และสามารถเปลี่ยนขนาดของ Array ได้โดยการเพิ่มหรือลบสมาชิก

ที่น่าสนใจคือ จริงๆ แล้ว C Array ไม่ได้มีขนาดตายตัว…. มันไม่มีขนาดด้วยซ้ำ

Array ในภาษา C จริงๆ แล้วมันคือ Pointer ซึ่งเก็บที่อยู่ของข้อมูล การใช้ Pointer ในภาษา C จะประมาณนี้

ถ้าลองรันดูจะเห็นว่า output คือ 10 ถึงเราจะไม่ได้แก้ x ตรงๆ แต่เราแก้ผ่าน pointer แทน

คำสั่ง *x_ptr จะเป็นการอ่านค่าที่ตำแหน่งที่ x_ptr ชี้ไปอยู่ ซึ่งจริงๆ แล้วคำสั่งนี้มีค่าเท่ากับ x_ptr[0]… แล้ว x_ptr[1] คืออะไรล่ะ?

x_ptr[1] มีค่าเท่ากับ *(x_ptr + 1) เนื่องจากใน C สมาชิกทุกตัวใน array จะอยู่ใน memory ตำแหน่งที่ติดกันไปเรื่อยๆ และสมาชิกทุกตัวมีขนาดเท่ากัน (เพราะเป็น data type เดียวกัน) ดังนั้นถ้าเราทราบที่อยู่ของสมาชิกตัวแรก ตัวถัดไปก็คือเลื่อนไปจากสมาชิกตัวแรกเท่ากับขนาดของสมาชิก 1 ตัว

ดังนั้นตัวแปรที่เก็บ C array จริงๆ แล้วไม่ได้เก็บ array แต่เก็บตำแหน่งของสมาชิกตัวแรกเท่านั้น ส่วนการประกาศ array จริงๆ แล้วก็คือการจองพื้นที่พอให้เก็บสมาชิกใน array ตามจำนวนที่ขอ และคืนตำแหน่งของสมาชิกตัวแรกมาให้

แต่จริงๆ แล้ว เราสามารถอ่านหรือเขียนค่าไปเกินกว่าพื้นที่ที่ขอได้เช่นเดียวกัน เนื่องจาก C ไม่มีการเก็บไว้ด้วยซ้ำว่า array มีขนาดเท่าไร (แต่ไม่การันตีผลลัพท์นะว่าถ้าอ่านเขียนเกินพื้นที่ที่จองไว้จะได้ผลอย่างไร)

Portable assembly

หลังฉากของภาษา C แล้วน่าสนใจว่ามันเป็นภาษาที่ไม่ค่อยสูงกว่า assembly เท่าไรนัก มันไม่พยายามซ่อนการทำงานของคอมพิวเตอร์ ซึ่งก็ตรงตามสิ่งที่ผู้สร้าง C คิดไว้คือมันเป็นเพียงแค่ Portable Assembly

ซึ่งในภาษา C เองก็ยังมีคำสั่ง __asm__ ที่เอาไว้เขียน assembly code ผสมกับภาษา C ได้เมื่อจำเป็น

และคำสั่งนี้ก็มีใช้อยู่ในโค้ดจริงๆ ด้วย เช่นถ้าเราไปอ่านโค้ดของ H.264 decoder ก็จะเห็นว่าเค้าใช้ Assembly ผสมกับโค้ด C เพราะการ decode video นั้นอาจจะใช้ฟีเจอร์เฉพาะของ CPU เข้ามาช่วยได้ ซึ่ง compiler อาจจะไม่สามารถแปลงโค้ด C เป็นคำสั่ง CPU พวกนี้ได้ (*)

Hardware acceleration

หลายๆ อย่างที่คอมพิวเตอร์เราทำอยู่นั้น ถึงแม้ว่าคอมพิวเตอร์จะเร็วขึ้นแต่การที่ไม่มี hardware พิเศษมารองรับก็อาจจะทำให้ทำงานได้ช้าหรือทำงานไม่ได้เลย

GPU ของ Raspberry Pi นั้นสามารถถอดรหัส video H.264 (mp4) ได้สบายๆ หลายคนเอา Raspberry Pi มาลง Kodi ดูหนังซึ่งก็จะเห็นว่าภาพก็ลื่นดี แต่ถ้าโปรแกรมที่ใช้นั้นไม่รองรับการใช้ hardware acceleration แล้วก็จะพบว่า CPU ของ Raspberry Pi decode ไฟล์ mp4 ไม่ไหวเลย

บน PC ก็เช่นเดียวกัน ถ้าเราดูไฟล์วิดีโอ MP4 ในเครื่อง จะเห็นว่า CPU load จะไม่ถึง 10% เท่านั้น แต่ถ้าลองดู YouTube 4K จะพบว่า CPU ขึ้นไปสูงถึง 50-100% เลยทีเดียว เนื่องจากฟอร์แมต VP9 (ในขณะที่เขียนนี้) hardware หลายๆ รุ่นยังไม่รองรับการถอดรหัส VP9 เลยจะต้องใช้พลัง CPU ประมวลผล ซึ่งนอกจากจะหน่วงเครื่องแล้วยังเปลืองแบตเตอรี่อีกด้วย

อย่าลืมปรับเป็น 4k 60fps

สมัย Windows XP ถ้าใครเคย Capture โปรแกรมวิดีโอด้วยปุ่ม print screen ก็จะเห็นว่ากรอบที่เล่น video จะเป็นจอดำ หรือเวลากด Print screen บนเกม Full screen ก็เช่นกัน วิธีแก้ไขก็คือใช้โปรแกรมพิเศษที่จับภาพหน้าจอเกมได้ เช่น Fraps

ที่เป็นอย่างนี้ก็เพราะ Video หรือเกมก็แล้วแต่นั้น ภาพถูกสร้างขึ้นบนการ์ดจอโดยตรงโดยไม่ได้ผ่าน desktop เมื่อเรากด print screen จึงจะเห็นแค่ฉากหลังดำๆ เท่านั้น

ตั้งแต่ Windows Vista เป็นต้นมา Desktop compositing (Aero) เป็นที่นิยมมากขึ้นซึ่งทำให้ประสบการณ์ใช้งาน desktop ดีขึ้น ภาพไม่กระพริบ เวลาลากโปรแกรมไม่กระตุก (ข้อเสียคือเกมที่รันใน Windowed mode จะไม่สามารถรันเร็วกว่าเฟรมเรทของ Compositor ได้ ซึ่งถ้าใครใช้จอ 120Hz อาจจะต้องรันเกมใน Full screen แทน) ซึ่ง Desktop compositing นี้ทำงานบนการ์ดจอทำให้การทำ Print screen เปลี่ยนไปและเรามักจะสามารถ screenshot ทุกอย่างบนหน้าจอได้หมดแล้ว นอกเหนือจากเกม Full screen


ผมคิดว่าการศึกษาการทำงานของคอมพิวเตอร์เป็นเรื่องที่น่าสนใจมาก ถ้ามีคนถามว่าทำไม print screen แล้วจอดำ เราจะได้เข้าใจเหตุผลว่ามันไม่ใช่ “เพราะคุณกด print screen จอเกมไม่ได้ถ้าไม่ได้ใช้ Fraps” แต่เพราะภาพมันอยู่ที่การ์ดจอแล้วเรา print screen บน CPU ต่างหากล่ะ

Programming Languages I Write

ตอนนี้เขียนโปรแกรมอยู่หลายภาษา ก็คิดว่าอยากลองเขียนดูบ้างว่าเราคิดว่าจุดแข็งของแต่ละภาษาคืออะไร แล้วเราเลือกใช้มันยังไง

กฎส่วนตัวเราเวลาบอกว่าเขียนภาษานี้ “เป็น” พอจะใส่ใน Resume คือถ้า Ecosystem ในเรื่องนั้นมันพร้อมเราสามารถทำ Task อะไรก็ได้ในภาษานั้นๆ และเขียนออกมา Idiomatic เฉพาะตัวแบบที่ภาษานั้นๆ เขียนอยู่ด้วย

หลักๆ ที่เขียนเลยก็จะมี

  • Python
  • Go
  • JavaScript & TypeScript

ภาษาอื่นๆ ที่เคยเขียนก็จะมี Java, C, C++, Rust, Kotlin, PHP แต่ในบทความนี้คงจะไม่พูดให้ครบทุกอัน

Python

Rule of thumb ตอนนี้คือถ้ามันจะต้องต่อ database เราจะเลือกใช้ Python และ Django เท่านั้น ไม่มีอะไรที่ทำให้เราทำงานเสร็จเร็วเท่า Django อีกแล้ว

นอกจาก Django แล้ว Python ฝั่ง Data Science ก็ค่อนข้างแข็ง แต่เราไม่ค่อยได้ใช้เท่าไร แล้วก็ยังทำ scripting ต่างๆ ได้เร็ว

ข้อเสียของ Python คือมันเป็นภาษาที่ปวกเปียกมาก

Package manager มันอยู่ระหว่าง requirements.txt ที่ใช้ได้แต่ค่อนข้าง manual และไม่มี lock กับ Poetry ที่ยังไม่ดัง (และคนไปเลือกใช้ Pipenv ที่เลิกทำแล้วมากกว่า) และ Virtualenv มันค่อนข้าง Hack หน่อยๆ เมื่อเทียบกับภาษาใหม่ๆ ที่เลิกมี global package repository แล้ว

Import syntax ที่ถ้ามีไฟล์อยู่ folder ข้างๆ จะนั่งงงมากว่าต้อง import ยังไง (มันไม่มี “absolute” import มีแต่ relative โดยใช้ syntax แปลกๆ)

Type checking ที่ยังตั้งไข่มากๆ ถึงจะทำมาหลายปีแล้ว และ syntax ที่มันแปลกๆ หน่อย

Speed ของมันที่ค่อนข้างช้าในการ execute ซึ่งปกติก็จะไม่ค่อยใส่ใจ แต่ก็มีครั้งนึงที่ทำให้พลาดข้อใน Codejam มาแล้วเพราะโค้ดเหมือนกันรันใน Python เกิน 5 นาที ไม่ผ่าน ไปเขียนใหม่ใช้วิธีเดิมใน C รันจบใน 30 วินาที

Web server deployment มันที่ยังต้อง deploy WSGI container เหมือนภาษาโบราณๆ ไม่ใช่ one click และก็จะติดเรื่อง thread pool ที่ต้องมาจูน

JavaScript

ผมไม่ชอบ JavaScript เท่าไรนัก แต่จำเป็นต้องเขียนเพราะมันใช้ได้หลายที่มากๆ มันเป็นภาษาเดียวที่รันได้ใน Browser เวลาจะทำอะไรที่เขียนครั้งเดียวใช้ได้ทุกที่ต้องใช้ JavaScript เลย

ข้อดีของ JavaScript คือ syntax มันค่อนข้างมาตรฐานไม่หวือหวา แล้วพอบวก TypeScript มามันทำให้การ code project ใหญ่ๆ ทำงานงายขึ้นเพราะ editor จะฉลาดขึ้นเยอะ

ข้อเสียของ JavaScript คือภาษามันค่อนข้างฟรีสไตล์และมันไม่เก่ง Class กลายเป็นว่าคนชอบเขียนเป็น functional แต่มันก็ไม่ใช่ภาษาที่ออกแบบเป็น functional มาตั้งแต่แรก โค้ดมันก็เลยเละมาก

แล้วที่ผมไม่ชอบ functional ใน JavaScript มากคือการที่เราเอา higher order function ที่ add functionality ทีละนิด แต่ใช้ซ้อนกันเยอะๆ เวลาไล่โค้ดมันจะงง flow มากว่ามันเข้าแล้วอะไรโผล่เข้ามาตอนไหน รวมถึง syntax มันที่จะเป็น a(b(c(d))) ซึ่งไม่ค่อยเป็นธรรมชาติในการอ่านเพราะ functionality หลักมักจะอยู่ที่ d

นึกภาพว่าถ้า Unix pipe มันเขียนว่า wc(tar('xf', gzcat(file)))ก็คงใช้ลำบากกว่า gzcat file | tar xf - | wc

แล้วการเขียน helper มาทำให้มันกลายเป็นซ้ายไปขวา ก็ทำได้ยุ่งยากใน Javascript เพราะถ้าเราเขียน chain(a, instance.methodB, c, d) this ใน methodB ก็จะผิดอีก ต้องมา bind ก่อน ซึ่งไม่มีภาษาอื่นทำกัน (แล้วผมก็ยังไม่เคยเห็นว่ามี use case ไหนเลยที่จะใช้มันโดยไม่ bind)

สรุปคือมันทำได้ทุกอย่างแต่ไม่เก่งสักอย่าง แต่ก็ยังต้องใช้มันอยู่เพราะใน Browser มันผูกขาด

Node.js

ผมจำไม่ได้ว่าสมัยที่ Node.js เพิ่งมาผมคิดกับมันไว้ยังไง (สมัยนั้นเขียน PHP กับ Web.py) น่าจะไม่ชอบที่เอา JavaScript ไปรันบน server เพราะมันช้า

แต่ในปัจจุบันปรากฏว่ามันเร็วมาก เร็วกว่า Python เสียอีกเพราะ JavaScript ใน browser มีเงินลงทุนมหาศาลจากบริษัทเว็บต่างๆ

ข้อดีของ Node คือ async io ซึ่งมาแรกๆ หลายคนไม่เชื่อว่าไม่ต้องมี application server คั่นหน้าแล้ว เอา Node รับ load ได้ตรงๆ เลย

แต่ข้อเสียของ async io ใน Node คือ syntax มันไม่ค่อยสวยเท่าไรนัก ไม่ว่าจะเป็น Callback หรือ Promise + Await ก็ตามมันก็ไม่ดูดีเท่า Sequential (a().b().c() vs. await (await (await a()).b()).c())

นอกจากนี้เนื่องจาก standard library ที่มีให้ค่อนข้างจำกัด ทำให้เกิด npm ecosystem ที่บูมมากๆ อะไรก็อยู่บน npm ได้หมดแม้แต่ application อย่าง Chromium ก็โหลดผ่าน npm ได้ ข้อเสียก็คือแต่ละคนก็เลือกใช้ lib คนละตัวแตกต่างกันไป รวมถึงพอแยกกัน maintenance คุณภาพก็แตกต่างกันออกไปตั้งแต่ระดับดีมากๆ อย่าง React ไปจนถึง left-pad ที่คนทำอยู่ดีๆ ก็เอาลง

พอ community มันเปิดกว้าง มันก็กลายเป็นว่า project structure เปิดมาแต่ละอันไม่ซ้ำกันเลย เวลาอ่านก็ต้องไปนั่งไล่ก่อนว่าทางเข้าทางออกอยู่ตรงไหนบ้าง แล้วแต่ละคนก็จะทำท่าไม่เหมือนกันเลยเพราะคนไม่ค่อยใช้ Framework (อาจจะมีใช้ Next/Nuxt.js บ้างแต่ก็ไม่ใช่ทุกคนจะชอบ)

ข้อจำกัดอีกเรื่องของ Node คือมันทำอะไรที่ CPU bound ไม่ได้เลยเพราะมันเป็น single thread แถมยังไม่มีวิธีแตก thread เลยแม้แต่วิธีเดียวเนื่องจากมันมี Global lock เหมือน Python (แต่ Python ยังมี multiprocess ให้ใน standard library) แต่คิดว่าเร็วๆ นี้น่าจะมา

ตอนนี้จุดเดียวที่เรายังเลือก Node.js อยู่คือ Socket.io เนื่องจากภาษาอื่นๆ ในยุคก่อนมันทำ Streaming ไม่ได้ (thread pool จะเต็มเอา) พอมาถึงยุคนี้ที่ใครๆ ก็ทำ async แล้วก็เลยโดดข้ามไป WebSocket เลย จะมีแต่ Socket.io เท่านั้นที่ทำได้ทั้ง Long polling และ WebSocket ได้ในเวลาเดียวกัน และใช้โค้ดเดียวกัน

Go

ช่วงที่เขียน Rust ผมบอกว่าจะไม่เขียน Go เดี๋ยวใจแตก แล้วก็เป็นอย่างนั้นจริงๆ

Go แก้ทุกปัญหาของ Node ที่ผมบ่นไว้ด้านบนได้เกือบหมด

ภาษามันเป็น Static typed ในขณะเดียวกัน map เป็น first class data structure ของภาษา ไม่เหมือนภาษายุคก่อนหน้า และมันยังไม่กลัวที่จะใช้ interface{} type

Go มี Standard library + golang.org/x ที่ค่อนข้างดีทำให้ third party ไม่ต้องนั่งตบตีกันว่า HTTP client ต้องใช้ตัวไหน (Go ก็มีให้เลือก แต่ส่วนมากคนก็ยังเชียร์ http.Client ใน standard library อยู่)

Syntax ของภาษาที่เรียบง่ายมากๆ ทีม Go เคยบอกว่าเขียน Go คือเขียนโค้ด ไม่ใช่ไปนั่งเขียน Type

Go มี gofmt และ compiler เองก็เป็น linter ในตัว (no unused variable, enforce ชื่อ function ตัวใหญ่เป็น public เป็นต้น) ทำให้โค้ด Go ไม่ว่า project ไหนส่วนมากก็แทบจะเป็นแบบเดียว

ตั้งแต่เขียนโค้ดมาคิดว่าเรา contribute Go pull request มากที่สุดแล้วถึงจะมาเขียนหลังสุด เพราะมันไม่ต้องกลัวว่า maintainer จะด่าอะไรเราในโค้ดมั้ย

(แอบชอบสไตล์ modulename.FunctionName() ของ Go ด้วย อ่านแล้วมันเคลียร์เลยทันทีว่า function มาจากไหน และตัวใหญ่ทำให้สะดุดตาโดดข้ามไปอ่านง่าย ต่างกับใน JS ที่คนชอบ destructure เอาแต่ functionName มา มันเพิ่ม cognitive load ต้องจำว่าตัวแปรนี้มาจากไหน)

วิธีแก้ปัญหา async แล้ว syntax ไม่สวยของ Go คือเลิกทำ async ทุกอย่างกลายเป็น sync อะไรที่อยากจะรันข้างหลังค่อยสั่งเปิด goroutine ซึ่งเพิ่มแค่คำว่า go ข้างหน้า (เทียบกับ Python thread นี่เขียนกันหลายบรรทัดเลย)

ที่คนเขียน Go อาจจะไม่รู้คือที่เห็น Go เป็น sync จริงๆ ด้านล่างมันก็เป็น async คล้ายๆ กับที่ Node ทำ แล้วมันใช้ scheduler เป็น abstraction ทำให้มันกลายเป็น sync (เหยด!)

แล้ว Go ไม่มี Global lock เหมือน Python หรือ JavaScript มันทำให้ performance ยิ่งดีขึ้นไปอีก แต่ก็อาจจะต้องระมัดระวัง race condition เองมากขึ้น สำหรับเราเราคิดว่ามันตื่นเต้นและเป็นประสบการณ์ที่อยากเรียนรู้ เพราะภาษาอื่นที่เขียนมี global lock หมดเลย

เวลา Deploy Go ก็ทำได้ง่ายกว่าภาษาอื่นๆ มาก เพราะมัน compile มาได้ binary ตัวเดียวใหญ่ๆ (20-200MB) แล้วคลิกเดียวรันได้เลย

ทุกวันนี้เราเลยพบว่ามาเขียน Go บ่อยขึ้นมาก แทบทุกอย่างที่ไม่ต้องแตะ Database ก็จะไปเขียน Go แม้แต่ scripting บางทียังเลือกใช้ Go เพราะมัน Deploy ได้ง่ายกว่าเยอะ

ข้อเสียของ Go คือ module ซึ่งมันมาช้าไปหน่อย และก็ยังออกแบบมาไม่ค่อยดีอยู่ดี ปัญหาที่เห็นคือระบบ versioning ที่ไม่เคลียร์เท่า Node.js และการใช้ URL import ทำให้เวลา fork ต้องแก้ทั้ง project (แล้วเกิดอยากจะ merge กลับจะทำได้ยาก)

Go ไม่มี generic ทำให้บางอย่างทำได้ยาก โดยเฉพาะการ search in array ที่เป็น operator ใน Python แต่ใน Go ต้องนั่งเขียน loop ทุกครั้ง

Go ไม่มี implements ที่เอาไว้เช็คว่า function/struct นี้ satisfy interface แล้วหรือยัง ถ้าไม่ตรง มันจะไป error ตรง call site แทนที่จะ error ที่ struct (ซึ่งลำดับการเขียนโค้ด เรามักจะเขียน struct ให้เสร็จก่อนแล้วค่อยไป create + pass ไปยังคนที่ใช้)

แล้วด้วยความที่มันเป็น static typed ก็คิดว่ายังไม่อยากเอามันไปทำงานที่ใช้ JSON มากๆ เท่าไร

Java

ยังไม่แน่ใจว่าไม่ชอบ Java หรือไม่ชอบ Spring แต่ที่แน่ๆ คือไม่ชอบที่ Java เพราะพยายาม violate YAGNI ทุกวันนี้ยังตั้งคำถามอยู่ว่าถ้าให้เรา rebuild ecosystem Java ให้ใช้ standard เหมือน Python (แต่ไม่แก้ compiler) จะอยากเขียน Java มั้ย

ปัญหาของ Java คือ type system มัน strict เกินไป เวลาจะเพิ่มนิดๆ หน่อยๆ ทำไม่ได้ เช่น ถ้ามี request object แล้วอยากจะฝากข้อมูลไปบน request object ก็ต้องทำ object อีกตัวมาครอบแล้ว delegate เข้าไปใน request (เทียบกับ JavaScript/Python ที่ใช้ req.data ได้เลย หรือ Go ก็มี embed struct ไปบน struct อีกตัว)

คนเขียน Java ก็เลยจะนิยมว่าทำ interface ไว้ให้ทุกอย่าง “เผื่อแก้” data ต่างๆ บน class อื่น ต้องวิ่งผ่าน getter เท่านั้น (ใน Go เรา mutate field บน http.Request กันสนุกเลย)

สองคือภาษามันเก่าแล้วมันไม่มี first class map เหมือนภาษาใหม่ๆ ทำให้ท่าที่จะเขียนโค้ดง่ายขึ้นกลับกลายเป็นโค้ดยุบยับที่อ่านลำบาก

สามคือภาษามันไม่มี first class function & class เวลาส่ง function และ class เข้าไปมันจะฟีลเหมือนเขียน reflection หน่อยๆ ซึ่งทำให้หลายๆ ท่าลำบากในการเขียน

หลายๆ ฟีเจอร์พวกนี้ถูกแก้ด้วย code generation บนภาษาใหม่ๆ เช่น Kotlin, Groovy หรือ Scala ที่ข้างหลังก็ไป generate class ออกมาอยู่ดี

PHP

ตอนเรียนจบ PHP เคยอยู่ใน resume ทุกวันนี้หลายๆ ครั้งก็ยังวิเคราะห์ PHP design อยู่ว่ามันพลาดไปตรงไหน

เราคิดว่า Design ของ PHP ออกแบบมาน่าสนใจ มันเป็นภาษากระแสหลักภาษาเดียวที่ออกแบบมาให้เขียนเว็บเพียงอย่างเดียว

ไม่มีภาษาอื่นไหนที่เขียน hello world เป็นหน้าเว็บได้ใน 1 บรรทัด อย่างน้อยๆ ก็ต้องเขียนส่วนที่รับ request object เข้ามาก่อน แต่ใน PHP มันอยู่ใน global มาตั้งแต่แรก

แล้วถ้าอยากจะ set header สักตัว ก็แค่เพิ่ม header("Content-Type: application/json"); จากหนึ่งบรรทัดกลายเป็นสองบรรทัด

ตัวภาษาเองยัง compact พอที่จะเป็น template engine ในตัวด้วย อย่างที่ WordPress ทำอยู่

แต่ community PHP อยู่ดีๆ ก็อยากเป็น Java แล้วทิ้งพวกนี้ไปโดยไปทำ Symfony และ Laravel มา

จากภาษาที่ echo ก็ออกหน้าจอได้แล้ว กลายเป็นว่าต้อง return Response object กลับไปเหมือนภาษาอื่นๆ แถมยังพยายามทำเป็น OOP จัดๆ ทั้งๆ ที่ตอน PHP4 ไม่มี class เลย พวก function ต่างๆ เช่น echo หรือ header กลายเป็นสิ่งที่ไม่ควรใช้

ก็ไม่รู้ว่า PHP พลาดไปตรงไหน เพราะ Zend หรือเปล่านะที่พยายามทำให้ PHP กลายเป็นการค้าแล้วก็ทำให้มันขายได้ หรือเพราะช่วงเปลี่ยนผ่านที่คนยังไม่ซื้อ VPS กันแล้วจำเป็นต้องใช้ PHP (แล้วที่ JavaScript ทุกวันนี้มันเป็นแบบนี้ ก็เพราะเหตุผลนี้หรือเปล่านะ?)

ทุกวันนี้ก็ยังฝันอยู่ว่าถ้าสร้าง PHP ขึ้นมาใหม่ในยุคนี้จะออกแบบมันยังไงดี แล้วมีใครทำแล้วหรือยังนะ?

ที่เอา PHP ออกจาก resume ตอนนี้เพราะตั้งแต่มันมี Symfony และ Laravel มา ก็ไม่ได้ตามแล้ว เคยเขียนอยู่ 2 project ใน stack นั้นได้ ก็ยังคิดว่า Django ดีกว่า

สองคือ คนเขียน PHP แย่ๆ มีเยอะในประเทศนี้เลยไม่อยากเสี่ยงไปทำงานกับคนพวกนี้ (เหมือนที่ 37signals ใช้ Ruby เพราะใครเขียนเป็นในยุคนั้นคือเซียน จะได้คัดกรองคนง่าย) สมัยที่เคยทำ freelance มา ทุก project ที่มี PHP code เรา penetration test แล้วเจอช่องโหว่ทุกอัน พอแจ้งไปก็มักจะมีข้ออ้างที่ไม่สนใจจะแก้ (เคยเจอขนาดว่าแก้ให้แล้วมา overwrite ทับ)

สามคือคนที่ยังใช้ PHP อยู่ ส่วนนึงคือติดอยู่ใน environment ที่ต้องใช้ PHP (และมักจะเป็นรุ่นเก่า) เราคิดว่าพอหลุดพ้นจาก environment นั้นไปได้แล้ว มันเปิดกว้างให้ใช้ภาษาอะไรก็ได้

Rust

เคยจับ Rust มาผ่านๆ ด้วยเหตุผลว่าเราไม่มีภาษาไหนเขียน low level เลย (ตอนนั้นยังไม่ได้เขียน Go)

ปัจจุบันก็คงคิดว่าไม่กลับไปเขียนแล้ว เพราะ ecosystem มันพร้อมเลยสำหรับงาน high level และ borrow checker ที่ทำให้เรา unproductive (ถ้ายอมมี garbage collection แล้วเขียนโปรแกรมได้เร็วขึ้น 10 เท่า สำหรับงานที่ผมทำมันไม่เลือกก็พลาดแล้ว)

It Depends

สรุปว่าเราเลือกใช้ตามนี้

  • ถ้าทำเว็บ ต่อ Database ใช้ Python และ Django
  • ถ้าทำอะไรที่ไม่ต้องต่อ Database (เช่น stateless API) อาจจะใช้ Go
  • บน browser ยังคงต้องใช้ JavaScript อยู่
  • Scripting ต่างๆ ถ้าเอาเร็วใช้ Python
  • แต่ถ้าจะเอาความ Deploy ง่าย ใช้ Go

ตอนนี้ยังไม่มีแผนจะเรียนภาษาเพิ่ม เพราะดูจะยังไม่มี use case ไหนขาดตกจนใช้ภาษาที่เขียนแก้ไม่ได้เลยเลยสักภาษา แล้วพอเรียนภาษาใหม่แต่ไม่ได้ใช้มันก็จะลืม (เคยจะลองเขียน Ruby แต่พอพบว่ามันทับซ้อนกับ Python ก็ไม่ได้ใช้ ลืมหมดแล้ว)

สุดท้ายแล้วถึงแต่ละภาษาจะมีจุดแข็ง – จุดอ่อนต่างๆ และมี clear use case ที่เราเลือกใช้ แต่หลายๆ ครั้งก็จะเลือกตามนั้นไม่ได้ถ้าทำหลายคน แล้วคนอื่นไม่ได้เขียนด้วย อันนั้นก็ต้องคุยกันอีกที