ดังที่ผมกล่าวไว้ในบทก่อน ในยุคแรกของการคอมพิวติ้ง ส่วนควบคุมทั้งหมดทำด้วยมือ เครื่องคอมพิวเตอร์ตั้งโต๊ะที่ช้าในตอนแรกถูกควบคุมด้วยมือ เช่น การคูณที่ทำโดยการบวกซ้ำ ๆ พร้อมการเลื่อนคอลัมน์หลังแต่ละหลักของตัวคูณ การหารก็ทำในลักษณะเดียวกันโดยการลบซ้ำ ๆ ต่อมาเริ่มใช้มอเตอร์ไฟฟ้า ทั้งเพื่อให้กำลังและเพื่อการควบคุมการคูณและการหารที่เป็นอัตโนมัติมากขึ้น เครื่องเจาะบัตร (punch card machines) ถูกควบคุมด้วยการเดินสายบน plug board เพื่อบอกเครื่องว่าควรหา ข้อมูลจากที่ไหน ทำอะไรกับมัน และจะใส่คำตอบไว้ที่ใดบนบัตร (หรือบนแผ่นพิมพ์ของ tabulator) แต่การควบคุมบางส่วนอาจมาจากบัตรเอง โดยทั่วไปเป็นการเจาะ X และ Y (ตัวเลขอื่น ๆ ในบางครั้งก็อาจควบคุมการทำงาน) แผงปลั๊ก (plug board) จะเดินสายพิเศษสำหรับแต่ละงาน และในสำนักงานบัญชี แผงที่เดินสายไว้จะถูกเก็บไว้และนำมาใช้ซ้ำตามสัปดาห์หรือเดือนตามรอบการทำบัญชี
เมื่อมาใช้เครื่องรีเลย์ หลังจาก Complex Number Computer ของ Stibitz เครื่องเหล่านี้ถูกควบคุมโดยเทปกระดาษเจาะรู (punched paper tapes) เทปกระดาษเป็นปัญหาเมื่อทำงานแบบหนึ่งครั้ง—มันยุ่งยาก และการติดกาวเพื่อแก้ไขหรือทำเป็นลูปก็ลำบาก (หนึ่งในปัญหาคือกาวมักจะติดเข้ากับ 'นิ้วอ่าน' ของเครื่อง!) เนื่องจากมีหน่วยความจุภายในน้อยมากในช่วงแรก โปรแกรมจึงไม่สามารถเก็บไว้ในเครื่องได้อย่างประหยัด (แม้ว่าผมเชื่อว่าผู้ออกแบบน่าจะพิจารณาเรื่องนี้แล้ว)
ENIAC ในตอนแรก (1945–1946) ถูกควบคุมด้วยการเดินสายเหมือนกับเป็น plug board ขนาดยักษ์ แต่ต่อมา Nick Metropolis และ Dick Clippinger ได้ปรับเปลี่ยนให้มันถูกโปรแกรมจากตาราง ballistic (ballistic tables) ซึ่งเป็นชั้นวางขนาดใหญ่ของปุ่มหมุนที่สามารถตั้งตัวเลขทศนิยมของโปรแกรมผ่านปุ่มปรับของสวิตช์ทศนิยมได้
การโปรแกรมภายในเครื่อง (internal programming) เกิดขึ้นจริงเมื่อมีหน่วยความจำที่ใช้ได้อย่างเพียงพอ และแม้มักจะถูกอ้างถึงว่าเป็นผลงานของ von Neumann แต่เขาเป็นเพียงที่ปรึกษาของ Mauchly และ Eckert กับทีมของพวกเขา ตามที่ Harry Huskey กล่าว พวกเขาได้หารือเรื่องการโปรแกรมภายในกันบ่อยครั้งก่อนที่ von Neumann จะเริ่มให้คำปรึกษา การอภิปรายที่แพร่หลายในวงกว้างครั้งแรก (หลังจากที่ Lady Lovelace เคยเขียนและเผยแพร่โปรแกรมบางชิ้นสำหรับเครื่องวิเคราะห์ของ Babbage ที่เสนอไว้) คือรายงานของ von Neumann สำหรับกองทัพ ซึ่งถูกเผยแพร่อย่างกว้างขวางแต่ไม่เคยตีพิมพ์ในที่อ้างอิงอย่างเป็นทางการ
รหัสในยุคแรกส่วนใหญ่เป็นแบบ one address (หมายความว่าแต่ละคำสั่งประกอบด้วยส่วนคำสั่งและที่อยู่ซึ่งจะเป็นตำแหน่งของตัวเลขที่ต้องอ่านหรือส่งไป) เราก็มีรหัสแบบ two-address ด้วย โดยเฉพาะในเครื่องที่มีกรงลานหมุน (rotating drum machines) ดังนั้นคำสั่งถัดไปจะพร้อมใช้งานทันทีเมื่อคำสั่งก่อนหน้าทำเสร็จ—เหมือนกันกับสายหน่วงปรอท (mercury delay lines) และอุปกรณ์เก็บข้อมูลแบบอนุกรมอื่น ๆ การเข้ารหัสเช่นนี้เรียกว่า minimum-latency coding และคุณคงจินตนาการได้ถึงความยากของโปรแกรมเมอร์ในการคำนวณว่าจะวางคำสั่งและตัวเลขถัดไปตรงไหน (เพื่อหลีกเลี่ยงความหน่วงและความขัดแย้งให้ได้มากที่สุด) ไหนจะการตามหาข้อผิดพลาดในการเขียนโปรแกรม (bugs) อีก ในไม่ช้าโปรแกรมชื่อ soap (symbolic optimizing assembly program) ก็มีให้ใช้เพื่อทำการปรับแต่งเชิงเพิ่มประสิทธิภาพโดยใช้เครื่อง IBM 650 เอง นอกจากนี้ยังมีรหัสแบบสามและสี่ที่อยู่ด้วย แต่ผมจะไม่กล่าวถึงที่นี่
เรื่องน่าสนใจเกี่ยวกับ soap คือสำเนาของโปรแกรม สมมติว่าเรียกว่าโปรแกรม A ถูกโหลดเข้าเครื่องทั้งในฐานะโปรแกรมและถูกประมวลเป็นข้อมูล ผลลัพธ์จากการประมวลนี้คือโปรแกรม B จากนั้น B ถูกโหลดเข้า 650 และ A ถูกรันในฐานะข้อมูลเพื่อสร้างโปรแกรม B ใหม่ ความต่างของเวลารันทั้งสองครั้งเพื่อผลิตโปรแกรม B แสดงให้เห็นว่าการปรับแต่งของโปรแกรม soap (โดย soap เอง) ให้ผลมากเพียงใด นับเป็นตัวอย่างแรก ๆ ของการ 'self-compiling'
ในตอนแรกเราจัดโปรแกรมเป็น absolute binary หมายความว่าเราจดที่อยู่จริงในรูปแบบไบนารี และเขียนส่วนคำสั่งเป็นไบนารียิ่งด้วย! มีแนวทางสองทางที่จะหลุดพ้นจากนี้: octal ซึ่งจัดกลุ่มบิตไบนารีเป็นกลุ่มละสาม และ hexadecimal ซึ่งจัดเป็นกลุ่มละสี่ตัว ต้องใช้ตัว A, B, C, D, E, F เพื่อแทนตัวเลขเกิน 9 (และแน่นอนว่าต้องเรียนตารางการคูณและการบวกจนถึง 15)
ถ้าเมื่อต้องแก้ไขข้อผิดพลาดและต้องการแทรกคำสั่งที่ละเลยไป คุณก็เอาคำสั่งก่อนหน้านั้นมาแทนที่ด้วยคำสั่งโอน (transfer) ไปยังพื้นที่ว่าง แล้วที่นั่นใส่คำสั่งที่คุณเขียนทับไว้ เติมคำสั่งที่ต้องการแทรก แล้วตามด้วยการโอนกลับไปยังโปรแกรมหลัก ดังนั้นโปรแกรมจะกลายเป็นลำดับของการกระโดดของการควบคุมไปยังที่ต่าง ๆ เมื่อเกือบทุกครั้งเมื่อมีข้อผิดพลาดในการแก้ไข คุณก็ใช้วิธีเดิมอีกครั้งโดยใช้พื้นที่ว่างอื่น ๆ ผลที่ได้คือเส้นทางการควบคุมในหน่วยความจำของโปรแกรมมีลักษณะเหมือนเส้นสปาเก็ตตี้ ทำไมไม่แทรกคำสั่งไว้ตรงกลางล่ะ? เพราะถ้าทำเช่นนั้นคุณจะต้องย้อนกลับไปเปลี่ยนที่อยู่ทั้งหมดที่อ้างถึงคำสั่งที่ย้ายไปแล้ว! หลีกเลี่ยงสิ่งนั้นให้ได้!
เราได้ไอเดียเรื่อง reusable software เร็วมาก จริง ๆ แล้ว Babbage ก็มีแนวคิดนี้ เราเขียนไลบรารีทางคณิตศาสตร์เพื่อใช้ซ้ำเป็นบล็อกของโค้ด แต่ไลบรารีที่ใช้ที่อยู่แบบสัมบูรณ์หมายความว่าเมื่อเรียกใช้รูทีนจากไลบรารีนั้น มันต้องอยู่ในตำแหน่งเดียวกันทุกครั้ง เมื่อไลบรารีใหญ่เกินไปรูทีนจะต้องไปสู่การเขียนโปรแกรมแบบ relocatable programs กลเม็ดการโปรแกรมที่จำเป็นอยู่ในรายงาน von Neumann ซึ่งไม่เคยถูกตีพิมพ์อย่างเป็นทางการ
หนังสือเล่มแรกที่ตีพิมพ์ซึ่งทุ่มเทให้การเขียนโปรแกรมคือของ Wilkes, Wheeler, and Gill ซึ่งเกี่ยวกับ EDSAC ที่ Cambridge, England (1951). ผมเองและคนอื่น ๆ ได้เรียนรู้อะไรมากจากมัน อย่างที่คุณจะเห็นอีกไม่นาน
มีคนคิดว่าถ้าเขียนโปรแกรมสั้น ๆ ที่จะอ่านชื่อเชิงสัญลักษณ์ของคำสั่ง (เช่น add) แล้วแปลเป็นเลขฐานสองที่เครื่องใช้ภายใน (เช่น 01100101) ในเวลาป้อนข้อมูล (at input time) ก็จะสะดวก ซึ่งตามมาด้วยแนวคิดการใช้ที่อยู่เชิงสัญลักษณ์—ซึ่งเป็นเรื่องเฮเรติกสำหรับโปรแกรมเมอร์รุ่นเก่า คุณไม่ได้เห็นการเขียนโปรแกรมแบบ absolute heroic มากนักในวันนี้ (ยกเว้นคุณเล่นกับคอมพิวเตอร์พกพาที่โปรแกรมได้แล้วพยายามทำให้มันทำมากกว่าที่ผู้ออกแบบตั้งใจ)
ผมเคยใช้เวลาปีกว่าเต็ม ๆ ร่วมกับโปรแกรมเมอร์หญิงจาก Bell Telephone Laboratories ทำงานปัญหาใหญ่โดยเขียนเป็น absolute binary สำหรับ IBM 701 ซึ่งใช้รีจิสเตอร์ 32K ทั้งหมดที่มี หลังประสบการณ์นั้นผมสาบานว่าจะไม่ให้ใครทำงานหนักเช่นนั้นอีก เมื่อได้ยินเรื่องระบบเชิงสัญลักษณ์จาก Poughkeepsie, IBM ผมให้เธอสั่งและใช้มันในปัญหาถัดไป ซึ่งเธอก็ทำตาม และอย่างที่ผมคาด เธอรายงานว่ามันง่ายกว่ามาก เราจึงบอกทุกคนเรื่องวิธีใหม่นี้ แปลว่าราว 100 คนที่มากินในโรงอาหารของ IBM ใกล้เครื่อง ครึ่งหนึ่งเป็นคนจาก IBM และอีกครึ่งเป็นคนนอกเช่าชั่วโมง ที่ผมรู้มีเพียงคนเดียว—ใช่ เพียงคนเดียว—จากคนทั้ง 100 ที่แสดงความสนใจ!
สุดท้ายมีการคิดค้น more complete, and more useful, Symbolic Assembly Program (sap) หลังจากผ่านหลายปีมากกว่าที่คุณคิด ในช่วงเวลานั้นโปรแกรมเมอร์ส่วนใหญ่ยังคงเขียนเป็น absolute binary เมื่อ sap ปรากฏขึ้นผมคาดว่ามีเพียงประมาณ 1% ของโปรแกรมเมอร์รุ่นเก่าที่สนใจ — การใช้ sap ถูกมองว่าเป็น 'เรื่องของพวกที่อ่อนแอ' และโปรแกรมเมอร์จริง ๆ จะไม่เสียเวลาให้การประกอบแบบนี้ จริง ๆ! โปรแกรมเมอร์ไม่สนใจ แตเมื่อถูกกดดันพวกเขาต้องยอมรับว่าวิธีเดิมใช้เวลามากกว่า sap ในการหาข้อผิดพลาดและแก้ไข หนึ่งในคำร้องเรียนหลักคือเมื่อใช้ระบบเชิงสัญลักษณ์คุณจะไม่รู้ว่าของทุกอย่างอยู่ที่ไหนในหน่วยความจำ — ถึงในยุคแรกจะมีแผนที่เชื่อมสัญลักษณ์กับที่อยู่จริง แต่เชื่อไหมว่าพวกเขายังกลับมาจมอยู่กับแผ่นพวกนั้นแทนที่จะตระหนักว่าไม่ต้องรู้ข้อมูลนั้นถ้าทำงานภายในระบบ — ไม่! เมื่อแก้ไขข้อผิดพลาดพวกเขายังคงชอบทำในที่อยู่แบบ absolute binary
Fortran ซึ่งหมายถึง formula translation ถูกเสนอโดย Backus และเพื่อน ๆ และอีกครั้งถูกคัดค้านโดยโปรแกรมเมอร์แทบทั้งหมด ประการแรกมีคนบอกว่าไม่สามารถทำได้ ประการที่สองถ้าทำได้มันจะเสียเวลาและทรัพยากรเครื่อง ประการที่สามแม้มันจะใช้ได้ โปรแกรมเมอร์ที่มีชื่อเสียงจะไม่ใช้—มันมีไว้สำหรับคนที่ 'อ่อนแอ' เท่านั้น!
การใช้ Fortran เหมือนกับการใช้โปรแกรมเชิงสัญลักษณ์ก่อนหน้านั้น ใช้เวลาช้าสำหรับผู้เชี่ยวชาญ และเป็นแบบที่เราเห็นกับกลุ่มอาชีพแทบทั้งหมด แพทย์มักไม่ทำตามคำแนะนำที่ให้คนอื่น และมักมีสัดส่วนการติดยาเสพติดสูง ทนายความมักไม่ทิ้งพินัยกรรมดี ๆ เมื่อพวกเขาตาย มืออาชีพส่วนใหญ่ช้าในการใช้ความเชี่ยวชาญของตนเอง สถานการณ์สรุปได้ด้วยสุภาษิตเก่า ๆ “The shoemaker’s children go without shoes.” คิดถึงอนาคตเมื่อคุณเป็นผู้เชี่ยวชาญใหญ่ ๆ จะต้องหลีกเลี่ยงความผิดพลาดแบบนี้!
เมื่อ Fortran มีให้ใช้และรันได้ ผมสั่งให้โปรแกรมเมอร์ของผมทำปัญหาถัดไปด้วย Fortran ให้เธอแก้ข้อผิดพลาด ดูผลให้ผมทดสอบว่าทำงานถูกต้อง แล้วเธอสามารถถ้าอยากจะแต่งลูปภายในใหม่ด้วยภาษาเครื่องเพื่อให้เร็วขึ้นและประหยัดเวลาเครื่อง ผลคือเราทำงานได้เกือบสิบเท่าของคนอื่นด้วยความพยายามเท่าเดิม แต่สำหรับคนอื่นการเขียนโปรแกรมด้วย Fortran ไม่ใช่ของ 'โปรแกรมเมอร์จริง ๆ'
ในเชิงปฏิบัติ การจัดการ IBM 701 ที่สำนักงานใหญ่ IBM ในนครนิวยอร์กที่เราเช่าชั่วโมงเป็นเรื่องแย่มาก มันเป็นการเสียเวลาเครื่องอย่างสิ้นเชิง (ตอนนั้น $300 ต่อชั่วโมงถือว่าแพงมาก) และเสียเวลาเพราะมนุษย์ด้วย ดังนั้นผมจึงปฏิเสธที่จะสั่งซื้อเครื่องใหญ่จนกว่าผมจะคิดระบบมอนิเตอร์ออก—ซึ่งคนอื่นสุดท้ายก็สร้างให้กับ IBM 709 เครื่องแรกของเรา และต่อมาปรับให้กับ IBM 7096
อีกครั้ง มอนิเตอร์ ซึ่งปัจจุบันมักเรียกว่า “the system” เช่นเดียวกับขั้นตอนก่อน ๆ ที่ผมกล่าวถึง ควรจะเป็นสิ่งที่ชัดเจนสำหรับผู้ที่ใช้เครื่องในทุกวัน แต่ผู้ใช้ส่วนใหญ่ดูเหมือนจะยุ่งเกินกว่าจะคิดหรือสังเกตว่ามันแย่แค่ไหน และคอมพิวเตอร์สามารถทำอะไรให้สะดวกและประหยัดกว่าได้มากเพียงใด เพื่อจะเห็นสิ่งที่ชัดเจนนั้นมักต้องใช้คนนอกหรือลองคิดอย่างผมที่สงสัยว่าตัวเองกำลังทำอะไรและทำไมต้องทำทั้งหมดนั้น แม้เมื่อถูกบอก คนรุ่นเก่าก็ยังยืนยันวิธีที่เขาเรียนมา อาจเพราะความภาคภูมิใจในอดีตและไม่ยอมรับว่าจะมีวิธีที่ดีกว่าที่เขาใช้มานาน
วิธีหนึ่งที่จะอธิบายเหตุการณ์ในประวัติศาสตร์ของซอฟต์แวร์คือเราค่อย ๆ เปลี่ยนจากเครื่อง 'absolute' ไปสู่ virtual machines ก่อนเรากำจัดรหัสคำสั่งจริง จากนั้นที่อยู่จริง แล้วใน Fortran ก็ลดความจำเป็นต้องเรียนรู้รายละเอียดภายในของเครื่องที่ซับซ้อนเหล่านั้น เรากำลังบัฟเฟอร์ผู้ใช้ให้ห่างจากเครื่องเอง ค่อนข้างเร็วที่ Bell Telephone Laboratories เราสร้างอุปกรณ์บางอย่างเพื่อทำให้ยูนิตเทปเป็นแบบเสมือน และอิสระจากเครื่อง เมื่อคุณมี virtual machine แบบสมบูรณ์เท่านั้นคุณจะสามารถย้ายซอฟต์แวร์จากเครื่องหนึ่งไปยังอีกเครื่องหนึ่งได้โดยไม่ต้องพบปัญหาและข้อผิดพลาดแทบไม่มีที่สิ้นสุด
Fortran ประสบความสำเร็จเกินกว่าที่ใครคาดเพราะเหตุทาง psychological ที่ว่ามันเป็นอย่างชื่อ—การแปลสมการ (formula translation) ของสิ่งที่คนเคยทำในโรงเรียน ไม่ต้องเรียนชุดวิธีคิดใหม่
Algol ประมาณปี 1958–1960 ได้รับการสนับสนุนจากองค์กรคอมพิวเตอร์ทั่วโลก รวมทั้ง ACM มันเป็นความพยายามของนักทฤษฎีในการปรับปรุง Fortran แต่เพราะว่าเป็นนักตรรกะพวกเขาจึงสร้างภาษาที่เป็นเชิงตรรกะ ไม่ใช่ภาษาที่เป็นมิตรทางจิตวิทยา และตามที่คุณทราบมันล้มเหลวในระยะยาว มันถูกกำหนดในรูปแบบตรรกะแบบบูลีนซึ่งไม่เข้าถึงคนธรรมดา (และบางครั้งแม้แต่นักตรรกะเองก็ยังไม่เข้าใจ!) หลายภาษาที่ออกแบบอย่างตรรกะซึ่งคิดว่าจะมาทดแทน Fortran ต่างก็ผ่านไปแล้ว และ Fortran (ปรับปรุงบ้างตามเวลา) ยังคงใช้อย่างแพร่หลาย แสดงให้เห็นถึงพลังของภาษาที่ออกแบบตามจิตวิทยาของผู้ใช้เหนือภาษาเชิงตรรกะ
นี่คือจุดเริ่มต้นของความหวังอย่างยิ่งสำหรับภาษาเฉพาะด้าน (pols = problem-oriented languages) มีคุณค่าในแนวคิดนี้ แต่ความฮึกเหิมจางหายเพราะปัญหาจำนวนมากเกี่ยวข้องกับมากกว่าหนึ่งสาขา และภาษาต่าง ๆ มักไม่เข้ากัน นอกจากนี้ในระยะยาวมันมีค่าใช้จ่ายสูงในช่วงการเรียนรู้ที่มนุษย์ต้องเรียนหลายภาษาที่ต้องการ
ประมาณปี 1962 ภาษาลิสป์ (Lisp) เริ่มขึ้น ข่าวลือต่าง ๆ หมุนเวียนเกี่ยวกับที่มาของมัน ความจริงน่าจะเป็นอย่างนี้: John McCarthy เสนอองค์ประกอบของภาษาในเชิงทฤษฎี ข้อเสนอนั้นถูกนำไปขยายโดยคนอื่น ๆ และเมื่อมีนักศึกษาคนหนึ่งสังเกตว่าเขาสามารถเขียนคอมไพเลอร์ให้มัน in lisp โดยใช้กลเม็ดง่าย ๆ ของการ self-compiling ทุกคนต่างทึ่ง รวมทั้ง McCarthy เองด้วย แต่เขาส่งเสริมให้นักศึกษาลอง และเหมือนเวทมนตร์ในชั่วข้ามคืน พวกเขาก็ย้ายจากทฤษฎีมาสู่คอมไพเลอร์ Lisp ที่ทำงานได้จริง!
ผมขอเบี่ยงมาพูดถึงประสบการณ์กับ IBM 650 มันเป็นเครื่องแบบสองที่อยู่ (two-address drum machine) และทำงานด้วยจุดทศนิยมคงที่ (fixed decimal point) จากประสบการณ์วิจัยผมรู้ว่าจำเป็นต้องมีฟลอยติ้งพอยต์ (แม้ von Neumann จะคิดต่าง) และผมต้องการรีจิสเตอร์ดัชนีซึ่งเครื่องไม่ได้ให้มา IBM บอกว่าจะให้ซับรูทีนฟลอยติ้งพอยต์ในอนาคต แต่นั่นไม่พอสำหรับผม ผมเคยรีวิวหนังสือ EDSAC และในภาคผนวก D มีโปรแกรมประหลาดเขียนเพื่อยัดโปรแกรมใหญ่เข้าในหน่วยความจำเล็ก มันเป็น interpreter แต่ถ้ามันอยู่ในภาคผนวก D พวกเขาเห็นความสำคัญไหม? ผมสงสัย! และในฉบับที่สองมันยังอยู่ในภาคผนวก D ดูเหมือนไม่มีใครตระหนักว่ามันคืออะไร
เรื่องนี้ชี้ให้เห็นปัญหาอันน่าอึดอัดว่าของบางสิ่งถูกเข้าใจเมื่อไหร่ ใช่ พวกเขาเขียนและใช้มัน แต่พวกเขาเข้าใจความทั่วไปของ interpreter และ compiler ไหม? ผมเชื่อว่าไม่ เช่นเดียวกัน เมื่อเวลานั้นหลายคนตระหนักว่าคอมพิวเตอร์ 'จริง ๆ แล้วเป็นตัวจัดการสัญลักษณ์' (symbol manipulators) ไม่ใช่แค่ตัวคำนวณตัวเลข พวกเราไปบรรยายและเห็นคนพยักหน้าราวกับเข้าใจ แต่ผมก็รู้ว่าพวกเขาส่วนใหญ่ไม่เข้าใจ แน่นอนคุณอาจบอกว่า Turing ในบทความปี 1937 แสดงให้เห็นว่าคอมพิวเตอร์จัดการสัญลักษณ์ได้ แต่เมื่ออ่านรายงาน von Neumann อย่างละเอียดคุณจะไม่คาดคิดผู้เขียนจะรู้เรื่องนี้ แม้จะมีโปรแกรมเชิงผสมและการเรียงลำดับตัวอย่างหนึ่งก็ตาม
ประวัติศาสตร์มักให้อภัยในกรณีนี้ มันให้เครดิตแก่ผู้ที่เข้าใจเมื่อเราเริ่มทำสิ่งใดสิ่งหนึ่ง แต่มีสุภาษิตอันชาญฉลาดว่า “เกือบทุกคนที่เปิดสนามใหม่มักไม่เข้าใจมันเหมือนผู้ตาม” หลักฐานสำหรับเรื่องนี้น่าเศร้า นอกจากนี้ได้กล่าวว่าในฟิสิกส์ผู้สร้างของสิ่งสำคัญ ๆ มักไม่เข้าใจสิ่งที่ตนทำ ผมไม่เคยเห็น Einstein ในทฤษฎีสัมพัทธภาพพิเศษชัดเจนเท่าคนที่มาอธิบายทีหลัง และอย่างน้อยเพื่อนคนหนึ่งเคยพูดหลัง ๆ ว่า 'Hamming ดูเหมือนไม่เข้าใจรหัสแก้ข้อผิดพลาด!' เขาอาจถูก; ผมเองก็อาจไม่เข้าใจสิ่งที่ผมคิดค้นชัดเท่าที่คนอื่นเข้าใจ เหตุผลที่เกิดขึ้นบ่อยคือผู้คิดค้นต้องฝ่าฟันอุปสรรคมืด ๆ มากมาย และต้องทนอยู่กับความเข้าใจผิด พวกเขาจึงไม่เห็นแสงที่คนภายหลังเห็นได้ โปรดจำไว้ ผู้คิดค้นมักจะมองสิ่งที่เขาคิดค้นในมุมมองจำกัด และคนอื่น ๆ (อาจเป็นคุณ?) มองเห็นได้มากกว่า แต่ก็จำไว้เมื่อคุณเป็นผู้ประดิษฐ์สิ่งใหม่ ราวเวลาผ่านไป คนอื่นอาจเข้าใจมันมากกว่าคุณ มีการกล่าวว่า Newton เป็นคนสุดท้ายของชาวโบราณ ไม่ใช่คนแรกของสมัยใหม่ แม้เขาจะมีบทบาทสำคัญในการสร้างโลกสมัยใหม่ของเรา
กลับมาที่ IBM 650 และผมเอง ผมเริ่มต้น (ประมาณปี 1956) ด้วยกฎสี่ข้อดังนี้สำหรับการออกแบบภาษา:
- ง่ายต่อการเรียนรู้
- ใช้งานง่าย
- ง่ายต่อการดีบัก (ค้นหาและแก้ไขข้อผิดพลาด)
- ใช้ subroutines ได้ง่าย
ข้อสุดท้ายเป็นสิ่งที่คุณไม่ต้องกังวลมากนัก เพราะในสมัยนั้นเราแยกความแตกต่างระหว่าง “open” และ “closed” subroutines ซึ่งอธิบายยากในปัจจุบัน!
คุณอาจกล่าวว่าผมทำ top-down programming แต่ผมก็เขียนรายละเอียดของลูปภายในออกมาเพื่อตรวจว่าทำได้อย่างมีประสิทธิภาพ (เป็นการ bottom-up programming) และหลังจากนั้นผมจึงกลับไปสู่แนวทางเชิงท็อปดาวน์เชิงปรัชญา ดังนั้นแม้ผมเชื่อในการโปรแกรมแบบ top-down แต่ผมยอมรับว่า bottom-up ก็จำเป็นในบางครั้ง
ผมทำให้เครื่องแบบสองที่อยู่ที่มีจุดทศนิยมคงที่ดูเหมือนเป็นเครื่องแบบสามที่อยู่ที่มีจุดลอยตัว—นั่นคือเป้าหมายของผม—A op. B = C ผมใช้สิบหลักทศนิยมของเครื่อง (สำหรับผู้ใช้ถือเป็นเครื่องแบบทศนิยม) ในรูปแบบดังนี้:
| A address (ที่อยู่ A) | Op. (การปฏิบัติการ) | B address (ที่อยู่ B) | C address (ที่อยู่ C) |
| xxx | x | xxx | xxx |
ทำอย่างไร? ง่ายมาก! ผมวาดลูปต่อไปนี้ในใจ (Figure 4.1). ก่อนอื่นเราต้องการ Current Address Register (car) ดังนั้นผมจึงมอบหนึ่งในรีจิสเตอร์ 2,000 ตัวของ IBM 650 ให้ทำหน้าที่นี้ แล้วเราเขียนโปรแกรมที่ทำสี่ขั้นตอนจากบทก่อน: (1) ใช้ car หาไปยังตำแหน่งของคำสั่งถัดไปของโปรแกรมที่คุณเขียน (แน่นอนว่าเขียนในภาษาของผม) (2) แยกคำสั่งนั้นออกและเก็บที่อยู่ทั้งสาม A, B, และ C ในตำแหน่งที่เหมาะสมในหน่วยความจำของ 650 (3) เพิ่มค่าคงที่ที่แน่นอนเข้าไปใน operation (op.) ของคำสั่งแล้วไปยังที่อยู่นั้น ที่นั่นสำหรับแต่ละคำสั่งจะมี subroutine ที่อธิบายการปฏิบัตินั้น คุณอาจคิดว่าผมมีเพียงสิบการปฏิบัติเท่านั้น แต่จริง ๆ แล้วยังมีเพียงสี่การปฏิบัติแบบสามที่อยู่—การบวก การลบ การคูณ และการหาร—ดังนั้นผมจึงใช้คำสั่ง 0 เพื่อหมายถึง “ไปที่ที่อยู่ B แล้วค้นหารายละเอียดเพิ่มเติมที่ต้องการ” แต่ละ subroutine เมื่อเสร็จแล้วจะโอนการควบคุมไปยังตำแหน่งหนึ่งในลูป (4) จากนั้นเราเพิ่ม 1 ไปยังเนื้อหาในรีจิสเตอร์ car ปรับแต่งรายละเอียดบางอย่าง แล้วเริ่มใหม่ เช่นเดียวกับการทำงานภายในของเครื่องเดิม แน่นอนคำสั่งโอน ทั้งเจ็ดคำสั่งอย่างที่ผมจำได้ ล้วนใส่ที่อยู่ลงใน car และโอนไปยังจุดในลูปหลังการเพิ่ม 1 ให้กับ car
รูปที่ 4.1—ลูปของโปรแกรม
การพิจารณากระบวนการแสดงให้เห็นว่าความหมายใด ๆ ที่คุณอยากผูกกับคำสั่งต้องมาจาก subroutines ที่เขียนขึ้นสอดคล้องกับหมายเลขคำสั่ง Those subroutines define the meaning of the language. ในกรณีง่าย ๆ นี้แต่ละคำสั่งมีความหมายของตนเองโดยไม่ขึ้นกับคำสั่งอื่น แต่ชัดเจนว่าง่ายที่จะทำให้คำสั่งบางอย่างตั้งสวิตช์ ธง (flags) หรือบิตอื่น ๆ เพื่อให้คำสั่งต่อ ๆ มาตีความตามค่าเหล่านั้นในรูปแบบต่าง ๆ ดังนั้นคุณจึงเห็นว่าคุณสามารถออกแบบ any language you want ได้ตราบเท่าที่คุณสามารถกำหนดมันอย่างเฉพาะเจาะจง มันอยู่ด้านบนของคำสั่งของเครื่อง ทำให้เครื่องกลายเป็นเครื่องอื่นตามที่คุณต้องการ แน่นอน นี่เป็นสิ่งที่ Turing พิสูจน์ด้วย Universal Turing Machine แต่ดังที่กล่าวมาแล้ว มันยังไม่เข้าใจกันชัดเจนจนกว่าเราจะทำสำเร็จหลาย ๆ ครั้ง
ระบบซอฟต์แวร์ที่ผมสร้างถูกวางไว้ในรีจิสเตอร์หน่วยความจำหมายเลข 1,000 ถึง 1,999 ดังนั้นโปรแกรมใด ๆ ในภาษาสังเคราะห์ที่มีเพียงสามหลักทศนิยมจึงสามารถอ้างถึงที่อยู่ 000 ถึง 999 เท่านั้น และไม่สามารถอ้างถึงหรือเปลี่ยนรีจิสเตอร์ใด ๆ ในซอฟต์แวร์และทำลายมันได้: เป็นการป้องกันความปลอดภัยของซอฟต์แวร์จากผู้ใช้ที่ออกแบบไว้
ผมอธิบายรายละเอียดข้อนี้ค่อนข้างมากเพราะเรามักเขียนภาษาอยู่บนภาษาของเครื่อง และอาจเขียนภาษาที่สูงขึ้นอีกหลายชั้นกัน จนกว่าจะได้ภาษาที่ต้องการใช้สื่อปัญหาต่อเครื่อง หากคุณใช้ interpreter ในแต่ละชั้น แน่นอนจะมีประสิทธิภาพด้อยบ้าง การใช้ compiler ที่ชั้นบนสุดหมายความว่าภาษาชั้นสูงสุดถูกแปลไปยังภาษาที่ต่ำกว่าเพียงครั้งเดียว แต่อาจยังต้องการ interpreter บางระดับ และเหมือนกรณี EDSAC มักได้การบีบอัดงานเขียนโปรแกรมและหน่วยความจำอย่างมาก ผมอยากชี้ให้เห็นความแตกต่างระหว่างการเขียนภาษาในเชิงตรรกะและเชิงจิตวิทยาอีกครั้ง
น่าเสียดายที่โปรแกรมเมอร์ซึ่งมักมีแนวคิดเชิงตรรกะและไม่ค่อยเน้นมิติด้านมนุษย์ มักเขียนและยกย่องภาษาที่เชิงตรรกะ ตัวอย่างสูงสุดคงเป็น APL โดยเชิงตรรกะ APL เป็นภาษาที่ยอดเยี่ยมและยังมีผู้ศรัทธาอยู่ แต่สำหรับคนทั่วไปมันไม่เหมาะ ในภาษาแบบนี้มีเกม “one liners” คือให้มีหนึ่งบรรทัดของโค้ดแล้วถามว่ามันหมายถึงอะไร แม้แต่ผู้เชี่ยวชาญก็เคยสะดุด
การเปลี่ยนตัวอักษรเพียงตัวเดียวใน APL อาจเปลี่ยนความหมายทั้งหมดได้ ภาษานี้จึงเกือบไม่มี redundancy แต่มนุษย์ไม่เชื่อถือได้และต้องการความซ้ำซ้อน ภาษาพูดของเรามักมีความซ้ำซ้อนราว 60% ส่วนภาษาที่เขียนราว 40% คุณอาจคิดว่าภาษาพูดและเขียนเหมือนกัน แต่คุณผิด ลองเขียนบทสนทนาแล้วอ่านออกมาจริง ๆ จะเห็นความต่าง แทบไม่มีใครเขียนบทสนทนาให้เหมือนภาษาพูด และแม้มันจะฟังดูถูกต้องก็ยังไม่ใช่ภาษาพูดจริง ๆ
มนุษย์ไม่เชื่อถือได้ ตามที่ผมย้ำ ความซ้ำซ้อนต่ำหมายถึงมีข้อผิดพลาดที่ไม่ถูกตรวจจับมาก ในขณะที่ความซ้ำซ้อนสูงมักจับข้อผิดพลาดได้ ภาษาพูดส่งผ่านช่องสัญญาณเสียงที่มีเสียงรบกวนและต้องเข้าใจแบบเรียลไทม์ ส่วนภาษาที่เขียนถูกพิมพ์และคุณสามารถหยุด ย้อนอ่าน และใช้เครื่องมืออื่น ๆ เพื่อสกัดความหมายของผู้เขียน สังเกตว่าในภาษาอังกฤษคำต่างกันมักมีเสียงเดียวกัน (เช่น “there” กับ “their”) มากกว่าที่คำมีการสะกดเหมือนกันแต่เสียงต่าง (“record” เป็นคำนามหรือกริยา และ “tear” ความหมายต่างกัน) ดังนั้นคุณควรตัดสินภาษาว่ามันเหมาะกับมนุษย์อย่างไร—และจำไว้ผมรวมการฝึกในโรงเรียนด้วย มิฉะนั้นคุณต้องพร้อมฝึกมากเพื่อรับมือภาษาประเภทใหม่ที่ใช้ หากภาษานั้นง่ายสำหรับผู้เชี่ยวชาญคอมพิวเตอร์ไม่ได้หมายความว่าจะง่ายสำหรับผู้ไม่เชี่ยวชาญ และมีแนวโน้มว่าผู้ไม่เชี่ยวชาญจะทำงานเขียนโปรแกรมมากในอนาคตอันใกล้
สิ่งที่ต้องการในระยะยาวคือให้ผู้ที่มีปัญหาเป็นผู้เขียนโค้ดจริง ๆ โดยไม่มีคนกลางที่แบ่งแยกระหว่างผู้รู้ปัญหาและผู้รู้ภาษาโปรแกรม แม้วันที่จะมาถึงยังไกลเกินไป แต่ผมคิดว่าในปี 2020 คงเป็นเรื่องปกติที่ผู้เชี่ยวชาญในสาขาประยุกต์จะเตรียมโปรแกรมเอง แทนที่จะปล่อยให้ผู้เชี่ยวชาญด้านคอมพิวเตอร์ (ที่ไม่รู้เรื่องสาขาประยุกต์) เตรียมโปรแกรม
น่าเสียดาย ในความเห็นของผม ภาษา Ada ถูกออกแบบโดยผู้เชี่ยวชาญ และมันสะท้อนลักษณะที่ไม่เป็นมิตรกับมนุษย์ทั้งหมดที่คุณคาดหวังจากพวกเขา ในความเห็นของผมมันเป็นงานของนักวิทยาศาสตร์คอมพิวเตอร์แบบ hacking—อย่าเพิ่งพยายามเข้าใจว่าคุณกำลังทำอะไร แค่ทำให้มันรันได้ ดังนั้นจากการออกแบบทางจิตวิทยาที่ไม่ดี การสำรวจส่วนตัวของผมในกลุ่มคนรู้เรื่องชี้ว่าถึงแม้สัญญารัฐอาจระบุภาษาที่ต้องใช้เป็น Ada แต่กว่า 90% น่าจะทำใน Fortran ดำเนินการดีบัก ทดสอบ แล้วค่อยแปลงอย่างเจ็บปวดด้วยมือเป็นโปรแกรม Ada ที่ไม่ดี มีความเป็นไปได้สูงที่จะมีข้อผิดพลาด!
พื้นฐานของภาษาในแง่นี้ยังไม่เข้าใจจนถึงปัจจุบัน ครั้งหนึ่งในต้นทศวรรษ 1950 ผมพา 'ผู้เชี่ยวชาญภาษาธรรมชาติ' ในท้องถิ่นไปเยี่ยม IBM 701 แล้วไปทานข้าว และตอนของหวานผมถาม "Professor Pei, ช่วยพูดถึงประสิทธิภาพเชิงวิศวกรรมของภาษาให้ฟังหน่อย" เขาไม่สามารถเข้าใจคำถามนี้และพูดแต่ลักษณะเฉพาะของภาษา เช่น บอกว่าภาษานี้ใส่พหูพจน์ไว้กลางคำ ภาษานั้นมีคุณสมบัติหรือไม่มีคุณสมบัตินั้น ฯลฯ สิ่งที่ผมอยากรู้คือเราจะทำหน้าที่สื่อสารให้มีประสิทธิภาพได้อย่างไรเมื่อเรามีอำนาจออกแบบภาษา และเมื่อปลายทางด้านหนึ่งคือมนุษย์ซึ่งมีข้อบกพร่อง และอีกด้านคือเครื่องที่มีความน่าเชื่อถือสูงทำตามคำสั่งเท่านั้น ผมอยากรู้ว่าควรมีความซ้ำซ้อนแค่ไหนสำหรับภาษาเหล่านี้ ความหนาแน่นของคำกริยาปกติและไม่ปกติ อัตราส่วนของคำพ้องความหมายกับคำตรงข้าม ทำไมมีจำนวนเท่าที่เป็นอยู่ วิธีบีบอัดช่องสื่อสารอย่างมีประสิทธิภาพแล้วยังคงเหลือความซ้ำซ้อนที่ใช้ได้สำหรับมนุษย์ ฯลฯ ดังที่ผมพูดเขาฟังไม่ออกถึงคำถามเกี่ยวกับประสิทธิภาพเชิงวิศวกรรมของภาษา และผมไม่เห็นการศึกษามากนักเกี่ยวกับเรื่องนี้นับแต่นั้นมา แต่จนกว่าเราจะเข้าใจสิ่งเหล่านี้อย่างแท้จริง—สมมติว่าภาษาธรรมชาติที่วิวัฒนาการมายาวนานเหมาะสมกับงานที่มนุษย์ต้องทำ—เราจะยังไม่รู้วิธีออกแบบภาษาสำหรับการสื่อสารคนกับเครื่องอย่างมีประสิทธิภาพ ดังนั้นผมคาดว่าจะมีปัญหาอีกมากจนกว่าเราจะเข้าใจการสื่อสารระหว่างมนุษย์ผ่านภาษาธรรมชาติ ซึ่งปัญหาการสื่อสารคนกับเครื่องแตกต่างจากคนกับคนอย่างมีนัยยะ แต่แตกต่างอย่างไรและมากแค่ไหนยังไม่เป็นที่รู้และยังไม่ได้รับการศึกษา
จนกว่าเราจะเข้าใจภาษาสำหรับการสื่อสารที่เกี่ยวข้องกับมนุษย์ในลักษณะที่เป็นอยู่ (หรือสามารถฝึกได้ง่าย) โอกาสที่ปัญหาซอฟต์แวร์ของเราจะหายไปมีไม่มากนัก
เมื่อไม่นานมานี้มี 'fifth generation' ของคอมพิวเตอร์ที่ญี่ปุ่นวางแผนจะใช้ควบคู่กับ AI เพื่อปรับปรุงอินเทอร์เฟซระหว่างเครื่องกับผู้แก้ปัญหามนุษย์ มีการกล่าวอ้างยิ่งใหญ่ทั้งเรื่องเครื่องและภาษา ผลลัพธ์จนถึงตอนนี้คือเครื่องออกมาตามที่โฆษณา แต่การใช้ AI เพื่อช่วยการเขียนโปรแกรมยังต้องกลับไปสู่กระดานออกแบบอีกครั้ง ตามที่ผมทำนายไว้ตอนนั้น (สำหรับ Los Alamos) เพราะผมไม่เห็นว่าญี่ปุ่นพยายามเข้าใจพื้นฐานของภาษาในความหมายเชิงวิศวกรดังกล่าว มีหลายอย่างที่เราทำได้เพื่อลด 'the software problem' แต่ต้องใช้ความเข้าใจพื้นฐานของภาษาในการสื่อความ 'ความเข้าใจ' ระหว่างมนุษย์ และระหว่างมนุษย์กับเครื่อง ก่อนที่เราจะมีทางแก้ที่ดีสำหรับปัญหาที่มีค่าใช้จ่ายสูงนี้ มันจะไม่หายไปง่าย ๆ
คุณมักอ่านเรื่อง 'engineering the production of software' ทั้งด้านประสิทธิภาพการผลิตและความน่าเชื่อถือของผลิตภัณฑ์ แต่คุณไม่คาดหวังให้นักเขียนนิยาย 'engineer the production of novels' คำถามคือ 'การเขียนโปรแกรมใกล้กับการเขียนนิยายมากกว่ากับวิศวกรรมแบบดั้งเดิมหรือไม่?' ผมว่าใช่! เมื่อพูดถึงปัญหาพาผู้คนขึ้นสู่อวกาศ ทั้งรัสเซียและอเมริกาทำได้ค่อนข้างเหมือนกัน ทั้งคู่ถูกจำกัดด้วยกฎฟิสิกส์เหมือนกัน แต่ให้สองนักเขียนนิยายเขียนเรื่อง 'the greatness and misery of man' คุณจะได้สองนิยายที่ค่อนข้างต่างกัน ให้ปัญหาซับซ้อนเดียวกันกับสองโปรแกรมเมอร์สมัยใหม่ ผมเชื่อว่าคุณจะได้โปรแกรมสองชุดที่ค่อนข้างต่างกัน ดังนั้นผมเชื่อว่าการปฏิบัติการเขียนโปรแกรมปัจจุบันคล้ายกับการเขียนนิยายมากกว่าวิศวกรรม นักเขียนนิยายถูกจำกัดเพียงโดยจินตนาการ ซึ่งก็คล้ายกับโปรแกรมเมอร์เมื่อเขียนซอฟต์แวร์ ทั้งสองกิจกรรมมีองค์ประกอบสร้างสรรค์มาก แม้คุณอยากให้การเขียนโปรแกรมเหมือนวิศวกรรมจริง ๆ ก็ต้องใช้เวลามาก—และบางทีในระยะยาวคุณอาจไม่อยากจริง ๆ ก็ได้! มันอาจฟังดูดีเท่านั้น คุณจะต้องคิดเรื่องนี้หลายครั้งในปีหน้า คุณควรตัดความที่มาในโฆษณาและความคิดที่ไม่เป็นจริงออก ซอฟต์แวร์ของโปรแกรมยูทิลิตี้ถูกทำซ้ำบ่อยและมีขอบเขตจำกัด จึงอาจถูก 'วิศวกรรม' ได้ แต่การเตรียมซอฟต์แวร์ทั่วไปไม่น่าจะอยู่ภายใต้ 'engineering control' ได้อีกหลายปี
มีข้อเสนอมากมายในการปรับปรุงผลิตภาพของโปรแกรมเมอร์รายบุคคล และกลุ่มผมได้กล่าวถึง top-down และ bottom-up แล้วยังมีบทบาทอื่น ๆ เช่น head programmer, lead programmer, การพิสูจน์ความถูกต้องของโปรแกรมเชิงคณิตศาสตร์ และ waterfall model เป็นต้น แต่แม้แต่ละวิธีย่อมมีคุณค่า ผมเชื่อแค่ข้อเดียวซึ่งแทบไม่ค่อยถูกเอ่ยถึง—think before you write the program ก่อนเริ่ม คิดอย่างรอบคอบถึงทั้งภาพรวม รวมทั้งจะทดสอบยอมรับมันได้อย่างไร และการบำรุงรักษาภาคสนามในภายหลังจะทำอย่างไร ทำให้ถูกตั้งแต่ครั้งแรกดีกว่ามาแก้ทีหลัง!
ปัญหาอย่างหนึ่งของการเขียนโปรแกรมมาก ๆ คือบ่อยครั้งไม่มีงานที่กำหนดไว้อย่างชัดเจน กระบวนการเขียนโปรแกรมเองมักจะค้นพบว่าปัญหาคืออะไร! ความต้องการให้คุณได้รับปัญหาที่กำหนดชัดก่อนเริ่มโปรแกรมมักไม่ตรงกับความเป็นจริง และดังนั้นข้อเสนอมากมายที่จะ 'แก้ปัญหาการเขียนโปรแกรม' จะล้มเหลวถ้านำมาใช้เข้มงวด
การใช้ภาษาระดับสูงขึ้นหมายถึงความก้าวหน้ามาก ตารางต่อไปนี้แสดงการประมาณการหนึ่งของการปรับปรุงใน 30 ปี
| ประเภทของการปรับปรุง | ปัจจัยการปรับปรุงสะสม | ||
|---|---|---|---|
| Assembler:machine code (Assembler: รหัสเครื่อง) | \= | 2:1 | ×2 |
| C language:assembler (C language: แอสเซมเบลอร์) | \= | 3:1 | ×6 |
| Timeshare:batch (Timeshare: batch) | \= | 1.5:1 | ×9 |
| UNIX:monitor (UNIX: มอนิเตอร์) | \= | 4:3 | ×12 |
| System QA:debugging (System QA: การดีบัก) | \= | 2:1 | ×24 |
| Prototyping:top-down (Prototyping: top-down) | \= | 1.3:1 | ×30 |
| C++:C (C++: C) | \= | 2:1 | ×60 |
| Reuse:redo (Reuse: ลดการทำซ้ำ) | \= | 1.5:1 | ×90 |
เราดูเหมือนจะเพิ่มปัจจัยผลผลิตโดยรวมของโปรแกรมเมอร์ขึ้นประมาณ 90 เท่าใน 30 ปี (อัตราการปรับปรุงเพียง 16% เท่านั้น!) นี่เป็นการคาดการณ์ของคน ๆ หนึ่ง และอย่างน้อยก็สมเหตุสมผล แต่เมื่อเทียบกับความเร็วของเครื่องแล้วมันน้อยมาก! ผู้คนอยากให้มนุษย์ถูกเร่งความเร็วเช่นเดียวกัน แต่คอขวดพื้นฐานคือ 'มนุษย์ตามสภาพที่เป็น' ไม่ใช่อย่างที่เราปรารถนา
การศึกษาหลายชิ้นแสดงว่าโปรแกรมเมอร์มีความแตกต่างด้านผลผลิตจากแย่สุดถึงดีที่สุดมากกว่าปัจจัยสิบ ข้อสรุปของผมคือจ่ายค่าจ้างโปรแกรมเมอร์ที่ดีสูง ๆ แต่ไล่พนักงานที่แย่ออกเป็นประจำ—ถ้าคุณทำได้! ทางหนึ่งคือจ้างเป็นสัญญาแทนการเป็นพนักงานประจำ แต่กฎหมายมักจะจำกัดสิ่งนั้น ซึ่งดูเหมือนต้องการรับประกันว่าคนแย่ที่สุดก็จะมีงาน ในทางปฏิบัติคุณอาจจ่ายให้คนแย่หยุดอยู่บ้านจะดีกว่าเพื่อไม่ให้เป็นอุปสรรคแก่คนที่มีความสามารถ (ผมพูดจริง ๆ นะ!)
คอมพิวเตอร์ดิจิทัลตอนนี้ถูกใช้กันอย่างแพร่หลายในการจำลอง neural nets และอุปกรณ์คล้าย ๆ กันกำลังคืบคลานเข้าสู่สนามคอมพิวติ้ง Neural nets—ถ้าคุณยังไม่คุ้นเคย—สามารถ learn ให้ได้ผลลัพธ์เมื่อให้ชุดอินพุตและเอาต์พุตที่ยอมรับได้ โดยไม่ต้องบอกวิธีการผลิตผลลัพธ์ทีละขั้น พวกมันสามารถจัดประเภทวัตถุเป็นคลาสที่สมเหตุสมผล โดยไม่จำเป็นต้องมีการบอกล่วงหน้าว่าคลาสใดจะถูกใช้หรือค้นพบ พวกมันเรียนรู้ด้วย feedback แบบง่าย ๆ ซึ่งใช้ข้อมูลว่าผลลัพธ์ที่ได้จากอินพุตไม่เป็นที่ยอมรับ ในทางหนึ่งพวกมันแทนทางแก้ 'the programming problem' — เมื่อสร้างแล้วพวกมันแทบไม่ถูก 'โปรแกรม' อีก แต่ยังสามารถแก้ปัญหาได้หลากหลายอย่างอย่างน่าพอใจ เป็นสาขาที่กำลังมาและผมจะต้องข้ามในหนังสือเล่มนี้ แต่พวกมันน่าจะมีบทบาทมากในอนาคตของคอมพิวเตอร์ ในความหมายหนึ่งพวกมันเป็น 'ฮาร์ดไวร์' คอมพิวเตอร์ (อาจจะเป็นเพียงโปรแกรม) เพื่อแก้คลาสปัญหากว้าง ๆ เมื่อเลือกพารามิเตอร์ไม่กี่ตัวและป้อนข้อมูลจำนวนมาก
มุมมองอีกอย่างของ neural nets คือพวกมันเป็นคลาสทั่วไปของระบบ feedback ที่มีเสถียรภาพ คุณเลือกชนิดและปริมาณ feedback ที่คิดว่าพอเหมาะ จากนั้นระบบ feedback ของ neural net จะรวมตัวจนถึงคำตอบที่ต้องการ อีกครั้ง มันหลีกเลี่ยงการโปรแกรมรายละเอียดจำนวนมาก เพราะอย่างน้อยใน neural net ที่จำลองบนคอมพิวเตอร์ เมื่อเขียนโปรแกรมชิ้นกว้าง ๆ ครั้งเดียว คุณก็จะมีคลาสปัญหากว้าง ๆ ที่โปรแกรมไว้แล้ว และโปรแกรมเมอร์แทบไม่ได้ทำอะไรเกินการเรียกใช้คำสั่ง
ชิ้นงานโปรแกรมทั่วไปอื่น ๆ ที่สามารถทำแบบเดียวกันได้ยังไม่เป็นที่รู้ — คุณอาจคิดว่านี่เป็นหนึ่งในทางแก้ 'ปัญหาการเขียนโปรแกรม'
ในบทฮาร์ดแวร์ผมได้อภิปรายข้อจำกัดบางประการอย่างละเอียด—ขนาดของโมเลกุล ความเร็วของแสง และการระเหยความร้อน ผมควรสรุปข้อจำกัดด้านซอฟต์แวร์ที่ไม่แน่นอนในลักษณะเดียวกัน
ผมเปรียบการเขียนซอฟต์แวร์กับการเขียนวรรณกรรม ทั้งสองดูเหมือนจะขึ้นอยู่กับการคิดที่ชัดเจน การโปรแกรมที่ดีสอนกันได้ไหม? ถ้าเทียบกับหลักสูตร 'creative writing' เราพบว่านักเรียนส่วนใหญ่ของคอร์สดังกล่าวไม่ได้กลายเป็นนักเขียนที่ยิ่งใหญ่ และนักเขียนที่ยิ่งใหญ่ในอดีตส่วนใหญ่ไม่ได้เรียนคอร์สเขียนสร้างสรรค์! ดังนั้นจึงเป็นเรื่องสงสัยว่าผู้เชี่ยวชาญด้านโปรแกรมมิ่งที่ยอดเยี่ยมจะถูกฝึกได้ง่าย
ประสบการณ์ช่วยได้ไหม? ข้าราชการหลังจากปี ๆ ที่เขียนรายงานและคำสั่งดีขึ้นไหม? ผมไม่มีข้อมูลแน่ชัด แต่ผมสงสัยว่าตามเวลาอาจแย่ลง! การใช้ 'governmentese' เป็นนิสัยนาน ๆ อาจซึมซับเข้าสู่สไตล์การเขียนและทำให้แย่ลง ผมสงสัยว่าคนเขียนโปรแกรมก็เช่นกัน! ทั้งปีของประสบการณ์หรือจำนวนภาษาที่ใช้ไม่ใช่เหตุผลที่บอกได้ว่าโปรแกรมเมอร์ดีขึ้น การตรวจสอบหนังสือเกี่ยวกับการเขียนโปรแกรมบ่งชี้ว่าแอธอร์ส่วนใหญ่ไม่ใช่โปรแกรมเมอร์ที่ดี!
ผลลัพธ์ที่ผมพอนึกภาพไม่สวยนัก แต่สิ่งที่คัดค้านคุณได้มีเพียงความหวังเท่านั้น—ผมมีหลักฐานจากปีแล้วปีเล่าที่ทำงานด้านโปรแกรมมิ่งอยู่ข้างผม!