API การกำหนดเวอร์ชัน


9

สมมติว่าคุณมีโครงการขนาดใหญ่ที่สนับสนุนโดย API พื้นฐาน โครงการนี้ยังจัดส่ง API สาธารณะที่ผู้ใช้สามารถใช้ (สิ้นสุด)

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

สมมติว่าคุณกำลังใช้วัตถุเหล่านี้ใน API สาธารณะของคุณวัตถุสาธารณะก็จะเปลี่ยนทุกครั้งที่คุณทำเช่นนี้ซึ่งไม่พึงประสงค์เนื่องจากลูกค้าของคุณอาจพึ่งพาวัตถุ API ที่เหลือเหมือนกันสำหรับรหัสการแยกวิเคราะห์เพื่อทำงาน (ไคลเอนต์ C ++ WSDL สำหรับไอ ... )

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

ดังนั้นสติบางอย่างที่มักใช้กับสถานการณ์นี้คืออะไร? ฉันรู้ว่าบริการสาธารณะจำนวนมากเช่น Git สำหรับ Windows ใช้ API รุ่น แต่ฉันมีปัญหาในการจินตนาการสถาปัตยกรรมที่สนับสนุนสิ่งนี้โดยไม่ต้องใช้รหัสซ้ำจำนวนมากครอบคลุมวิธีการที่หลากหลายและวัตถุอินพุต / เอาท์พุต

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


1
I don't see a good way to do that without duplicating code- API ใหม่ของคุณสามารถเรียกใช้เมธอดใน API เก่าของคุณหรือในทางกลับกัน
Robert Harvey

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

มีแพลตฟอร์ม / บริบทเฉพาะสำหรับเรื่องนี้หรือไม่? (เช่น DLL ของ REST API และอื่น ๆ )
GrandmasterB

.NET พร้อม MVC และ Webforms ui คลาส dll เรามี API พักผ่อนและสบู่
คดี

คำตอบ:


6

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

  1. เพิ่มฟังก์ชั่นใหม่ใน API ที่มีอยู่
  2. ฟังก์ชั่นเก่าเลิกใช้งานจาก API
  3. ฟังก์ชั่นที่มีอยู่ในการเปลี่ยนแปลง API ในบางวิธี

ฟังก์ชันการทำงานใหม่เพิ่มไปยัง API ที่มีอยู่

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

ฟังก์ชั่นเก่าเลิกใช้งานจาก API

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

ฟังก์ชั่นที่มีอยู่ในการเปลี่ยนแปลง API ในบางวิธี

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

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

ความคิดอื่น ๆ

Rather, the API is likely to extend the private objects we are using for our base API, but then we run into the same problem because added properties would also be available in the public API when they are not supposed to be.

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

The problem is more that it seems like many or most changes require breaking the public API if the objects aren't more separated, but I don't see a good way to do that without duplicating code.

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

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

ตัวอย่าง

สมมติว่าคุณกำลังจัดหาโซลูชันการประมวลผลการชำระเงิน คุณใช้ PaymentProviderA เพื่อทำธุรกรรมบัตรเครดิต หลังจากนั้นคุณจะได้รับอัตราที่ดีขึ้นผ่านตัวประมวลผลการชำระเงินของ PaymentProviderB หาก API ของคุณเปิดเผยฟิลด์บัตรเครดิต / ที่อยู่ที่เรียกเก็บเงินของประเภทของคุณแทนการเป็นตัวแทนของ PaymentProviderA การเปลี่ยนแปลงของ API คือ 0 เนื่องจากอินเทอร์เฟซยังคงเหมือนเดิม (หวังว่าอย่างไรก็ตามถ้า PaymentProviderB ต้องการข้อมูลที่ไม่จำเป็นต้องใช้ สนับสนุนทั้งสองหรือรักษาอัตราที่เลวร้ายยิ่งขึ้นด้วย PaymentProviderA)


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

1
ฉันไม่ทราบถึงตัวอย่างที่ดีใด ๆ ที่อยู่บนหัวของฉันถ้าฉันมีเวลาในช่วงสุดสัปดาห์นี้ฉันสามารถสร้างแอปทดสอบเพื่อโยน GitHub เพื่อแสดงให้เห็นว่าสิ่งเหล่านี้สามารถนำไปใช้ได้อย่างไร
Phil Patterson

1
ส่วนที่ยุ่งยากคือจากระดับสูงมีหลายวิธีที่จะพยายามลดการเชื่อมต่อระหว่างไคลเอนต์และเซิร์ฟเวอร์ WCF มีส่วนต่อประสานที่เรียกว่า IExtensibleDataObject ซึ่งช่วยให้คุณส่งผ่านข้อมูลที่ไม่ได้อยู่ในสัญญาจากลูกค้าและส่งผ่านสายไปยังเซิร์ฟเวอร์ Google สร้าง Protobuf เพื่อการสื่อสารระหว่างระบบ (มีการใช้งานโอเพ่นซอร์สสำหรับ. NET, Java และอื่น ๆ ) นอกจากนี้ยังมีระบบที่ใช้ข้อความเป็นจำนวนมากที่สามารถทำงานได้ (สมมติว่ากระบวนการของคุณสามารถดำเนินการแบบอะซิงโครนัส)
Phil Patterson

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