شیء گرایی چیه Object Oriented Programming

برنامه نویسی شیء گرا یا OOP چیه؟ Object Oriented Programming

توی مصاحه از OOP و خصوصیاتش سوال زیاد میشه. از طرفی لازمه که یه برنامه نویس این رو بدونه. میشه گفت:

به ترکیت دیتا و توابع با هم میگیم OOP. این تعریف خیلی ناقصه. از طرفی به زبان ساده تر میشه گفت “یک روش برنامه نویسی که بشه باهاش دنیای واقعی رو مدل کرد” این هم باز کلیه و اگه بخایم بیشتر توضیح بدیم:

سه تا تکنیک توی برنامه نویسی وجود داره:

  • Encapsulation یا کپسوله کردن یا بسته بندی کردن
  • Inheritance یا ازثبری
  • Polymorphism یا چند شکلی

این 3 تکنیک برنامه نویسی رو اگر در برنامه های خودمون رعایت کنیم، میگیم داریم با تکنیک OOP کد میزنیم. و توی زبانهای OOP مثل Java C# Python و … این تکنیک ها رعایت میشه بخاطر همین بهشون میگیم زبانهای شیء گرا (البته پایتون مجبورتون نمیکنه صد درصد OOP کد بزنید).

آیا این تکنیک ها با پیدایش زبان های OO اومدن؟ خیر خیلی از برنامه نویسان C از قدیم از این تکنیک ها استفاده میکردند اما مجبور نبودند با این تکنیک کد بزنن و چون اینا تکنیک های خوبی بودن بعدا با زبان C++ رسمی شد و بمرور در زبان های مختلف تکامل پیدا کرد و استفاده ازشون آسون تر و بهینه تر شد و حتی اجباری شد.

Encapsulation

فرض کنید که بشه دور دسته ای از داده ها و توابع یک خط کشید و از بیرون این خط به این داده ها نشه دسترسی داشت و فقط خود اون توابع بتونن این داده ها رو تغییر بدن. در واقع داده ها و توابع private باشن و فقط به روش هایی استاندارد بشه بهشون به صورت غیر مستقیم یا بعضی از اونا مستقیم دسترسی داشت. این کار با مفهوم class انجام میشه و به این تکنیک میگن Encapsulation یا کپسوله کردن.

Inheritance

ارثبری ساده است. فرض کنید بخشی از توابع یا داده های یک کلاس رو دوباره از اول تعریف کنیم و بقیه بخش ها رو بدون تغییر کپی کنیم و استفاده کنیم به این میگن ارثبری.

مثال بالا خیلی خوب ارثبری رو نشون میده. یک کلاس Animal داریم. طبیعتا همه حیوانات یه سری خصوصیات مشترک دارن مثلا پا دارن حرکت میکنن و صدا دارن. دو کلاس Duck و Lion از Animal ارث بردن چون اینها هم حیوان هستن و این خصوصیات رو دارن و اونا رو به ارث بردن اما این خصوصیات مشترکشون کمی فرق داره اردک شنا میکنه و شیر میدوه، صدای هر حیوان هم فرق داره پس همینطور که میبینید این خصوصیات دوباره تعریف شدن با این که به ارث هم بردن.

Polymorphism

برای توضیح چندشکلی یه مثال واقعی میزنیم. میدونیم توی UNIX برای خوندن و نوشتن داده device های مختلفی وجود داره که به دیوایس های ورودی میگیم STDIN و به دیوایس های خروجی میگیم STDOUT. دیوایس خروجی مثل صفحه مانتور و اسپیکر و دیوایس ورودی مثل کیبورد و ماوس. حالا یه تابع نوشتیم با اسم کپی که از یه دیوایس ورودی میخونه و کپی میکنه تو دیوایس خروجی

ولی توی این کد ما مشخص نکردیم کدوم دیوایس ورودی و خروجی. UNIX این مشکل رو حل کرده میگه شما هر دیوایس که میسازی و می نویسی توی دایورش باید 5 تا تابع تغریف کنی که برنامه های مختلف بتونن باهاش کار کنن. این توابع open close read write seek هستن. یعنی همه دیوایس ها توی درایورشون این توابع رو دارن. و باید تعریف اونا رو هم بنویسید مثلا چجوری بخونی و بنویسی توش چه جوری باز کنی و ببندیش بنابراین مثلا یک فایل باید این توابع رو اینجوری تعریف کنن براش:

و توی اون درایور باید همین توابع رو تعریف کنه و اون رو لود کنه چیزی مثل زیر (یعنی در واقع قابل استفاده اش کنه)

حالا اون تابع copy میتونه ازش استفاده کنه اگر تابع getchar اینجوری تعریف شده باشه

ببینید اینجوری تابع copy نیاز به تغییر نداره فقط getchar رو صدا میزنه و این getchar هم همون تابع read رو صدا میزنه که توی درایور هست.

بنابراین polymorhpism این قابلیت رو به برنامه ها میده که مثل پلاگین عمل کنن. یعنی اگر صد تا دیوایس اضافه بشه با صد تا درایور دیگه نیازی به تغییر copy نیست چون بهرحال اون درایور تابع read داره.

plymophism اینه یعنی این تابع copy صد شکل از دیوایس رو پوشش میده پس بهش میگیم تکنیک چند شکلی.

قدرت polymorphism در همینه که بخش های برنامه از هم جدا میشن و میتونی هر کدوم رو جدا توسعه بدی و تکامل بدی بخش های محتلف برنامه مثل پلاگین با هم کار میکنن توسعه هرکدام مستقل ادامه پیدا میکنه.

Signal و Middleware توی پروسه لاگین (جلوگیری از چندین لاگین همزمان با یک نام کاربری)

توی یه پروژه خواستیم یک نام کاربری دو تا session نداشته باشه یعنی یه کاربر توی دوتا مرورگر یا دو تا سیستم لاگین نکنه. برای این کار از Middleware و Signal توی پروژه استفاده کردم.

توی Middleware.py توی app مربط کد زیر کد زیر رو زدم:

حالا اینو توی MIDDLEWARE توی SETTING اضافه میکنیم.

Signal زیر رو اضافه میکنم که اگر کسی logtout کرد session اش پاک شه که بشه جای دیگه لاگین کنن:

خروجی کد مصاحبه

خروجی کد زیر چیه؟

طبق حدثم:

ولی else چی میگه

خروجی:

یعنی اگه Exception اتفاق نیوفته else هم اتفاق میوفته. در هر حالتی finally اتفاق میوفته

سوال مصاحبه ارثبری

امروز توی یه مصاحبه سوال زیر مطرح شد و گفتن که خروجی برنامه چیه و من بعدا که تستش کردم سورپرایز شدم.

خروجی کد از قرار زیره:

بله سورپرایز شدیم. حالا برای اینکه بفهمیم چرا اینطور شد کد زیر رو اجرا میکنیم:

و خروجی کد:

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

اما متغیری که توی کلاس تعریف شده داستانش فرق میکنه. توی کلاس A پدر متغیر val به یه آدرس توی حافظه اشاره میکنه. کلاس B و C که فرزند هستن به همون آدرس حافظه اشاره مکنه. حالا وقتی B.val رو تغییر میدیم (از اونجایی که integer توی پایتون immutable هست) اون خونه حافظه تغییر نمیکنه بلکه یک خونه جدید با مقدار جدید ساخته میشه و B.val به اون اشاره میکنه. حالا باید خونه قبلی حافظه رو پاک کنه اما چون 2 تا pointer دیگه بهش وصله اونو پاک نمیکنه (Garbage collector وقتی اون خونه حافظه رو پاک میکنه که هیچ pointer ای به اون اشاره نکنه)

حالا داستان دوم. با این منطق اگر A.val رو تغییر بدیم باید C.val تغییر نکنه چون A.val به آدرس جدید اشاره میکنه ولی خانه قبلی پاک نمیشه چون هنوز C.val به خانه قبلی اشاره میکنه. اما مساله دیگه ای هم هست این جا از ارثبری استفاده کردیم و C فرزند A هست پس حالا که A.val به خانه جدیدی از حافظه اشاره میکنه این pointer رو توی فرزندانش هم عوض میکنه و بازم C.val و A.val به یک خانه جدید یکسان اشاره میکنن. ولی B.val دیگه این اتفاق براش نمیوفته چون از قبل به خونه دیگه ای اشاره میکنه (تغییر کرده) اگر پایتون این رو جوری دیگه پیاده سازی میکرد قطعا به مشکل میخوردیم.

واقعا سوال باحالی بود.

برگه تقلب راه اندازی RabbitMQ و Celery روی داکر

برای بالا آوردن RabbitMQ و اجرای Celery به شرط تنظیمات درستش همین دستورات زیر کافیه:

راه اندازی RabbitMQ تو Docker

راه اندازی Celery:

راه اندازی مستقیم با جنگو

راه اندازی Celery beat

اکستنشن Celery beat

مانیتور flow

افزودن فیلد به مدل با کمترین impact

یه مدل داریم تو جنگو که پروفایل شرکت های مختلف توی اون ذخیره میشه:

لازم شد که لوگو شرکت هم اضافه بشه اما از اونجایی که این مدل جاهای مختلف استفاده شده بود و توی فرمها و view های مختلف ازش استفاده شده اگه یه فیلد برای لوگو بهش اضافه کنیم قطعا باید خیلی از جاهای کد هم تغییر بدیم و احتمالا باگ هایی تولید بشن و از اونجایی که این سیستم براش تست نوشته نشده ممکن اطفاقات بدی بیوفته.

بنابراین رفتم دنبال اینکه چطور میشه بدون تغییر این مدل لوگو رو اضافه کنم. حداقل طوری که اگر جایی از این مدل داره استفاده میشه دیگه فیلدهاش عوض نشه. راه های مختلفی وجود داره ولی بهترینش بنظرم اینه که یه مدل جدید برای لوگو بسازیم و ارتباط OneToOne بینشون برقرار کنیم.

و اینطوری ازش استفاده کنم

پیاده سازی کوتاه و مختصرRabbitMQ و اجرای Celery

Search: Rabbitmq docker in google

Starting RabbitMQ


Starting Celery

Note: If you are using windows save yourself using gevent execution pool:

(https://stackoverflow.com/questions/62524908/task-receive-but-doesnt-excute)

and for Django:

Running Celery worker and Beat


Django Celery Beat extention


Flow monitoring

Flow monitoring

گشت و گذار اولیه توی داکر for inspection

دستورات اولیه کار با داکر و تنظیمات اولیه.

پیاده سازی gitlab بر روی داکر با پشتیبانگیری

برای پیاده سازی gitlab بر روی داکر از compose زیر استفاده کردم:

برای پشتیبانی گیری و برگرداندن بک آپ هم از کامند های زیر استفاده می شود: