ดังที่ผมกล่าวไว้ในบทที่แล้ว ในยุคแรกเริ่มของการคอมพิวติ้ง ส่วนควบคุมทั้งหมดทำด้วยมือ เครื่องคอมพิวเตอร์แบบตั้งโต๊ะที่ช้านั้นในตอนแรกควบคุมด้วยมือ ตัวอย่างเช่น การคูณทำได้โดยการบวกซ้ำๆ พร้อมเลื่อนหลักหลังจากแต่ละหลักของตัวคูณ การหารก็ทำในลักษณะเดียวกันโดยการลบซ้ำๆ ต่อมาจึงมีการใช้มอเตอร์ไฟฟ้า ทั้งเพื่อเพิ่มกำลังและเพื่อการควบคุมการคูณหารแบบอัตโนมัติมากขึ้น เครื่องเจาะบัตรถูกควบคุมด้วยการเดินสายบนปลั๊กบอร์ดเพื่อบอกเครื่องว่าต้องหาข้อมูลจากที่ไหน ทำอะไรกับมัน และต้องวางคำตอบไว้ที่ใดบนบัตร (หรือบนแผ่นพิมพ์ของ tabulator) แต่การควบคุมบางส่วนก็อาจมาจากตัวบัตรเอง โดยเฉพาะการเจาะ X และ Y (หลักอื่นๆ ในบางครั้งก็สามารถควบคุมสิ่งที่เกิดขึ้นได้) ปลั๊กบอร์ดแต่ละอันถูกเดินสายเฉพาะสำหรับงานแต่ละอย่าง และในสำนักงานบัญชี บอร์ดที่เดินสายไว้แล้วมักจะถูกเก็บไว้และนำกลับมาใช้ใหม่ทุกสัปดาห์หรือทุกเดือนตามรอบของงานบัญชี
เมื่อเรามาถึงเครื่องรีเลย์ หลังจาก Complex Number Computer เครื่องแรกของ Stibitz เครื่องเหล่านี้ส่วนใหญ่ถูกควบคุมด้วยเทปกระดาษเจาะรู เทปกระดาษเป็นสิ่งที่แย่มากเมื่อใช้กับปัญหาที่ทำครั้งเดียว—มันยุ่งเหยิง และการติดเทปเพื่อแก้ไขหรือทำเป็นลูปก็เป็นปัญหา (เพราะว่า กาวมักจะเข้าไปติดที่หัวอ่านของเครื่อง!) ด้วยหน่วยความจำภายในที่มีน้อยมากในยุคแรก ทำให้ไม่สามารถเก็บโปรแกรมไว้ในเครื่องได้อย่างคุ้มค่า (ถึงแม้ผมจะเชื่อว่าผู้ออกแบบคงคิดถึงเรื่องนี้)
เครื่อง eniac ในตอนแรก (1945–1946) ถูกควบคุมด้วยการเดินสายเหมือนกับปลั๊กบอร์ดขนาดยักษ์ แต่ต่อมา Nick Metropolis และ Dick Clippinger ได้เปลี่ยนมันให้เป็นเครื่องที่โปรแกรมจากตาราง ballistic ซึ่งเป็นชั้นวางขนาดใหญ่ที่มีหน้าปัดสำหรับตั้งค่าหลักเลขฐานสิบของโปรแกรมผ่านลูกบิดของสวิตช์เลขฐานสิบ
การเขียนโปรแกรมภายในเครื่อง (internal programming) กลายเป็นความจริงเมื่อมีหน่วยความจำในปริมาณที่พอใช้ และถึงแม้โดยทั่วไปจะยกความดีความชอบให้กับ von Neumann แต่เขาเป็นเพียงที่ปรึกษาของ Mauchly และ Eckert และทีมของพวกเขา ตามที่ Harry Huskey กล่าว การเขียนโปรแกรมภายในเครื่องถูกพูดคุยกันโดยพวกเขา ก่อน ที่ von Neumann จะเริ่มเข้ามาเป็นที่ปรึกษา เอกสารชุดแรกที่เป็นที่เข้าถึงได้อย่างกว้างขวาง (หลังจากที่ Lady Lovelace ได้เขียนและตีพิมพ์โปรแกรมสองสามโปรแกรมสำหรับ เครื่อง Babbage analytical engine ที่เสนอไว้) คือรายงาน von Neumann Army ซึ่งถูกเผยแพร่อย่างกว้างขวางแต่ไม่เคยถูกตีพิมพ์ในวารสารที่ผ่านการกลั่นกรองใดๆ
รหัสในยุคแรกส่วนใหญ่เป็นแบบ one address หมายความว่าแต่ละคำสั่งประกอบด้วยส่วนของคำสั่งและที่อยู่ที่จะค้นหาหรือส่งตัวเลขไป เรายังมีรหัสแบบ two-address ซึ่งโดยทั่วไปใช้กับเครื่องที่มี rotating drum เพื่อให้คำสั่งถัดไปพร้อมใช้งานทันทีหลังจากคำสั่งก่อนหน้าเสร็จ—หลักการเดียวกันนี้ใช้กับ mercury delay lines และอุปกรณ์เก็บข้อมูลอื่นๆ ที่เข้าถึงแบบอนุกรม การเขียนรหัสแบบนี้เรียกว่า minimum-latency coding และคุณคงนึกภาพออกว่าโปรแกรมเมอร์ต้องลำบากแค่ไหนในการคำนวณว่าจะวางคำสั่งถัดไปและตัวเลขไว้ที่ไหน (เพื่อหลีกเลี่ยงความล่าช้าและความขัดแย้งให้ดีที่สุด) นอกเหนือจากการหา errors (bugs) ในโปรแกรมอีกด้วย ต่อมามีโปรแกรมชื่อ soap (symbolic optimizing assembly program) ที่ช่วยทำ optimization นี้โดยใช้เครื่อง ibm 650 เอง ก็ยังมีรหัสแบบ three และ four-address ด้วย แต่ผมจะไม่พูดถึงในที่นี้
เรื่องที่น่าสนใจเกี่ยวกับ soap คือสำเนาของโปรแกรม สมมติว่าเรียกมันว่าโปรแกรม A ถูกโหลดเข้าเครื่องทั้งในฐานะโปรแกรมและถูกประมวลผลในฐานะข้อมูล ผลลัพธ์ที่ได้คือโปรแกรม B จากนั้น B ถูกโหลดเข้าเครื่อง 650 และ A ถูกรันเป็นข้อมูลเพื่อสร้างโปรแกรม B ใหม่ ความแตกต่างของเวลารันระหว่างสองครั้งในการสร้างโปรแกรม B บอกให้เราทราบว่า optimization ของโปรแกรม soap (โดย soap เอง) ให้ผลดีแค่ไหน นับเป็นตัวอย่างแรกๆ ของ self-compiling เท่าที่มีมา
ในตอนแรกเราเขียนโปรแกรมด้วย absolute binary หมายความว่าเราเขียนที่อยู่จริงของข้อมูลในรูปแบบ binary และเขียนส่วนคำสั่งใน binary ด้วย! มีสองแนวทางที่จะหลีกหนีจากสิ่งนี้: octal ซึ่งก็คือการจัดกลุ่ม binary digits เป็นชุดละสามตัว และ hexadecimal ซึ่งใช้ทีละสี่หลัก และต้องใช้ A, B, C, D, E, และ F เพื่อแทนตัวเลขที่เกิน 9 (และแน่นอน คุณต้องเรียนรู้ตารางการคูณและการบวกถึง 15)
ในการแก้ไข error ถ้าคุณต้องการแทรกคำสั่งที่ตกหล่นไป คุณก็จะนำคำสั่งก่อนหน้านั้นมาแทนที่ด้วย transfer instruction ไปยังพื้นที่ว่างบางแห่ง ตรงนั้นคุณใส่คำสั่งเดิมที่คุณเขียนทับลงไป เพิ่มคำสั่งที่คุณต้องการแทรก ตามด้วย transfer กลับมาที่โปรแกรมหลัก ดังนั้นโปรแกรมก็จะกลายเป็นลำดับของการกระโดดของ control ไปยังที่ต่างๆ เมื่อมี error ในการแก้ไข ซึ่งแทบจะเกิดขึ้นเสมอ คุณก็ใช้เทคนิคเดิมอีกครั้ง โดยใช้พื้นที่ว่างอื่นๆ ผลลัพธ์ก็คือเส้นทางของ control ในหน่วยความจำกลายเป็นเหมือนเส้นสปาเก็ตตี ทำไมไม่แทรกคำสั่งเข้าไปในลำดับปกติ? เพราะถ้าทำอย่างนั้นคุณจะต้องกลับไปแก้ทั้งโปรแกรมเพื่อเปลี่ยนที่อยู่ทั้งหมดที่อ้างถึงคำสั่งที่ถูกย้าย! อะไรแบบนั้นไม่เอาแน่ๆ!
เราเริ่มมีแนวคิดเรื่อง reusable software อย่างที่เรียกกันในปัจจุบัน อันที่จริง Babbage ก็เคยมีแนวคิดนี้มาก่อน เราเขียน library ทางคณิตศาสตร์เพื่อนำบล็อกของโค้ดกลับมาใช้ใหม่ แต่ library แบบ absolute address หมายความว่าทุกครั้งที่มีการใช้ routine จาก library มันจะต้องอยู่ในตำแหน่งหน่วยความจำเดิม เมื่อ library มีขนาดใหญ่เกินไป เราก็ต้องเปลี่ยนไปใช้ relocatable programs เทคนิคการเขียนโปรแกรมที่จำเป็นมีอยู่ในรายงานของ von Neumann ซึ่งไม่เคยถูกตีพิมพ์อย่างเป็นทางการ
หนังสือเล่มแรกที่ตีพิมพ์เกี่ยวกับการเขียนโปรแกรม โดย Wilkes, Wheeler, และ Gill ซึ่งใช้กับเครื่อง edsac ที่ Cambridge ประเทศอังกฤษ (1951) ผมและคนอื่นๆ อีกมากได้เรียนรู้จากหนังสือเล่มนี้อย่างมาก ดังที่คุณจะเห็นในอีกไม่กี่นาที
มีคนเกิดแนวคิดว่าเราสามารถเขียนโปรแกรมสั้นๆ ที่อ่านชื่อสัญลักษณ์ของการดำเนินการ (เช่น add ) และแปลมัน ในตอนที่ป้อนข้อมูล ให้เป็น binary representation ที่ใช้ภายในเครื่อง (เช่น 01100101 ) ตามมาด้วยแนวคิดของการใช้ symbolic addresses—ซึ่งเป็นเรื่องนอกรีตอย่างแท้จริงสำหรับโปรแกรมเมอร์ยุคเก่า คุณคงไม่ค่อยเห็นการเขียน absolute programming แบบวีรบุรุษยุคเก่าในปัจจุบัน (ยกเว้นกรณีที่คุณเล่นกับเครื่องคิดเลข programmable แบบพกพาและพยายามให้มันทำสิ่งที่ผู้ออกแบบและผู้สร้างไม่เคยตั้งใจ)
ผมเคยใช้เวลาทั้งปี โดยได้รับความช่วยเหลือจากโปรแกรมเมอร์หญิงจาก Bell Telephone Laboratories กับปัญหาขนาดใหญ่หนึ่งปัญหา โดยเขียนโค้ดใน absolute binary สำหรับเครื่อง ibm 701 ซึ่งใช้ register ทั้งหมด 32K ที่มีอยู่ในตอนนั้น หลังจากประสบการณ์นั้นผมก็ปฏิญาณว่าจะไม่ขอให้ใครทำงานหนักแบบนั้นอีก เมื่อได้ยินเกี่ยวกับระบบ symbolic system จาก Poughkeepsie, ibm ผมขอให้เธอส่งของนั้นมาและใช้มันในปัญหาถัดไป ซึ่งเธอก็ทำ ตามที่คาดไว้ เธอรายงานว่ามันง่ายกว่ามาก เราจึงบอกทุกคนเกี่ยวกับวิธีการใหม่นี้ นั่นคือคนประมาณ 100 คนที่กำลังกินข้าวใน ibm cafeteria ใกล้กับที่ตั้งของเครื่อง ประมาณครึ่งเป็นคนของ ibm และอีกครึ่งเป็นคนนอกอย่างเราที่เช่าเวลาใช้เครื่อง เท่าที่ผมรู้ มีแค่คนเดียว—ใช่ แค่คนเดียว—จากทั้งหมด 100 คนที่แสดงความสนใจ!
ในที่สุด Symbolic Assembly Program ที่สมบูรณ์และมีประโยชน์มากขึ้น ( sap ) ก็ถูกพัฒนาขึ้น—หลังจากเวลาที่นานกว่าที่คุณจะเชื่อได้ ในระหว่างนั้นโปรแกรมเมอร์ส่วนใหญ่ยังคงเขียน absolute binary programming แบบวีรบุรุษต่อไป เมื่อ sap ปรากฏตัวครั้งแรก ผมเดาว่ามีโปรแกรมเมอร์รุ่นเก่าแค่ประมาณ 1% เท่านั้นที่สนใจมัน—การใช้งาน sap เป็น "ของสำหรับพวกกะเทย" และโปรแกรมเมอร์ตัวจริงจะไม่ยอมลดตัวลงมาเสียความสามารถของเครื่องไปกับการทำ assembly ใช่แล้ว! โปรแกรมเมอร์ไม่ต้องการมีส่วนเกี่ยวข้องกับมันเลย ถึงแม้ว่าเมื่อถูกกดดันพวกเขาต้องยอมรับว่าวิธีการเก่าใช้เวลาเครื่องมากกว่าในการค้นหาและแก้ไข errors มากกว่าที่โปรแกรม sap เคยใช้ ข้อร้องเรียนหลักข้อหนึ่งคือเมื่อใช้ระบบ symbolic คุณจะไม่รู้ว่าอะไรอยู่ที่ไหนในหน่วยความจำ—ถึงแม้ว่าในช่วงแรกเราจะให้แผนที่การแมประหว่าง symbolic กับหน่วยความจำจริง และเชื่อหรือไม่ว่าต่อมาพวกเขากลับชอบก้มหน้าอ่านแผ่นเหล่านั้น แทนที่จะตระหนักว่าพวกเขาไม่จำเป็นต้องรู้ข้อมูลนั้นถ้าพวกเขาทำงานภายในระบบ—ไม่เลย! เมื่อต้องแก้ไข errors พวกเขาชอบที่จะใช้ absolute binary addresses
fortran ซึ่งย่อมาจาก for mula tran slation ถูกเสนอโดย Backus และเพื่อนๆ และอีกครั้งที่ถูกคัดค้านโดยโปรแกรมเมอร์เกือบทั้งหมด ข้อแรก บอกว่ามันเป็นไปไม่ได้ ข้อสอง ถ้ามันเป็นไปได้ ก็จะสิ้นเปลืองเวลาและความสามารถของเครื่องมากเกินไป ข้อสาม ถึงแม้มันจะทำงานได้ ก็ไม่มีโปรแกรมเมอร์ที่น่านับถือคนไหนใช้มัน—มันมีไว้สำหรับพวกกะเทยเท่านั้น!
การใช้งาน fortran เช่นเดียวกับ symbolic programming ในยุคแรก ถูกนำมาใช้โดยกลุ่มมืออาชีพอย่างช้ามาก และนี่เป็นเรื่องปกติของกลุ่มมืออาชีพแทบทุกกลุ่ม หมอเองก็ไม่ปฏิบัติตามคำแนะนำที่ให้กับคนไข้ และยังมีสัดส่วนของผู้ติดยาสูงอีกด้วย ทนายความมักจะไม่ทำพินัยกรรมที่ดีเมื่อพวกเขาตาย กลุ่มมืออาชีพเกือบทั้งหมดใช้ความเชี่ยวชาญของตนเองกับงานของตัวเองอย่างช้า สถานการณ์นี้ถูกสรุปไว้อย่างดีด้วยสุภาษิตโบราณที่ว่า "ลูกช่างทำรองเท้าไม่มีรองเท้าใส่" ลองคิดดูว่าในอนาคต เมื่อคุณเป็นผู้เชี่ยวชาญที่ยิ่งใหญ่ คุณจะหลีกเลี่ยงข้อผิดพลาดทั่วไปนี้ได้อย่างไร
เมื่อ fortran พร้อมใช้งานและทำงานได้ ผมบอกให้โปรแกรมเมอร์ของผมทำปัญหาถัดไปด้วย fortran แก้ errors ออกจากมัน ให้ผมทดสอบเพื่อดูว่ามันกำลังแก้ปัญหาที่ถูกต้อง จากนั้นเธอสามารถ ถ้าเธอต้องการ เขียน inner loop ใหม่ใน machine language เพื่อเพิ่มความเร็วและประหยัดเวลาเครื่อง ผลลัพธ์คือเราสามารถ ด้วยความพยายามที่เท่าๆ กัน ผลิตผลงานได้มากกว่าคนอื่นเกือบสิบเท่า แต่สำหรับพวกเขาแล้ว การเขียนโปรแกรมด้วย fortran ไม่ใช่สำหรับโปรแกรมเมอร์จริง!
การจัดการทางกายภาพของเครื่อง ibm 701 ที่ ibm Headquarters ในนิวยอร์กซิตี้ที่เราเช่าเวลาใช้นั้นแย่มาก มันเป็นการสิ้นเปลืองเวลาเครื่อง (ในตอนนั้น $300 ต่อชั่วโมงถือว่าแพงมาก) รวมถึงเวลาของคนด้วย ด้วยเหตุนี้ผมจึงปฏิเสธที่จะสั่งซื้อเครื่องขนาดใหญ่ในภายหลังจนกว่าผมจะคิดหาวิธีการมีระบบ monitor—ซึ่งสุดท้ายคนอื่นก็สร้างมันให้กับเครื่อง ibm 709 เครื่องแรกของเรา และต่อมาก็ปรับปรุงมันสำหรับ ibm 7096
อีกครั้งหนึ่ง ระบบ monitor ซึ่งปัจจุบันมักเรียกว่า "the system" เช่นเดียวกับทุกขั้นตอนก่อนหน้านี้ที่ผมกล่าวถึง ควรจะเป็นสิ่งที่ชัดเจนสำหรับใครก็ตามที่ใช้เครื่องเหล่านี้ทุกวัน แต่ผู้ใช้ส่วนใหญ่ดูจะยุ่งเกินกว่าจะคิดหรือสังเกตว่าสิ่งต่างๆ แย่แค่ไหน และคอมพิวเตอร์สามารถทำอะไรได้มากแค่ไหนเพื่อทำให้ทุกอย่างง่ายขึ้นและถูกลงอย่างมีนัยสำคัญ การจะมองเห็นสิ่งที่ชัดเจนมักต้องใช้คนนอก หรือไม่ก็คนอย่างผมที่ช่างคิดและสงสัยว่าเขากำลังทำอะไรอยู่และทำไมทั้งหมดนี้ถึงจำเป็น ถึงแม้เมื่อถูกบอก คนรุ่นเก่าก็ยังคงยึดติดกับวิธีที่พวกเขาเรียนรู้มา อาจเป็นเพราะความภูมิใจในอดีตของพวกเขาและความไม่เต็มใจที่จะยอมรับว่ามีวิธีที่ดีกว่าวิธีที่พวกเขาใช้มานาน
วิธีหนึ่งที่จะอธิบายสิ่งที่เกิดขึ้นในประวัติศาสตร์ของซอฟต์แวร์คือเราค่อยๆ เคลื่อนจาก absolute ไปสู่ virtual machines อันดับแรก เรากำจัดรหัสคำสั่งจริงออกไป จากนั้นก็ที่อยู่จริง ต่อมาใน fortran ก็กำจัดความจำเป็นในการเรียนรู้ภายในเครื่องที่ซับซ้อนเหล่านี้และวิธีการทำงานของมัน เรากำลังสร้าง buffer ระหว่างผู้ใช้กับตัวเครื่อง ตั้งแต่ค่อนข้างเร็วที่ Bell Telephone Laboratories เราสร้างอุปกรณ์บางอย่างเพื่อทำให้ tape units กลายเป็น virtual ไม่ขึ้นอยู่กับเครื่อง เมื่อใดก็ตาม—และเมื่อนั้นเท่านั้น—ที่คุณมี totally virtual machine คุณจะมีความสามารถในการถ่ายโอนซอฟต์แวร์จากเครื่องหนึ่งไปยังอีกเครื่องหนึ่งโดยไม่มีปัญหาและ errors ที่ไม่รู้จบ
fortran ประสบความสำเร็จเกินความคาดหมายของใครๆ เพราะข้อเท็จจริงทาง จิตวิทยา ที่ว่ามันเป็นไปตามที่ชื่อของมันบอก—คือการ for mula tran slation ของสิ่งที่เราทำในโรงเรียนมาโดยตลอด มันไม่จำเป็นต้องเรียนรู้วิธีการคิดแบบใหม่
Algol ในช่วงประมาณ 1958–1960 ได้รับการสนับสนุนจากองค์กรคอมพิวเตอร์ทั่วโลกมากมาย รวมถึง acm มันเป็นความพยายามของนักทฤษฎีที่จะปรับปรุง fortran อย่างมาก แต่เนื่องจากพวกเขาเป็นนักตรรกศาสตร์ พวกเขาจึงสร้างภาษาที่เป็น logical ไม่ใช่ humane, psychological และแน่นอน อย่างที่คุณรู้ มันล้มเหลวในระยะยาว เหนือสิ่งอื่นใด มันถูกนำเสนอในรูปแบบ Boolean logical ซึ่งมนุษย์ธรรมดาไม่สามารถเข้าใจได้ (และบ่อยครั้งแม้แต่นักตรรกศาสตร์เองก็ไม่เข้าใจ!) ภาษาอื่นๆ ที่ออกแบบอย่างมีตรรกะอีกมากมายที่ควรจะมาแทนที่ fortran ที่ดูธรรมดาๆ ก็มาแล้วก็ไป ในขณะที่ fortran (ซึ่งถูกปรับปรุงบ้างแน่นอน) ยังคงเป็นภาษาที่ใช้กันอย่างแพร่หลาย แสดงให้เห็นอย่างชัดเจนถึงพลังของภาษาที่ออกแบบทางจิตวิทยาเหนือภาษาที่ออกแบบทางตรรกะ
นี่เป็นจุดเริ่มต้นของความหวังอันยิ่งใหญ่สำหรับภาษาพิเศษ ที่เรียกว่า pol s ย่อมาจาก problem-oriented languages แนวคิดนี้มีข้อดีอยู่บ้าง แต่ความกระตือรือร้นอันยิ่งใหญ่ก็จางหายไปเพราะปัญหามากมายเกี่ยวข้องกับมากกว่าหนึ่งสาขาพิเศษ และภาษาเหล่านี้มักจะเข้ากันไม่ได้ ยิ่งไปกว่านั้น ในระยะยาว มันมีต้นทุนในช่วงการเรียนรู้ที่สูงเกินไปสำหรับมนุษย์ที่จะเชี่ยวชาญภาษาต่างๆ ที่พวกเขาอาจต้องการทั้งหมด
ในช่วงประมาณปี 1962 ภาษา lisp ก็เริ่มต้นขึ้น มีข่าวลือต่างๆ นานาเกี่ยวกับที่มาที่แท้จริงของมัน ความจริงที่น่าจะเป็นไปได้คือประมาณนี้: John McCarthy เสนอองค์ประกอบของภาษาเพื่อวัตถุประสงค์ทางทฤษฎี ข้อเสนอนี้ถูกนำไปต่อยอดและขยายความอย่างมีนัยสำคัญโดยคนอื่นๆ และเมื่อนักเรียนคนหนึ่งสังเกตว่าเขาสามารถเขียน compiler สำหรับมัน ใน lisp โดยใช้เทคนิคง่ายๆ ของ self-compiling ทุกคนต่างตกตะลึง รวมถึง McCarthy เองด้วย แต่เขาก็กระตุ้นให้นักเรียนลอง และอย่างน่าอัศจรรย์ เกือบข้ามคืน พวกเขาเคลื่อนจากทฤษฎีไปสู่ lisp compiler ที่ทำงานได้จริง!
ขอผมแยกไปพูดถึงประสบการณ์ของผมกับเครื่อง ibm 650 มันเป็น drum machine แบบสองที่อยู่ (two-address) และทำงานใน fixed decimal point ผมรู้จากประสบการณ์การวิจัยที่ผ่านมาว่า floating point เป็นสิ่งจำเป็น (von Neumann คิดตรงกันข้าม) และผมต้องการ index registers ซึ่งไม่มีในเครื่องตามที่ส่งมอบ ibm บอกว่าสักวันหนึ่งพวกเขาจะจัดหา floating point subroutines ให้ แต่นั่นไม่เพียงพอสำหรับผม ผมเคยวิจารณ์หนังสือ edsac เกี่ยวกับการเขียนโปรแกรมให้กับวารสาร และในภาคผนวก D มีโปรแกรมแปลกๆ ที่เขียนขึ้นเพื่อนำโปรแกรมขนาดใหญ่เข้าไปเก็บในหน่วยความจำขนาดเล็ก มันคือ interpreter แต่ถ้ามันอยู่ในภาคผนวก D พวกเขาเห็นความสำคัญของมันหรือไม่? ผมสงสัย! ยิ่งไปกว่านั้น ในฉบับพิมพ์ครั้งที่สอง มันยังคงอยู่ในภาคผนวก D ดูเหมือนว่าพวกเขาไม่รู้ว่ามันคืออะไร
สิ่งนี้ทำให้เกิดประเด็นที่ยาก เมื่อไหร่กันที่เราเข้าใจอะไรบางอย่างจริงๆ ใช่ พวกเขาเขียนมันขึ้นมาและใช้งานมัน แต่พวกเขาเข้าใจความทั่วไปของ interpreters และ compilers หรือไม่? ผมเชื่อว่าไม่ เช่นเดียวกัน เมื่อช่วงเวลานั้นพวกเราหลายคนตระหนักว่าคอมพิวเตอร์ จริงๆ แล้วคือเครื่องจักรที่จัดการสัญลักษณ์ (symbol manipulators) ไม่ใช่แค่เครื่องคำนวณตัวเลข เราไปบรรยายตามที่ต่างๆ และผมเห็นคนพยักหน้าอย่างรู้เรื่องเมื่อผมพูด แต่ผมก็รู้ว่าส่วนใหญ่พวกเขาไม่เข้าใจจริงๆ แน่นอนคุณอาจบอกว่าบทความต้นฉบับของ Turing (1937) แสดงให้เห็นชัดเจนว่าคอมพิวเตอร์เป็นเครื่องจักรที่จัดการสัญลักษณ์ แต่เมื่ออ่านรายงานของ von Neumann อย่างละเอียด คุณคงไม่เดาได้ว่าผู้เขียนเข้าใจเรื่องนี้ ถึงแม้จะมีโปรแกรม combinatorial หนึ่งโปรแกรมและ sorting routine อยู่ก็ตาม
ประวัติศาสตร์มักจะใจดีในเรื่องนี้ มันให้เครดิตว่าเราเข้าใจความหมายของสิ่งที่เราทำเมื่อเราทำมันครั้งแรก แต่มีคำกล่าวที่ฉลาดว่า "เกือบทุกคนที่เปิดสาขาใหม่ไม่ได้เข้าใจมันอย่างที่ผู้ตามเข้าใจจริงๆ" หลักฐานสำหรับเรื่องนี้ โชคไม่ดี ที่มีมากเกินไป มีการกล่าวกันว่าในฟิสิกส์ ไม่มีผู้สร้างสิ่งที่สำคัญใดๆ เลยที่เข้าใจสิ่งที่เขาทำลงไปอย่างแท้จริง ผมไม่เคยพบว่า Einstein เกี่ยวกับทฤษฎีสัมพัทธภาพพิเศษชัดเจนเท่ากับผู้วิจารณ์รุ่นหลังบางคน และเพื่อนของผมอย่างน้อยหนึ่งคนเคยพูดลับหลังว่า "Hamming ดูเหมือนจะไม่เข้าใจ error correcting codes!" เขาอาจจะถูก ผมไม่เข้าใจสิ่งที่ผมประดิษฐ์ขึ้นอย่างชัดเจนเท่าเขา เหตุผลที่สิ่งนี้เกิดขึ้นบ่อยครั้งก็คือผู้สร้างต้องต่อสู้ผ่านอุปสรรคที่มืดมนมากมาย และต้องลุยผ่านความเข้าใจผิดและความสับสนมากมาย พวกเขาจึงไม่สามารถมองเห็นแสงสว่างได้อย่างที่คนอื่นมองเห็น เมื่อประตูเปิดแล้วและเส้นทางถูกทำให้ง่ายขึ้นแล้ว โปรดจำไว้ว่า นักประดิษฐ์มักจะมีมุมมองที่จำกัดมากเกี่ยวกับสิ่งที่เขาประดิษฐ์ขึ้น และคนอื่นๆ (คุณ?) สามารถมองเห็นได้มากกว่า แต่ก็จำสิ่งนี้ไว้ด้วยเมื่อคุณเป็นผู้สร้างสิ่งใหม่ที่ยอดเยี่ยม เมื่อเวลาผ่านไป สิ่งเดียวกันนี้อาจเป็นจริงสำหรับคุณ มีการกล่าวกันว่า Newton เป็นบุคคลสุดท้ายของยุคโบราณ ไม่ใช่บุคคลแรกของยุคสมัยใหม่ ถึงแม้ว่าเขาจะมีความสำคัญอย่างมากในการสร้างโลกสมัยใหม่ของเรา
กลับมาที่เครื่อง ibm 650 และตัวผม ผมเริ่มต้น (ประมาณปี 1956) ด้วยกฎสี่ข้อต่อไปนี้สำหรับการออกแบบ ภาษา:
- เรียนรู้ง่าย (Easy to learn)
- ใช้งานง่าย (Easy to use)
- แก้ไข errors ได้ง่าย (Easy to debug)
- ใช้ subroutines ได้ง่าย (Easy to use subroutines)
ข้อสุดท้ายอาจไม่ใช่สิ่งที่คุณต้องกังวล เพราะในสมัยนั้นเราแยกความแตกต่างระหว่าง subroutine แบบ "open" และ "closed" ซึ่งยากที่จะอธิบายในตอนนี้!
คุณอาจบอกว่าผมกำลังทำ top-down programming แต่ผมเขียนรายละเอียดของ inner loop ทันทีเพื่อตรวจสอบว่ามันสามารถทำได้อย่างมีประสิทธิภาพ (bottom-up programming) และหลังจากนั้นผมจึงกลับไปใช้แนวทาง top-down แบบเชิงปรัชญา ดังนั้น ในขณะที่ผมเชื่อว่า top-down programming เป็นแนวทางที่ดี ผมก็ตระหนักชัดเจนว่า bottom-up programming ก็จำเป็นในบางครั้งเช่นกัน
ผมทำให้เครื่อง two-address fixed point decimal ดูเหมือนเครื่อง three-address floating point—นั่นคือเป้าหมายของผม— A op. B = C ผมใช้เลขฐานสิบ 10 หลักของเครื่อง (ซึ่งเป็นเครื่องเลขฐานสิบเท่าที่ผู้ใช้เกี่ยวข้อง) ในรูปแบบนี้:
| A address (ที่อยู่ A) | Op. (คำสั่ง) | B address (ที่อยู่ B) | C address (ที่อยู่ C) |
| xxx | x | xxx | xxx |
ทำได้อย่างไร? ง่ายมาก! ผมเขียน loop ต่อไปนี้ในใจ Figure 4.1 อันดับแรก เราต้องการ Current Address Register car ดังนั้นผมจึงกำหนด register หนึ่งใน 2,000 registers ของเครื่อง ibm 650 เพื่อทำหน้าที่นี้ จากนั้นเราเขียนโปรแกรมเพื่อทำสี่ขั้นตอนของบทที่แล้ว: (1) ใช้ car เพื่อหาว่าจะไปที่ไหนสำหรับคำสั่งถัดไปของโปรแกรมที่คุณเขียน (ซึ่งเขียนด้วยภาษาของผมแน่นอน) (2) จากนั้นแยกคำสั่งและเก็บ three addresses คือ A, B, และ C ไว้ในตำแหน่งที่เหมาะสมในหน่วยความจำของ 650 (3) จากนั้นบวกค่าคงที่กับ operation (op.) ของคำสั่งและไปยังที่อยู่นั้น ที่นั่น สำหรับแต่ละคำสั่ง จะมี subroutine ที่อธิบายการดำเนินการที่สอดคล้องกัน คุณอาจคิดว่าผมจึงมีการดำเนินการที่เป็นไปได้เพียงสิบอย่าง แต่จริงๆ แล้วมีแค่สี่ three-address operations—addition, subtraction, multiplication, และ division—ดังนั้นผมจึงใช้คำสั่ง 0 หมายถึง "ไปที่ address B และหารายละเอียดเพิ่มเติมของสิ่งที่ต้องการ" แต่ละ subroutine เมื่อมันเสร็จสิ้น จะถ่ายโอน control ไปยังตำแหน่งที่กำหนดใน loop (4) จากนั้นเราบวก 1 เข้าไปในเนื้อหาของ car register ล้างรายละเอียดบางอย่าง และเริ่มต้นใหม่อีกครั้ง เช่นเดียวกับการทำงานภายในของเครื่องดั้งเดิม แน่นอนว่า transfer instructions (เท่าที่จำได้คือเจ็ดคำสั่ง) ทั้งหมดใส่ address ลงใน car และถ่ายโอนไปยังตำแหน่งใน loop ที่อยู่หลังการบวก 1 เข้าไปในเนื้อหาของ car register
Figure 4.1—Program loop (ลูปการทำงานของโปรแกรม)
การตรวจสอบกระบวนการนี้แสดงให้เห็นว่าความหมายใดๆ ที่คุณต้องการผูกกับคำสั่งจะต้องมาจาก subroutines ที่เขียนขึ้นตามหมายเลขคำสั่ง subroutines เหล่านั้นคือตัวกำหนดความหมายของภาษา ในกรณีง่ายๆ นี้ แต่ละคำสั่งมีความหมายของตัวเองโดยอิสระจากคำสั่งอื่นๆ แต่เห็นได้ชัดว่ามันง่ายที่จะทำให้คำสั่งบางคำสั่งตั้งค่า switches, flags, หรือ bits อื่นๆ เพื่อให้คำสั่งต่อมา เมื่อปรึกษาค่าเหล่านั้น จะถูกตีความในหลายวิธีที่แตกต่างกัน ดังนั้นคุณจึงเห็นว่าคุณสามารถออกแบบ ภาษาใดก็ได้ที่คุณต้องการ ตราบใดที่คุณสามารถกำหนดมันได้อย่างชัดเจนในลักษณะที่แน่นอน มันทำงานอยู่เหนือภาษาของเครื่อง ทำให้เครื่องกลายเป็นเครื่องอื่นใดก็ได้ที่คุณต้องการ แน่นอน นี่คือสิ่งที่ Turing พิสูจน์ด้วย Universal Turing Machine ของเขา แต่ดังที่กล่าวไว้ข้างต้น มันไม่ถูกเข้าใจอย่างชัดเจนจนกระทั่งเราทำมันหลายครั้ง
ระบบซอฟต์แวร์ที่ผมสร้างขึ้นถูกวางไว้ใน storage registers 1,000 ถึง 1,999 ดังนั้นโปรแกรมใดๆ ในภาษาเชิงสังเคราะห์ (synthetic language) ซึ่งมีเลขฐานสิบเพียงสามหลัก จะสามารถอ้างอิงถึง addresses 000 ถึง 999 เท่านั้น และไม่สามารถอ้างอิงหรือแก้ไข register ใดๆ ในซอฟต์แวร์ ซึ่งจะทำให้มันเสียหาย: นี่คือการออกแบบ security protection ของระบบซอฟต์แวร์จากผู้ใช้
ผมลงรายละเอียดเรื่องนี้เพราะโดยทั่วไปเรามักเขียนภาษาหนึ่งเหนือภาษาเครื่อง และอาจเขียนภาษาที่สูงขึ้นอีกหลายภาษา ซ้อนกันไปเรื่อยๆ จนกระทั่งเราได้ภาษาที่ต้องการใช้ในการแสดงปัญหาของเรากับเครื่อง ถ้าคุณใช้ interpreter ในแต่ละชั้น แน่นอนว่ามันจะค่อนข้างไม่มีประสิทธิภาพ การใช้ compiler ที่ชั้นบนสุดหมายความว่าภาษาสูงสุดจะถูกแปลไปยังภาษาที่ต่ำกว่าภาษาหนึ่งทันทีและตลอดไป ถึงแม้ว่าคุณอาจยังต้องการ interpreter ในบางชั้นก็ตาม นอกจากนี้ ยังหมายถึง เช่นเดียวกับกรณีของ edsac โดยปกติแล้วจะช่วยลดความพยายามในการเขียนโปรแกรมและพื้นที่จัดเก็บได้อย่างมาก ผมต้องการชี้ให้เห็นอีกครั้งถึงความแตกต่างระหว่างการเขียนภาษาเชิงตรรกะ (logical) และภาษาเชิงจิตวิทยา (psychological)
โชคไม่ดีที่โปรแกรมเมอร์ ซึ่งมักคิดเชิงตรรกะ และไม่ค่อยคิดเชิงมนุษย์ มักจะเขียนและยกย่องภาษาเชิงตรรกะ ตัวอย่างที่ดีที่สุดของเรื่องนี้อาจเป็น apl ในเชิงตรรกะ apl เป็นภาษาที่ยอดเยี่ยมและจนถึงทุกวันนี้ยังมีผู้ศรัทธาอย่างแรงกล้า แต่มันก็ไม่เหมาะสำหรับมนุษย์ปกติที่จะใช้งาน ในภาษานี้มีเกมที่เรียกว่า "one liners": มีโค้ดหนึ่งบรรทัดให้ดู และคุณต้องตอบว่ามันหมายถึงอะไร แม้แต่ผู้เชี่ยวชาญในภาษานี้ก็เคยพลาดอย่างรุนแรงกับบางบรรทัด
การเปลี่ยนตัวอักษรเพียงตัวเดียวใน apl สามารถเปลี่ยนความหมายได้อย่างสิ้นเชิง ดังนั้นภาษานี้แทบจะไม่มี redundancy เลย แต่มนุษย์นั้นไม่น่าเชื่อถือและต้องการ redundancy ภาษาพูดของเรามักจะมีความซ้ำซ้อนประมาณ 60% ในขณะที่ภาษาเขียนประมาณ 40% คุณอาจคิดว่าภาษาเขียนและภาษาพูดเหมือนกัน แต่คุณคิดผิด ลองเขียนบทสนทนาแล้วอ่านออกเสียงดูเพื่อเห็นความแตกต่าง แทบไม่มีใครสามารถเขียนบทสนทนาให้ฟังดูเป็นธรรมชาติได้ และเมื่อมันฟังดูเป็นธรรมชาติแล้ว มันก็ยังไม่ใช่ภาษาพูดจริงๆ
มนุษย์เป็นสัตว์ที่ไม่น่าเชื่อถือ อย่างที่ผมย้ำอยู่เสมอ ดังนั้น redundancy ต่ำหมายถึง errors ที่ไม่ถูกตรวจจับจำนวนมาก ในขณะที่ redundancy สูงมักจะช่วยจับ errors ภาษาพูดเดินทางผ่านช่องสัญญาณเสียงที่มี noise และต้องถูกจับความหมายทันทีขณะที่พูด ภาษาเขียนถูกพิมพ์ คุณสามารถหยุด ย้อนกลับไปดู และทำอย่างอื่นเพื่อค้นหาความหมายของผู้เขียน สังเกตว่าในภาษาอังกฤษ คำที่ต่างกันแต่ออกเสียงเหมือนกัน (เช่น "there" และ "their") มีบ่อยกว่าคำที่สะกดเหมือนกันแต่ออกเสียงต่างกัน (เช่น "record" เป็น noun หรือ verb และ "tear" ในความหมายน้ำตากับการฉีกขาด) ดังนั้นคุณควรตัดสินภาษาจากความเหมาะสมกับมนุษย์อย่างที่เขาเป็น—และจำไว้ว่าผมรวมถึงการที่พวกเขาได้รับการฝึกฝนในโรงเรียนด้วย มิฉะนั้นคุณต้องเตรียมพร้อมที่จะฝึกฝนอย่างหนักเพื่อจัดการกับภาษาใหม่ที่คุณจะใช้ การที่ภาษาหนึ่งง่ายสำหรับผู้เชี่ยวชาญด้านคอมพิวเตอร์ไม่ได้หมายความว่ามันง่ายสำหรับผู้ที่ไม่ใช่ผู้เชี่ยวชาญ และในอนาคตอันใกล้ ผู้ที่ไม่ใช่ผู้เชี่ยวชาญน่าจะเป็นผู้เขียนโปรแกรม (coding ถ้าคุณต้องการ) ส่วนใหญ่
สิ่งที่ต้องการในระยะยาวก็คือ ให้คนที่มีปัญหาทำการเขียนโค้ดจริง โดยไม่มีคนกลางระหว่างคนที่รู้ปัญหาและคนที่รู้ภาษาโปรแกรมมิ่งอย่างที่เรามักมีในทุกวันนี้ น่าเสียดายที่วันนั้นยังห่างไกลเกินกว่าจะเกิดผลดีในทันที แต่ผมคิดว่าภายในปี 2020 การที่ผู้เชี่ยวชาญในสาขาการประยุกต์ใช้จะเป็นผู้เตรียมโปรแกรมจริงๆ แทนที่จะให้ผู้เชี่ยวชาญด้านคอมพิวเตอร์ (ที่ไม่รู้เรื่องสาขาการประยุกต์ใช้) เป็นคนเตรียมโปรแกรม น่าจะกลายเป็นแนวปฏิบัติทั่วไป
โชคไม่ดี อย่างน้อยในความเห็นของผม ภาษา ada ถูกออกแบบโดยผู้เชี่ยวชาญ และมันแสดงให้เห็นถึงคุณลักษณะที่ไม่เป็นมิตรกับมนุษย์ทั้งหมดที่คุณคาดหวังได้จากพวกเขา ในความเห็นของผม มันเป็นงาน hacking แบบฉบับของวิทยาการคอมพิวเตอร์—อย่าพยายามเข้าใจสิ่งที่คุณกำลังทำ แค่ทำให้มันรันได้ ผลจากการออกแบบทางจิตวิทยาที่แย่นี้ การสำรวจส่วนตัวของผมจากคนที่มีความรู้ชี้ว่า ถึงแม้สัญญาของรัฐบาลจะระบุให้เขียนโปรแกรมด้วย ada แต่กว่า 90% จะถูกเขียนด้วย fortran แก้ debug ทดสอบ แล้วจึงถูกแปลงเป็นโปรแกรม ada ที่แย่ๆ ด้วยมืออย่างทรมาน โดยมีความน่าจะเป็นของ errors สูง!
พื้นฐานของภาษายังไม่เป็นที่เข้าใจจนถึงทุกวันนี้ ช่วงต้นทศวรรษ 1950 ผมพาผู้เชี่ยวชาญภาษาธรรมชาติในขณะนั้น (ที่เป็นที่รู้จักของสาธารณชน) ไปเยี่ยมชมเครื่อง ibm 701 แล้วไปทานอาหารกลางวัน และเมื่อถึงเวลา dessert ผมพูดว่า "Professor Pei, ช่วยพูดคุยกับเราเกี่ยวกับ engineering efficiencies ของภาษาต่างๆ ได้ไหมครับ" เขาไม่สามารถเข้าใจคำถามได้เลย และบอกแต่เพียงว่าภาษานี้วางพหูพจน์ไว้กลางคำ ภาษาอื่นมีคุณลักษณะหนึ่งแต่ไม่มีอีกอย่างหนึ่ง ฯลฯ สิ่งที่ผมอยากรู้คือ งานของการสื่อสารสามารถทำได้อย่างมีประสิทธิภาพอย่างไรเมื่อเรามีอำนาจในการออกแบบภาษา และเมื่อปลายด้านหนึ่งของภาษาคือมนุษย์ ที่มีข้อบกพร่องทั้งหมด และอีกด้านคือเครื่องจักรที่มีความน่าเชื่อถือสูงในการทำสิ่งที่ถูกบอก แต่ไม่ทำอะไรอื่น ผมอยากรู้ว่าควรมี redundancy แบบไหนสำหรับภาษาเหล่านี้ ความหนาแน่นของคำกริยาอปกติและปกติ อัตราส่วนของ synonyms ต่อ antonyms ทำไมเราถึงมีจำนวนเท่าที่มี จะบีบอัดช่องทางการสื่อสารอย่างมีประสิทธิภาพและยังเหลือ redundancy สำหรับมนุษย์ที่ใช้งานได้อย่างไร ฯลฯ อย่างที่ผมบอก เขาไม่ได้ยินคำถามเกี่ยวกับ engineering efficiency ของภาษา และผมไม่เห็นการศึกษามากมายเกี่ยวกับเรื่องนี้ตั้งแต่นั้นมา แต่จนกว่าเราจะเข้าใจสิ่งเหล่านี้อย่างแท้จริง—โดยสมมติว่าภาษาธรรมชาติในปัจจุบันผ่านวิวัฒนาการอันยาวนานนั้นเหมาะสมกับงานที่มันทำเพื่อมนุษย์อย่างสมเหตุสมผล—เราจะไม่รู้วิธีออกแบบภาษาประดิษฐ์สำหรับการสื่อสารระหว่างมนุษย์กับเครื่องจักร ดังนั้นผมคาดว่าจะมีปัญหามากมายจนกว่าเราจะเข้าใจการสื่อสารของมนุษย์ผ่านภาษาธรรมชาติ แน่นอน ปัญหาของการสื่อสารระหว่างมนุษย์กับเครื่องจักรนั้นแตกต่างอย่างมีนัยสำคัญจากการสื่อสารระหว่างมนุษย์กับมนุษย์ แต่ว่าแตกต่างในทางใดและมากแค่ไหนดูเหมือนจะไม่เป็นที่รู้จักหรือแม้แต่ถูกค้นหา
จนกว่าเราจะเข้าใจภาษาของการสื่อสารที่เกี่ยวข้องกับมนุษย์อย่างที่เขาเป็น (หรือสามารถถูกฝึกฝนได้อย่างง่าย) ได้ดีขึ้น มันไม่น่าเป็นไปได้ที่ปัญหาซอฟต์แวร์มากมายของเราจะหายไป
เมื่อไม่นานมานี้มีโครงการ " fifth generation" ของคอมพิวเตอร์ที่ญี่ปุ่นวางแผนจะใช้ พร้อมกับ ai เพื่อสร้าง interface ที่ดีขึ้นระหว่างเครื่องจักรและผู้แก้ปัญหาที่เป็นมนุษย์ มีการอ้างสิทธิ์ที่ยิ่งใหญ่สำหรับทั้งเครื่องจักรและภาษา ผลลัพธ์จนถึงตอนนี้คือเครื่องจักรออกมาได้ตามที่โฆษณา และพวกเขากลับไปที่กระดานวาดภาพเกี่ยวกับการใช้ ai เพื่อช่วยในการเขียนโปรแกรม มันเป็นไปตามที่ผมทำนายไว้ในตอนนั้น (สำหรับ Los Alamos) เพราะผมไม่เห็นว่าญี่ปุ่นกำลังพยายามเข้าใจพื้นฐานของภาษาในความหมายทางวิศวกรรมที่กล่าวข้างต้น มีหลายสิ่งที่เราสามารถทำได้เพื่อลด "the software problem" อย่างที่มันถูกเรียก แต่จะต้องอาศัยความเข้าใจพื้นฐานเกี่ยวกับภาษาในฐานะที่ใช้สื่อสาร ความเข้าใจ ระหว่างมนุษย์ และระหว่างมนุษย์กับเครื่องจักร ก่อนที่เราจะมีวิธีแก้ปัญหาที่ดีจริงๆ สำหรับปัญหาที่มีต้นทุนสูงนี้ มันจะไม่หายไปง่ายๆ
คุณอ่านเจอตลอดเกี่ยวกับ "engineering the production of software" ทั้งเพื่อประสิทธิภาพในการผลิตและความน่าเชื่อถือของผลิตภัณฑ์ แต่คุณไม่คาดหวังให้นักประพันธ์ "engineering the production of novels" คำถามคือ: "การเขียนโปรแกรมใกล้เคียงกับการเขียนนวนิยายมากกว่าวิศวกรรมคลาสสิกหรือไม่?" ผมขอเสนอว่าใช่! กำหนดปัญหาในการส่งมนุษย์ไปอวกาศ ทั้งรัสเซียและอเมริกาทำมันในแบบที่ใกล้เคียงกันมาก เมื่อพิจารณาทุกอย่างและเผื่อการจารกรรมบางอย่าง พวกเขาถูกจำกัดด้วยกฎฟิสิกส์ที่ตายตัวเดียวกัน แต่มอบปัญหาการเขียนเกี่ยวกับ "ความยิ่งใหญ่และความทุกข์ยากของมนุษย์" ให้นักประพันธ์สองคน คุณอาจจะได้นวนิยายที่แตกต่างกันมากสองเรื่อง (โดยไม่ต้องพูดถึงวิธีการวัด) มอบปัญหาที่ซับซ้อนเดียวกันให้โปรแกรมเมอร์สองคนในยุคปัจจุบัน ผมขออ้างว่าคุณจะได้โปรแกรมที่ค่อนข้างแตกต่างกันสองโปรแกรม ดังนั้นความเชื่อของผมคือแนวปฏิบัติการเขียนโปรแกรมในปัจจุบันใกล้เคียงกับการเขียนนวนิยายมากกว่าวิศวกรรม นักประพันธ์ถูกจำกัดด้วยจินตนาการของพวกเขาเท่านั้น ซึ่งค่อนข้างคล้ายกับโปรแกรมเมอร์เมื่อพวกเขากำลังเขียนซอฟต์แวร์ ทั้งสองกิจกรรมมีองค์ประกอบเชิงสร้างสรรค์ขนาดใหญ่ และในขณะที่คุณต้องการทำให้การเขียนโปรแกรมเหมือนวิศวกรรม มันจะใช้เวลานานมากกว่าจะถึงจุดนั้น—และบางทีคุณอาจ ในระยะยาว ไม่ต้องการทำมันจริงๆ! บางทีมันแค่ฟังดูดี คุณจะต้องคิดเกี่ยวกับมันหลายครั้งในปีต่อๆ ไป คุณอาจเริ่มตอนนี้และลดน้ำหนักของ propaganda ที่คุณได้ยิน รวมถึง wishful thinking ทั้งหมดที่เกิดขึ้นในพื้นที่นี้! ซอฟต์แวร์ของ utility programs ของคอมพิวเตอร์ถูกทำบ่อยครั้งพอ และมีขอบเขตจำกัด ดังนั้นมันอาจถูกคาดหวังอย่างสมเหตุสมผลว่าสามารถกลายเป็น "engineered" ได้ แต่การเตรียมซอฟต์แวร์ทั่วไปไม่น่าจะอยู่ภายใต้ "engineering control" ไปอีกหลายต่อหลายปี
มีข้อเสนอมากมายเกี่ยวกับวิธีปรับปรุง productivity ของโปรแกรมเมอร์แต่ละคน รวมถึงกลุ่มโปรแกรมเมอร์ ผมได้กล่าวถึง top-down และ bottom-up ไปแล้ว ยังมีอื่นๆ เช่น head programmer, lead programmer, การพิสูจน์ว่าโปรแกรมถูกต้องในเชิงคณิตศาสตร์ และ waterfall model of programming เพียงแค่ยกตัวอย่างบางส่วน ในขณะที่แต่ละวิธีมีข้อดีอยู่บ้าง ผมเชื่อมั่นในวิธีเดียวเท่านั้น ซึ่งแทบจะไม่ถูกกล่าวถึง— คิดก่อนที่คุณจะเขียนโปรแกรม , อาจเรียกแบบนั้นได้ ก่อนที่คุณจะเริ่ม คิดอย่างรอบคอบเกี่ยวกับทุกสิ่ง รวมถึง สิ่งที่จะเป็น acceptance test ของคุณว่ามันถูกต้อง รวมถึงการบำรุงรักษาในภาคสนามในภายหลังจะทำอย่างไร การทำให้ถูกต้องตั้งแต่ครั้งแรกดีกว่าการแก้ไขในภายหลังมาก!
ปัญหาหนึ่งของการเขียนโปรแกรมส่วนใหญ่ก็คือ บ่อยครั้งที่ไม่มีงานที่ถูกกำหนดไว้อย่างชัดเจนให้ทำ ตรงกันข้าม กระบวนการเขียนโปรแกรมเองจะค่อยๆ ค้นพบว่าปัญหาคืออะไร! ความปรารถนาที่คุณจะได้รับปัญหาที่กำหนดไว้อย่างชัดเจนก่อนเริ่มเขียนโปรแกรมมักจะไม่ตรงกับความเป็นจริง และด้วยเหตุนี้ ข้อเสนอในปัจจุบันมากมายที่จะ "แก้ปัญหาการเขียนโปรแกรม" จะล้มเหลวถ้าถูกนำไปใช้อย่างเคร่งครัด
การใช้ภาษาระดับสูง (higher-level languages) หมายถึงความก้าวหน้าอย่างมาก ตารางต่อไปนี้แสดงการประมาณการปรับปรุงในรอบ 30 ปี
| ประเภทของการปรับปรุง (Type of improvement) | ปัจจัยการปรับปรุงสะสม (Cumulative improvement factor) |
|---|
| Assembler:machine code | \= | 2:1 | ×2 |
| C language:assembler | \= | 3:1 | ×6 |
| Timeshare:batch | \= | 1.5:1 | ×9 |
| UNIX:monitor | \= | 4:3 | ×12 |
| System QA:debugging | \= | 2:1 | ×24 |
| Prototyping:top-down | \= | 1.3:1 | ×30 |
| C++:C | \= | 2:1 | ×60 |
| Reuse:redo | \= | 1.5:1 | ×90 |
เห็นได้ชัดว่าเราได้เพิ่ม productivity โดยรวมของโปรแกรมเมอร์ประมาณ 90 เท่าใน 30 ปี (อัตราการปรับปรุงเพียง 16%!) นี่เป็นการเดาของบุคคลคนหนึ่ง และอย่างน้อยก็เป็นไปได้ แต่เมื่อเทียบกับความเร็วที่เพิ่มขึ้นของเครื่องจักรแล้ว มันแทบไม่มีอะไรเลย! ผู้คนปรารถนาให้มนุษย์สามารถเพิ่มความเร็วได้เช่นกัน แต่ bottleneck พื้นฐานคือสัตว์ที่เรียกว่ามนุษย์อย่างที่มัน เป็น ไม่ใช่อย่างที่เราอยากให้มันเป็น
การศึกษาหลายชิ้นแสดงให้เห็นว่าโปรแกรมเมอร์มีความแตกต่างในด้าน productivity จากแย่ที่สุดไปถึงดีที่สุด มากกว่าปัจจัยสิบเท่า จากนี้ผมสรุปมานานแล้วว่านโยบายที่ดีที่สุดคือจ่ายโปรแกรมเมอร์ที่ดีของคุณให้ดีมาก แต่ไล่คนที่แย่ออกเป็นประจำ—ถ้าคุณทำได้! วิธีหนึ่งก็คือ จ้างพวกเขาเป็นสัญญาจ้าง (contract) แทนที่จะเป็นพนักงานประจำ แต่นั่นกำลังขัดต่อกฎหมายมากขึ้น ซึ่งดูเหมือนต้องการรับประกันว่าแม้แต่คนที่แย่ที่สุดก็ยังมีงานทำ ในทางปฏิบัติ คุณอาจจะดีกว่าถ้าจ่ายเงินให้คนที่แย่ที่สุดอยู่บ้านและไม่ขัดขวางคนที่มีความสามารถมากกว่า (และผมพูดจริง!)
คอมพิวเตอร์ดิจิทัลในปัจจุบันถูกใช้อย่างแพร่หลายในการจำลอง neural nets และอุปกรณ์ที่คล้ายกันกำลังคืบคลานเข้าสู่วงการคอมพิวเตอร์ Neural nets ถ้าคุณไม่คุ้นเคยกับมัน สามารถ เรียนรู้ เพื่อให้ได้ผลลัพธ์เมื่อคุณให้ชุดของ inputs และ acceptable outputs แก่มัน โดยไม่ต้องบอกว่าต้องสร้างผลลัพธ์อย่างไร มันสามารถจัดประเภทวัตถุออกเป็นคลาสที่สมเหตุสมผล โดยไม่ต้องบอกอีกว่าจะใช้หรือค้นหาคลาสอะไร มันเรียนรู้ด้วย feedback ง่ายๆ ซึ่งใช้ข้อมูลว่าผลลัพธ์ที่คำนวณจาก input ไม่เป็นที่ยอมรับ ในแง่หนึ่ง มันเป็นตัวแทนของวิธีแก้ "the programming problem"—เมื่อมันถูกสร้างขึ้นแล้ว มันไม่ได้ถูกเขียนโปรแกรมเลยจริงๆ แต่ก็ยังสามารถแก้ปัญหาที่หลากหลายได้อย่างน่าพอใจ มันเป็นสาขาที่กำลังมาแรงซึ่งผมจะต้องข้ามไปในหนังสือเล่มนี้ แต่มันอาจจะมีบทบาทสำคัญในอนาคตของคอมพิวเตอร์ ในแง่หนึ่ง มันเป็นคอมพิวเตอร์แบบ "hard-wired" (หรืออาจเป็นแค่โปรแกรม) ที่ใช้แก้ปัญหาประเภทกว้างๆ เมื่อเลือกพารามิเตอร์ไม่กี่ตัวและป้อนข้อมูลจำนวนมาก
อีกมุมมองหนึ่งของ neural nets คือพวกมันเป็นตัวแทนของคลาสที่ค่อนข้างทั่วไปของระบบ feedback ที่เสถียร คุณเลือกชนิดและปริมาณของ feedback ที่คุณคิดว่าเหมาะสม จากนั้นระบบ feedback ของ neural net ก็ลู่เข้าสู่คำตอบที่ต้องการ อีกครั้ง มันหลีกเลี่ยงการเขียนโปรแกรมโดยละเอียดมากมาย เนื่องจาก อย่างน้อยใน neural net ที่จำลองบนคอมพิวเตอร์ การเขียนโปรแกรมทั่วไปหนึ่งครั้งจะทำให้คุณมีปัญหาประเภทกว้างๆ ที่ถูกเขียนโปรแกรมไว้แล้ว และโปรแกรมเมอร์แทบไม่ต้องทำอะไรมากไปกว่าการให้ calling sequence
ยังไม่เป็นที่ทราบในตอนนี้ว่าชิ้นส่วนโปรแกรมทั่วไปอื่นใดอีกที่สามารถทำได้ในลักษณะเดียวกัน—คุณสามารถคิดถึงมันในฐานะหนึ่งในวิธีแก้ปัญหาที่เป็นไปได้สำหรับ "programming problem"
ในบทเกี่ยวกับฮาร์ดแวร์ ผมได้พูดถึงข้อจำกัดบางอย่างอย่างละเอียด—ขนาดของโมเลกุล ความเร็วของแสง และการระบายความร้อน ผมควรสรุปข้อจำกัดที่ยืดหยุ่นน้อยกว่าของซอฟต์แวร์ในทำนองเดียวกัน
ผมได้เปรียบเทียบการเขียนซอฟต์แวร์กับการเขียนวรรณกรรม ทั้งสองอย่างดูเหมือนจะขึ้นอยู่กับการคิดที่ชัดเจนเป็นพื้นฐาน การเขียนโปรแกรมที่ดีสอนกันได้หรือไม่? ถ้าเราดูการสอนที่คล้ายกันในคอร์ส "creative writing" เราจะพบว่านักเรียนส่วนใหญ่ของคอร์สเหล่านี้ไม่ได้กลายเป็นนักเขียนที่ยอดเยี่ยม และนักเขียนที่ยอดเยี่ยมส่วนใหญ่ในอดีตก็ไม่ได้เรียนคอร์ส creative writing! ดังนั้นจึงเป็นที่น่าสงสัยว่าโปรแกรมเมอร์ที่ยอดเยี่ยมสามารถถูกฝึกฝนได้ง่าย
ประสบการณ์ช่วยได้หรือไม่? นักการระบบที่เขียนรายงานและคำสั่งเป็นเวลาหลายปีดีขึ้นหรือไม่? ผมไม่มีข้อมูลจริง แต่ผมสงสัยว่าเมื่อเวลาผ่านไปพวกเขาแย่ลง! การใช้ "governmentese" เป็นประจำหลายปีอาจซึมซาบเข้าสู่รูปแบบการเขียนและทำให้พวกเขาแย่ลง ผมสงสัยว่าเป็นเช่นเดียวกันสำหรับโปรแกรมเมอร์! ทั้งปีของประสบการณ์หรือจำนวนภาษาที่ใช้ไม่ใช่เหตุผลที่จะคิดว่าโปรแกรมเมอร์ดีขึ้นจากประสบการณ์เหล่านี้ การตรวจสอบหนังสือเกี่ยวกับการเขียนโปรแกรมชี้ให้เห็นว่าผู้เขียนส่วนใหญ่ไม่ใช่โปรแกรมเมอร์ที่ดี!
ผลลัพธ์ที่ผมวาดภาพไว้นั้นไม่สวยงาม แต่สิ่งที่คุณมีเพื่อคัดค้านมันก็คือ wishful thinking—ผมมีหลักฐานจากประสบการณ์การเขียนโปรแกรมหลายต่อหลายปีอยู่ข้างผม!