Python BackendHub – Telegram
Python BackendHub
7.51K subscribers
314 photos
46 videos
11 files
432 links
Learning python & Backend Engineering, with Mani!

Youtube: https://www.youtube.com/@GitOverHere
Github: https://github.com/ManiMozaffar
Linkedin: https://www.linkedin.com/in/manimozaffar

تبلیغات نداریم

Admin: @Mani_nikou
Download Telegram
<خرافاتی و دروغ هایی که برنامه نویس ها بهش باور دارن>


Falsehoods programmers believe about names
People's names do not change
People’s names have an order to them
My system will never have to deal with names from China
I can safely assume that this dictionary of bad words contains no people’s names in it
People have names
---------------------------------------------------
Falsehoods programmers believe about time
The time zone in which a program has to run will never change
The system clock will never be set to a time that is in the distant past or the far future
One minute on the system clock has exactly the same duration as one minute on any other clock
A time stamp of sufficient precision can safely be considered unique
The duration of one minute on the system clock would never be more than an hour
---------------------------------------------------
More falsehoods programmers believe about time
The local time offset (from UTC) will not change during office hours.
My software is only used internally/locally, so I don’t have to worry about timezones
I can easily maintain a timezone list myself
Time passes at the same speed on top of a mountain and at the bottom of a valley
---------------------------------------------------
Falsehoods programmers believe about time zones
Every day without DST changes is 86400 (60 * 60 * 24) seconds long
If you have two UTC timestamps it is possible to calculate how many seconds will be between them even if one of the timestamps are a year into the future
The time 23:59:60 is always invalid
---------------------------------------------------
Falsehoods programmers believe about geography
Places have only one official name
Place names follow the character rules of the language
Place names can be written with the exhaustive character set of a country
Places have only one official address
Street addresses contain street names
---------------------------------------------------
Falsehoods programmers believe about addresses
No buildings are numbered zero
A road will have a name
A single postcode will be larger than a single building
OK, but you don't get multiple postcodes per building
Addresses will have a reasonable number of characters — less than 100, say
---------------------------------------------------
Falsehoods programmers believe about maps
All coordinates are in “Latitude/Longitude”
The shortest path between two points is a straight line
All programmers agree on the ordering of latitude and longitude pairs

منبع
@ManiFoldsPython
👍3😁2
https://www.sequoiacap.com/article/sebastian-ramirez-spotlight/
مصاحبه (زندگی نامه) سباستین رامیرز رو چند ساعت پیش خوندم و واقعا WOW!

شخصا این نکاتو حداقل برداشت کردم:

۱. برای موفق نشدن دلایل خیلی بیشتری داشت تا موفق شدن، ولی جا نزد!
۲. نشون میده شما مدرک دانشگاه نداشته باشید دنیا به اخر نمیرسه. سباستین حتی دیپلم هم نداره!
۳. به برنامه نویسی به عنوان درامد زایی نگاه نمیکرد بلکه لذت میبرد.
۴. خلاقیت و ترکیب و استفاده از برنامه نویسی برای حل چالش های شخصیش
۵. پافشاری رو اهدافش

حتماا بخونید توصیه میشه
@ManiFoldsPython
👍18
آموزش ماگریشن نویسی با alembic - پارت اول:‌کلیات
آلمبیک یک tool برای ماگریشن نویسی هست که تو fastapi و flask استفاده میشه وقتی که داریم از sqlalchemy استفاده میکنیم. اول از هرچیزی با کامند های alembic اشنا شیم.

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

تو المبیک هر ماگریشن که میسازیم یک revision id داره که بتونیم track کنیم.

بریم سراغ کامند ها:
>> alembic init
فایل و استراچکر ‍alembic رو براتون init میکنه.

>> alembic current
>> {'deleted_tables': [], 'created_tables': [], 'deleted_cols': [], 'created_cols': [], 'deleted_constraints': [], 'created_constraints': []}
این کامند به شما میگه که تغییرات تیبلتون دقیقا چی بوده نسبت به آخرین ماگریشن. جای لیست تغییرات تیبلتون میاد.

>> alembic history
به شما سابقه ماگریشن هاتون رو نشون میده

>> alembic stamp {revision_id}
وقتی یک revision رو شما ‍stampt کنید
تا اون revision همه ماگریشن هارو ایگنور میکنه و فرض میکنه که دیتابیستون اون تغییراتی که اون ماگریشن ها اعمال میکردن رو داره.

>> alembic upgrade {revision_id}
تمام ماگریشن هایی که ران نشدن رو تا اون revision id ران میکنه

>> alembic merge
دو تا ماگریشن رو مرج میکنه تو یک ماگریشن.


نکته: وقتی فایل آلمبیک init میشه خط به خط برید مطالعه اش کنید. بعضی چیزاشو باید کانفیگ کنید. مثلا فایل آلمبیکتون باید از مدل های دیتابیستون آگاه باشه که بتونه بسازه اونا رو. اگه از async engine دارید استفاده میکنید باید تمپلیت رو تغییر بدید که async استفاده شه. که میشه
alembic init -t async

چند قابلیت داره مثل افلاین و انلاین ماگریشن که تو این پست دیگه بهشون نمیپردازم. تو پست بعدی به بست پرکتیس ها و نحوه تست alembic میپردازم
اگه میخواین بیشتر راجب خود alembic بدونید توصیه میکنم اینو بخونید.
https://alembic.sqlalchemy.org/en/latest/cookbook.html


@ManiFoldsPython
👍9
آموزش ماگریشن نویسی با alembic - پارت دوم:‌بست پرکتیس ها

۱. لایه بندی و جدا سازی هر دیتابیس تو معماری SOA
۱اگه از معماری ‍SOA استفاده میکنید سعی کنید برای هر دیتابیستون یک پکیج پایتونی داشته باشید. میتونید اون پکیجو مستقیما نصب کنید و استفاده کنید. داخل هر پکیج دیتابیستون فایل alembic داشته باشید.
IDENTITY
- models
- migration (alembic here)
- repository
- data

میتونید از پترن ریپازیتوری استفاده کنید و query های مربوط به اون دیتابیس رو بنویسید. بعد تو بقیه سرویس هاتون همون query ها رو sub queryکنید.

۲. توی فایل models که دیتابیس model هاتون وجود داره تو فایل init.py تمام مدل هایی که تو دیتابیستون رجیستر کردین رو ایمپورت کنید و تو alembic فقط همونا رو ایمپورت کنید. اینطوری alembic فقط از مدل های دیتابیستون آگاه هست.

.۳ همیشه برای تست نویسی دیتا sample بسازید. باید همیشه تو پروژتون یک استراچکری داشته باشید که بتونید دیتا سمپل رو اونجا تعریف کنید. همیشه وقتی دارین از alembic استفاده میکنید سعی کنید git flow رو رعایت کنید چون خیلی به دردتون میخوره. مثلا شما رو یک برنچی هستین که یک سری تغییرات به دیتابیس دادین یا یک تیبل جدید اضافه کردین. پس سمپل دیتا شما هم همون تغییرات روش اعمال شده. پس وقتی دیتابیس رو ریست کنید دیتابیس جدید شما به آخرین وضعیت دیتابیستون تغییر میکنه. بنابراین تست کردن ماگریشن خیلی سخت یا غیرممکن میشه.

۴. قبل از ایجاد هر ماگریشن‍, ابتدا مطمئن شید که state دیتابیستون درست هست. با کامند current میتونید چک کنید. اگه state دیتابیستون درست نبود یک دور branch ای که ازش branch ساختید رو checkout کنید و دیتا رو ریست کنید. برگردین برنچ خودتون. اینطوری دقیقا دیتابیسی دارین که وضعیتش دقیقا تو یک یک نسخه قبل از تغییرات شما قرار داره. حالا میتونید ماگریشن رو بسازید. اگه current رو ران کنید این دفعه به شما دقیقا همون تغییرات رو نشون میده.

۵. تو حالتی که ماگریشن رو اتوجنریت میسازید حواستون باشه که تغییراتی که اتوجنریت وارد شدن شامل این تغییرات تو سطح دیتابیس نمیشن:
* no creation / update or deletion of Enum occurs
* field type is not changed
* indexes are not recreated
زمانی از enum تو سطح دیتابیس باید استفاده کنید که لاجیک بیزنس کامل تعریف شده و هردفعه نیازی نیست هی enum اضافه یا کم شه. (مثلا سطح کاربری برنز/سیلور/گلد)

۶. برای ماگریشنتون میتونید smoke test بنویسید. حواستون باشه smoke test ای که مینویسید فقط باید تو مرحله پروداکشن انجام شه. که build پروداکشن فیل شه اگه اسموک تست fail شه. چون ماگریشن state دیتابیس رو تغییر میده پس stateful هست پس unit test نمیشه براش نوشت.
https://github.com/schireson/pytest-alembic

۷. برای اینکه تست کنید ماگریشن کار میکنه باید طبق مرحله ۴ دیتابیس رو ریست کنید ماگریشن رو ران کنید. و بعد چک کنید ایا دیتا درست جا به جا شده یا نه(به صورت دستی). اینقدر باید این loop رو تکرار کنید تا ماگریشن اعمال شه.

۸. کل ماگریشن تو یک transaction رخ میده. پس اگه fail شه فاجعه بزرگی رخ نمیده. اما هر ماگریشن تو یک transaction رخ میده. پس بهتره تو هر ریلیز به پروداکشن تو staging بیایم migration هارو مرج کنیم که کلا یک ماگریشن شه. بعد یا اون ماگریشن اعمال میشه یا fail میشه. یعنی دیتابیس یا طبق ریلیز بعدی state اش تغییر میکنه یا ریلیز انجام نمیشه. اینکار به شدت توصیه میشه.

۹. لاجیک پشت ماگریشن اگه حجم دیتا پروداکشن زیاد نباشه میتونه تو همون ماگریشن نوشته شه. اگه حجم دیتا پروداکشن زیاد باشه باید به صورت جدا ران شه بعد از اعمال ماگریشن به صورت pipeline. دلیلش اینه که دیتابیس موقع ران کردن ماگریشن کاملا ‍down میشه. مثال بخوام بزنم شما full name دارین و حالا میخواین first name و last name ‍اضافه کنید و full name رو deprecate کنید . اگه مثلا ‍۱۰۰ یوزر دارین که میتونه تو همون ماگریشنتون قرار بگیره. ولی اگه مثلا ۱۰ میلیون یوزر دارید چون ران تایم خیلی زیاد میشه باعث میشه چند ساعت دیتابیس down شه که اصلا جالب نیست پس باید ماگریشن ابتدا ران شه و بعدا این لاجیک جدا سازی اعمال شه به صورت یک event


@ManiFoldsPython
👍6
این دو روز داشتم رو این کار میکردم. کد چلنج یکی از شرکت‌ها که براشون رزومه فرستاده بودم. یک سیستم خرید کریپتو. این طوری خریدها رو میگیره داخل ردیس ذخیره میکنه ایونت و رکورد خرید رو. بعد یک تسک هر چند وقت یک‌بار اجرا میشه و اون خرید‌ها رو نهایی میکنه و ایونتش رو از ردیس پاک میکنه.

این روش درست پیاده سازی همچین چیزی نیست چون یک تایم (اینجا ۳۰ ثانیه) طول میکشه ک اون تسک نهایی کردن خرید‌ها ران بشه. درستش پیاده سازی با آپاچی کاکفا و من چون بلد نبودم با سلری و ... زدمش :)

ستاره بدید خوشحال شم 🫠

https://github.com/TorhamDev/buy-cryptocurrency
TorhamDev | تورهام 😳
این دو روز داشتم رو این کار میکردم. کد چلنج یکی از شرکت‌ها که براشون رزومه فرستاده بودم. یک سیستم خرید کریپتو. این طوری خریدها رو میگیره داخل ردیس ذخیره میکنه ایونت و رکورد خرید رو. بعد یک تسک هر چند وقت یک‌بار اجرا میشه و اون خرید‌ها رو نهایی میکنه و ایونتش…
چلنج این تسکی که به تورهام داده بودن رو خیلی دوست داشتم(صرافی کریپتو). برای همین خواستم ایراداتشو تکمیل کنم.
این ریپو رو تو ۴ ساعت کد زدم. که درواقع تمرکز رو EDD کردن بود با داینامیک کردن لاجیک بیزنس که کریپتو های جدید و api های جدید (جهت تحویل خودکار اوردر) و کلا فیچر های جدید خیلی راحت اضافه شن.

https://github.com/ManiMozaffar/edd-exchange

یک proto type برای دو سرویس exchange کریپو به سبک event driven هست

با ردیس استریم هم هندلش کردم که یکم ردیسم قوی تر شه.
نظرتون رو بگید راجب دیزاینش .

پ.ن: تست و ران و دیباگ نکردمش صرفا prototype بود جهت تمرین

@ManiFoldsPython
👍7👎2
یک پلاگین pytest نوشتم برای integration test که ممکنه به دردتون بخوره

تو اینتگریشن تست بعضا fixture هایی که استفاده میکنیم بسیار سنگین هستند. مثل مرورگر. برای ریست کردن اون fixture شما یک راه حلی که دارین اینه که اسکوپ تستون رو به فانکشن تغییر بدید که سر هر تست یک بار fixture تون مجدد نصب شه. ولی واقعا کاربردی نیست. چون fixture باید به اون استیت برسه دوباره که بتونه اون تست رو پرفوم کنه. مثلا میخواین چک ۱۰ تا اکشن تو یک صفحه view فرانتتون رو تست کنید. پس باید ۱۰ بار مروگر بالا بیارین و هر بار مرورگر بالا اوردن ۴ ثانیه طول میکشه. تستون ۴۰ ثانیه میشه فقط setup اش!

راه حل دوم چیه؟‌اینه که تو هر فایل شما کلی تست وابسطه به هم بنویسید. بعد با استفاده از پلاگین من اگه یکی از تستاتون fail شد بقیا تستای اون فایل رو xfail میکنه و اسکیپشون میکنه.
یعنی شما ۴ ثانیه یک مرورگر بالا میاری. بعد تو اون فایل واسه هر اکشن یک تست مینوسید. بعد مرورگر رو تو تست اول میبرین تو view ای که باید بره. بعد اکشن هارو تست میکنید. هرجایی هم fail شد مشکلی نداره دیباگ میکنیم فرانتو و دوباره تستو ران میکنیم. اینطوری ران تایم تست به شدت کاسته میشه.


البته این تو unit test اصلا توصیه نمیشه. تو unit test تو یک فایل نباید تستاتون به هم دیگه dependency داشته باشن.

کد پلاگین(تو conftest باید بره):

@pytest.fixture(scope="module", autouse=True)
def failure_marker(request: FixtureRequest):
request.node._has_failures = False
yield
del request.node._has_failures


@pytest.fixture(autouse=True)
def check_failure(request: FixtureRequest, failure_marker):
if getattr(request.node.parent, "_has_failures", False):
pytest.xfail("Previous test failed")


@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item: Item, call):
outcome = yield
report: TestReport = outcome.get_result()
if report.when == "call" and report.failed:
parent: Node = item.parent
parent._has_failures = True



@ManiFoldsPython
🔥6👏2
Python BackendHub
چلنج این تسکی که به تورهام داده بودن رو خیلی دوست داشتم(صرافی کریپتو). برای همین خواستم ایراداتشو تکمیل کنم. این ریپو رو تو ۴ ساعت کد زدم. که درواقع تمرکز رو EDD کردن بود با داینامیک کردن لاجیک بیزنس که کریپتو های جدید و api های جدید (جهت تحویل خودکار اوردر)…
مفاهیمی که تو این ریپو به کار برده شده رو کم کم توضیح میدم.

راجب معماری SOA چقدر اطلاع دارین؟
اولا تو SOA ما رو برنامه نویسی ماژولار خیلی تاکید داریم. یک دیتابیس میتونه توسط دو اپلیکیشن استفاده شه برعکس microservice. پس هر دیتابیس شما باید یک اینترفیس داشته باشه که طبق اون پیاده سازی انجام شده باشه. من اسم ماژولی که استفاده کردم اینجا ‍shared گذاشتم. بعد همین ماژول رو تو دو سرویس دیگه هم دیپلوی کردم.

تو بست پرکتیس هر دیتابیس شما باید جداگونه یک ماژول جدا باشه. ماگریشن هم میتونیم یا تو اون ماژول بذاریم یا تو سرویس اصلی اون دیتابیس. معمولا هر دیتابیس یک سرویس اصلی داره مثل monolithic ولی اگه نداشت پس باید تو ماژولش هم ماگریشن رو میذاریم. تو ماژول دیتابیس علاوه بر ماگریشن, باید ‍sql model database و query repository و سمپل دیتا تست هم باشه.

sql model database -> همون مدل دیتابیس که یک تیبل رو نمایش میده

query repository -> یک ریپازیتوری پترن که کوئری های تکراری داخلش هست که باعث تکرار کوئری تو اپلیکیشن های مختلف نشه. تو اپلیکیشن های مختلف همین کوئری رو ساب کوئری میکنیم

sample data -> دیتایی که تو محیط dev استفاده میشه و ساخته میشه

استفاده از جنگو تو SOA کمی سخته چون ست آپ کردن جنگو و استفادش به صورت ماژولار پیچیدگی کد رو به شدت بیشتر میکنه.

جدا از این, ما تو shared library هم business entities داریم. مثلا اینجا business entities های ما کریپتو, درگاه صرافی و واحد های پول مختلف بود. معمولا خیلی خوبه که همشون تایپینگ داشته باشند اینطوری اون تایپینگ تو سطح تمامی سرویس هامون رعایت میشه.

همینطور تو SOA ما تو shared library میایمentities architectureمون هم قرار میدیم. مثلا بروکر هایی که استفاده میکنیم. پیاده سازیشون. اینترفیسشون. معماری logging امون. معماری streamingمون. مثلا من یک کلس ساختم به نام AbanConsumer که abstract کلسی بود برای هر کانسیومری که تو هر سرویسی وجود داره. بعد بقیه سرویسا از همین کلس ارث بری میکنن و خیلی سریع میرن سراغ پیاده سازی consumer.

این shared module ها و shared database ها به ما اجازه میدن خیلی راحت سرویس جدید یا فیچر جدید اضافه کنیم. البته استارت SOA اولش یکم سخت و پیچیدست چون ‍deploy و CI/CD پیچیده تری داره نسبت به microservice و monolithic.


داخل ریپازیتوری من shared library کامل implement شده که میتونید ببینید.

@ManiFoldsPython
👏6👍3
نکته دومی که رعایت شده و اکثرا میبینم بین دوستان کم تجربه تر رعایت نمیکنن استفاده از دیزاین پترنه!

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

من تو کدم از strategy pattern و factory pattern به همراه interface استفاده کردم.

اینترفیس هام یا abstract بودن یا protocol بسته به سطح حساسیت interface و کلس هایی که باید از روش ساخته میشد. (اگه این جمله رو متوجه نشدین حتما این ویدیو رو ببینید)

من crypto و API Integration ام رو استراتژی پترن زدم. که البته با Enum هم یک مپر ساختم و هر کلسی که ساختم مپ کردم به یک Enum . مثلا کریپتو آبان و تتر تو این مثال:



from enum import auto
from typing import Type

from shared.enums import StrEnum

from .aban import AbanCrypto
from .abc import AbstractCrypto
from .tether import TetherCrypto


class ECurrenciesType(StrEnum):
TETHER = auto()
ABAN = auto()


CRYPTO_MAPPER: dict[ECurrenciesType, Type[AbstractCrypto]] = {
ECurrenciesType.TETHER: AbanCrypto,
ECurrenciesType.TETHER: TetherCrypto,
}


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

بعد تو قسمت Currency که در واقع واحد های پول بود از پترن فکتوری استفاده کردم که راحت کارنسی جدید اضافه کنم.
در نتیجه با این دیزاین پترن هایی که استفاده کردم خیلی راحت میتونم یک API جدید اضافه کنم‍, یک currency جدید اضافه کنم, یک کریپتو حذف کنم یا اضافه کنم, و کاملا دستم بازه تو سمت لاجیک بیزنس.

@ManiFoldsPython
👍5🔥4
نهایتا API این شکلی شد

توی تسک اشاره شده برای مثال کریپتو آبآن پیاده سازی شه. و این یکم نکته داره.
چون که گفته شده برای مثال کریپتو آبان پیاده سازی شه دلیل نمیشه شما به داینامیک نبودن این دقت نکنید.

یا گفته شده فرض کنید صرافی سفارشات زیر ۱۰ دلار نمیگیره. (API Integration). چون گفته شده فرض کنید اینطوره دلیل نمیشه همه صرافی ها اینطور باشه.

موقع زدن تسک:
۱. به بیزنس لاجیک خیلی دقت کنید و سعی کنید داینامیک باشه
۲. تمام edge case هارو در نظر بگیرید.
۳. موقع دیزاین کردن اصلا به فرضیات دقت نکنید. موقع کد زدن به فرضیات بچسبید.
۴. .وقتتون رو سره چیزایی که ارزش گذاری نشده تو تسک تلف نکنید

@ManiFoldsPython
👍6
من این تسکو خیلی دوست داشتم ولی چیزی که اصلا دوست نداشتم راجب این تسک زمانش بود! این تسک فقط ۴۸ ساعت فرصت داشت که روی تست نویسی, سالید, معماری تمیز, کلین کد و داکرایز مانور رفته بود. همچنین جایی اشاره نشده بود که مثلا سیستم احراز هویت ننویسید یا فلان چیزو ننویسید که حجم تسک کمتر شه.

تو خود تسکم گفته شده بود <تراکنش کریپتویی یوزر باید بلافاصله انجام شه>‌ که نشون میده دیزاین سیستم باید real time و ‍event driven باشه.

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


"The only way to go fast is to go well." - Uncle bob

@ManiFoldsPython
👏103👍1
🤣17👍1😁1
یک توصیه به دوستانی که دارن یادگیری fastapi/flask رو شروع میکنن:

خواهشا از tortoise استفاده نکنید. در مقابل sqlalchemy جوکه. استفاده از sqlalchemy باعث میشه کمی از سینتکس orm django فاصله بگیرین و SQLتون قوی تر شه. مخصوصا اگه از جنگو دارین شیفت میکنید احتمال خیلی زیاد پایه SQLتون ضعیفه و ابتدای کار دستتون کند باشه تو نوشتن query و دیباگش.

همینطور ORM کاملا shit عی هست. از تعداد ایشو هاش نسبت به ستارش فکر کنم مشخص باشه. پختگی و mature بودن sqlalchemy به کنار. من ۲ ماه تو مارکت آلمان و هلند دنبال کار بودم یک آگهی ندیدم نوشته باشه باید مسلط باشین رو tortoise orm. ولی تا دلتون بخواد sqlalchemy بود.

@ManiFoldsPython
👍26
من با این کد خیلی حال کردم
https://github.com/Kludex/fastapi-responses/tree/master

یک سر بزنید بهش. کلا ۹۰ خطه.
چند تا ایشو باز و help wanted داره. با توجه به حجم کمش و دولوپر قوی که پشتشه میتونه open source contribution خوبی برای رزومتون باشه.

@ManiFoldsPython
5👍1
Forwarded from ‌BenDev
👍6
ray-so-export (4).png
1.3 MB
یک use case خاص داشتم که باید بنا به دلیلی لاگ های سطح های مختلفو تو فایل های مختلفی سیو میکردم.
و لاگ هر consumer رو جدا ذخیره میکردم تو یک فایل مجزا

از rich و loguru استفاده کردم
شاید به درد کسی خورد.

(یکم کد عجیب شد بخاطر اینکه میخواستم دقیقا مثل rich اکسپشنو بندازم)
@ManiFoldsPython
🔥5🥰1
Forwarded from Sadra Codes
کور دولوپرهای تیم Pydatic

واقعا باعث افتخاره که حسن رمضانی هم عضوی از این تیمه. :) ❤️
23🔥2
خیلیا Depends و DIP رو اشتباه میگیرن. فکر میکنن هرجا از Depends تو fastapi استفاده کردن پس DIP رو رعایت کردن!

دوستان, مفهوم واژه DIP یعنی dependency inversion principle. یکی از پنج اصل سالیده. اصلا ربطی به Depends نداره. یعنی که که ماژول‌های سطح بالا باید به Abstraction وابستگی داشته باشند به جای low level module. این اصل به کاهش وابستگی‌های میان اجزا در برنامه شما کمک میکنه و می‌تواند کد شما را انعطاف‌پذیرتر، قابل نگهداری‌تر و آزمایش‌پذیرتر کنه.

هیچ کدی نیست که DIP رو رعایت کرده باشه ولی نشه تستش کرد. میخواد streaming باشه. میخواد ربات باشه. میخواد کراول باشه. علتی که تو فریم ورکی مثل scrapy ما تست نویسی نداریم چون این فریم ورک سورس کدش شت کده و DIP توش رعایت نشده برای همین نمیشه تست نوشت. رعایت DIP یک اصله هیچ ربطی به Depends نداره. شما میتونی تو کل اپلیکیشنت ‍Depends بذاری ولی بازم DIP رو رعایت نکرده باشی.


چه چیزی رو باید dependancy inject کنید؟ هرجایی که میتونید decoupling انجام بدید, و یا flexibility اضافه کنید, و یا نیاز به maintainability داره باید براش اینترفیس بنویسید. بعد implementation های مختلف اون اینترفیس رو dependency inject کنید.

پس این بستگی داره به پروژتون. مثلا اگه دارین یک لایبری اوپن سورس مینویسید و میخواین دست یوزر باز باشه تو تغییر روتر ها, اون موقع باید کنترلر روتر رو اینجکت کنید. همیشه باید جواب این ۴ سوال رو بدید موقع inject
1. Will it reduce the coupling?
2. Will it make my code more maintable?
3. Has flexibility increased?
4. Can I now write the test easily with mocking dependencies?
اگه یکی از این سوالا جوابش نه بود یعنی نباید DIP رو اعمال کنید.

مثلا authorization برای user role های مختلف باید inject شه!‌

حالا سوال اصلی, پس D‍epends چیه؟ depends یک فریم ورکی تو فست هست که DIP رو برای شما خیلی راحت میکنه.
خلاصش اینه که یک مپر اون پشت هست که Depends object هارو به یک callable وصل میکنه و موقع اجرا شدن روتر اون callable رو اجرا میکنه.

از دو نظر خوبه:
۱. نیاز ‍global variable رو از بین میبره تو سطح برنامه. در نتیجه برنامتون میتونه RAM خیلی کمی مصرف کنه موقع استارت شدن و سریع استارت شه.
۲. پیاده سازی DIP رو خیلی راحت میکنه.

موقع استارت شدن اپلیکیشنتون شما میتونید override_dependency کنید. یا برای هر روتر میتونید هم همینکارو کنید. اینطوری مثلا شما یک abstract database دارید, بعد میتونید همون اینترفیس رو با چند مدل مختلف دیتابیستون تو روتر های مختلف استفاده کنید. یا مسیج بروکر. مثلا یک روترتون message رو با کافکا produce میکنه و یک روترتون میتونه مسیج رو با rabbitmq بفرسته.

@ManiFoldsPython
👍91
یک سوال دارم از همتون,

چرا تو کامینیتی پستایی مثل دیزاین و کلین کد و اصول کد نویسی engage خیلی کمتری دارن؟‌ به جاش مثلا دیدم یک پستی راجب یک موضوع تخصصی تر تو پایتون خیلی engage بیشتری داره! یا مثلا پستم راجب sqlalchemy و tortoise که یک نصیحت و نظر شخصی ساده بود.

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

نظره شخصیم اینه که هممون قرار نیست magic code بنویسیم. هممون قرار نیست اینترنال cpython رو خوب بلد باشیم. هممون قرار نیست پروژه big data داشته باشیم که مثلا یک جایی یک خطه کد efficient نبود پروداکشن زیر بار و فشار بره.

ولی هممون داریم رو یک پروداکت کار میکنیم که خیلی مهمه راحت بتونیم بهش فیچر اضافه کنیم و بیزنس fail نشه بخاطر دیزاین بدمون. هممون تست مینویسیم ولی حتی پستای تست نویسی منم engage خوبی نداشتن!

دلیل engage تو این بحثا نداشتمون چیه؟

@ManiFoldsPython
🤔7👍2😁2