คุณจะจัดระเบียบซอฟต์แวร์ที่ปรับแต่งได้อย่างไร


28

ฉันกำลังทำงานในโครงการซอฟต์แวร์ขนาดใหญ่ซึ่งได้รับการปรับแต่งอย่างดีสำหรับลูกค้าที่หลากหลายทั่วโลก ซึ่งหมายความว่าเราอาจมีรหัส 80% ซึ่งเป็นเรื่องปกติระหว่างลูกค้าหลายราย แต่ยังมีรหัสจำนวนมากที่ต้องเปลี่ยนจากลูกค้ารายหนึ่งเป็นลูกค้ารายอื่น ในอดีตที่ผ่านมาเราทำการพัฒนาของเราในที่เก็บแยกต่างหาก (SVN) และเมื่อโครงการใหม่เริ่มต้น (เรามีน้อย แต่ลูกค้าขนาดใหญ่) สร้างพื้นที่เก็บข้อมูลอื่นตามโครงการที่ผ่านมามีพื้นฐานรหัสที่ดีที่สุดสำหรับความต้องการของเรา สิ่งนี้ได้ผลในอดีต แต่เราพบปัญหาหลายประการ:

  • ข้อบกพร่องที่ได้รับการแก้ไขในที่เก็บหนึ่งจะไม่ได้รับการแก้ไขในที่เก็บอื่น ๆ นี่อาจเป็นปัญหาขององค์กร แต่ฉันพบว่ามันยากที่จะแก้ไขและแก้ไขข้อบกพร่องในที่เก็บ 5 แห่งที่แตกต่างกันโดยคำนึงว่าทีมที่ดูแลพื้นที่เก็บข้อมูลนี้อาจอยู่ในอีกส่วนหนึ่งของโลกและเราไม่มีสภาพแวดล้อมการทดสอบ ไม่ทราบกำหนดการหรือข้อกำหนดที่ต้องมี ("ข้อบกพร่อง" ในประเทศหนึ่งอาจเป็น "คุณสมบัติ" ในอีกประเทศหนึ่ง)
  • คุณสมบัติและการปรับปรุงที่ทำไว้สำหรับโครงการหนึ่งซึ่งอาจเป็นประโยชน์สำหรับโครงการอื่นหายไปหรือหากใช้ในโครงการอื่นมักทำให้เกิดอาการปวดหัวขนาดใหญ่รวมจากรหัสฐานหนึ่งไปยังอีกโครงการหนึ่ง (เนื่องจากทั้งสองสาขาอาจได้รับการพัฒนาอย่างอิสระเป็นเวลาหนึ่งปี )
  • Refactorings และการปรับปรุงรหัสที่ทำในสาขาการพัฒนาหนึ่งอาจสูญหายหรือก่อให้เกิดอันตรายมากกว่าดีถ้าคุณต้องรวมการเปลี่ยนแปลงทั้งหมดเหล่านี้ระหว่างสาขา

ขณะนี้เรากำลังพูดถึงวิธีการแก้ปัญหาเหล่านี้และในขณะนี้ได้มีแนวคิดต่อไปนี้เกี่ยวกับวิธีการแก้ไขปัญหาดังกล่าว:

  1. ทำการพัฒนาในสาขาที่แยกกันแต่จัดระเบียบได้ดีขึ้นด้วยการมีที่เก็บส่วนกลางที่มีการแก้ไขข้อบกพร่องทั่วไปและรวมโครงการทั้งหมดเข้าด้วยกันการเปลี่ยนแปลงจากที่เก็บส่วนกลางนี้เป็นของตัวเองเป็นประจำ (เช่นทุกวัน) เรื่องนี้ต้องมีวินัยอย่างมากและมีความพยายามอย่างมากในการผสานระหว่างสาขา ดังนั้นฉันไม่มั่นใจว่ามันจะทำงานได้และเราสามารถรักษาวินัยนี้โดยเฉพาะอย่างยิ่งเมื่อเวลากดดัน

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

วิธีที่สองดูเหมือนจะสง่างามกว่า แต่เรามีปัญหาที่ยังไม่คลี่คลายในแนวทางนี้ ตัวอย่างเช่นวิธีจัดการกับการเปลี่ยนแปลง / การเพิ่มเติมในแบบจำลอง / ฐานข้อมูลของคุณ เราใช้. NET กับ Entity Framework เพื่อพิมพ์เอนทิตีอย่างยิ่ง ฉันไม่เห็นวิธีที่เราสามารถจัดการคุณสมบัติที่จำเป็นสำหรับลูกค้ารายหนึ่ง แต่ไร้ประโยชน์สำหรับลูกค้ารายอื่นโดยไม่เกะกะโมเดลข้อมูลของเรา เรากำลังคิดที่จะแก้ปัญหานี้ในฐานข้อมูลโดยใช้ตารางดาวเทียม (มีตารางแยกต่างหากที่คอลัมน์พิเศษของเราสำหรับเอนทิตีที่เจาะจงอยู่ด้วยการแมป 1: 1 กับเอนทิตีดั้งเดิม) แต่นี่เป็นเพียงฐานข้อมูล คุณจัดการเรื่องนี้ในรหัสได้อย่างไร แบบจำลองข้อมูลของเราอาศัยอยู่ในห้องสมุดกลางซึ่งเราไม่สามารถขยายให้ลูกค้าแต่ละรายใช้วิธีการนี้ได้

ฉันแน่ใจว่าเราไม่ใช่ทีมเดียวที่ต้องดิ้นรนกับปัญหานี้และฉันก็ตกใจที่พบเนื้อหาในหัวข้อนี้น้อยมาก

ดังนั้นคำถามของฉันมีดังต่อไปนี้:

  1. คุณมีประสบการณ์ใดบ้างกับซอฟต์แวร์ที่ปรับแต่งได้เองคุณเลือกวิธีการแบบใดและมันทำงานอย่างไรให้คุณ
  2. คุณแนะนำวิธีใดและทำไม มีแนวทางที่ดีกว่านี้ไหม?
  3. มีหนังสือหรือบทความดีๆในหัวข้อที่คุณสามารถแนะนำได้หรือไม่?
  4. คุณมีคำแนะนำเฉพาะสำหรับสภาพแวดล้อมด้านเทคนิคของเรา (.NET, Entity Framework, WPF, DI) หรือไม่

แก้ไข:

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

ฉันยังไม่แน่ใจว่าเราจะไปทางไหนและฉันไม่ได้ตัดสินใจ (คนเดียว) แต่ฉันจะผ่านมันไปในทีมของฉันและฉันแน่ใจว่ามันจะเป็นประโยชน์

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

ดังนั้นขอขอบคุณอีกครั้งสำหรับคำตอบทั้งหมด!


พิจารณารักษาตารางฐานข้อมูลเป็นรหัส

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

คำตอบ:


10

ดูเหมือนปัญหาพื้นฐานไม่ได้บำรุงรักษาพื้นที่เก็บข้อมูลรหัสเพียง แต่ขาดของสถาปัตยกรรมที่เหมาะสม

  1. อะไรคือแก่นแท้ / สาระสำคัญของระบบที่จะถูกแบ่งปันโดยทุกระบบ?
  2. ลูกค้าแต่ละรายต้องการการปรับปรุง / การเบี่ยงเบนอะไรบ้าง

เฟรมเวิร์กหรือไลบรารีมาตรฐานครอบคลุมอดีตในขณะที่ส่วนหลังจะถูกนำไปใช้เป็นส่วนเสริม (ปลั๊กอิน, คลาสย่อย, DI, อะไรก็ตามที่เหมาะสมสำหรับโครงสร้างรหัส)

ระบบควบคุมแหล่งที่มาซึ่งจัดการสาขาและการพัฒนาแบบกระจายอาจช่วยได้ ฉันเป็นแฟนของ Mercurial คนอื่นชอบ Git กรอบงานจะเป็นสาขาหลักแต่ละระบบที่กำหนดเองจะเป็นสาขาย่อยตัวอย่างเช่น

เทคโนโลยีเฉพาะที่ใช้ในการติดตั้งระบบ (. NET, WPF หรืออะไรก็ตาม) นั้นส่วนใหญ่จะไม่สำคัญ

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

คุณอาจพบว่าหนังสือสถาปัตยกรรมซอฟต์แวร์: หลักการและรูปแบบขององค์กรมีประโยชน์

โชคดี!


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

ฉันคิดว่ามีส่วนแบ่งขนาดใหญ่ระหว่างสาขาของเราหลายแห่ง (> 90%) แต่ 10% สุดท้ายอยู่ในสถานที่ที่แตกต่างกันเสมอดังนั้นจึงมีองค์ประกอบน้อยมากที่ฉันไม่สามารถจินตนาการถึงการเปลี่ยนแปลงที่เฉพาะเจาะจงของลูกค้ายกเว้นห้องสมุดสาธารณูปโภคบางแห่ง ไม่มีตรรกะทางธุรกิจใด ๆ
aKzenT

@aKzenT: hmmm ... ไม่คิดลองวัดแทน สำรวจรหัสและดูสถานที่ทั้งหมดที่มีการปรับแต่งเกิดขึ้นทำรายการส่วนประกอบที่แก้ไขสังเกตความถี่ที่แต่ละองค์ประกอบได้รับการแก้ไขและคิดถึงประเภทและรูปแบบของการปรับเปลี่ยนที่ได้ทำไปแล้วจริง พวกเขาเป็นเครื่องสำอางหรืออัลกอริทึม? พวกเขากำลังเพิ่มหรือเปลี่ยนฟังก์ชันการทำงานพื้นฐานหรือไม่ อะไรคือสาเหตุของการเปลี่ยนแปลงแต่ละประเภท? นี่เป็นงานที่หนักและคุณอาจไม่ชอบความหมายของสิ่งที่คุณค้นพบ
Steven A. Lowe

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

11

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

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

การมีทุกอย่างในรหัสฐานข้อมูลทั่วไปสำหรับลูกค้าทุกคนมีข้อดีบางประการ แต่ในทางกลับกันการอ่านรหัสจะยากเมื่อมีจำนวนนับไม่ถ้วนifที่จะทำให้โปรแกรมทำงานแตกต่างกันไปสำหรับลูกค้าแต่ละราย

แก้ไข: เรื่องเล็ก ๆ น้อยหนึ่งที่ทำให้เข้าใจได้ง่ายขึ้น:

โดเมนของ บริษัท นั้นคือการจัดการคลังสินค้าและงานหนึ่งของระบบการจัดการคลังสินค้าคือการหาที่เก็บสินค้าฟรีสำหรับสินค้าขาเข้า ฟังดูง่าย แต่ในทางปฏิบัติต้องมีข้อ จำกัด และกลยุทธ์มากมาย

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

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

ฉันรู้ว่า LOC ไม่ใช่การวัดที่ดี แต่อย่างไรก็ตามขนาดของโมดูล "ยืดหยุ่น" คือ ~ 3000 LOC (PL / SQL) ในขณะที่โมดูลที่กำหนดเองสำหรับงานเดียวกันใช้เวลาประมาณ ~ 100.5050 LOC ดังนั้นการพยายามที่จะยืดหยุ่นเพิ่มขนาดของฐานรหัสได้อย่างมากโดยไม่เพิ่มความสามารถในการนำกลับมาใช้ใหม่ที่เราหวังไว้


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

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

+1 สิ่งนี้ตรงกับประสบการณ์ของโครงการที่จัดการเรื่องนี้ได้ดี หากคุณกำลังจะใช้วิธี 'ifs สำหรับลูกค้าที่แตกต่างกัน' 2 คะแนน: 1. อย่าทำถ้า (ลูกค้า 1) ... , ทำแทนหาก (configurationOption1) ... และมีตัวเลือกการกำหนดค่าต่อลูกค้า 2. พยายามอย่าทำ! อาจเป็น 1% ของเวลาที่จะเป็นตัวเลือกที่ดีกว่า (เข้าใจได้ / บำรุงรักษาง่ายกว่า) กว่ามีโมดูลเฉพาะการกำหนดค่า
vaughandroid

@Baqueta: เพียงชี้แจง: คุณแนะนำให้ใช้โมดูลต่อลูกค้าแทนตัวเลือกการกำหนดค่า (ifs) ใช่ไหม? ฉันชอบความคิดของคุณในการแยกความแตกต่างระหว่างคุณสมบัติแทนที่จะเป็นลูกค้า ดังนั้นการรวมกันของทั้งสองจึงจะมี "โมดูลคุณสมบัติ" ต่างๆซึ่งควบคุมโดยตัวเลือกการกำหนดค่า จากนั้นลูกค้าจะแสดงเป็นชุดของโมดูลคุณลักษณะอิสระเท่านั้น ฉันชอบวิธีนี้มาก แต่ฉันไม่แน่ใจว่าจะออกแบบสิ่งนี้ได้อย่างไร DI แก้ปัญหาการโหลดโมดูลและการแลกเปลี่ยน แต่คุณจะจัดการตัวแบบข้อมูลที่แตกต่างกันระหว่างลูกค้าได้อย่างไร?
aKzenT

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

5

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

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

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

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

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

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

ดังนั้นเพื่อตอบคำถามของคุณ:

  1. มากมายและนั่นเป็นหนึ่งในทีมที่ดีที่สุดที่ฉันเคยร่วมงานด้วย Codebase ในเวลานั้นประมาณ 1M loc ฉันไม่ได้เลือกวิธี แต่มันก็ใช้ได้ดีทีเดียว แม้จะอยู่ในเหตุการณ์หลังค่อมฉันก็ไม่เห็นวิธีที่ดีกว่าในการจัดการกับสิ่งต่าง ๆ
  2. ฉันแนะนำวิธีที่สองที่คุณแนะนำด้วยความแตกต่างที่ฉันพูดถึงในคำตอบของฉัน
  3. ไม่มีหนังสือที่ฉันสามารถนึกได้ แต่ฉันจะค้นคว้าการพัฒนาหลายแพลตฟอร์มในฐานะผู้เริ่มต้น
  4. จัดตั้งสถาบันธรรมาภิบาล เป็นกุญแจสำคัญในการตรวจสอบให้แน่ใจว่าคุณปฏิบัติตามมาตรฐานการเข้ารหัส การปฏิบัติตามมาตรฐานเหล่านี้เป็นวิธีเดียวที่จะทำให้สิ่งต่างๆสามารถจัดการและบำรุงรักษาได้ เรามีส่วนแบ่งของคำอ้อนวอนที่ไม่กระตือรือร้นเพื่อทำลายแบบจำลองที่เราติดตาม แต่ไม่มีการอุทธรณ์ใด ๆ เลยที่ส่งผลต่อทีมพัฒนาอาวุโสทั้งหมด

ขอบคุณที่แบ่งปันประสบการณ์ของคุณ เพียงเพื่อให้เข้าใจได้ดีขึ้น: แพลตฟอร์มกำหนดไว้อย่างไรในกรณีของคุณ Windows, Linux, X86 / x64? หรือสิ่งที่เกี่ยวข้องกับลูกค้า / สภาพแวดล้อมที่แตกต่างกัน คุณกำลังทำจุดที่ดีใน 4) ฉันคิดว่ามันเป็นหนึ่งในปัญหาที่เรามี เรามีทีมงานที่เป็นคนเก่งและมีคุณสมบัติมากมาย แต่ทุกคนมีแนวคิดที่แตกต่างกันเล็กน้อยเกี่ยวกับวิธีการทำสิ่งต่าง ๆ หากไม่มีใครรับผิดชอบงานสถาปัตยกรรมอย่างชัดเจนมันยากที่จะเห็นด้วยกับกลยุทธ์ทั่วไปและคุณมีความเสี่ยงที่จะสูญเสียการอภิปรายโดยไม่ต้องเปลี่ยนอะไรเลย
aKzenT

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

4

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

เรามี 2 ทีมแยก: ทีมพัฒนาหลักซึ่งรับผิดชอบรหัสระบบหลัก (ซึ่งจะเป็นรหัสที่ใช้ร่วมกัน 80% ของคุณด้านบน) และทีมงานติดตั้งซึ่งมีความเชี่ยวชาญด้านโดเมนในระบบบำนาญและรับผิดชอบลูกค้าการเรียนรู้ ข้อกำหนดและสคริปต์การเข้ารหัสและรายงานสำหรับลูกค้า

เรามีตารางทั้งหมดของเราที่กำหนดโดย Xml (สิ่งนี้มาก่อนเวลาที่เฟรมเวิร์กเอนทิตีได้รับการทดสอบตามเวลาและร่วมกัน) ทีมงานการใช้งานจะออกแบบตารางทั้งหมดใน Xml และแอปพลิเคชันหลักอาจได้รับแจ้งให้สร้างตารางทั้งหมดใน Xml นอกจากนี้ยังมีไฟล์สคริปต์ VB ที่เกี่ยวข้องรายงาน Crystal เอกสาร Word ฯลฯ สำหรับลูกค้าแต่ละราย (นอกจากนี้ยังมีรูปแบบการสืบทอดที่สร้างไว้ใน Xml เพื่อเปิดใช้งานการนำไปใช้งานอื่น ๆ อีกครั้ง)

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

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

เรามีแหล่งเก็บข้อมูลแยกต่างหากสำหรับรหัสระบบหลักและรหัสการนำไปใช้งาน

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

การแบ่งส่วนตรรกะหลักและตรรกะที่กำหนดเองเป็นความท้าทายที่ยากลำบาก อย่างไรก็ตามเรามักรู้สึกว่าเป็นการดีกว่าที่จะมีระบบหลักหนึ่งระบบที่ใช้งานไคลเอนต์หลายตัวแทนที่จะเป็นหลาย ๆ สำเนาของระบบที่ใช้สำหรับลูกค้าแต่ละราย


ขอบคุณสำหรับความคิดเห็น. ฉันชอบความคิดของการมีฟิลด์เพิ่มเติมในพจนานุกรม สิ่งนี้จะช่วยให้เรามีคำจำกัดความเดียวของเอนทิตีและใส่ข้อมูลเฉพาะของลูกค้าทั้งหมดลงในพจนานุกรม ฉันไม่แน่ใจว่าหากมีวิธีที่ดีในการทำให้มันทำงานกับ ORM wrapper (Entity Framework) ของเรา และฉันก็ไม่แน่ใจเหมือนกันว่าถ้าเป็นความคิดที่ดีที่จะมีโมเดลข้อมูลที่ใช้ร่วมกันทั่วโลกแทนที่จะมีโมเดลสำหรับทุกคุณสมบัติ / โมดูล
aKzenT

2

ฉันทำงานบนระบบที่เล็กกว่า (20 kloc) และพบว่า DI และการกำหนดค่าเป็นวิธีที่ยอดเยี่ยมในการจัดการความแตกต่างระหว่างไคลเอนต์ แต่ไม่เพียงพอที่จะหลีกเลี่ยงการฟอร์กระบบ ฐานข้อมูลถูกแยกระหว่างส่วนเฉพาะของแอปพลิเคชันซึ่งมีสคีมาคงที่และส่วนที่ขึ้นกับไคลเอ็นต์ซึ่งกำหนดผ่านเอกสารกำหนดค่า XML ที่กำหนดเอง

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


คุณแยกความแตกต่างระหว่าง core library ที่เหมือนกันระหว่างลูกค้าหรือคุณแยก tree tree ทั้งหมดหรือไม่ คุณรวมกฎระเบียบจากการฉีดไปยังส้อมแต่ละคน? และถ้าใช่ค่าใช้จ่ายประจำวันรวมเท่าไหร่และคุณหลีกเลี่ยงขั้นตอนนี้อย่างไรเมื่อความกดดันด้านเวลาเริ่มต้น (เช่นเคยที่จุดหนึ่งในโครงการเสมอ) ขออภัยสำหรับคำถามมากมาย: p
aKzenT

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

ฉันอยากรู้ว่า: Mercury IIRC นั้นเป็น DVCS ที่คล้ายคลึงกับ git คุณสังเกตเห็นว่ามีข้อได้เปรียบในการผสานระหว่างสาขาเมื่อเปรียบเทียบกับการโค่นล้มหรือ VCS ดั้งเดิมอื่น ๆ หรือไม่? ฉันเพิ่งเสร็จสิ้นกระบวนการผสานที่เจ็บปวดมากระหว่าง 2 สาขาที่พัฒนาแล้วโดยใช้การโค่นล้มและคิดว่าถ้ามันง่ายกว่านี้ถ้าเราใช้คอมไพล์
aKzenT

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

2

ฉันกลัวว่าฉันไม่มีประสบการณ์ตรงของปัญหาที่คุณอธิบาย แต่ฉันมีความคิดเห็น

ตัวเลือกที่สองการนำรหัสมารวมกันในที่เก็บส่วนกลาง (เท่าที่สามารถทำได้) และการสร้างสถาปัตย์เพื่อปรับแต่ง

ปัญหาคือวิธีที่คุณวางแผนที่จะไปที่นั่นและใช้เวลานานแค่ไหน

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

สิ่งนี้จะช่วยให้คุณสามารถย้ายไปยังสถาปัตยกรรมที่รองรับการปรับแต่งได้โดยตรงโดยไม่ต้องทำในคราวเดียว


2

วิธีที่สองดูเหมือนจะสง่างามกว่า แต่เรามีปัญหาที่ยังไม่คลี่คลายในแนวทางนี้

ฉันมั่นใจว่าปัญหาเหล่านี้จะสามารถแก้ไขได้ หากคุณติดขัดให้ถามที่นี่หรือทาง SO เกี่ยวกับปัญหาเฉพาะ

ดังที่คนอื่น ๆ ชี้ให้เห็นการมี codebase ส่วนกลางหนึ่ง / หนึ่งที่เก็บเป็นตัวเลือกที่คุณควร ฉันพยายามตอบคำถามตัวอย่างของคุณ

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

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

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

  • ตอนนี้มันควรจะชัดเจนว่าจะใช้ในรหัส: มีเพียงรหัสทั่วไปสำหรับการเข้าถึงตารางเหล่านั้นและรหัสบุคคล (อาจจะแยกต่างหากในปลั๊กอิน DLL แยกต่างหากซึ่งขึ้นอยู่กับคุณ) สำหรับการตีความคุณลักษณะที่ถูกต้อง

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

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


ปัญหาที่ฉันเห็นด้วยการเพิ่ม CustomAttributes หรือคอลัมน์ XML เพื่อเก็บคุณสมบัติที่กำหนดเองคือพวกเขามีข้อ จำกัด ในความสามารถของพวกเขา ตัวอย่างเช่นการเรียงลำดับการจัดกลุ่มหรือการกรองตามคุณลักษณะเหล่านี้เป็นสิ่งที่ท้าทายมาก ฉันเคยทำงานในระบบที่ใช้ตารางคุณลักษณะพิเศษและมันซับซ้อนมากขึ้นในการดูแลและจัดการคุณสมบัติที่กำหนดเองเหล่านี้ ด้วยเหตุนี้ฉันจึงคิดแทนที่จะวางคุณลักษณะเหล่านี้เป็นคอลัมน์ในตารางพิเศษซึ่งถูกแมป 1: 1 กับต้นฉบับ ปัญหาเกี่ยวกับวิธีการกำหนดแบบสอบถามและจัดการสิ่งเหล่านี้ยังคงเหมือนเดิม
aKzenT

@aKzenT: การปรับแต่งไม่ได้มาฟรีคุณจะต้องแลกกับความสะดวกในการใช้งานกับความสามารถในการปรับแต่งเอง ข้อเสนอแนะทั่วไปของฉันคือคุณไม่แนะนำการขึ้นต่อกันโดยที่ส่วนหลักของระบบขึ้นอยู่กับส่วนใด ๆ ที่กำหนดเองไม่ว่าจะในทางใดก็ตาม ตัวอย่างเช่นเมื่อแนะนำ "ตารางเพิ่มเติม" เหล่านี้สำหรับลูกค้า 1 คุณสามารถหลีกเลี่ยงการปรับใช้ตารางนั้นและรหัสที่เกี่ยวข้องสำหรับลูกค้า 2 ได้หรือไม่ หากคำตอบคือใช่แสดงว่าการแก้ปัญหานั้นใช้ได้
Doc Brown

0

ฉันสร้างแอปพลิเคชั่นดังกล่าวเพียงตัวเดียว ฉันจะบอกว่า 90% ของหน่วยขายถูกขายตามที่เป็นอยู่ไม่มีการปรับเปลี่ยน ลูกค้าแต่ละรายมีผิวที่กำหนดเองและเราให้บริการระบบภายในสกินนั้น เมื่อสมัยไม่มาในการที่ได้รับผลกระทบส่วนหลักที่เราพยายามใช้IF แตกแขนง เมื่อ mod # 2 เข้ามาในส่วนเดียวกันเราเปลี่ยนเป็นตรรกะของ CASEซึ่งได้รับอนุญาตสำหรับการขยายตัวในอนาคต สิ่งนี้ดูเหมือนจะจัดการกับคำขอย่อยส่วนใหญ่

คำขอเล็ก ๆ น้อย ๆ ที่กำหนดเองเพิ่มเติมใด ๆ ได้รับการจัดการโดยใช้ Case ตรรกะ

หาก mods เป็นสองอนุมูลเราสร้างโคลน (แยกรวม) และห่อ CASE ไว้รอบ ๆ เพื่อรวมโมดูลที่แตกต่างกัน

การแก้ไขข้อผิดพลาดและการแก้ไขบนแกนหลักมีผลกับผู้ใช้ทั้งหมด เราทดสอบอย่างละเอียดในการพัฒนาก่อนไปผลิต เรามักจะส่งอีเมลแจ้งเตือนที่มาพร้อมกับการเปลี่ยนแปลงและไม่เคยไม่เคยโพสต์การเปลี่ยนแปลงการผลิตในวันศุกร์ ... ไม่

สภาพแวดล้อมของเราคือ Classic ASP และ SQL Server เราไม่ได้เป็นร้านขายสปาเก็ตตี้รหัส ... ทุกอย่างเป็นโมดูลที่ใช้รวมถึงซับรูทีนและฟังก์ชั่น


-1

เมื่อฉันถูกขอให้เริ่มการพัฒนาของ B ซึ่งแบ่งปันฟังก์ชั่น 80% กับ A ฉันจะ:

  1. โคลน A และแก้ไขมัน
  2. แยกฟังก์ชันการทำงานที่ทั้ง A และ B แบ่งปันลงใน C
  3. ทำให้ A สามารถกำหนดค่าได้เพียงพอที่จะตอบสนองความต้องการของทั้ง B และตัวมันเอง (ดังนั้น B จึงถูกฝังอยู่ใน A)

คุณเลือก 1 และดูเหมือนจะไม่เหมาะกับสถานการณ์ของคุณ ภารกิจของคุณคือคาดการณ์ว่าข้อ 2 และ 3 ใดที่เหมาะสม


1
ฟังดูง่าย แต่จะต้องทำอย่างไรในทางปฏิบัติ คุณจะทำให้ซอฟท์แวร์ของคุณสามารถปรับแต่งได้อย่างไรโดยไม่เกะกะกับ "if (customer1)" ซึ่งทำให้ไม่สามารถแก้ไขได้หลังจากผ่านไประยะหนึ่ง
aKzenT

@aKzenT นั่นเป็นเหตุผลที่ฉันเลือก 2 และ 3 ให้คุณเลือก หากการเปลี่ยนแปลงที่จำเป็นในการทำให้โครงการของลูกค้า 1 สนับสนุนความต้องการของลูกค้า 2 ผ่านการกำหนดค่าจะทำให้โค้ดไม่สามารถรักษาได้ดังนั้นอย่าทำ 3
Moshe Revah

ฉันชอบทำ "if (option1)" แทนที่จะเป็น "if (customer1)" วิธีนี้มีตัวเลือก N ฉันสามารถจัดการลูกค้าที่เป็นไปได้มากมาย เช่นด้วยตัวเลือกบูลีน N คุณสามารถจัดการ 2 ^ N ลูกค้าโดยมีเพียง N 'ถ้า' ... เป็นไปไม่ได้ที่จะจัดการด้วยกลยุทธ์ "if (customer1)" ซึ่งจะต้องใช้ 2 ^ N 'ถ้า'
Fil
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.