วิธีหลีกเลี่ยงอินเตอร์เฟสแบบช่างพูด


10

พื้นหลัง: ฉันกำลังออกแบบแอปพลิเคชันเซิร์ฟเวอร์และสร้าง dll แยกต่างหากสำหรับระบบย่อยที่แตกต่างกัน เพื่อให้สิ่งต่าง ๆ ง่ายขึ้นสมมติว่าฉันมีระบบย่อยสองระบบ: 1) Users2)Projects

ส่วนต่อประสานสาธารณะของผู้ใช้มีวิธีการดังนี้:

IEnumerable<User> GetUser(int id);

และส่วนต่อประสานสาธารณะของโครงการมีวิธีการดังนี้:

IEnumerable<User> GetProjectUsers(int projectId);

ตัวอย่างเช่นเมื่อเราต้องการแสดงผู้ใช้สำหรับโครงการบางอย่างเราสามารถเรียกGetProjectUsersและจะให้วัตถุกลับมาพร้อมข้อมูลที่เพียงพอที่จะแสดงใน DataGrid หรือคล้ายกัน

ปัญหา: ตามหลักแล้วProjectsระบบย่อยไม่ควรเก็บข้อมูลผู้ใช้และควรเก็บรหัสผู้ใช้ที่เข้าร่วมในโครงการ ในการให้บริการGetProjectUsersจำเป็นต้องมีการเรียกGetUserใช้Usersระบบสำหรับแต่ละ id ผู้ใช้ที่เก็บไว้ในฐานข้อมูลของตัวเอง อย่างไรก็ตามสิ่งนี้ต้องการการGetUserเรียกที่แยกจากกันจำนวนมากทำให้เกิดคิวรี่ SQL แยกต่างหากมากมายภายในUserระบบย่อย ฉันไม่ได้ทดสอบสิ่งนี้จริงๆ แต่การมีการออกแบบช่างพูดนี้จะส่งผลกระทบต่อความสามารถในการขยายระบบ

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

คำถาม: ทุกคนสามารถแนะนำวิธีการแยกออกจากกันในขณะที่หลีกเลี่ยงการGetUserโทรบุคคลเหล่านี้ในระหว่างGetProjectUsersหรือไม่


ตัวอย่างเช่นสิ่งหนึ่งที่ฉันคิดว่าเป็นสำหรับผู้ใช้ในการให้ความสามารถแก่ระบบภายนอกในการ "แท็ก" ผู้ใช้ที่มีคู่ค่าป้ายกำกับและเพื่อขอผู้ใช้ด้วยค่าที่แน่นอนเช่น:

void AddUserTag(int userId, string tag, string value);
IEnumerable<User> GetUsersByTag(string tag, string value);

จากนั้นระบบโปรเจ็กต์สามารถแท็กผู้ใช้แต่ละรายเมื่อพวกเขาถูกเพิ่มในโครงการ:

AddUserTag(userId,"project id", myProjectId.ToString());

และในระหว่าง GetProjectUsers มันสามารถร้องขอผู้ใช้โครงการทั้งหมดในการโทรครั้งเดียว:

var projectUsers = usersService.GetUsersByTag("project id", myProjectId.ToString());

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

คำตอบ:


10

สิ่งที่ขาดหายไปในระบบของคุณคือแคช

คุณพูด:

อย่างไรก็ตามสิ่งนี้ต้องการการGetUserเรียกที่แยกจากกันจำนวนมากทำให้เกิดคิวรี่ SQL แยกต่างหากมากมายภายในUserระบบย่อย

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

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

  • ไม่ว่าคุณจะไม่แนะนำแคชเลยในภายหลัง

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

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


เมื่ออ่านคำถามของคุณอีกครั้งฉันสังเกตเห็นคำหลักที่ฉันพลาดในครั้งแรก: ความสามารถในการปรับขนาดได้ ตามกฎของหัวแม่มือคุณอาจทำตามรูปแบบถัดไป:

  1. ถามตัวเองว่าระบบช้าหรือไม่ (เช่นเป็นการละเมิดข้อกำหนดด้านประสิทธิภาพที่ไม่สามารถใช้งานได้หรือเป็นฝันร้ายที่จะใช้)

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

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

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

ปัญหาที่แท้จริงของProjectsระบบย่อยคือการขอข้อมูลสู่Usersระบบย่อย?

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

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

หากปรากฏว่ามีปัญหาคอขวดและเกิดจากการที่Projectsผู้ใช้ร้องขอผ่านUsersระบบย่อย (และตั้งอยู่ที่ระดับการสืบค้นฐานข้อมูล) คุณควรค้นหาทางเลือกอื่นเท่านั้น

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


นอกจากว่าฉันเข้าใจคุณผิดคุณกำลังพูดว่า "เก็บสาย GetUser ไว้ แต่ใช้การแคชเพื่อหลีกเลี่ยง db roundtrips"
Eren Ersönmez

@ ErenErsönmez: GetUserแทนที่จะค้นหาฐานข้อมูลจะค้นหาในแคช ซึ่งหมายความว่าไม่สำคัญว่าคุณจะโทรติดต่อกี่ครั้งGetUserเนื่องจากจะโหลดข้อมูลจากหน่วยความจำแทนฐานข้อมูล (เว้นแต่ว่าแคชจะไม่ถูกต้อง)
Arseni Mourzenko

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

@ ErenErsönmez: ยิ่งคุณมีข้อมูลมากเท่าไหร่แคชยิ่งมีความสำคัญมากขึ้นเท่านั้น ตามกฎของหัวแม่มือให้เปรียบเทียบจำนวนการอ่านกับจำนวนการเขียน หากมีการเพิ่มเอกสาร "หลายพัน" ต่อวันและมีselectคำค้นหานับล้านรายการต่อวันคุณควรใช้แคช ในทางกลับกันหากคุณเพิ่มเอนทิตีหลายพันล้านรายการในฐานข้อมูล แต่รับเพียงไม่กี่พันรายการselectที่มีการเลือกมากการwhereแคชอาจไม่มีประโยชน์
Arseni Mourzenko

คุณอาจถูกต้อง - ฉันอาจพยายามแก้ไขปัญหาที่ฉันยังไม่มี ฉันอาจจะดำเนินการตามที่เป็นอยู่และพยายามปรับปรุงในภายหลังหากจำเป็น หากการแคชไม่เหมาะสมเพราะเช่นมีแนวโน้มที่จะอ่านเพียง 1-2 ครั้งหลังจากที่เพิ่มคุณคิดว่าวิธีแก้ปัญหาที่เป็นไปได้ที่ฉันผนวกเข้ากับคำถามอาจใช้งานได้หรือไม่ คุณเห็นปัญหาใหญ่กับเรื่องนี้หรือไม่?
Eren Ersönmez
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.