ยำ TypeScript รวมมิตร

Pasin Sukjaimitr
Sep 2, 2018 · 3 min read

เปิดหัวมางงอีกละ 555

อ่ะเข้าเรื่องเลย บล็อคบ่นเกี่ยวกับ programming เหมือนเดิมไม่รู้จะมีประโยชน์ต่อใครเปล่า แต่ถ้าใครอ่านแล้วช่วยเสนอความคิดกับสิ่งที่ผมเจอ จะขอบคุณมากๆเพราะรู้สึกเหมือนตัวเองเดินหลงทางอีกละ

ถ้าใครเคยอ่านบล็อคเก่าของผม ศาสนาเพื่อโปรแกรม จะกล่าวถึงประสบการณ์ช่วงกำลัง hype กับ FP (functional programming) ก็พยายามฝึก Clojure มาเรื่อยๆ ก็รู้สึกตัวเองชอบมันเลยล่ะ (เกี่ยวกับเนื้อหา เดี๋ยวพูดถึงต่อ 55)

จากบล็อคเก่าเหมือนเดิม ผมทำงานกับ angular มาประมาณ 2 ปีแล้ว โดยใช้ตั้งแต่ angularJS จนถึง angular 6 ในปัจจุบัน โดยเริ่มจาก angularJS แล้วมีบางสิ่งบางอย่างที่ผมรู้สึกไม่ชอบ จนตัดสินใจเปลี่ยนไป angular2

ผมไม่รู้คนอื่นเป็นเหมือนผมหรือเปล่า แต่ผมก่อนหน้านี้เวลาอยากลอง technology อะไรใหม่ๆ จะเริ่มจากอ่าน guide ของ docs และเขียนตามไปเรื่อยๆ พอติดปัญหาทีก็ google ทีดูตัวอย่างตาม github หาคำตอบตาม stack overflow ไปเรื่อยๆ โดยไม่ได้มีความสนใจจะหาหนังสือที่มีคนเรียบเรียงไว้มาอ่านเลย (อย่าว่าแต่หนังสือเลย บางที docs ก็อ่านแบบงงๆ ไม่ได้อ่านละเอียดอ่านแบบทำได้เป็นพอ)

ผลคือผมติดนิสัยทำอะไรแบบรีบๆ จะเขียนใช้งานตรงไหนก็ไปหาตรงจุดที่จะใช้แค่นั้น ผลที่ตามมาจากการทำแบบนี้ในแง่ programming แน่นอน! คุณต้องได้รับ code ที่โคตร complex ตามมาตอบแทนคุณแบบสาสมเลย คุณจะรู้สึกได้ต่อเมื่อระบบคุณใหญ่ขึ้นเรื่อยๆ ถ้าใครทำ project ที่เสร็จแล้วคือเสร็จ ไม่ได้พัฒนาต่อวิธีการเบื้องต้นอาจจะถูกต้อง แต่มันมีจริงๆเหรอ? project ในลักษณะนั้น

อ้างอิงด้านบน

ประสบการณ์ที่ผมทำคือ ผมเขียน angular2 ตอนที่ยังไม่มี style guide ชัดเจนในแบบปัจจุบัน มีแค่ตัวอย่างโปรเจคที่ออกมา และผมก็เดาวิธีเขียนเอาเองจากตัวอย่าง ซึ่งพอมีอะไรนอกเหนือจากตัวอย่างก็ตามสไตล์ตัวเอง ไป search จาก stack overflow แล้วก็แปะๆ ตามเค้าไป (zombie code) ทุกคนน่าจะรู้ว่า angular นั้นต้องใช้ typescript เป็นภาษาหลักในการเขียน โดยตอนแรกผมคิดเอาเองว่า typescript เป็น strict type อารมณ์เหมือน java ผมอยากให้งานออกมาดีที่สุด ผมก็พยายามเอา OOP เข้าไปใส่เต็มที่ ทุก method ทุก attribute มี type และ access modifier กำกับเอาไว้หมด

แต่พองานเริ่มเยอะ ?

ข้อเสียอย่างนึงของ strict type ที่เขียนในรูปแบบ OOP ที่เห็นได้ชัดเจนเลยคือ คุณจะทำอะไรขึ้นมาเพิ่มคุณต้องเขียน code เพิ่มค่อนข้างเยอะ ซึ่งมันจะทำให้งานคุณช้า ยิ่งผมสลับไปเขียน Clojure ซึ่งเขียนสนุกกว่าเยอะด้วยแล้ว แน่นอนผมจมอยู่กับ strict type ได้ไม่นานพองานเริ่มเยอะ + เร่ง ด้วยความชุ่ยส่วนตัว ผมก็เจอวิธีการเขียนมันให้เร็วขึ้นด้วยการใส่ type เป็น any เม่งให้หมดทุกอย่างเลย จะได้ไม่ต้องมานั่งคิดนั่ง design เราต้องทำงานให้เสร็จตาม timeline ไปก่อน เดี๋ยวค่อยมาแก้กันทีหลัง (เกลียดความคิดตรงนี้ของตัวเองมาก เพราะมาสังเกตุได้จริงๆว่า เดี๋ยวค่อยแก้ที่หลังมันไม่มีจริง เพราะงานมันก็มาอยู่เรื่อยๆ ไม่ได้มีเวลาว่างมาให้ แก้อีกรอบหรอก)

ทำไปเรื่อยๆผมรู้สึกได้ว่าโปรเจคผมห่างไกลจากคำว่า DRY มากๆ มันถูกรื้อมาเขียนซ้ำตลอดเวลา service ที่ตอนแรกผมแยกเอาไว้พอมีการเปลี่ยน feature ผมต้องแก้ service ก็ต้องมานั่งไล่ test ซ้ำเรื่อยๆอยู่ดี

เละครับเละ ไม่ได้มีข้อดีของการเปลี่ยนผ่าน technology ที่ตัดสินใจไว้ตอนแรกเลย สุดท้ายก็เละอยู่ดี ไปทำงานแต่ละวันก็หมดอาลัยตายอยาก แก้อย่างที่ต้องแก้ไปเรื่อยๆ วันๆ พอหดหู่มากๆเข้าก็พยายามหนีด้วยการ ไปหาอ่านภาษาอื่นทำโปรเจคอื่น ซึ่งพออ่านมากๆเข้าก็เริ่มเห็นข้อดีของภาษาอื่น เริ่มไม่อยากทำโปรเจคปัจจุบัน

หลังจากพยายามหนีอยู่พักนึงผมก็ระลึกได้ว่า มันเป็นงานของผมเองแม้ผมจะมีคนมาคอยบอกว่าควรจะทำแบบนี้ๆแล้วผมทำตาม แต่คนที่ตัดสินใจที่จะทำออกมาแบบนี้มันก็ผมเองทั้งนั้น คงถึงเวลาที่จะโล๊ะโปรเจคของผมใหม่อีกรอบ

ผมกลับมาอ่าน style guide ของ angular ใหม่อีกรอบ ผมไม่อยากพลาดแบบเดิม ผมอยากให้ project ของผม clean และ style ไปในทางเดียวกับคนอื่นมากที่สุด (ยังคงเชื่อในข้อดีของการ scale โปรเจคและทีมไปด้วยกันของ angular 555)

ปรากฎว่าหลังจากผมพยายามมานั่งไล่ดูโปรเจคชาวบ้านเค้า ผมดันไปเจอว่ามีหลายโปรเจคเลยที่ที่เค้าเขียนแบบไม่กำกับ type ไว้ ผมก็ เห้ย! มันทำได้ด้วยเหรอเขียนโดยไม่กำกับ ซึ่งพอผมไปหาอ่านดูคือ typescript เวอร์ชั่น 2.4 + อนุญาติให้ไม่ต้องเขียนกำกับได้

เนื่องจากความ noob เหมือนเดิม ผมก็เริ่มคิดตามละ WTF #@#! มึงเกิดมาเป็น typescript ทำไม? ชื่อมึงก็บอกอยู่ “type” script ซึ่งอ่านๆเรื่อยๆ ยิ่งหลงทาง การเขียนผมยิ่งมั่วละ ตกลงกุจะใส่ type หรือไม่ใส่ดี ทำไมหลอกกันแบบนี้ support การไม่ใส่โดยปล่อยให้มันเป็น any นี่คือจะออกมาบอกว่า “เราเห็นใจคุณนะเราจะ support ความชุ่ยของคุณละกัน” อย่างนี้เหรอ?

งงอยู่พักใหญ่ๆ จนมาเจอคำว่า “gradual typing” อ่านเจอก็เริ่มสงสัยมันคืออะไร ซึ่งไปตามหาอ่านเรื่อยๆอยู่นานมากจึงเข้าใจว่าทำไมมันถึง support การทำในลักษณะนี้

Gradual Typing

คือการรวมกันระหว่าง static และ dynamic type ถ้าพูดมาแค่นี้ หลายๆคนอาจจะยังนึกภาพไม่ออก “อ่าว แล้วไปรวมทำไมอ่ะ เราเขียน dynamic เพราะต้องการความยืดหยุ่น มีโครงสร้าง structure ที่สวยกว่า อ่านง่ายกว่า ทำโปรเจคได้เร็วกว่า เขียน static เพราะอยากให้ debug ง่ายกว่า เวลาเขียนมั่นใจว่ามี attribute นั้นจริงๆใน flow ของโปรแกรมเอามารวมกัน เขียนบ้าง ไม่เขียนบ้าง มันก็เละดิ” ใช่ครับมันเป็นอย่างนั้นจริงๆ จริงๆแล้วการเขียนในลักษณะนี้ ออกแบบมาเพื่อ support ความขี้เกียจของ developer ที่อยากใช้งานข้อดีของทั้งสองภาษาครับ ผมขอเล่าเคสสั้นๆ ลองนึกภาพตามกันดูนะครับ ขี้เกียจทำภาพ หรือ code 555

Static Type

ปัญหา Integration Legacy Code

สมมุติเรามี library นึงของ project เก่าอยู่ซึ่งการทำงานเหมือนจะเอามาใช้กับ project ใหม่เราได้ แต่ด้วยตัว structure ของ library ค่อนข้างจะเละ และมีการทำงานข้างในที่ complex เกินความจำเป็นมากๆ (ผมเชื่อว่าส่วนใหญ่ถ้าเจอแบบนี้ จะรื้อเขียนใหม่กัน ฮ่าๆ) ซึ่งคนส่วนใหญ่ก็คงบอก “ไม่เห็นยากเลย ก็เขียน adapter ขึ้นมาสิ แล้วให้ adapter เป็นตัวจัดการ manipulate data ระหว่าง library กับ project ก็สิ้นเรื่อง”

เออมันก็ใช่ครับ แต่สุดท้ายมันก็เอามาใช้เลยไม่ได้ไง มันก็ต้องไปไล่ดูอยู่ดีว่า library ทำอะไรไว้รับอะไรบ้างส่งอะไรออกมา ต้องมานั่ง design code structure โปรเจคใหม่ให้รองรับ adapter ด้วย “แสดงว่า document ของ library ทำไว้ไม่ดีน่ะสิ ถึงไม่สามารถใช้งานมันแบบ black box และเขียน adapter แบบไวๆได้” หึหึหึ ที่เสียงเหล่านั้นพูดมาไม่มีอะไรผิดเลย แต่ส่วนตัวผมรู้สึกนั่นมันทำได้แค่ในอุดมคติครับ พอถึงเวลาเราจะเขียนอะไรขึ้นมาจริงๆ ก่อนเขียนเราแทบจะไม่สามารถชั่งน้ำหนักได้จริงๆว่า “library นี้ต้องเขียนให้ดีนะ เพราะมีสิทธิ์จะใช้ในอนาคตได้สูง”, “ตรงนี้ไม่ต้องเขียน library นะ เทียบกับเวลาแล้วส่วนอื่นสำคัญกว่าเยอะ”, “code ตรงนี้ดูสามารถใช้งาน global โปรเจคอื่นได้ก็จริง แต่โอกาศจะเจอโปรเจคที่ขึ้นรูปใหม่แบบนี้เลย แถมเทคโนโลยีใช้เหมือนเดิมแบบนี้เลยน้อยมาก เพราะงั้นไม่ต้องเขียนแยกก็ได้เขียนรวมไปนี่แหละ น่าจะได้เขียนครั้งเดียว” ผมไม่รู้เพราะความ noob ส่วนตัวหรือเปล่า แต่ผมตัดสินใจเรื่องแบบนี้ผิด เยอะอยู่เหมือนกัน อาจจะเป็นที่ทีมผมมีขนาดเล็กด้วย ทำให้เวลารีบๆ ผมมักจะ type เป็น any ไปก่อน และไม่มีเวลาที่กลับไปแก้มันจริงๆ สักที

เอาจริงๆแล้วถึงจะเขียน library แบบรีบๆและไม่มี doc ดีๆไว้ใช้ในอนาคตก็จริง แต่ libray นั้นเราก็ทำการ test หรือ รัน unit test ไปแล้ว จนมั่นใจในระดับที่เอาไปใช้งานไปแล้วรอบนึง เราพอจะรู้คร่าวๆว่า data มัน in และ out แบบไหนถึงจะไม่ละเอียดมาก ทำไมต้องมาเสียเวลาเขียน adapter เพื่อรองรับ รูปแบบ project ที่มัน strict ขนาดนั้นด้วย?

ปัญหา Higher Order Function

ก็ตามชื่อครับ ถ้าเราไปใช้งานมันใน method โดยเรียก method ของ Class ตัวเองโดยอยาก combine สัก 2 method ขึ้นไปการมานั่ง implement type ให้มัน เป็นอะไรที่หงุดหงิดมากๆครับ

“อย่าใช้สิ” — ครับ ผมให้ลูกอม ole พี่เลยครับ / เอาจริงๆนะ อย่าใช้เนี่ยมันน่าจะเป็นคำตอบที่น่าจะถูกต้องที่สุดก็ได้ แต่ในเมื่อภาษามันมีมาให้ใช้อ่ะ แล้วคนที่เขียนลักษณะ FP ไปแล้วครั้งนึง จะกลับไปนั่ง เก็บ state แยก method design implment ให้มันทำงานในลักษณะเดียวกับ Higher Order ได้นี่มันหงุดหงิดจริงๆนะ (กระแดะ 555) ยิ่งใน angular ใช้ RxJS เป็นหลักด้วยแล้ว ถ้าห้ามไม่ให้ใช้อีกนีก็เกินไปละ

Dynamic Type

โดยส่วนตัวผมถูกโฉลกกับอะไรแบบนี้มากกว่า แต่ก็ยังมีปัญหาเวลา dev แล้วเรียกใช้งานคำสั่งผิดกว่าจะรู้ตัวก็ต่อเมื่อ run test แล้ว ซึ่งก็เป็นปัญหาของคนทั่วไปที่เจอใน Dynamic Type ครับ ผมจะไม่ต่ออะไรตรงนี้มาก เพราะทางแก้มันก็พอจะมีอยู่ บางคนก็บอกให้เขียน test ให้ดี นู้นนี่นั้น ก็ลองๆกันดูครับ

กลับเข้าเรื่องต่อ

จากตัวอย่างข้างต้นจะเห็นว่าแต่ละ Type มันก็มีข้อดีของมัน Gradual จึงเกิดขึ้นคือ “เขียน Type เมื่ออยากเขียน” ฟังดูเหมือนชุ่ย แต่จริงๆไม่ใช่ครับ เวลาเรา dev กัน ส่วนมากมักจะมี timeline ที่ค่อนข้างเร่งรีบ แต่คุณก็ควรจะเขียนโปรเจคที่ดีด้วย เพื่อไม่ต้องตามชดใช้กรรม ซึ่ง บางทีมันเสียเวลามากกว่า design ให้ดีเลิศไปเลยตั้งแต่แรก แต่แน่นอนเราไม่รู้จริงๆหรอกครับ อันไหนดี อันไหนไม่ดี บางทีเขียนชุ่ยๆไป แต่ทำงานได้ตาม requirement แถมใช้งานรอบเดียวจบ ไม่มีการรื้อขึ้นมาใหม่หรือการเพิ่ม ใช้ man day ไปแค่ วัน สองวัน หรือบางงานบอกเป็นโปรเจคระยะยาว desing กันหลายอาทิตย์ แต่พอ product ออกไปจริงๆกลับไม่มี market ซึ่ง base code อาจจะมีประโยชน์ในอนาคต แต่โอกาศที่ไม่มีประโยชน์มันก็มีครับ ซึ่ง concept “เขียน Type เมื่ออยากเขียน” เนี่ยมันก็มีคนตีความไปหลายแบบ แต่ส่วนใหญ่คือ code ตรงไหนที่เรามั่นใจมากๆแล้วว่ามันจะไม่ผิดพลาดแน่นอน ไม่ต้องไปนั่ง design type ให้มันใหม่ส่วนอันไหนที่เราเขียนขึ้นมาใหม่ก็ควร strict type ให้มัน เพื่อง่ายต่อการ debug ตรงไหนที่เราใช้งานมันในรูปแบบ pipe function, higher order function ถ้ามันเขียนกำกับยากจริงๆ เราจะได้ไม่ต้องไปเสียเวลากับมันมากครับ เพราะบางทีถ้าเราเขียนเป็น FP เราก็เห็นอยู่โต้งๆว่ามันออกมาเป็นอะไร

โดยส่วนตัวผมก็ไม่ได้ชอบ Gradual Typing สักเท่าไหร่ยังรู้สึกห่างไกลจาก “Code as Data” อยู่ แต่มันทำให้ผมใช้ชีวิตกับ Static Type ที่เป็น OOP ได้ง่ายขึ้นเยอะ โดยไม่ต้องนั่ง design ทุกอย่างให้เป็น OOP จ๋า ก่อนจะลงมือเขียน การเขียนสไตล์นี้อาจจะเหมาะกับงานหรือคนบางประเภทเท่านั้น

สรุป

จากเบื้องต้นจะเห็นว่า ตอนแรกตั้งใจให้ style ไปในทางเดียวกับคนอื่น แต่ด้วยผลลัพธ์ จากสภาพแวดล้อมแล้ว เหมือนโปรเจคผมจะห่างไกลออกไปทุกที เลยเป็นที่มาของชื่อ ยำรวมมิตร ก็พยายามกันต่อไป 5555

ปัจจุบันพยายามศึกษาการ convert โปรเจคที่มีอยู่แล้ว (Angular 6, Ngrx) ให้รองรับ Native Script อยู่ เพื่อรวมทุกอย่างอยู่ในที่เดียว สามารถ build prod (web app, mobile app) จากคนละ theme คนละ config เดี๋ยวเป็นรูปเป็นร่างแล้วจะมาแชร์ประสบการณ์อีกทีครับ ใครเคยมีประสบการณ์ตรงนี้ หรือมี pain point อะไรมาแชร์กันได้ครับ เพราะปัจจุบันดื้อพยายามรวมโปรเจค เลยเจอ pain point ที่หนักหน่วงอยู่ ฮ่าๆ

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade