API และการเขียนโปรแกรมการทำงาน


15

จากการเปิดรับ (จำกัด ของฉัน) กับภาษาโปรแกรมที่ใช้งานได้เช่น Clojure ดูเหมือนว่าการห่อหุ้มข้อมูลมีบทบาทสำคัญน้อยกว่า โดยทั่วไปแล้วประเภทเนทีฟประเภทต่าง ๆ เช่นแผนที่หรือชุดเป็นสกุลเงินที่ต้องการใช้แทนข้อมูล นอกจากนี้ข้อมูลนั้นโดยทั่วไปไม่เปลี่ยนรูป

ตัวอย่างเช่นนี่เป็นคำพูดที่โด่งดังจาก Rich Hickey of Clojure ที่มีชื่อเสียงในการสัมภาษณ์เกี่ยวกับเรื่องนี้ :

Fogus: ตามความคิดนั้น - บางคนประหลาดใจกับความจริงที่ว่า Clojure ไม่ได้มีส่วนร่วมในการซ่อนข้อมูลในประเภท ทำไมคุณถึงตัดสินใจทิ้งการซ่อนข้อมูลไว้?

Hickey: ชัดเจนว่า Clojure เน้นการเขียนโปรแกรมให้เป็นนามธรรม ถึงจุดหนึ่งบางคนจะต้องเข้าถึงข้อมูล และหากคุณมีความเห็นว่า "ส่วนตัว" คุณต้องมีแนวคิดเกี่ยวกับสิทธิ์และความน่าเชื่อถือที่สอดคล้องกัน และนั่นเป็นการเพิ่มความซับซ้อนและคุณค่าเพียงเล็กน้อยสร้างความแข็งแกร่งในระบบและมักบังคับให้สิ่งต่าง ๆ อาศัยอยู่ในสถานที่ที่ไม่ควรทำ นี่คือนอกเหนือไปจากการสูญเสียอื่น ๆ ที่เกิดขึ้นเมื่อข้อมูลง่าย ๆ ถูกใส่เข้าไปในชั้นเรียน ในกรณีที่ข้อมูลไม่เปลี่ยนรูปมีอันตรายเล็กน้อยที่สามารถให้การเข้าถึงนอกเหนือจากที่ใครบางคนอาจขึ้นอยู่กับสิ่งที่อาจเปลี่ยนแปลง เอาล่ะคนทำอย่างนั้นตลอดเวลาในชีวิตจริงและเมื่อสิ่งต่าง ๆ เปลี่ยนแปลงพวกเขาก็ปรับตัว และถ้าพวกเขามีเหตุผล พวกเขารู้เมื่อพวกเขาตัดสินใจตามสิ่งที่สามารถเปลี่ยนแปลงได้ว่าพวกเขาจะต้องปรับตัวในอนาคต ดังนั้นจึงเป็นการตัดสินใจในการจัดการความเสี่ยงฉันคิดว่าโปรแกรมเมอร์ควรมีอิสระที่จะทำ หากผู้คนไม่มีความรู้สึกอ่อนไหวต่อความปรารถนาที่จะเขียนโปรแกรมให้เป็นนามธรรมและระมัดระวังในการแต่งงานกับรายละเอียดการดำเนินการพวกเขาจะไม่เป็นโปรแกรมเมอร์ที่ดี

มาจากโลกของ OO ดูเหมือนว่ามันจะซับซ้อนหลักการบางอย่างที่ฉันได้เรียนรู้ในช่วงหลายปีที่ผ่านมา สิ่งเหล่านี้รวมถึงการซ่อนข้อมูลกฎหมายของ Demeter และหลักการเข้าถึงแบบเดียวกัน กระทู้ทั่วไปที่ถูกห่อหุ้มช่วยให้เราสามารถกำหนด API ให้ผู้อื่นรู้ว่าพวกเขาควรและไม่ควรสัมผัส ในสาระสำคัญการสร้างสัญญาที่อนุญาตให้ผู้ดูแลโค้ดบางส่วนสามารถทำการเปลี่ยนแปลงและรีแฟคเตอร์ได้อย่างอิสระโดยไม่ต้องกังวลว่ามันจะแนะนำบั๊กในรหัสของผู้บริโภคได้อย่างไร (หลักการเปิด / ปิด) นอกจากนี้ยังมีอินเทอร์เฟซที่สะอาดและ curated สำหรับโปรแกรมเมอร์อื่น ๆ เพื่อให้ทราบว่าเครื่องมือใดที่พวกเขาสามารถใช้เพื่อรับหรือสร้างตามข้อมูลนั้น

เมื่อข้อมูลได้รับอนุญาตให้เข้าถึงโดยตรงสัญญา API นั้นจะใช้งานไม่ได้และข้อดีของการห่อหุ้มทั้งหมดจะหายไป นอกจากนี้ข้อมูลที่ไม่เปลี่ยนรูปอย่างเคร่งครัดดูเหมือนว่าจะส่งผ่านโครงสร้างเฉพาะโดเมน (วัตถุ, โครงสร้าง, บันทึก) มีประโยชน์น้อยกว่ามากในแง่ของการเป็นตัวแทนของรัฐและชุดของการกระทำที่สามารถทำได้ในสถานะนั้น

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


2
คุณสามารถกำหนดอินเทอร์เฟซที่เป็นทางการได้โดยไม่ต้องคำนึงถึงวัตถุ เพียงสร้างฟังก์ชันของอินเทอร์เฟซที่บันทึกไว้ อย่าให้เอกสารสำหรับรายละเอียดการใช้งาน คุณเพิ่งสร้างอินเทอร์เฟซ
Scara95

@ Scara95 นั่นไม่ได้หมายความว่าฉันต้องทำงานเพื่อใช้รหัสสำหรับส่วนต่อประสานและเขียนเอกสารเกี่ยวกับเรื่องนี้มากพอที่จะเตือนผู้บริโภคว่าควรทำอย่างไรและจะต้องทำอย่างไร? เกิดอะไรขึ้นถ้ารหัสการเปลี่ยนแปลงและเอกสารประกอบจะเก่า? โดยทั่วไปฉันชอบรหัสการจัดทำเอกสารด้วยตนเองด้วยเหตุนี้
jameslk

คุณต้องจัดทำเอกสารส่วนต่อประสาน
Scara95

3
Also, strictly immutable data seems to make passing around domain-specific structures (objects, structs, records) much less useful in the sense of representing a state and the set of actions that can be performed on that state.ไม่ได้จริงๆ สิ่งเดียวที่เปลี่ยนแปลงคือการเปลี่ยนแปลงจะจบลงที่วัตถุใหม่ นี่เป็นชัยชนะครั้งใหญ่เมื่อพูดถึงเหตุผลเกี่ยวกับรหัส ผ่านวัตถุที่ไม่แน่นอนรอบ ๆ หมายถึงการติดตามว่าใครอาจกลายพันธุ์พวกเขาปัญหาที่ไต่ขึ้นกับขนาดของรหัส
Doval

คำตอบ:


10

ก่อนอื่นฉันจะพูดถึงความเห็นที่สองของเซบาสเตียนเกี่ยวกับสิ่งที่ใช้งานได้ดีการพิมพ์แบบไดนามิกคืออะไร โดยทั่วไป Clojure เป็นหนึ่งในภาษาเชิงฟังก์ชั่นและชุมชนและคุณไม่ควรพูดคุยมากเกินไป ฉันจะพูดบางอย่างจากมุมมอง ML / Haskell มากขึ้น

ตามที่ Basile กล่าวถึงแนวคิดของการควบคุมการเข้าถึงนั้นมีอยู่ใน ML / Haskell และมักจะใช้ "แฟคตอริ่ง" นั้นแตกต่างจากภาษา OOP ทั่วไปเล็กน้อย ใน OOP แนวคิดของคลาสเล่นบทบาทของประเภทและโมดูลพร้อมกันในขณะที่ภาษาที่ใช้งานได้

อีกประเด็นหนึ่งคือ ML / Haskell นั้นมีน้ำหนักมากในยาชื่อสามัญที่มีประเภทการลบและสามารถใช้เพื่อให้รสชาติที่แตกต่างของ "การซ่อนข้อมูล" มากกว่า OOP encapsulation เมื่อส่วนประกอบรู้ชนิดของรายการข้อมูลเป็นพารามิเตอร์ประเภทเท่านั้นส่วนประกอบนั้นสามารถส่งค่าได้อย่างปลอดภัยประเภทนั้น แต่ก็จะถูกป้องกันไม่ให้ทำอะไรกับพวกเขาได้มากเพราะไม่ทราบและไม่ทราบประเภทที่เป็นรูปธรรม (ไม่มีภาษาสากลinstanceofหรือการส่งนักแปลในภาษาเหล่านี้) บล็อกนี้เป็นหนึ่งในตัวอย่างเบื้องต้นที่ฉันโปรดปรานสำหรับเทคนิคเหล่านี้

ถัดไป: ในโลก FP มันเป็นเรื่องธรรมดามากที่จะใช้โครงสร้างข้อมูลแบบโปร่งใสเป็นอินเทอร์เฟซสำหรับองค์ประกอบทึบแสง / ห่อหุ้ม ตัวอย่างเช่นรูปแบบของล่ามเป็นเรื่องธรรมดามากใน FP ซึ่งมีการใช้โครงสร้างข้อมูลเป็นต้นไม้ไวยากรณ์ที่อธิบายถึงตรรกะและป้อนรหัสที่ "ดำเนินการ" รัฐกล่าวอย่างถูกต้องแล้วมีอยู่อย่างไม่เป็นผลเมื่อล่ามทำงานที่ใช้โครงสร้างข้อมูล การใช้งานล่ามยังสามารถเปลี่ยนแปลงได้ตราบใดที่ยังคงสื่อสารกับลูกค้าในแง่ของชนิดข้อมูลเดียวกัน

สุดท้ายและยาวที่สุด: การซ่อนข้อมูล / การซ่อนข้อมูลเป็นเทคนิคไม่ใช่จุดจบ ลองคิดดูว่ามันมีอะไรบ้าง Encapsulation เป็นเทคนิคสำหรับการกระทบยอดสัญญาและการใช้งานหน่วยซอฟต์แวร์ สถานการณ์ทั่วไปคือสิ่งนี้: การนำระบบไปใช้ยอมรับค่าหรือระบุว่าไม่ควรมีอยู่ตามสัญญา

เมื่อคุณดูด้วยวิธีนี้เราสามารถชี้ให้เห็นว่า FP ให้นอกเหนือจากการห่อหุ้มเครื่องมือเพิ่มเติมจำนวนหนึ่งที่สามารถใช้ในจุดสิ้นสุดเดียวกันได้:

  1. Immutability เป็นค่าเริ่มต้นที่แพร่หลาย คุณสามารถส่งค่าข้อมูลที่โปร่งใสไปยังรหัสของบุคคลที่สามได้ พวกเขาไม่สามารถแก้ไขได้และทำให้พวกเขาอยู่ในสถานะที่ไม่ถูกต้อง (คำตอบของคาร์ลทำให้ประเด็นนี้)
  2. ระบบประเภทที่ซับซ้อนพร้อมกับประเภทข้อมูลเกี่ยวกับพีชคณิตที่ช่วยให้คุณสามารถควบคุมโครงสร้างประเภทของคุณอย่างละเอียดโดยไม่ต้องเขียนโค้ดจำนวนมาก ด้วยการใช้สิ่งอำนวยความสะดวกเหล่านี้อย่างรอบคอบคุณมักจะสามารถออกแบบประเภทที่ "สภาวะเลวร้าย" เป็นไปไม่ได้ (สโลแกน: "ทำให้รัฐที่ผิดกฎหมายไม่สามารถอธิบายได้" ) แทนที่จะใช้การห่อหุ้มเพื่อควบคุมชุดสถานะที่ยอมรับได้ของทางอ้อมโดยอ้อมฉันควรแค่บอกผู้แปลว่าพวกเขามีอะไรและรับประกันพวกเขาสำหรับฉัน!
  3. รูปแบบของล่ามดังที่ได้กล่าวมาแล้ว กุญแจสำคัญในการออกแบบประเภทต้นไม้ที่เป็นนามธรรมที่ดีคือ:
    • ลองและออกแบบชนิดข้อมูลทรีของไวยากรณ์ไวยากรณ์เพื่อให้ค่าทั้งหมดเป็น "ใช้ได้"
    • หากไม่ทำเช่นนั้นให้ล่ามตรวจพบชุดค่าผสมที่ไม่ถูกต้องอย่างชัดเจนและปฏิเสธอย่างชัดเจน

ซีรีย์ F # "การออกแบบที่มีประเภท" นี้เหมาะสำหรับการอ่านที่น่าสนใจในบางหัวข้อเหล่านี้โดยเฉพาะอย่างยิ่ง # 2 (ซึ่งเป็นที่มาของลิงก์ "ทำให้รัฐที่ไม่สามารถอธิบายได้ผิดกฎหมาย" จากด้านบน) หากคุณมองอย่างใกล้ชิดคุณจะทราบว่าในส่วนที่สองพวกเขาสาธิตวิธีใช้การห่อหุ้มเพื่อซ่อนตัวสร้างและป้องกันไม่ให้ลูกค้าสร้างอินสแตนซ์ที่ไม่ถูกต้อง อย่างที่ฉันได้กล่าวไปแล้วมันเป็นส่วนหนึ่งของชุดเครื่องมือ!


9

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

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

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


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

8

แนวโน้มของ Clojure ในการใช้แฮชและการใช้แบบดั้งเดิมนั้นไม่ได้อยู่ในความคิดของฉันส่วนหนึ่งของมรดกที่ใช้งานได้ แต่เป็นส่วนหนึ่งของมรดกที่มีพลัง ฉันเคยเห็นแนวโน้มที่คล้ายกันใน Python และ Ruby (ทั้งเชิงวัตถุความจำเป็นและแบบไดนามิกแม้ว่าทั้งสองมีการสนับสนุนที่ดีสำหรับฟังก์ชั่นการสั่งซื้อที่สูงขึ้น) แต่ไม่ได้อยู่ในการพูด Haskell (ซึ่งพิมพ์แบบคงที่ มีสิ่งก่อสร้างพิเศษที่จำเป็นในการหลบหนีไม่สามารถเปลี่ยนแปลงได้)

ดังนั้นคำถามที่คุณต้องถามไม่ใช่ภาษาที่ใช้งานได้จัดการกับ API ขนาดใหญ่ได้อย่างไร แต่ภาษาแบบไดนามิกทำอย่างไร คำตอบคือ: เอกสารที่ดีและการทดสอบหน่วยจำนวนมาก โชคดีที่ภาษาไดนามิกที่ทันสมัยมักมาพร้อมกับการสนับสนุนที่ดีสำหรับทั้งสองอย่าง ตัวอย่างเช่น Python และ Clojure มีวิธีการฝังเอกสารในโค้ดเองไม่ใช่แค่ความคิดเห็น


เกี่ยวกับภาษาที่พิมพ์แบบคงที่ (หมดจด) ภาษาที่ใช้งานได้ไม่มีวิธี (ง่าย) ในการพกพาฟังก์ชันที่มีประเภทข้อมูลเหมือนกับในการเขียนโปรแกรม OO ดังนั้นเอกสารสำคัญอยู่แล้ว ประเด็นคือคุณไม่ต้องการการสนับสนุนด้านภาษาเพื่อกำหนดส่วนต่อประสาน
Scara95

5
@ Scara95 คุณช่วยอธิบายสิ่งที่คุณหมายถึงโดย "พกฟังก์ชั่นที่มีประเภทข้อมูล"?
เซบาสเตียนเรดล

6

ภาษาหน้าที่บางภาษาให้ความสามารถในการห่อหุ้มหรือซ่อนรายละเอียดการใช้งานในประเภทข้อมูลนามธรรมและโมดูล

ตัวอย่างเช่นOCamlมีโมดูลที่กำหนดโดยคอลเลกชันของประเภทนามธรรมที่มีชื่อและค่า (สะดุดตาฟังก์ชั่นการดำเนินงานในประเภทนามธรรมเหล่านี้) ดังนั้นในแง่หนึ่งโมดูลของ Ocaml ก็กำลังรวม API ใหม่ Ocaml ยังมี functors ซึ่งเปลี่ยนบางโมดูลเป็นอีกโมดูลหนึ่งดังนั้นจึงให้โปรแกรมทั่วไป ดังนั้นโมดูลจึงเป็นองค์ประกอบ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.