چرا اطلاعات تماس را مستقیم روی User نگذاشتم
یک تصمیم کوچک معماری که مقیاس و نگهداری سیستم هویت را سادهتر میکند.
اسکیمای رایج اینطور است:
User
├── email
├── phone_number
├── telegram
├── whatsapp
└── ...
ساده بهنظر میرسد — تا وقتی موجودیت User مسئولیتهایی را جمع میکند که مال او نیست.
مسئله در یک دیاگرام
آدمها بهندرت یک ایمیل یا تلفن ابدی دارند. کانالها زیاد میشوند؛ اپها کانال جدید اختراع میکنند.
فکر کردن با aggregate
بهجای پرکردن User از کانالها، یک aggregate جدا به نام Contact آوردم:
User Account
│
├── Email
├── Mobile
├── Telegram
└── WhatsApp
- User → هویت داخل سیستم
- Contact → چگونه به او برسید
- هر aggregate قواعد و چرخهٔ عمر خودش را دارد
هر تماس چه چیزهایی میتواند داشته باشد
تأیید، رمزنگاری و اعتبارسنجی برای هر کانال فرق میکند. وقتی تماسها first-class باشند راحتتر است:
مزایا
۱. گسترشپذیری
نوع تماس جدید → بدون migration مدل User برای هر تغییر محصول.
۲. جداسازی مسئولیت
حساب و کانال بهدلایل متفاوت عوض میشوند. استقلال، پیچیدگی تصادفی را کم میکند.
۳. کنترل امنیتی بهتر
کانالهای مختلف workflow تأیید، سیاست رمزنگاری و قواعد اعتبارسنجی متفاوت میخواهند.
۴. مدل واقعگرایانهتر
آدمها شماره عوض میکنند. تلگرام اضافه میکنند. یک ایمیل را بازنشسته میکنند. مدل باید اجازه بدهد — نه اینکه وانمود کند همه برای همیشه دقیقاً یکی از هر کدام دارند.
پیچیدگی تصادفی چطور رشد میکند
روز اول
یک ستون ایمیل. شipped.
ماه سوم
تلفن دوم. «فقط یک فیلد دیگر.»
سال اول
استثنا، null، و کانالهای نیمهتأییدشده روی User.
رفکتور
Contact aggregate — همان چیزی که روز اول آرزویش را داشتید.
هدف
هدف جدول بیشتر نبود. هدف مرز روشنتر بود: دسترسی در برابر ارتباط.
ادامه: Citizenship بهعنوان Relationship.
نسخهٔ canonical. همچنین در Medium.