July 27, 2012

Git: รวม branch เข้าด้วยกัน

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

ตอนนี้จะเขียนโปรแกรมให้รับ argument เป็นชื่อคนจาก command line แล้วเปลี่ยนไปทักทายคนเหล่านั้นแทน

สร้าง branch ใหม่เช่นเคย (สังเกตว่าเปลี่ยนไปใช้ checkout -b ซึ่งเป็นรูปย่อของการสร้าง branch พร้อม checkout) แล้วแก้ไขไฟล์ hello.py เป็นดังนี้

ทดสอบโปรแกรมกันหน่อย

โปรแกรมทำงานได้ตามที่ออกแบบไว้ ก็ได้เวลา commit เข้าระบบ

เรียบร้อยแล้วสลับกลับมาที่ branch master และสั่ง merge (รวม branch) hi-name กับ master เข้าด้วยกัน

เพียงเท่านี้ที่ branch master ก็จะได้รับ code ที่เพิ่ม feature ใหม่ๆ มาจาก branch ที่แตกไปแล้วครับ

อันที่จริง ถ้าสังเกตดูรายงาน จะเห็นว่าเป็นการ Fast-forward ซึ่งหมายถึงหมายเลข commit ของ branch master ย้ายไปใช้ตัวเดียวกับของ hi-name เท่านั้นเอง ยังไม่ใช่การ merge ที่แท้จริงแต่อย่างใด

และเนื่องจากตอนนี้ branch hi-name ก็ได้ทำหน้าที่ของมันเรียบร้อยแล้ว สั่งลบได้เลยครับ

สังเกตว่าเปลี่ยนไปใช้ -d (ตัวเล็ก) แทน ซึ่งตัวเลือกนี้จะเช็คดูให้แน่ในก่อนว่า branch นั้นถูก merge เรียบร้อยแล้วถึงจะลบทิ้งได้ครับ

July 26, 2012

Git: แตก branch

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

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

ลองแตก branch จากโปรเจค hello โดยให้ชื่อว่า polyglot สามารถสั่งได้ดังนี้

และดู branch ที่มีด้วย

จะเห็นว่ามี branch master กับ polyglot โดยตอนนี้อยู่ที่ branch master ซึ่งเป็น branch หลักที่ Git สร้างไว้ให้ โดย branch นี้ควรจะเก็บโปรเจคช่วงที่ stable เอาไว้ครับ

ตอนนีเรารู้แล้วว่าต้องการทำงานที่ branch polyglot ก็สามารถสลับ branch ไปได้โดยสั่ง

จะทดลองลองเขียนโปรแกรมแบบรองรับหลายภาษา โดยแก้ไขไฟล์ hello.py กันนิดหน่อย ให้เป็นดังนี้

เรียบร้อยแล้วคอมไพล์เป็น C++ และทดสอบการทำงานทั้ง 2 ภาษาดู

ทำงานได้ผ่านเรียบร้อยก็เตรียมตัว commit code ซึ่งถ้าลองตรวจสถานะโปรเจคดู จะพบว่ามีไฟล์ a.out ซึ่งจะไม่ถูกจำเข้าระบบด้วย

เนื่องจากไฟล์ a.out เกิดจากการคอมไพล์ไฟล์ hello.py และยังไม่มีความจำเป็นต้องใช้ในเวลานี้ เราอาจสั่งให้ Git ลบไฟล์ทั้งหมดที่ไม่รู้จักโดย

ถึงตรงนี้ ก็พร้อม commit แล้ว ซึ่งถ้าไม่อยากเสียเวลาไล่สั่ง add ไฟล์ที่แก้ไข สามารถใส่ -a เพื่อบอกให้ add ไฟล์เหล่านั้นแบบอัตโนมัติได้ครับ



แต่เนื่องจาก branch polyglot นี้ มันค่อนข้างพัฒนาโปรแกรมต่อได้ยาก เราจะลบ branch นี้ทิ้งไปครับ โดยก่อนอื่นต้องเปลี่ยนไปอยู่ branch master ก่อน แล้วสั่งลบด้วยคำสั่งนี้

July 25, 2012

Git: จัดการไฟล์พื้นฐาน

ตอนก่อนเราได้สวัสดีชาวโลกกันไปแล้ว แต่จะเห็นว่าไวยากรณ์ผิดพลาดอยู่บ้าง ลองแก้ไฟล์ hello.py เป็น

พร้อมกับเขียนไฟล์ใหม่ชื่อ README.md เพื่อบอกข้อมูลพื้นฐานของโปรแกรมนี้ โดยมีเนื้อหาว่า

และอีกไฟล์ชื่อ MANUAL.md

ลองเช็คสถานะของโปรเจคนี้ดู จะได้ผลลัพท์ดังนี้

ซึ่งบอกว่า ทั้งไฟล์ hello.py ที่เพิ่งแก้ไขไป และไฟล์ MANUAL.md, README.md ที่เพิ่มมาใหม่นั้น จะไม่ถูกจำสำหรับการ commit ในครั้งถัดไป

ดังนั้น เราต้องเพิ่มไฟล์ทั้งสองเข้าไปในระบบก่อน โดยสั่ง add เหมือนตอนที่แล้วครับ

เช็คสถานะไฟล์อีกครั้ง

พร้อมแล้วก็สั่ง commit เลยครับ



แต่ตอนนี้เราจะเห็นว่า ไฟล์ MANUAL.md และ README.md นั้น มีเนื้อหาน้อยมาก และสามารถจับเอามารวมกันได้ แก้ไขไฟล์ README.md เป็นดังนี้

ถึงตอนนี้ เราจะไม่ต้องการไฟล์ MANUAL.md แล้ว ก็สั่งลบไฟล์ออกจากระบบโดย

จะเห็นว่าไฟล์ MANUAL.md หายไปจากไดเรคทอรี่เป็นที่เรียบร้อย ตอนนี้ก็ได้เวลาสั่ง commit งานที่เพิ่งแก้ไขกันครับ

อย่าลืมว่าก่อน commit ต้อง add ไฟล์ที่ถูกแก้ไขทุกครั้งนะครับ

PHP: Send mail

การใช้ PHP ส่งเมลนั้นทำได้ง่ายมาก อาจจะเป็นภาษาที่ส่งเมลได้ง่ายที่สุดในบรรดาภาษาคอมพิวเตอร์ที่มีอยู่ในโลก ฟังชั่นที่ใช้ส่งเมลคือ mail()
mail ( $to, $subject, $message [, $headers[ , $additional_param] ] )
พารามิเตอร์ที่จำเป็นมีอยู่ 3 ตัว และพารามิเตอร์เสริม 2 ตัว คือ
  • $to ที่อยู่อีเมลผู้รับ
  • $subject หัวข้อของอีเมล
  • $message เป็นเนื้อหาของอีเมล
  • $headers เป็นพารามิเตอร์เสริม เอาไว้กำหนดหัวเมลเพิ่มเติม
  • $additional_param เป็นพารามิเตอร์เสริม สำหรับส่งค่าให้กับโปรแกรมส่งเมล (ไม่ค่อยได้ใช้)
การขึ้นบรรทัดใหม่ในเมลนั้นจะใช้ \r\n (เหมือนการขึ้นบรรทัดใหม่ในโปรแกรมของฝั่ง Windows) แทนที่จะใช้ \n อย่างเดียว ไม่ว่าจะส่งจาก OS ที่เป็น Windows หรือ Linux แค่นี้ก็จบ

แต่ถ้าต้องการระบุอีเมลที่ใช้ส่ง รวมทั้งการใช้เนื้อหาในอีเมลเป็น HTML จะต้องใส่ $headers ลงไปด้วย ข้อจำกัดของอีเมลที่ควรรู้ไว้คือ
  • แนบ JavaScript ลงไปไม่ได้ (ที่จริงก็แนบได้ แต่โปรแกรมอ่านเมลทั้งหลายปิดการทำงานของ JavaScript ทิ้งเพื่อความปลอดภัย)
  • หากใช้ CSS จะต้องแทรกลงไปในเนื้อหาอีเมล ไม่สามารถแนบเป็นไฟล์ภายนอกไปได้
  • หากต้องการแทรกรูปภาพจะต้องใช้พาธเต็ม แต่หากไม่จำเป็นก็ไม่ควรจะใส่ลงไป

July 24, 2012

Git: มารู้จักกับโปรแกรมบริหารซอร์สกันเถอะ

1969 Linus Torvalds (คนเดียวกับผู้สร้าง Linux) เกิด
1972 กำเนิดโปรแกรม SCCS โปรแกรมจัดการซอร์สโปรแกรมแรกๆ
1990 กำเนิดโปรแกรม CVS
2000 กำเนิดโปรแกรม SVN
2005 Linus ให้กำเนิด Git



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

โดย Git นั้นเป็นโปรแกรมบริหารซอร์สแบบกระจายศูนย์ ที่จะแจกซอร์สทั้งหมดให้ผู้ใช้ทุกคนเหมือนกัน ไม่แบ่งแยกชนชั้นครับ (ถ้าใครเป็น CVS/SVN มาก่อน ก็อาจถือได้ว่าต้องเรียนรู้ใหม่เกือบหมดเลยทีเดียว)

ผู้ใช้ Windows สามารถใช้ msysGit แทนได้ (โปรแกรมจะไปรันบน MinGW อีกที)

ส่วนผู้ใช้ Linux ก็เช่นเคย apt-get install git กันได้เลย

หลังจากติดตั้งโปรแกรมเรียบร้อยแล้ว ก็ต้องตั้งค่าเริ่มต้นที่จำเป็นกันหน่อย โดยสั่ง



ลองเริ่มใช้โปรแกรมเลยดีกว่า สมมติจะสร้างโปรเจค hello ก็สั่งดังนี้

Git จะสร้างไดเรกทอรี .git/ พร้อมไฟล์ระบบต่างๆ ของโปรเจคนี้ให้ครับ

คราวนี้มาเขียนโปรแกรมหลักของโปรเจคนี้กัน

ทดสอบแล้วรันได้ไม่มีปัญหา ก็ได้เวลาสั่งให้ Git จำ code เข้าระบบโดย

เท่านี้ก็เรียบร้อยครับ

ปล. โปรแกรมบริหารซอร์สแบบนี้ ใช้คนเดียวยังไงก็ไม่สนุก อย่างลืมชวนเพื่อนๆ มา code เล่นด้วยกันนะครับ

July 21, 2012

Python: เขียน TDD อย่างง่ายด้วย doctest

วิธีที่ง่ายที่สุดในการทำ TDD บน Python คือ ใช้ module doctest แล้วแนบคำสั่งที่ต้องการทดสอบพร้อมผลลัพท์ (เขียนรูปแบบเดียวกับการสั่งงาน Python shell) ลงไปที่ docstring ของฟังก์ชัน เช่นนี้

เซฟเป็นไฟล์ to_test.py แล้วเรียกโปรแกรมนี้ผ่าน terminal จะเห็นผลลัพท์ดังนี้

ซึ่งหมายความว่า test เราไม่ผ่านอยู่ 1 test case เมื่อส่งข้อความ 'World' ให้กับฟังก์ชั่น คราวนี้ลองปรับปรุงบรรทัดที่สั่ง print ให้เป็น

เมื่อสั่ง $ python to_test.py อีกรอบ จะไม่ได้ค่าอะไรคืนมาแล้ว ซึ่งก็คือ test ผ่านหมดนั่นเองครับ

หรือจะขอดูรายงานแบบเต็มๆ ก็ย่อมได้ โดยการเพิ่ม argument -v เข้าไปเช่นนี้




สำหรับส่วน docstring เราสามารถแนบคำอธิบายอื่นๆ ลงไปกับ test ได้ โดยต้องเว้นบรรทัดว่างเอาไว้เพื่อบอกให้รู้ว่าส่วนไหนที่หมด output จาก test แล้ว และสามารถเขียนส่วน input test หลายบรรทัดได้ สำหรับกรณี error สามารถใส่ ... ตามตัวอย่าง เพื่อบอกว่าไม่ต้องสนใจ output ส่วนที่เป็นรายงานอย่างละเอียดก็ได้ครับ

นอกจากนี้ ใน production code จริง การเรียกฟังก์ชัน doctest.testmod() ลงไปอาจไม่เหมาะสมนัก เราสามารถยกส่วนนั้นทิ้งไปได้ (เหลือแต่ code เปล่าๆ กับ docsting ที่มี test case อยู่) แล้วสั่งผ่าน shell เช่นนี้แทน



หรือถ้าส่วน test case นั้นใหญ่มากจนไม่ควรจะไปอยู่กับ docstring เราอาจยก test case มาเขียนเป็นไฟล์ใหม่ที่บรรจุเฉพาะข้อมูล test ไปเลยก็ได้ ดังนี้

ไฟล์ to_test.py


ไฟล์ info_test.txt

เรียกผ่าน shell ไม่ต่างจากเดิม เพียงแค่เปลี่ยน argument เป็นไฟล์ที่เขียน test เอาไว้เท่านั้นครับ

July 4, 2012

PHP: Session และสิ่งที่แตกต่างจาก Cookie

ในการเขียนโปรแกรมทั่ว ๆ ไป เราสามารถเก็บข้อมูลของผู้ใช้ เช่น ชื่อ ข้อมูลของแต่ละขั้นตอนที่ผู้ใช้ได้ทำลงไปในตัวแปรแบบปกติได้ แต่สำหรับการเขียนโปรแกรมสำหรับเว็บนั้นทำแบบนั้นไม่ได้ เพราะ URL ไม่สามารถบ่งบอกตัวผู้ใช้ และไม่สามารถเก็บข้อมูลตัวแปรได้ (ยกเว้นจะใช้ GET ซึ่งไม่ปลอดภัยสักเท่าไหร่ เพราะถ้ามีใครรู้ URL ก็สามารถปลอมตัวเป็นคน ๆ นั้นได้ มันคงไม่สนุก ถ้าเขาปลอมเป็นเรา แล้วโอนเงินในธนาคารออกไปจนหมด) PHP จึงสร้างตัวแปรพิเศษขึ้นมาคือ session

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

จะใช้ session ต้องประกาศก่อน และต้องทำก่อนที่จะส่งข้อมูลใด ๆ ออกมา ไม่ใช่นั้นจะเจอข้อความ headers already sent เวลาเรียกใช้ก็เรียกใช้เหมือนอาเรย์ปกติ ผ่านทางตัวแปร $_SESSION ซึ่งเป็นตัวแปรชนิด superglobal หากต้องการลบค่านั้นออกจาก session สามารถสั่ง unset ทีละตัวหรือทำลาย session นั้นทิ้งไปเลยก็ได้ แต่ถึงจะไม่ทำลาย ถ้าผู้ใช้ออกจากเว็บข้อมูลใน session ก็ถูกทำลายอยู่ดี โดยทั่วไปแล้ว session จะคล้าย ๆ กับ cookie คือเก็บข้อมูลของผู้ใช้ไว้เหมือน ๆ กัน ต่างกันตรงที่ว่า
  • cookie จะส่งข้อมูลนั้นกลับเป็นไฟล์ไปยังเบราว์เซอร์ และเก็บไว้ที่ฝั่งผู้ใช้ด้วย แต่ session ส่ง UID ของ session ไปอย่างเดียว ข้อมูลยังอยู่ฝั่งเซิฟเวอร์
  • cookie เก็บข้อมูลไว้เป็นไฟล์ข้อความธรรมดา สามารถเปิดขึ้นมาแก้ไขได้ หากรู้วิธี
  • cookie จะยังคงอยู่แม้ว่าจะออกจากเว็บไปแล้ว (เพราะเก็บอยู่บนเครื่องผู้ใช้) เมื่อกลับเข้ามาใหม่ ก็สามารถเรียกใช้ข้อมูลเหล่านั้นได้อยู่
  • หากต้องการเก็บข้อมูลใน session เอาไว้ ต้องเขียนลงไฟล์ หรือฐานข้อมูลเอาเอง