ไฟล์เดียว · Bash + Python stdlib · localhost:8765

Tan's Tasks
จากรายการงานใน Jira เป็นตารางวันนี้ที่ลงปฏิทินไปแล้ว

ดับเบิลคลิกไฟล์เดียวแล้วเบราว์เซอร์เปิดขึ้นมาเอง — ติ๊กงานที่จะทำวันนี้ ลากเวลา แล้วกดลง Google Calendar ทีเดียว จากจุดนั้นมันโตขึ้นเป็นที่ทำงานประจำวันทั้งชุด ทั้งโน้ต ผู้ช่วย AI และร่าง standup ที่เขียนจากงานที่ทำจริง

Bash Python stdlib Jira REST Google Calendar Gmail API Vanilla JS No build step
Empathize · Define

เครื่องมือสองตัวที่รู้คนละครึ่งของเรื่องเดียวกัน

Jira รู้ว่ามีงานอะไรค้างอยู่ · ปฏิทินรู้ว่าเวลาว่างตรงไหน · ไม่มีตัวไหนรู้ทั้งสองอย่าง คนเลยต้องเป็นสะพานเองทุกเช้า

ทุกเช้าเปิด Jira ไล่อ่านว่ามีงานอะไร ตัดสินใจในหัวว่าวันนี้จะทำอันไหน แล้วพิมพ์ชื่องานเดิมซ้ำอีกรอบลงปฏิทิน — งานคิดใช้เวลาสองนาที งานพิมพ์ซ้ำใช้เวลานานกว่า และตอนเย็นก็จำไม่ได้อยู่ดีว่าวันนี้แตะอะไรไปบ้าง

— โจทย์ตั้งต้น ก่อนเขียนบรรทัดแรก

ต้องพิมพ์ชื่องานเดิมซ้ำสองที่

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

ลงงานทับช่วงที่มีประชุมอยู่แล้ว

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

ตอนเย็นเขียน standup ไม่ออก

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

เครื่องมือสำเร็จรูปต้องเอา token ของบริษัทไปฝากไว้

บริการเชื่อม Jira กับปฏิทินมีให้เลือกเยอะ แต่ทุกเจ้าขอ API token ของที่ทำงานไปเก็บไว้บนเซิร์ฟเวอร์ของเขา ซึ่งเป็นการตัดสินใจที่ไม่ควรทำคนเดียวเพื่อความสะดวกส่วนตัว


Ideate

ตัดสินใจว่า “ที่เก็บ token” คือข้อจำกัดข้อแรก ไม่ใช่ฟีเจอร์

พอเอาข้อนี้ขึ้นมาเป็นเกณฑ์ตั้งต้น ทางเลือกก็เหลือน้อยลงมากและตัดสินใจง่ายขึ้น

ทางเลือกtoken อยู่ที่ไหนต้นทุนเหตุที่ตก / รับ
บริการเชื่อมอัตโนมัติ เซิร์ฟเวอร์ผู้ให้บริการ รายเดือน ต่อได้เร็วที่สุด แต่ต้องยก API token ของที่ทำงานให้บุคคลที่สามเก็บไว้ถาวร
ปลั๊กอินใน Jira บนระบบของบริษัท ต้องขออนุมัติ ปลอดภัยเรื่อง token แต่เป็นการแก้เครื่องมือกลางของทีม เพื่อแก้ปัญหาส่วนตัวของคนคนเดียว
เว็บแอปที่ต้อง deploy เซิร์ฟเวอร์ตัวเอง ค่าโฮสต์ + ค่าดูแล ได้อิสระเต็มที่ แต่ต้องดูแลเซิร์ฟเวอร์กับ CI ตลอดไป เพื่อเครื่องมือที่เปิดวันละครั้ง
ไฟล์เดียวบนเครื่อง เลือก ในเครื่องตัวเอง ไม่มี ดับเบิลคลิกแล้วรัน ไม่มี deploy ไม่มีบัญชี ไม่มีอะไรออกจากเครื่อง และแก้โค้ดได้ทันทีระหว่างใช้งาน
ผลของการตัดสินใจข้อนี้

ทั้งโปรเจกต์เลยมี ไฟล์ที่ต้องรันแค่ไฟล์เดียว — bash ข้างในมี Python http.server ฝังอยู่ และมี HTML ทั้งแอปฝังอยู่ในนั้นอีกที ไม่มี build step ไม่มี framework ไม่มี node_modules ไฟล์ความลับทั้งสามตัวถูก gitignore ไว้ตั้งแต่ commit แรก


Prototype

สถาปัตยกรรมทั้งหมดอยู่ในไฟล์ที่ดับเบิลคลิกได้

ไฟล์ .command ทำให้ Finder รันมันได้เหมือนแอป โดยที่ข้างในยังเป็นเชลล์สคริปต์ที่อ่านออกและแก้ได้

ดับเบิลคลิก tans-tasks.command
ตามลิงก์ symlink ไปหาไฟล์จริงลงไลบรารี Google ครั้งแรกครั้งเดียวฆ่า process เก่าที่ค้างพอร์ต
Python http.server — localhost:8765
42 endpointไม่มี frameworkเปิดเบราว์เซอร์ให้เอง
แหล่งข้อมูลภายนอก
Jira RESTGoogle CalendarGmailday-log ในเครื่อง
ความลับที่ไม่เคยขึ้น git
config.jsoncredentials.jsontoken.jsontoken-gmail.json
แยก token คนละใบตามขอบเขตสิทธิ์

ตอนเพิ่มอีเมลเช้าเข้ามา ไม่ได้เอา scope ของ Gmail ไปยัดรวมกับ token ของปฏิทินที่มีอยู่ แต่แยกเป็น token คนละใบ — ถอนสิทธิ์อ่านเมลได้โดยไม่กระทบการลงปฏิทิน และถ้าใบไหนหลุด ความเสียหายจำกัดอยู่แค่ขอบเขตของใบนั้น


Prototype

วิธีทำงานตอนเช้า — 5 จังหวะ

จากเปิดเครื่องถึงตารางวันนี้ที่อยู่ในปฏิทินแล้ว

01

ดึงงานของเรามาแสดง

เรียก Jira ด้วย token ในเครื่อง จัดกลุ่มตาม Epic ย่อ-ขยายได้ พร้อมบอกจำนวนงานย่อยในแต่ละกลุ่ม

02

ติ๊กงานที่จะทำวันนี้

เลือกจากรายการจริง ไม่ต้องพิมพ์ชื่องานซ้ำ ระบบจำโปรเจกต์ที่เลือกล่าสุดไว้ให้ รอบหน้าเปิดมาอยู่ที่เดิม

03

ตั้งเวลาโดยเห็นของที่จองไว้แล้ว

ช่วงเวลาที่ปฏิทินมีนัดอยู่แล้วจะถูกกันไว้ตั้งแต่ตอนเลือก ไม่ใช่ไปรู้ตอนลงทับไปแล้ว

04

ลงปฏิทินทีเดียวทั้งชุด

สร้าง event ครบทุกงานที่ติ๊ก แล้วติดป้าย “ลงปฏิทินแล้ว” พร้อมเวลาไว้บนการ์ด กันลงซ้ำรอบสอง

05

ตอนเย็นกดสร้างร่าง standup

อ่านจาก day-log ของวันนั้น แล้วร่างให้เป็นข้อความพร้อมส่ง ย้อนวันได้ด้วยการระบุวันที่


Test & Iterate

ห้าเรื่องที่แก้เพราะใช้เองทุกวันแล้วทน ไม่ ไหว

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

ร่าง standup ที่เดาจากสถานะใน Jira ออกมาผิดแทบทุกวัน

เวอร์ชันแรกประกอบร่างจาก issue ที่สถานะเปลี่ยนวันนั้น ปัญหาคือสถานะไม่ได้บอกว่าลงแรงไปกับอะไร — งานที่นั่งทำทั้งวันแต่ยังไม่เสร็จจะไม่โผล่เลย ส่วนงานที่แค่กดปิดตอนเช้ากลับขึ้นเป็นพระเอก

แก้: เปลี่ยนให้อ่านจาก day-log ที่บันทึกงานจริงระหว่างวัน แล้วตัด Jira ออกจากเส้นทางนี้ทั้งหมด ไม่เหลือแม้แต่ทางสำรอง เพราะทางสำรองที่เดาผิดได้ แปลว่าวันไหนมันทำงานเราจะไม่รู้ตัว — ที่มาเดียวที่ถูก ดีกว่าสองที่มาที่ต้องมาเดาว่าอันไหนใช้ได้

dropdown ของระบบสั่งหน้าตาไม่ได้ ทำให้ทั้งแอปดูไม่เหมือนกัน

ใช้ dropdown มาตรฐานของเบราว์เซอร์ แล้วเจอว่าคุมความสูง ฟอนต์ และสถานะที่เลือกอยู่ไม่ได้จริงบน macOS หน้าที่ใช้มันเลยดูหลุดจากหน้าที่เหลือทุกที

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

ตั้งฟอนต์ให้ทั้งหน้าแล้ว แต่ปุ่มกับช่องกรอกไม่เปลี่ยนตาม

ประกาศฟอนต์ไทยไว้ที่ body เรียบร้อย ตัวหนังสือทั้งหน้าถูกหมด ยกเว้นข้อความในปุ่มและ input ที่ยังเป็นฟอนต์ระบบ ทำให้ดูเหมือนแอปประกอบจากสองที่

แก้: ตัวควบคุมฟอร์มไม่สืบทอด font-family จากพ่อแม่ ตามค่าเริ่มต้นของเบราว์เซอร์ ต้องสั่ง font: inherit ให้มันตรง ๆ — เป็นบั๊กที่มองไม่เห็นถ้าไม่ได้เอาสองตัวมาวางข้างกัน

ตั้งระยะเวลางานแล้วค่าไม่ถูกบันทึก

เลือกระยะเวลาไว้ พอกดลงปฏิทินกลับได้ค่าเริ่มต้นเสมอ ไล่หาที่ตัวจัดการ state อยู่นาน ทั้งที่ต้นเหตุอยู่ที่ตัว component เอง

แก้: เปลี่ยนจาก dropdown ที่มีบั๊กเป็นปุ่มตัวเลือกแบบกดเลือกได้เลย ซึ่งนอกจากจะหายบั๊กแล้วยังกดง่ายกว่าเดิมบนตัวเลือกที่มีไม่กี่อัน — บางทีทางแก้ที่ถูกคือเปลี่ยน control ไม่ใช่ซ่อมของเดิม

วงกลมหมุนทำให้รู้สึกช้ากว่าที่มันช้าจริง

ตอนโหลดงานจาก Jira ขึ้นวงกลมหมุนกลางจอ ระหว่างนั้นหน้าจอว่างเปล่า ทำให้ทุกวินาทีรู้สึกนานกว่าความจริง และไม่รู้ว่ากำลังจะได้อะไรกลับมา

แก้: เปลี่ยนเป็น skeleton ที่มีรูปร่างเหมือนการ์ดจริง + แบ่งหน้า + จำโปรเจกต์ที่เลือกล่าสุด — เวลาที่ใช้จริงเท่าเดิม แต่ความรู้สึกต่างกันมาก เพราะคนเห็นโครงของสิ่งที่กำลังจะมาแล้ว

Level Up

25 commit จาก “ลงปฏิทิน” กลายเป็นที่ทำงานประจำวัน

ไม่ได้วางแผนไว้ตั้งแต่ต้น แต่ละอย่างถูกเพิ่มตอนที่เจอปัญหาจริงระหว่างใช้

1
ไฟล์ที่ต้องรัน ไม่มี build step
42
endpoint ใน server ที่เขียนด้วย stdlib ล้วน
6,256
บรรทัด รวม bash + Python + HTML ทั้งแอป
0
ความลับที่เคยขึ้น git

Define

ขอบเขตที่ตั้งใจไม่ทำ

เครื่องมือส่วนตัวมีข้อได้เปรียบอย่างเดียวคือรู้ว่าผู้ใช้เป็นใคร ถ้าเผลอออกแบบเผื่อคนอื่น ข้อได้เปรียบนั้นจะหายไปทันที

Tan's Tasks

เครื่องมือที่เริ่มจากงานพิมพ์ซ้ำวันละสิบนาที แล้วโตขึ้นเป็นที่ที่เปิดเป็นอย่างแรกของวัน — ไฟล์เดียว ดับเบิลคลิก ไม่มีบัญชี ไม่มีเซิร์ฟเวอร์ และไม่มีความลับก้อนไหนออกจากเครื่อง

Bash Python http.server Vanilla JS Jira REST Google Calendar API Gmail API OAuth localhost only
Projects