تعارض Product و Engineering ⚔️📊
ءManagement بهدنبال quick wins بود. آنها ما را تحت فشار قرار میدادند که از سادهترین کامپوننتها شروع کنیم. این موضوع میان product management و تیم توسعه تنش ایجاد کرد.
دیدگاه product management روشن بود: باید به کسبوکار پیشرفت قابلمشاهده نشان داد. آنها برای توجیه سرمایهگذاری در بازنویسی سیستم، نیاز به خروجیهای قابلنمایش داشتند. کسبوکار پول قابلتوجهی خرج میکرد و میخواست هرچه سریعتر بازدهی ببیند. 💰📈
اما تیم توسعه واقعیت متفاوتی میدید. ما میدانستیم شروع از بخشهای حاشیهای یعنی ساختوساز روی پایههای سست. هستهی منطق کسبوکار در سیستم legacy باقی میماند و این موضوع هر نقطهی integration را پیچیدهتر میکرد. این بدهی فنی در طول زمان انباشته میشد.
بهعنوان یک technical lead، من بهشدت با این رویکرد مخالفت کردم. استدلالم ساده بود: فرآیند اصلی تولید قلب کل سیستم بود. تمام قابلیتهای جانبی به آن وابسته بودند. با بهتعویقانداختن مهاجرت این core، ما یک شبکهی درهمتنیده از وابستگیها میان سیستم جدید و قدیمی ایجاد میکردیم. هر قابلیت جدیدی که مهاجرت میدادیم نیازمند یک همگامسازی پیچیده با core legacy میشد. ما داشتیم روی ماسههای روان ساختوساز میکردیم. 🏜⚠️
من توصیه کردم ابتدا روی core domain تمرکز کنیم. درست است، نمایش اولین نتایج بیشتر طول میکشید. اما یک پایهی محکم برای ادامهی کار ایجاد میشد. کسبوکار باید دیرتر منتظر «پیشرفت قابلرویت» میبود، اما کل فرآیند مهاجرت سریعتر و قابلاتکاتر انجام میشد.
هیچیک از دو طرف در اهداف خود اشتباه نمیکردند. Product management نگرانیهای موجهی دربارهی نمایش progress داشت.
تیم توسعه نگرانیهای موجهی دربارهی پایداری فنی داشت.
اما این عدمهمراستایی باعث بهوجود آمدن مصالحههایی شد که بر timeline پروژه اثر گذاشت.
تا امروز معتقدم اگر از core business logic شروع کرده بودیم، مهاجرت سریعتر تمام میشد. 🕰🔧
معماری نرمافزار: ساختن برای آینده 🏗🔮
در مرحلهی discovery، ما domainهای کسبوکاری متمایز را در سیستم شناسایی کردیم. این موضوع ما را به سمت پیادهسازی یک modular monolith هدایت کرد. هر ماژول self-contained بود اما میتوانست از طریق یک event bus مشترک با دیگر ماژولها ارتباط برقرار کند.
تصمیمات کلیدی معماری: 🧩
🔸️ءModular monolith:
هر ماژول یک business domain مستقل را نمایش میداد. این کار مسیر روشنی برای حرکت احتمالی آینده به سمت microservices ایجاد میکرد.
🔹️ءAsynchronous communication:
ماژولها از طریق eventها و با استفاده از RabbitMQ با یکدیگر ارتباط برقرار میکردند. این کار coupling را کاهش داده و resiliency را افزایش داد.
🔸️ءShared database با مرزبندی مشخص:
تمام ماژولها از یک دیتابیس PostgreSQL استفاده میکردند، اما هر ماژول جدولها و schemaهای مخصوص خود را داشت. این رویکرد جداسازی منطقی را حفظ میکرد.
🔹️ءCloud-ready design:
سیستم با استفاده از containerization روی AWS مستقر شد. یک Jenkins pipeline امکان deployment به چند environment را در چند دقیقه فراهم میکرد. ☁️🚀