در قسمت دهم پلی لیست دیزاین پترن
تو این قسمتChain of Responsibility رو بررسی کردیم. یک مثال پروداکشنی با کد بویلرپلیت هم نمایش دادم که نسبتا مثال پیچیده ای بود تا واقعا یوزکیس این دیزاین پترن رو درک کنید. در نهایت به نقاط ضعف و قوت این دیزاین پترن پرداختیم. اگه سوالی داشتین حتما زیره ویدیو کامنت کنید. برای حمایت ممنون میشم سابسکرایب کنید و داخل گیتهاب استار بدین به ریپو.
لینک ویدیو:
https://youtu.be/F0YyisF7Hq4
لینک گیتهاب دوره دیزاین پترن; جزوه و مثال های دوره همه اینجا ذخیره خواهند شد:
https://github.com/ManiMozaffar/design-101
@PyBackEndHub
تو این قسمتChain of Responsibility رو بررسی کردیم. یک مثال پروداکشنی با کد بویلرپلیت هم نمایش دادم که نسبتا مثال پیچیده ای بود تا واقعا یوزکیس این دیزاین پترن رو درک کنید. در نهایت به نقاط ضعف و قوت این دیزاین پترن پرداختیم. اگه سوالی داشتین حتما زیره ویدیو کامنت کنید. برای حمایت ممنون میشم سابسکرایب کنید و داخل گیتهاب استار بدین به ریپو.
لینک ویدیو:
https://youtu.be/F0YyisF7Hq4
لینک گیتهاب دوره دیزاین پترن; جزوه و مثال های دوره همه اینجا ذخیره خواهند شد:
https://github.com/ManiMozaffar/design-101
@PyBackEndHub
❤8👍3
“… Because the problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle. “ —Joe Armstrong, creator of Erlang progamming language
وقتی به یک موز نیاز دارین تو یک تابعی , یک گوریلا با موز ندین به اون تابع! 😁 مقاله مدیوم:
https://medium.com/codemonday/banana-gorilla-jungle-oop-5052b2e4d588
یک مثال خیلی قشنگ. اشتباهی که خیلیا انجام میدن
مثلا شما به آیدی یوزر نیاز داری تو یک فانکشن. به جای اینکه یوزر رو بذاری تو signature و ایدی رو ازش بگیری سعی کن یوزر آیدی رو فقط بگیری. اینو به دلیل پرفومنس نمیگم چون تاثیری نداره ولی به این دلیل میگم که کدتون رو به شدت reusable تر میکنه. حالا میتونه اون فانکشن رو صدا بزنی بدون اینکه اطلاعات دیگه ای از یوزر داشته باشی یا بدون اینکه هیت بزنی به دیتابیس پس حتی میشه گفت پرفومنس رو بهتر هم میکنه.
به این قانون law of demeter هم میگن. هدفشم چیزی جز بهتر شدن reusability کدتون و راحت تر تست نوشتن نیست.
@PyBackEndHub
وقتی به یک موز نیاز دارین تو یک تابعی , یک گوریلا با موز ندین به اون تابع! 😁 مقاله مدیوم:
https://medium.com/codemonday/banana-gorilla-jungle-oop-5052b2e4d588
یک مثال خیلی قشنگ. اشتباهی که خیلیا انجام میدن
مثلا شما به آیدی یوزر نیاز داری تو یک فانکشن. به جای اینکه یوزر رو بذاری تو signature و ایدی رو ازش بگیری سعی کن یوزر آیدی رو فقط بگیری. اینو به دلیل پرفومنس نمیگم چون تاثیری نداره ولی به این دلیل میگم که کدتون رو به شدت reusable تر میکنه. حالا میتونه اون فانکشن رو صدا بزنی بدون اینکه اطلاعات دیگه ای از یوزر داشته باشی یا بدون اینکه هیت بزنی به دیتابیس پس حتی میشه گفت پرفومنس رو بهتر هم میکنه.
# BAD
def activate_user(user: User, session) -> None
session.execute(sa.update(User).where(User.id==user.id).values(is_active=True)
# GOOD
def activate_user(user_id: UserId, session) -> None
session.execute(sa.update(User).where(User.id==user_id).values(is_active=True)
به این قانون law of demeter هم میگن. هدفشم چیزی جز بهتر شدن reusability کدتون و راحت تر تست نوشتن نیست.
@PyBackEndHub
Medium
Banana Gorilla Jungle — OOP
From the famous quote,
👍15😁3💩1🙏1
This media is not supported in your browser
VIEW IN TELEGRAM
اختلال OTD خیلی رواج پیدا کرده این روزا! اگه نمیدونید چیه ویدیو رو ببینید 🤣
@PyBackEndHub
@PyBackEndHub
🤣25😁4💩2
میخوام یک چیزه باحال نشونتون بدم
فکر کنید یک hierarchy کلس دارین که میخواین پستاندار ها و خزنده ها و کلا تایپ های مختلف موجودات زنده نشون بدید. مثلا میخواین schema پایندانتیک براش در نظر بگیرین
پستاندار همیشه legs داره. خزنده همیشه length داره. حالا میخواین یک switch case بذارین که اگه پستاندار بود راه برو و اگه خزنده بود بخز.
چیکار میکنید؟ یک راه OOPای اینه که شما یک schema بیس بسازین برای پستاندار ها. بعد همه پستاندار ها از اون ارث بری کنند. و بعد با isintance چک کنید. اما یک راه حل به سبک Rust میخوام بهتون یاد بدم 😁 که شبیه Traits هست.
متوجه شدین چی شد؟ در واقع switch case میاد Pattern Matching رو اجرا میکنه. و طبق اون میاد attr هارو مقایسه میکنه. در نهایت متوجه میشه که الان کدوم حالته! 😎 افت پرفومنس داره چون runtime checkable داره انجام میشه که تو لینک زیر میتونید بخونید جواب کامل تر گذاشتن. ولی درکل خیلی باحال بود.
https://discuss.python.org/t/is-there-a-downside-to-typing-runtime-checkable/20731/4
@PyBackEndHub
فکر کنید یک hierarchy کلس دارین که میخواین پستاندار ها و خزنده ها و کلا تایپ های مختلف موجودات زنده نشون بدید. مثلا میخواین schema پایندانتیک براش در نظر بگیرین
from enum import StrEnum, auto
from typing import Literal
from pydantic import BaseModel
class MammalsEnums(StrEnum):
DOG = auto()
CAT = auto()
class ReptiliaEnum(StrEnum):
SNAKE = auto()
class Dog(BaseModel):
name: Literal[MammalsEnums.DOG] = MammalsEnums.DOG
legs: int = 4
class Cat(BaseModel):
name: Literal[MammalsEnums.CAT] = MammalsEnums.CAT
legs: int = 4
class Snake(BaseModel):
name: Literal[ReptiliaEnum.SNAKE] = ReptiliaEnum.SNAKE
length: int = 112
پستاندار همیشه legs داره. خزنده همیشه length داره. حالا میخواین یک switch case بذارین که اگه پستاندار بود راه برو و اگه خزنده بود بخز.
چیکار میکنید؟ یک راه OOPای اینه که شما یک schema بیس بسازین برای پستاندار ها. بعد همه پستاندار ها از اون ارث بری کنند. و بعد با isintance چک کنید. اما یک راه حل به سبک Rust میخوام بهتون یاد بدم 😁 که شبیه Traits هست.
from typing import runtime_checkable
@runtime_checkable
class MammalsTrait(Protocol):
legs: int
@runtime_checkable
class ReptiliaTrait(Protocol):
length: int
animal = Snake() # or any other animals
match animal:
case MammalsTrait():
print("This is Mammals")
case ReptiliaTrait():
print("This is Reptilia")
case _:
print("This is unknown animal")
متوجه شدین چی شد؟ در واقع switch case میاد Pattern Matching رو اجرا میکنه. و طبق اون میاد attr هارو مقایسه میکنه. در نهایت متوجه میشه که الان کدوم حالته! 😎 افت پرفومنس داره چون runtime checkable داره انجام میشه که تو لینک زیر میتونید بخونید جواب کامل تر گذاشتن. ولی درکل خیلی باحال بود.
https://discuss.python.org/t/is-there-a-downside-to-typing-runtime-checkable/20731/4
@PyBackEndHub
👍8❤1
یک سوال میپرسم ببینم چند نفر بلدن اینو 😁تو بحث distributed system و fault tolerancy و دیتابیس.
شما دو سرویس داری, یک سرویس IAM که وظیفش نگه داری اطلاعات شخصی کاربر و پرمیشن هاست, و یک سرویس دیگه یک محصولیه که دارین. مثلا فکر کنید فروشگاه اینترنتی تو zone ایران هست. حالا کاربر میخواد ثبت نام کنه تو این فروشگاه. یک فرم هست. یک بخشیش میشه مربوط به سرویس فروشگاه. یک بخشیش مربوط به سرویس IAM میشه. پس دو تا سرویس نیازه با هم صحبت کنند به طریقی. و قراره کل این کار به صورت unit of work با transaction انجام شه.
درخواست از سرویس فروشگاه ارسال میشه به سرویس IAM و کاربر رجیستر میشه و کلی entity اضافه یا modify میشه برای اون کاربر به اون سرویس. حواستون باشه صرفا INSERT نیست و میتونه UPDATE هم باشه. کل query هایی که زدیم هم اوکیه و ران میشن. درخواست برگشت به سرویس فروشگاه و اینجام همه query های داخل transaction ران شد. ولی وقتی میخوایم کامیت کنیم به مشکل integrity میخوریم و کامیتمون fail میشه. حالا سوال اینجاست که چطور درخواستی که رفته به سرویس IAM و کاربری که ساخته شده رو rollback کنیم جوری که انگار اون اتفاق نیافتاده؟ چطور این مسئله رو حل میکنید؟
@PyBackEndHub
شما دو سرویس داری, یک سرویس IAM که وظیفش نگه داری اطلاعات شخصی کاربر و پرمیشن هاست, و یک سرویس دیگه یک محصولیه که دارین. مثلا فکر کنید فروشگاه اینترنتی تو zone ایران هست. حالا کاربر میخواد ثبت نام کنه تو این فروشگاه. یک فرم هست. یک بخشیش میشه مربوط به سرویس فروشگاه. یک بخشیش مربوط به سرویس IAM میشه. پس دو تا سرویس نیازه با هم صحبت کنند به طریقی. و قراره کل این کار به صورت unit of work با transaction انجام شه.
درخواست از سرویس فروشگاه ارسال میشه به سرویس IAM و کاربر رجیستر میشه و کلی entity اضافه یا modify میشه برای اون کاربر به اون سرویس. حواستون باشه صرفا INSERT نیست و میتونه UPDATE هم باشه. کل query هایی که زدیم هم اوکیه و ران میشن. درخواست برگشت به سرویس فروشگاه و اینجام همه query های داخل transaction ران شد. ولی وقتی میخوایم کامیت کنیم به مشکل integrity میخوریم و کامیتمون fail میشه. حالا سوال اینجاست که چطور درخواستی که رفته به سرویس IAM و کاربری که ساخته شده رو rollback کنیم جوری که انگار اون اتفاق نیافتاده؟ چطور این مسئله رو حل میکنید؟
@PyBackEndHub
👍5😐3
Python BackendHub
یک سوال میپرسم ببینم چند نفر بلدن اینو 😁تو بحث distributed system و fault tolerancy و دیتابیس. شما دو سرویس داری, یک سرویس IAM که وظیفش نگه داری اطلاعات شخصی کاربر و پرمیشن هاست, و یک سرویس دیگه یک محصولیه که دارین. مثلا فکر کنید فروشگاه اینترنتی تو zone…
تو جواب ها اشاره کردن به بخش اول سوال. یک راه حل نسبتا کارگشا.
یک چیزی هست به اسم two phase commit. یعنی شما قبل اینکه بخوای یک transaction رو کامیت کنی میتونی یک اوکی بگیری از دیتابیس. دیتابیس بهت میگه این transaction تو اون لحظه ای که داری ازش میپرسی قابلیت کامیت شدن رو داره بدون مشکل یا نه. پس اون سرویس دوم باید two phase commit بزنه وقتی با سرویس اول داره حرف میزنه. و اگه اوکی بود ببره رو سرویس اول.
حالا مشکلی که وجود داره اینه که ممکنه اختلاف زمانی که تو two phase commit رخ میده ممکنه خودش باعث fail شدن transaction شه. یعنی state دیتابیس تو این چند ثانیه تغییر کرده باشه. ممکنه براتون سوال پیش بیاد باید چیکار کرد؟
هیچی باید تسلیم شد!
این بحث تو ریاضی بهش میگن Two Generals' Problem که هیچوقت حل نشده و ثابت شده حل نشدنیه.
یعنی چی؟ یعنی فکر کنید دو ژنرال میخوان به یک شهر حمله کنن با ۲ ارتش مختلف از ۲ نقطه مختلف. ژنرال اول به دوم میگه دو شنبه صبح حمله میکنیم. ژنرال اول نمیدونه ژنرال دوم پیامش رو دریافت کرد یا نه. برای همین باید صبر کنه که ژنرال دوم جواب بده. ژنرال دوم میگه باشه شنیدم. حالا ژنرال دوم نمیدونه که ژنرال اول پیامشو دریافت کرد یا نه. حالا باید صبر کنه دوباره ژنرال اول بگه شنیدم. و این loop تا انتها میتونه بره.
بنابر این قضیه, شما حتی میتونی درخواست HTTP بزنی که duplicate شه یعنی دو بار ارسال شه! چون acknowledge نشده.
واسه همین fault tolerancy همیشه تا یک حدی معقوله. از یک جا به بعد دیگه میشه مرز جنون :)) خوبه بهش فکر کنیم ولی یادمون نره وارد جنون نشیم 😁
@PyBackEndHub
یک چیزی هست به اسم two phase commit. یعنی شما قبل اینکه بخوای یک transaction رو کامیت کنی میتونی یک اوکی بگیری از دیتابیس. دیتابیس بهت میگه این transaction تو اون لحظه ای که داری ازش میپرسی قابلیت کامیت شدن رو داره بدون مشکل یا نه. پس اون سرویس دوم باید two phase commit بزنه وقتی با سرویس اول داره حرف میزنه. و اگه اوکی بود ببره رو سرویس اول.
حالا مشکلی که وجود داره اینه که ممکنه اختلاف زمانی که تو two phase commit رخ میده ممکنه خودش باعث fail شدن transaction شه. یعنی state دیتابیس تو این چند ثانیه تغییر کرده باشه. ممکنه براتون سوال پیش بیاد باید چیکار کرد؟
هیچی باید تسلیم شد!
این بحث تو ریاضی بهش میگن Two Generals' Problem که هیچوقت حل نشده و ثابت شده حل نشدنیه.
یعنی چی؟ یعنی فکر کنید دو ژنرال میخوان به یک شهر حمله کنن با ۲ ارتش مختلف از ۲ نقطه مختلف. ژنرال اول به دوم میگه دو شنبه صبح حمله میکنیم. ژنرال اول نمیدونه ژنرال دوم پیامش رو دریافت کرد یا نه. برای همین باید صبر کنه که ژنرال دوم جواب بده. ژنرال دوم میگه باشه شنیدم. حالا ژنرال دوم نمیدونه که ژنرال اول پیامشو دریافت کرد یا نه. حالا باید صبر کنه دوباره ژنرال اول بگه شنیدم. و این loop تا انتها میتونه بره.
بنابر این قضیه, شما حتی میتونی درخواست HTTP بزنی که duplicate شه یعنی دو بار ارسال شه! چون acknowledge نشده.
واسه همین fault tolerancy همیشه تا یک حدی معقوله. از یک جا به بعد دیگه میشه مرز جنون :)) خوبه بهش فکر کنیم ولی یادمون نره وارد جنون نشیم 😁
@PyBackEndHub
👍12😱1
Python BackendHub
تو جواب ها اشاره کردن به بخش اول سوال. یک راه حل نسبتا کارگشا. یک چیزی هست به اسم two phase commit. یعنی شما قبل اینکه بخوای یک transaction رو کامیت کنی میتونی یک اوکی بگیری از دیتابیس. دیتابیس بهت میگه این transaction تو اون لحظه ای که داری ازش میپرسی قابلیت…
Two general problem
@PyBackendHub
@PyBackendHub
👍6
Automagic is a drug
امروز یکجا اینو خوندم… و خیلی باهاش موافقم.
مثلا ری اکت وقتی بیلد میگیرین همه کدارو میریزه تو main.js که خیلی آپتیمایز نیست و اینو باید هندل کنید برای پرفومنس بهتر که بهش میگن code split
و از یک طرف دیگه next js خودکار اینو انجام میده و هندل میکنه.
کسی که از nextjs استفاده میکنه و نمیدونه این چطوری کار میکنه، مثل یک دراگ براش میمونه و همیشه مانعی براش میشه که سمت جواب و این سوال هیچوقت نره.
همین موضوع تو بک اندم خیلی زیاده…
@PyBackendHub
امروز یکجا اینو خوندم… و خیلی باهاش موافقم.
مثلا ری اکت وقتی بیلد میگیرین همه کدارو میریزه تو main.js که خیلی آپتیمایز نیست و اینو باید هندل کنید برای پرفومنس بهتر که بهش میگن code split
و از یک طرف دیگه next js خودکار اینو انجام میده و هندل میکنه.
کسی که از nextjs استفاده میکنه و نمیدونه این چطوری کار میکنه، مثل یک دراگ براش میمونه و همیشه مانعی براش میشه که سمت جواب و این سوال هیچوقت نره.
همین موضوع تو بک اندم خیلی زیاده…
@PyBackendHub
👍13👎2🤔2👌2❤1🤡1
Forwarded from Python BackendHub
یکی از مشکلاتی که اکثر برنامه نویسا دارن تو مدیریت دپندسیه! حالا لایبری جدید یا external service که قراره ازش استفاده کنن.
مشکل چیه؟برنامه نویس میاد یک توتوریال از اون دپندسی جدید میبینه با خودش میگه ایول چه باحاله و تصمیم میگیره اضافش کنه! و این بد ترین کاریه که میتونید بکنید. قراره وابسته بشین به چیزی. فکر کنید این وابستگی از جنس عاطفیه. همینقدر باید باهاش حساس برخورد کنید :))
خب چیکار کنیم؟
اولین کاری که میکنید اینه که توتوریالشو میریزین دور. میرین داکیومنتشو خوب میخونید. متوجه میشین limitation هاش چیه. متوجه میشین سیستمش چطور کار میکنه. یک داکیومنت مختصر شده ازش میسازین و cons pro هاشو در میارین. مثلا یعنی چی؟
فکر کنید مثلا دارین یک external system اضافه میکنید. مثلا یک CRM. خب اول باید چک کنید چه limitation هایی داره؟ایا api داره؟ایا web hook داره؟ ایا share state به وجود میاد؟ هزینش چقدره؟ alternative هاش چیه؟ چطور اصلا کار میکنه؟ اصلا خوب کار میکنه؟!
بعد تو درجه دوم میرین گوگل میکنید و مقاله هایی پیدا میکنید که نقاط ضعفشو بیشتر گفته. ممکنه همه نقاط ضعفش تو داکیومنتش نباشه و یکم پنهان باشه. میبینید بقیه چه چالش هایی داشتن موقع کار کردن باهاش.
در نهایت بین آپشن ها یک لیست pro cons میسازین و تصمیم گیری نهایی رو میکنید.
اگه این کارو نکنیم چه اتفاقی میفته؟
بذارین مثال بگم. مثلا شما ندیدین این api limit احمقانه ای داره. بعد کلی روش کد میزنید. یک روزی سایز بیزنستون بزرگ تر میشه و حالا هرچی کد رو زدین باید undo کنید.
همیشه تو انتخاب دپندسی هاتون خیلی فکر کنید! من بعضا دیدم بچه ها میگن <کارفرما اینطوری گفته> یا <مدیر تیم با این بیشتر حال کرده>. اینا دلایل منطقی اصلا نیستن برای انتخاب یک دپندسی.
@ManiFoldsPython
مشکل چیه؟برنامه نویس میاد یک توتوریال از اون دپندسی جدید میبینه با خودش میگه ایول چه باحاله و تصمیم میگیره اضافش کنه! و این بد ترین کاریه که میتونید بکنید. قراره وابسته بشین به چیزی. فکر کنید این وابستگی از جنس عاطفیه. همینقدر باید باهاش حساس برخورد کنید :))
خب چیکار کنیم؟
اولین کاری که میکنید اینه که توتوریالشو میریزین دور. میرین داکیومنتشو خوب میخونید. متوجه میشین limitation هاش چیه. متوجه میشین سیستمش چطور کار میکنه. یک داکیومنت مختصر شده ازش میسازین و cons pro هاشو در میارین. مثلا یعنی چی؟
فکر کنید مثلا دارین یک external system اضافه میکنید. مثلا یک CRM. خب اول باید چک کنید چه limitation هایی داره؟ایا api داره؟ایا web hook داره؟ ایا share state به وجود میاد؟ هزینش چقدره؟ alternative هاش چیه؟ چطور اصلا کار میکنه؟ اصلا خوب کار میکنه؟!
بعد تو درجه دوم میرین گوگل میکنید و مقاله هایی پیدا میکنید که نقاط ضعفشو بیشتر گفته. ممکنه همه نقاط ضعفش تو داکیومنتش نباشه و یکم پنهان باشه. میبینید بقیه چه چالش هایی داشتن موقع کار کردن باهاش.
در نهایت بین آپشن ها یک لیست pro cons میسازین و تصمیم گیری نهایی رو میکنید.
اگه این کارو نکنیم چه اتفاقی میفته؟
بذارین مثال بگم. مثلا شما ندیدین این api limit احمقانه ای داره. بعد کلی روش کد میزنید. یک روزی سایز بیزنستون بزرگ تر میشه و حالا هرچی کد رو زدین باید undo کنید.
همیشه تو انتخاب دپندسی هاتون خیلی فکر کنید! من بعضا دیدم بچه ها میگن <کارفرما اینطوری گفته> یا <مدیر تیم با این بیشتر حال کرده>. اینا دلایل منطقی اصلا نیستن برای انتخاب یک دپندسی.
@ManiFoldsPython
👍22❤3
تو کامپیوتر ساینس یک مدل باگی داریم که از همه باگا سخت تره دیباگش و خدا نصیبتون نکنه :)) اسمش هایزنباگ هست.
In computer programming jargon, a heisenbug is a software bug that seems to disappear or alter its behavior when one attempts to study it
از این باگا دیدین تاحالا؟ باگی که reproduce نمیشه وقتی میخواین دستی reproduce اش کنید و اگه خیلی خوب تست بنویسید شاید بتونید با تست reproduce کنید تو حالت خیلی خوش بینانه. اگه براتون تاحالا اتفاق افتاده کامنت کنید و بگین چطوری دیباگش کردین 🤓
@PyBackendHub
In computer programming jargon, a heisenbug is a software bug that seems to disappear or alter its behavior when one attempts to study it
از این باگا دیدین تاحالا؟ باگی که reproduce نمیشه وقتی میخواین دستی reproduce اش کنید و اگه خیلی خوب تست بنویسید شاید بتونید با تست reproduce کنید تو حالت خیلی خوش بینانه. اگه براتون تاحالا اتفاق افتاده کامنت کنید و بگین چطوری دیباگش کردین 🤓
@PyBackendHub
👍17💩1
یک بحث خیلی خوبی شد تو گروه, گفتم تو کانالم بهش اشاره کنم.
تو معماری Event driven هر وقت شما یک periodic taskای دارین باید یک نکته رو بهش خیلی دقت کنید. این تسک پریودیک شما خیلی خیلی باید تا جایی که میتونه کم بار باشه. یعنی چی؟
فکر کنید یک تسک پریودیک دارین که میخواد هر ۱ ساعت یک بار چک کنه به یوزر هایی که خیلی وقته تو پلفتورم شما فعالیت نداشتن notification بزنه. اگه یک تسک بذارین که اینکارو انجام بده خیلی لاجیک اشتباهیه. به جاش باید دو تسک باشه. یک تسک دیتابیس رو query میزنه و یک سری یوزر آیدی میگیره. و میده به تسک دوم به صورت یک به یک. یعنی به تعداد یوزر آیدی ها میاد مسیج produce میکنه. تسک دوم با استفاده از اون user id هر دیتایی که بخواد میگیره و query میزنه به دیتابیس یا سرویس دیگه و نوتیفیکشن رو ارسال میکنه.
حالا چرا؟
چون تسک periodic خودش ذاتا state داره. مثل یک سرویس web socket. سرویس هایی که state دارن خیلی سخت scale میشن. پس تا جایی که میتونید سعی کنید بخش state دار برنامتون رو کم کنید که scale برنامتون راحت شه.چرا؟ فکر کنید یک تسک دارین. اونوقت اگه scale کنید مجبور میشین دیتابیستون رو لاک کنید چون اگه نکنید ممکنه race condition بخورین و سرویستون همزمان به ۱ یوزر ۲ بار نوتیفیکشن بده.
اینطوری شما میتونی یک instance داشته باشی از سرویس periodic_producerاتون. و صد تا instance داشته باشین از سرویس notification_dispatcher تون. بنابراین اگه شما تو یک ساعت لازم باشه به ده هزار نفر نوتیف بدین میتونید بدید. یا اگه سرویس نوتیفتون یک لحظه قطع شه همه با هم fail نمیشن. و میره تو dead letter queue و یا میتونه حتی دوباره retry هم بشه.
@PyBackendHub
تو معماری Event driven هر وقت شما یک periodic taskای دارین باید یک نکته رو بهش خیلی دقت کنید. این تسک پریودیک شما خیلی خیلی باید تا جایی که میتونه کم بار باشه. یعنی چی؟
فکر کنید یک تسک پریودیک دارین که میخواد هر ۱ ساعت یک بار چک کنه به یوزر هایی که خیلی وقته تو پلفتورم شما فعالیت نداشتن notification بزنه. اگه یک تسک بذارین که اینکارو انجام بده خیلی لاجیک اشتباهیه. به جاش باید دو تسک باشه. یک تسک دیتابیس رو query میزنه و یک سری یوزر آیدی میگیره. و میده به تسک دوم به صورت یک به یک. یعنی به تعداد یوزر آیدی ها میاد مسیج produce میکنه. تسک دوم با استفاده از اون user id هر دیتایی که بخواد میگیره و query میزنه به دیتابیس یا سرویس دیگه و نوتیفیکشن رو ارسال میکنه.
حالا چرا؟
چون تسک periodic خودش ذاتا state داره. مثل یک سرویس web socket. سرویس هایی که state دارن خیلی سخت scale میشن. پس تا جایی که میتونید سعی کنید بخش state دار برنامتون رو کم کنید که scale برنامتون راحت شه.چرا؟ فکر کنید یک تسک دارین. اونوقت اگه scale کنید مجبور میشین دیتابیستون رو لاک کنید چون اگه نکنید ممکنه race condition بخورین و سرویستون همزمان به ۱ یوزر ۲ بار نوتیفیکشن بده.
اینطوری شما میتونی یک instance داشته باشی از سرویس periodic_producerاتون. و صد تا instance داشته باشین از سرویس notification_dispatcher تون. بنابراین اگه شما تو یک ساعت لازم باشه به ده هزار نفر نوتیف بدین میتونید بدید. یا اگه سرویس نوتیفتون یک لحظه قطع شه همه با هم fail نمیشن. و میره تو dead letter queue و یا میتونه حتی دوباره retry هم بشه.
@PyBackendHub
👍20❤3👏1
Forwarded from Python BackendHub
کاربرد گروهو میخوام تغییر بدم
به گروهی برای رفع مشکل و بحث در خصوص Backend Engineering و پایتون
مرجعی هم بشه که بتونید کلا سوالات flask یا kafka یا rabbitmq یا FastAPI یا ORM هرچیز دیگه ای که ممکنه براش community پیدا نکنید. لینک:
https://news.1rj.ru/str/PythonFellow
خوشحال میشم جوین شید. قانون خاصی نداره به جز حفظ احترام اعضای گروه.
@PyBackEndHub
به گروهی برای رفع مشکل و بحث در خصوص Backend Engineering و پایتون
مرجعی هم بشه که بتونید کلا سوالات flask یا kafka یا rabbitmq یا FastAPI یا ORM هرچیز دیگه ای که ممکنه براش community پیدا نکنید. لینک:
https://news.1rj.ru/str/PythonFellow
خوشحال میشم جوین شید. قانون خاصی نداره به جز حفظ احترام اعضای گروه.
@PyBackEndHub
Telegram
Python Backend Fellow
گروه رفع اشکال و بحث در مورد Backend Engineering و پایتون
Channel: @PyBackEndHub
Channel: @PyBackEndHub
👍15
یک تیبل میسازیم... به اسم deals که deal هایی که ثبت میشه رو وارد دیتابیس کنیم.
و یک سری دیتا هم اضافه میکنیم که تو عکس میتونید ببینید query رو که چه چیزی insert شده.
سوال اول: یک query بنویسید که برای هر region بزرگ ترین deal هارو نشون بده.
@PyBackendHub
CREATE TABLE deals (
deal_id INT PRIMARY KEY,
deal_amount DECIMAL (10, 2),
customer_name VARCHAR (255),
region VARCHAR(255),
deal_date DATE
و یک سری دیتا هم اضافه میکنیم که تو عکس میتونید ببینید query رو که چه چیزی insert شده.
سوال اول: یک query بنویسید که برای هر region بزرگ ترین deal هارو نشون بده.
@PyBackendHub
👍2
Python BackendHub
یک تیبل میسازیم... به اسم deals که deal هایی که ثبت میشه رو وارد دیتابیس کنیم. CREATE TABLE deals ( deal_id INT PRIMARY KEY, deal_amount DECIMAL (10, 2), customer_name VARCHAR (255), region VARCHAR(255), deal_date DATE و یک سری دیتا هم اضافه میکنیم که…
یک سری query کامنت کردن که بررسیشون میکنیم تک تک:
این query اشتباهه. چون داره deal هایی که مکس هستن رو گروپ میکنه به ازای هر ریجن در صورتی که صورت سوال دقیقا اینو نخواسته بود.
ایرادش چیه؟ ایرادش اینجاست که ریجن آسیا ۲ تا deal داره که amount شون ۱۵۰۰۰ هست! (یکی آیدی ۸ یکی آیدی ۱۰). ولی این فقط ۸ رو برگردوند. 😅 چون max همیشه فقط یکی رو برمیگردونه به ازای ریجن. سوال خواسته شده بزرگ ترین deal های هر ریجن رو در بیارین.
@PyBackendHub
SELECT max(deal_amount), d.*
From deals d
GROUP BY region
این query اشتباهه. چون داره deal هایی که مکس هستن رو گروپ میکنه به ازای هر ریجن در صورتی که صورت سوال دقیقا اینو نخواسته بود.
ایرادش چیه؟ ایرادش اینجاست که ریجن آسیا ۲ تا deal داره که amount شون ۱۵۰۰۰ هست! (یکی آیدی ۸ یکی آیدی ۱۰). ولی این فقط ۸ رو برگردوند. 😅 چون max همیشه فقط یکی رو برمیگردونه به ازای ریجن. سوال خواسته شده بزرگ ترین deal های هر ریجن رو در بیارین.
@PyBackendHub
👍3🔥2
Python BackendHub
یک سری query کامنت کردن که بررسیشون میکنیم تک تک: SELECT max(deal_amount), d.* From deals d GROUP BY region این query اشتباهه. چون داره deal هایی که مکس هستن رو گروپ میکنه به ازای هر ریجن در صورتی که صورت سوال دقیقا اینو نخواسته بود. ایرادش چیه؟ ایرادش…
یک query دیگه کامنت کردن که دوباره همین اتفاق بالا براش میفتاد. یک query هم با رنک نوشتن که جواب درست میده. اینکه رنک چیه رو تو پست های بعدی توضیح میدم. اما قبلش میپردازیم به راه حل های آسون تر بدون استفاده از PARTITION و RANK.
اولین راه حل مبتدیانه:
هیچوقت اینطوری subquery نزنید. تو این حالت تو inner query درواقع اومده رفرنس زده به outer query
اتفاقی که میفته تو سطح دیتابیس به ازای هر row این query inner ران میشه و باعث میشه خیلی کند ران شه. میتونیم subquery بهتری کنیم که دیگه این رفرنس اتفاق نیفته ولی بهتره به جاش از CTE استفاده کنیم (common table expression) چون هم خوانایی خوبی داره و هم هرچی query بزرگ تر شه بازم خواناییش سخت تر نمیشه و شکسته شکسته هست.
@PyBackendHub
اولین راه حل مبتدیانه:
SELECT *
FROM deals d1
WHERE d1.deal_amount = (
SELECT MAX(d2.deal_amount)
FROM deals d2
WHERE d2.region = d1.region
);
هیچوقت اینطوری subquery نزنید. تو این حالت تو inner query درواقع اومده رفرنس زده به outer query
اتفاقی که میفته تو سطح دیتابیس به ازای هر row این query inner ران میشه و باعث میشه خیلی کند ران شه. میتونیم subquery بهتری کنیم که دیگه این رفرنس اتفاق نیفته ولی بهتره به جاش از CTE استفاده کنیم (common table expression) چون هم خوانایی خوبی داره و هم هرچی query بزرگ تر شه بازم خواناییش سخت تر نمیشه و شکسته شکسته هست.
WITH max_deals_by_region AS (SELECT region, MAX(deal_amount) as max_deal_amount
FROM deals
GROUP BY region)
SELECT d.*
FROM deals d
JOIN max_deals_by_region rmd
ON d.region = rmd.region
AND d.deal_amount = rmd.max_deal_amount
ORDER BY d.deal_id;
@PyBackendHub
👍9🔥2
ادامه سری پست های SQL
تو SQL ما windows function داریم.ویندو فاکشن ها به ما اجازه میدن محاسباتی رو یک ستی از row ها انجام بدیم به صورت نسبی به row فعلی. یعنی چی؟ یعنی مثلا SUM مجموع row هارو حساب میکنه. توابع window چهار دسته تقسیم میشن. که برای هر دسته پست و مثال میذارم;
اولین درسته توابع رنک هستند, توابعی که رتبه دیتا رو تو یک دیتاست بر معیار یکی از ترتیبی که تعیین میکنید با ORDER BY مقایسه میکنه. مثلا یک تیبل دارین که جدول مسابقه لیگ فوتبال رو نشون میده. میخواین تیم ۱ تا ۲۰ رو رتبه بندی کنید اون موقع از توابع ranking استفاده کنید. بیایم سوال اول رو کمی تغییر بدیم,
سوال دوم:یک query بنویسید که برای هر ریجن ۳ تا از بزرگ ترین deal هارو نشون بده.
جوابش:
دقت کنید چه اتفاقی افتاد...
داخل CTE نوشتم که deal هارو انتخاب کن و rank شون کن با پاریشن region و ترتیب deal_amount به صورت desc
یعنی چی؟پارتیشن: دیتا رو به تیکه کوچیک تر تبدیل میکنه. که بعد سینتکس OVER() میاد. یعنی اول دیتا رو بیا طبق region هاشون بشکون. بعد به ترتیب deal_amount مرتبشون کن. و در آخر رتبشون رو حساب کن.
توابع رنک تو SQL:
ROW_NUMBER
RANK
DENSE_RANK
فرق اینا چیه؟ تو سوال سوم مشخص میشه.
تو سه سناریو زیر از کدوم فانکشن ranking استفاده میکنید؟
سناریو اول) صد دونده را در marathon شرکت کردن. رتبه دونده ها رو بر اساس تایم پایانشون حساب کنید. چنانچه دو دونده همزمان اتمام کردن هر دو دونده رو هم رتبه در نظر بگیرین. دونده ها لزوما از رتبه ۱ تا ۱۰۰ قرار نمیگیرن, مثلا اگه نفر ۹۹ و ۹۸ همزمان به خط پایانی رسیدن رتبه ۹۸ میشن. و نفر ۱۰۰ ام رتبه ۹۹ میشه.
سناریو دوم) در جدول لیگ فوتبال بیست تیم رو به ترتیب از رتبه ۱ تا ۲۰ رتبه بندی کنید بر اساس امتیازشون. چنانچه امتیاز برابری داشتن تفاضل گل رو در نظر بگیرین.
سناریو سوم) شرکتی میخواد به ۱۰۰ کاربر برترش مطابق سیستم امتیاز دهی اش جایزه بده. اما نمیخواد در حق کارمندا ناحقی شه برای همین اگه مثلا امتیاز نفره ۱۰۰ ام با ۱۰۱ام برابر بود, نفره ۱۰۱ ام هم رتبه ۱۰۰ در نظر میگیره و بهش جایزه میده. اما شرکت تو حالت ایده آل نمیخواد به بیشتر از ۱۰۰ کارمند جایزه بده.
@PyBackendHub
تو SQL ما windows function داریم.ویندو فاکشن ها به ما اجازه میدن محاسباتی رو یک ستی از row ها انجام بدیم به صورت نسبی به row فعلی. یعنی چی؟ یعنی مثلا SUM مجموع row هارو حساب میکنه. توابع window چهار دسته تقسیم میشن. که برای هر دسته پست و مثال میذارم;
اولین درسته توابع رنک هستند, توابعی که رتبه دیتا رو تو یک دیتاست بر معیار یکی از ترتیبی که تعیین میکنید با ORDER BY مقایسه میکنه. مثلا یک تیبل دارین که جدول مسابقه لیگ فوتبال رو نشون میده. میخواین تیم ۱ تا ۲۰ رو رتبه بندی کنید اون موقع از توابع ranking استفاده کنید. بیایم سوال اول رو کمی تغییر بدیم,
سوال دوم:یک query بنویسید که برای هر ریجن ۳ تا از بزرگ ترین deal هارو نشون بده.
جوابش:
WITH RankedDeals AS (
SELECT *,
RANK() OVER (PARTITION BY region ORDER BY deal_amount DESC) AS rank
FROM deals
)
SELECT *
FROM RankedDeals
WHERE rank < 4;
دقت کنید چه اتفاقی افتاد...
داخل CTE نوشتم که deal هارو انتخاب کن و rank شون کن با پاریشن region و ترتیب deal_amount به صورت desc
یعنی چی؟پارتیشن: دیتا رو به تیکه کوچیک تر تبدیل میکنه. که بعد سینتکس OVER() میاد. یعنی اول دیتا رو بیا طبق region هاشون بشکون. بعد به ترتیب deal_amount مرتبشون کن. و در آخر رتبشون رو حساب کن.
توابع رنک تو SQL:
ROW_NUMBER
RANK
DENSE_RANK
فرق اینا چیه؟ تو سوال سوم مشخص میشه.
تو سه سناریو زیر از کدوم فانکشن ranking استفاده میکنید؟
سناریو اول) صد دونده را در marathon شرکت کردن. رتبه دونده ها رو بر اساس تایم پایانشون حساب کنید. چنانچه دو دونده همزمان اتمام کردن هر دو دونده رو هم رتبه در نظر بگیرین. دونده ها لزوما از رتبه ۱ تا ۱۰۰ قرار نمیگیرن, مثلا اگه نفر ۹۹ و ۹۸ همزمان به خط پایانی رسیدن رتبه ۹۸ میشن. و نفر ۱۰۰ ام رتبه ۹۹ میشه.
سناریو دوم) در جدول لیگ فوتبال بیست تیم رو به ترتیب از رتبه ۱ تا ۲۰ رتبه بندی کنید بر اساس امتیازشون. چنانچه امتیاز برابری داشتن تفاضل گل رو در نظر بگیرین.
سناریو سوم) شرکتی میخواد به ۱۰۰ کاربر برترش مطابق سیستم امتیاز دهی اش جایزه بده. اما نمیخواد در حق کارمندا ناحقی شه برای همین اگه مثلا امتیاز نفره ۱۰۰ ام با ۱۰۱ام برابر بود, نفره ۱۰۱ ام هم رتبه ۱۰۰ در نظر میگیره و بهش جایزه میده. اما شرکت تو حالت ایده آل نمیخواد به بیشتر از ۱۰۰ کارمند جایزه بده.
@PyBackendHub
🐳3👍2🤔1
Python BackendHub
ادامه سری پست های SQL تو SQL ما windows function داریم.ویندو فاکشن ها به ما اجازه میدن محاسباتی رو یک ستی از row ها انجام بدیم به صورت نسبی به row فعلی. یعنی چی؟ یعنی مثلا SUM مجموع row هارو حساب میکنه. توابع window چهار دسته تقسیم میشن. که برای هر دسته پست…
سناریو اول dense_rank
سناریو دوم row_number
سناریو سوم rank
اما چرا؟؟ به عکس دقت کنید. رو همون دیتاستی که داشتیم سه تا رنک رو همزمان query زدیم
ریزالتش رو تو عکس بعدی میتونید ببینید. اتفاقی که میفته:
۱. همیشه ROW_NUMBER یکی یکی بالا میره. حتی اگه دو تا column تو رنکینگ مساوی شن بازم رتبه هاشون فرق میکنه. وقتی از این رنکینگ استفاده میکنید حواستون باشه fallback زیاد بذارین. مثل جدول فوتبال. مثلا اگه امتیاز مساوی بود اونوقت تفاضل. اگه تفاضل مساوی بود اونوقت ....
۲. رنک RANK بهتون رتبه نسبی میده. یعنی مثلا اگه دو تیم امتیازشون یکی شه رتبه شون یکی میشه. مثلا رتبه تیم اول تا پنجم میشه ۱-۲-۳-۳-۵ . اگه دقت کنید وقتی یک رتبه اسکیپ میشه فاصلش حفظ میشه. برای همین برای شرکت (سناریو سوم) گزینه مناسبی بود. چون فقط به شرطی بیشتر از ۱۰۰ کارمند جایزه میگرفتن که ۱۰۱ امین کارمند امتیازش برابر میشد با ۱۰۰مین کاربر. و یا ۱۰۲امین برابر میشد. برای سناریو هایی استفاده میشه که میخواین رتبه بندی کنید ولی نمیخواین کنترلتون رو تعداد آبجکت ها تا اون رتبه از دست بدید. مثلا رتبه ۱۰۰ گارانتی بهتون میده 100+n آبجکت وجود داره که n در واقع میشه تعداد مساوی ها با ۱۰۰امین آبجکت.
۳. رنک DENSE_RANK کاربرد کمتری داره. این رنک مثل RANK دیتاست های برابر رو هم رتبه میکنه. ولی فرقش اینجاست که دیگه compromise(جبران) نمیکنه موقع رتبه دادن به دیتا بعدی تو جدول. یعنی چی؟ یعنی فکر کنید مثل سناریو قبلی رتبه تیم اول تا پنجم اینطوری میتونه بشه: ۱-۱-۲-۲-۲. در صورتی که اگه rank بود میشد ۱-۱-۳-۳-۳. کاربرد تو دنیای واقعی من تاحالا ازش نداشتم.😅 برای همین مثالش یکم بد قلق بود.
@PyBackendHub
سناریو دوم row_number
سناریو سوم rank
اما چرا؟؟ به عکس دقت کنید. رو همون دیتاستی که داشتیم سه تا رنک رو همزمان query زدیم
SELECT deal_id, deal_amount, customer_name,
ROW_NUMBER() OVER
(PARTITION BY region ORDER BY deal_amount DESC)
AS row_number,
RANK() OVER
(PARTITION BY region ORDER BY deal_amount DESC)
AS rank,
DENSE_RANK() OVER
(PARTITION BY region ORDER BY deal_amount DESC)
AS dense_rank
FROM deals
ORDER BY region, deal_amount DESC;
ریزالتش رو تو عکس بعدی میتونید ببینید. اتفاقی که میفته:
۱. همیشه ROW_NUMBER یکی یکی بالا میره. حتی اگه دو تا column تو رنکینگ مساوی شن بازم رتبه هاشون فرق میکنه. وقتی از این رنکینگ استفاده میکنید حواستون باشه fallback زیاد بذارین. مثل جدول فوتبال. مثلا اگه امتیاز مساوی بود اونوقت تفاضل. اگه تفاضل مساوی بود اونوقت ....
۲. رنک RANK بهتون رتبه نسبی میده. یعنی مثلا اگه دو تیم امتیازشون یکی شه رتبه شون یکی میشه. مثلا رتبه تیم اول تا پنجم میشه ۱-۲-۳-۳-۵ . اگه دقت کنید وقتی یک رتبه اسکیپ میشه فاصلش حفظ میشه. برای همین برای شرکت (سناریو سوم) گزینه مناسبی بود. چون فقط به شرطی بیشتر از ۱۰۰ کارمند جایزه میگرفتن که ۱۰۱ امین کارمند امتیازش برابر میشد با ۱۰۰مین کاربر. و یا ۱۰۲امین برابر میشد. برای سناریو هایی استفاده میشه که میخواین رتبه بندی کنید ولی نمیخواین کنترلتون رو تعداد آبجکت ها تا اون رتبه از دست بدید. مثلا رتبه ۱۰۰ گارانتی بهتون میده 100+n آبجکت وجود داره که n در واقع میشه تعداد مساوی ها با ۱۰۰امین آبجکت.
۳. رنک DENSE_RANK کاربرد کمتری داره. این رنک مثل RANK دیتاست های برابر رو هم رتبه میکنه. ولی فرقش اینجاست که دیگه compromise(جبران) نمیکنه موقع رتبه دادن به دیتا بعدی تو جدول. یعنی چی؟ یعنی فکر کنید مثل سناریو قبلی رتبه تیم اول تا پنجم اینطوری میتونه بشه: ۱-۱-۲-۲-۲. در صورتی که اگه rank بود میشد ۱-۱-۳-۳-۳. کاربرد تو دنیای واقعی من تاحالا ازش نداشتم.😅 برای همین مثالش یکم بد قلق بود.
@PyBackendHub
👍6👏1