اختاپوس خسته

یادداشت‌هایی پیرامون کد، زندگی و دوستان

توسعهٔ میان‌نسخه‌ای

سال گذشته توی وبلاگ انگلیسی‌م پستی در مورد توسعهٔ نرم‌افزار بین نسخه‌های مختلف کیوت نوشته بودم که مدت‌هاست وقت نکردم ترجمه‌ش کنم. این پست در مورد توضیح یک روش کارامد برای کدنویسی بین نسخهٔ ۴ و ۵ کیوت هست اما میشه کلیت‌ش رو به تمام چارچوب‌ها و کتابخانه‌هایی که در یک بازهٔ زمانی چند نسخه دارند، تعمیم داد. برای برنامه‌هایی که به‌طور طولانی‌مدت پشتیبانی میشن، این شرایط خیلی زیاد پیش میاد.فرض کنید برنامه‌ای نوشته میشه که قراره با ZMQ نسخهٔ ۲ کار کنه. بعد از گذشت چند سال توسعه‌دهنده‌ها به این نتیجه می‌رسن که باید نسخهٔ ۳ پشتیبانی بشه و پکیج‌هایی از کدهای کامپایل شده با نسخهٔ ۳ تهیه بشه. بنابراین بهترین راه حل نوشتن کدی هست که با هر دو نسخه کامپایل بشه. برای ابزارهایی که کتابخانه نیستند هم همین صادق هست. مثلاً اسکریپتی که قراره با پایتون ۲ کار کنه اما باید با پایتون ۳ هم کار کنه.

کیوت نسخهٔ پنج نزدیک یک سال پیش منتشر شد. اولین نسخهٔ رسمی فاجعه‌آمیز بود! ۵٫۰٫۱ کمی بهتر بود، ۵٫۱٫۰ به‌قدر کافی خوب بود و ۵٫۱٫۱ پایدار شده بود. در حال حاضر نسخهٔ ۵٫۳٫۰ را داریم که با وجود نسخهٔ پچ صفرم، به‌قدر کافی پایدار و بی‌اشکال شده. برای یک توسعهٔ دهندهٔ کیوت، عادت کردن به نسخهٔ جدید زیاد سخت نیست. یک راهنمای بسیار عالی هم اینجا برای کسایی که می‌خوان از کیوت نسخهٔ چهار به پنج مهاجرت کنن نوشته شده.

برای من هم اتفاق مشابهی می‌افته… دیر یا زود مجبور میشم که تمام پروژه‌هام رو به کیوت پنج ارتقا بدم. خوب پس منتظر چی هستم؟ یه خبر بد اینه که: سازگاری عقبگرد کد باید حتماً رعایت بشه! این یک مقدار کارم رو سخت خواهد کرد. چون پروژه‌هام رو روی ویندوز با استفاده از آخرین نسخه‌های پایدار کیوت می‌سازم و روی لینوکس با استفاده از نسخه‌های مخازن سیستم‌عامل. اکثر توزیع‌های لینوکس همچنان نسخهٔ ۴ رو به‌عنوان نسخهٔ اصلی کیوت توی مخازن نگه داشتن. و البته دلیلش هم واضحه: حجم بسیار بزرگ وابستگی بسته‌های دیگه به کیوت. اما توی ویندوز که کلاً چیزی به اسم پکیجینگ یا مدیریت وابستگی نداریم، دلیلی هم نداره بچسبیم به یه نسخهٔ پایدار. (به شکلی بسیار ناکارآمد و احمقانه، همیشه تمام پیش‌نیازهای یک برنامه رو بغل‌دستش منتشر می‌کنیم، و این تقصیر توسعه‌دهنده‌ها نیست. ویندوز مدلش این‌شکلی‌یه!)

خوب پس بهترین راه حل برام تبدیل کد به یک حالت میانی هست که هم با کیوت ۴ کامپایل و اجرا بشه و هم با کیوت ۵. کسل‌کننده به‌نظر میرسه… خوب واقعاً هم کسل‌کننده‌ست.

راهکار مشابه پست قبلی‌م رو ادامه میدم. پس قانون اول میشه:

اگر روشی مثل (W) برای انجام وظیفه‌ای مثل (T) وجود داشته باشد، به‌طوری که هم با نسخهٔ ۴ و هم با نسخهٔ ۵ سازگار باشد، در این صورت از آن استفاده کنید؛ مگر این که پیچیدگی آن روش، بیشتر از مجموع پیچیدگی پیاده‌سازی روش ویژهٔ نسخهٔ چهارم و روش ویژهٔ نسخهٔ پنجم باشد. به بیان ریاضی:

1
2
3
4
5
6
7
8
9
if( W < W4+ W5) {
T.do(W);
}
else if (W > W4 + W5) {
if(Qt5)
T.do(W5);
else
T.do(W4);
}

و قانون دوم هم نتیجهٔ بدیهی قانون اول خواهد بود:

اگر روش مشترکی برای اجرای کیوت پنج و چهار وجود ندارد، هر دو روش را پیاده‌سازی کرده و زمان کامپایل تصمیم بگیرید که کدام پیاده‌سازی کامپایل شود.

اجازه بدید یک مثال از پروژهٔ Qtz بزنم. داخل فایل‌های پروژه من باید مراقب تغییرات در سیستم ماژول‌ها باشم. خوشبختانه ماکروهایی برای تشخیص نسخهٔ کیوت وجود دارند. حتا بهتر از آن متغیرهای شرطی برای اندازه‌گیری عدد نسخه.

1
2
3
4
QT += core gui sql
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 4): CONFIG   += C++11
lessThan(QT_MAJOR_VERSION, 5): QMAKE_CXXFLAGS += -std=c++11

و همین قاعده روی کدها هم تأثیر می‌ذاره:

1
2
3
4
5
6
7
8
9
10
11
CandleGraphicsItem::CandleGraphicsItem(const Candle& candle, QGraphicsItem
*parent)
    :QGraphicsItem(parent), candle_(candle)
{
#if QT_VERSION >= 0x050000
    setAcceptHoverEvents(true);
#else
    setAcceptsHoverEvents(true);
#endif
    this->setY(-(candle.low_+candle.high_)/2.0);
}

با استفاده از ماکروی QT_VERSION از هدر می‌تونید به‌راحتی نسخهٔ کیوت رو تشخیص بدید که این خیلی خوبه (: حالا من می‌تونم نرم‌افزارم رو روی کیوت‌های ۴٫۶ تا ۵٫۳ کامپایل کنم.

برای جزئیات بیشتر این مقاله از بچه‌های KDAB رو بخونید. اون‌ها همچنین یک اسکریپت برای تبدیل اتوماتیک کدها از کیوت ۴ به کیوت ۵ نوشتن.

دیدگاه‌ها