Parse, don't validate
فکر کنید یک دیتا کلس داریم
میخوایم این سناریو هارو پیاده سازی کنیم
Order that is received -> Order that is accepted
Order that is accepted -> Order that is paid
Order that is paid -> Order that is shipped
یک تابعی داریم که این چنین کار میکنه:
def ship_order(order: Order) -> Order:
...
خب طبیعتا مشکلی که وجود میاد اینه که چه چیزی باعث میشه که ما به flow و جریان دیتا احترام بذاریم؟
Order that is received -> Order that is shipped
چطور جلوی این رو میگیریم؟باید هردفعه تو ship order کلی چک بنویسیم که ۱۰۰درصد خیالمون راحت باشه که عملیاتی که میشه داره درست انجام میشه. به این کار میگن validation
تازه این یک سناریو ساده بود. همین ولیدیشن باید برای همه توابع دیگه ای که نیاز داریم نوشته شه یعنی:
accept_order
return_order
update_order
تازه وقتی تو سورس کد میبینیم همچین چیزی رو نمیدونیم کی باید این تابع رو کال کنیم و ایا type safe هست یا نه؟ یعنی اگه من هر اوردری بدم بهم اوردر شیپ شده میده؟ از کجا میتونم ۱۰۰درصد خیالم راحت باشه اروری چیزی نمیخوره؟ از کجا میتونم بفهمم اوردی که برمیگرده ship شده هست؟ پس باید doc string رو بخونم و همینطور کد هم چک کنم! و این خیلی بده 🙂
حالا parse چیه؟ وقتی اوردر رو parse میکنید یعنی دارید آنالیز میکنید اوردر دقیقا تو چه state ای قرار داره
def ship_order(order: PaidOrder) -> ShippedOrder:
...
و تو کلس PaidOrder هم ۱۰۰درصد پارس میکنم که اوردر باید تو وضعیت paid باشه. این کاملا تایپ سیفه یعنی هر PaidOrder ای بهش بدم ShippedOrder به من میده. بدون اینکه کد کثیف و پر از ولیدیشن نوشته شه تو تابع! و البته برای درکشم نیازی به داک استرینگ و خوندن کد ندارم:)
مقاله کامل تر
@ManiFoldsPython
فکر کنید یک دیتا کلس داریم
@dataclass
class Order:
id: UUID
customer: Customer
created_at: datetime
accepted_at: Optional[datetime]
paid_at: optional[datetime]
shipped_at: Optional[datetime]
میخوایم این سناریو هارو پیاده سازی کنیم
Order that is received -> Order that is accepted
Order that is accepted -> Order that is paid
Order that is paid -> Order that is shipped
یک تابعی داریم که این چنین کار میکنه:
def ship_order(order: Order) -> Order:
...
خب طبیعتا مشکلی که وجود میاد اینه که چه چیزی باعث میشه که ما به flow و جریان دیتا احترام بذاریم؟
Order that is received -> Order that is shipped
چطور جلوی این رو میگیریم؟باید هردفعه تو ship order کلی چک بنویسیم که ۱۰۰درصد خیالمون راحت باشه که عملیاتی که میشه داره درست انجام میشه. به این کار میگن validation
تازه این یک سناریو ساده بود. همین ولیدیشن باید برای همه توابع دیگه ای که نیاز داریم نوشته شه یعنی:
accept_order
return_order
update_order
تازه وقتی تو سورس کد میبینیم همچین چیزی رو نمیدونیم کی باید این تابع رو کال کنیم و ایا type safe هست یا نه؟ یعنی اگه من هر اوردری بدم بهم اوردر شیپ شده میده؟ از کجا میتونم ۱۰۰درصد خیالم راحت باشه اروری چیزی نمیخوره؟ از کجا میتونم بفهمم اوردی که برمیگرده ship شده هست؟ پس باید doc string رو بخونم و همینطور کد هم چک کنم! و این خیلی بده 🙂
حالا parse چیه؟ وقتی اوردر رو parse میکنید یعنی دارید آنالیز میکنید اوردر دقیقا تو چه state ای قرار داره
def ship_order(order: PaidOrder) -> ShippedOrder:
...
و تو کلس PaidOrder هم ۱۰۰درصد پارس میکنم که اوردر باید تو وضعیت paid باشه. این کاملا تایپ سیفه یعنی هر PaidOrder ای بهش بدم ShippedOrder به من میده. بدون اینکه کد کثیف و پر از ولیدیشن نوشته شه تو تابع! و البته برای درکشم نیازی به داک استرینگ و خوندن کد ندارم:)
مقاله کامل تر
@ManiFoldsPython
👍11👏3👌2
Python BackendHub
امروز با اختلاف بسییااااار فاحش یکی از سخت ترین مصاحبه های تکنیکالمو دادم. با شرکتی که 2 ماه پیش رزومه فرستاده بودم مصاحبه فنی گرفتم شرکت نسبتا بزرگ و پیشرفته ای هست. (اسم شرکت رو به دلایل شخصی نمیتونم بگم). 2 ساعت و 45 دقیقه مصاحبه طول کشید تماما فنی. اما…
یک سوال تو مصاحبه ای که روش ریپلای زدم پرسیده شده بود ازم جالب بود:
۱. تفاوت having و where تو sql . که خب سوال راحتیه.
۲. چرا تو سناریویی که از having استفاده میکنیم نمیتونیم از where استفاده کنیم؟ (دلیل فنی پشت implementation having یا بهتره بگم دلیل وجود سینتکس having )
که دومیو نمیدونستم چون واقعا کنجکاو نشده بودم تاحالا. و البته بعدش سرچ کردم فهمیدم. کلا بعد از اون مصاحبه معمولا از هرچیزی که استفاده میکنم روزانه سعی میکنم علتشو متوجه شم. و واقعا به باز شدن دیدم کمک کرده این موضوع
تو کامنتا جوابشو بگید
@ManiFoldsPython
۱. تفاوت having و where تو sql . که خب سوال راحتیه.
۲. چرا تو سناریویی که از having استفاده میکنیم نمیتونیم از where استفاده کنیم؟ (دلیل فنی پشت implementation having یا بهتره بگم دلیل وجود سینتکس having )
که دومیو نمیدونستم چون واقعا کنجکاو نشده بودم تاحالا. و البته بعدش سرچ کردم فهمیدم. کلا بعد از اون مصاحبه معمولا از هرچیزی که استفاده میکنم روزانه سعی میکنم علتشو متوجه شم. و واقعا به باز شدن دیدم کمک کرده این موضوع
تو کامنتا جوابشو بگید
@ManiFoldsPython
👍8
Python BackendHub
یک سوال تو مصاحبه ای که روش ریپلای زدم پرسیده شده بود ازم جالب بود: ۱. تفاوت having و where تو sql . که خب سوال راحتیه. ۲. چرا تو سناریویی که از having استفاده میکنیم نمیتونیم از where استفاده کنیم؟ (دلیل فنی پشت implementation having یا بهتره بگم دلیل…
جواب جفت سوالو تو کامنت اشاره کردن
دلیلش فقط به خاطر execution order و تایم لاینی هست که اجرا میشه. یعنی where میاد قبل از group by اجرا میشه برای همین نمیتونستیم هیچ فیلتری توی group by امون انجام بدیم. مثلا میخوایم بگیم sum فلان فیلد بیشتر از ۱۰۰ باشه. نمیتونستیم با این معماری و where . (البته میشه cte زد)
و مرسی از مهدی عزیز بابت اشتراک گذاری این پست:
Visualizing a SQL query
SQL statements are executed by the database system in several steps, including:
- Parsing the SQL statement and checking its validity
- Transforming the SQL into an internal representation, such as relational algebra
- Optimizing the internal representation and creating an execution plan that utilizes index information
- Executing the plan and returning the results
@ManiFoldsPython
دلیلش فقط به خاطر execution order و تایم لاینی هست که اجرا میشه. یعنی where میاد قبل از group by اجرا میشه برای همین نمیتونستیم هیچ فیلتری توی group by امون انجام بدیم. مثلا میخوایم بگیم sum فلان فیلد بیشتر از ۱۰۰ باشه. نمیتونستیم با این معماری و where . (البته میشه cte زد)
و مرسی از مهدی عزیز بابت اشتراک گذاری این پست:
Visualizing a SQL query
SQL statements are executed by the database system in several steps, including:
- Parsing the SQL statement and checking its validity
- Transforming the SQL into an internal representation, such as relational algebra
- Optimizing the internal representation and creating an execution plan that utilizes index information
- Executing the plan and returning the results
@ManiFoldsPython
👍12
Forwarded from Sadra Codes
بررسی جوانب پایتون ۳.۱۲
✅ از این به بعد میتونید fstring های تودرتو بنویسید. مثلا:
✅ لایبرری
✅ از این به بعد میتونید تایپ هینت
✅ تمام comprehensionهایی که در بدنه فانکشنها هستن، از لحاظ سرعت اجرا بهینهتر شدن.
✅ ارور مسیجها هم بهینه و هوشمندتر شدن. اگه که بتونن، در محدوده شرایط وسیعتری، سلوشن میدن.
➕ دوتا سینتکس جدید هم اضافه شده به پایتون. یکی
✅ از این به بعد میتونید fstring های تودرتو بنویسید. مثلا:
phrase = f"Hello {f"{name}"}"
# Hello Sadra
بنظرم آنچنان کاربردی نیست و فهمیدنش در نگاه اول یکم سخته. شاید هایلایترها درکش رو راحتتر کنن در آینده ولی یه فیچر جدید که اضافه شده و خوشم اومد، multiline fstring هست که بهتون اجازه میده، اف استرینگ رو در چند خط بنویسید و حسابی expandش کنید. تازه میتونید در بدنهاش، کامنت هم بنویسید:phrase = f"Hello {
name # User.name
}"
# Hello Sadra✅ بهینهسازی سیستم Tokenization. پایتون یه ماژول tokenizer داره که ازش واسه آنالیز و پارس کردن کلمات و حروف ولید پایتون استفاده میکنه. به هر چانک حروف از استرینگ ورودی توکن میگن. اکثر تولهای linting و formatting از این ماژول واسه فرمت و لینت کردن کد پایتون استفاده میکنن. تا نسخه ۳.۱۱، این ماژول به زبان پایتون بود. بدلیل اضافه شدن nested fstring و مولتی لاین fstring، مجبور شدن این ماژول رو بازنویسی کنن و با C نوشتنشن و از لحاظ زمان runtime، سرعتش به شدت رفته بالا. این باعث میشه تمام tool هایی که از tokenizer استفاده میکنن، سریعتر اون ماکروهاشون ران شن.
✅ لایبرری
distutils دیپریکت شده و دیگه توی standard library قرار نداره. از این لایبرری واسه نوشتن و توزیع کردن پکیج پایتون استفاده میشد که به دلیل سرعت پایین و محدودیتهایی که نسبت به پکیج setuptools داشت، ملت همیشه میرفتن سمت setuptools. حتی خود pip هم به setuptools وابسته هست. اگه venv بسازین، میبینید که بصورت دیفالت، setuptools نصبه. یه نکته که هست، setuptools جزو standard library نیست و درواقع از هسته distutils پایتون استفاده میکنه. از اونجا که distutilsی دیگه در کار نیست و pip نسخههای ۲۲.۱ به بالا دیگه وابستگی به setuptools نداره، عملا هیچ ابزار رسمیای واسه توزیع پکیج پایتون هم نخواهیم داشت. این هم خوبه، هم بد.pip (>= 22.1) does not require setuptools to be installed in the environment. setuptools-based (and distutils-based) packages can still be used with pip install, since pip will provide setuptools in the build environment it uses for building a package.حالا یه اتفاق دیگه هم افتاده. اونم اینکه
venv دیگه بخشی از پکیج setuptools نیست. تا امروز بود ولی دیگه نیس. حالا چیکار میشه کرد؟ خب distutils مستقل شده و شما میتونید خودتون setuptools رو pip install کنید و ازش استفاده کنید و واسه venv هم، virtualenv نصب کنید. دیگه کامند زیر کار نمیکنه:❌ python -m venv venv
بطور کلی، از این به بعد هر محیط venv که با virtualenv میسازید، در isolatedترین شکل ممکن قرار دارن و site-packageتون خالی خالیه. حتی wheel هم ندارید. فقط pip رو دارید.✅ از این به بعد میتونید تایپ هینت
kwargs** رو کاستومایز کنید. من خودم همیشه انوتیت میکردم به typing.Any ولی از این به بعد میتونید TypedDict رو بهش انوتیت کنید:from typing import TypedDict, Unpack
class Values(TypedDict):
name: str
age: int
def main(**kwargs: Unpack[Values]): ...
✅ یه تایپ هینت جدید اومده که خیلی خوشم اومد، typing.override هست. این موقعی بدرد میخوره که میخواین تایپ هینت ست کنید واسه متدی که توی subclass قراره اوررایت شه. اگه تغییری توی superclass ایجاد شه و اسم اون متد توی سوپرکلس تغییر کنه، اگه یه سیستم type checking داشته باشین یه چیز مثل mypy، حتما خطا رو میگیره و بهتون نشون میده. این درحالیه که اگه کد رو اجرا کنید، ممکنه خطا نگیرید و اون متد هم override نشه.from typing import override
class A:
def greet(): ...
class B(A):
@override
def greet(): ...
توی این مثال، اگه روزی برسه که اسم متد greet توی سوپرکلس تغییر کنه به greeting، حتما type checker ارور میده ولی اگه annotate نکرده باشید، اروری دریافت نمیکنید و صرفا اون logic درست کار نمیکنه.✅ تمام comprehensionهایی که در بدنه فانکشنها هستن، از لحاظ سرعت اجرا بهینهتر شدن.
✅ ارور مسیجها هم بهینه و هوشمندتر شدن. اگه که بتونن، در محدوده شرایط وسیعتری، سلوشن میدن.
➕ دوتا سینتکس جدید هم اضافه شده به پایتون. یکی
type هست که واسه Type Alias استفاده میشه و دیگری هم Type Parameter هست که یه مدل جدید واسه تعریف فانکشنها و کلسهای جنریک پایتونه. شیوه استفاده ازشون به این شکله:type name = str
type age = int
قبلا باید جنریک فانکشن رو اینجوری تعریف میکردیم:def greet(name: List[str]): ...
ولی الان مینویسیم:type T = List[str]
def greet[T](name: T): ...
این باعث میشه که پرینسیپل DRY آسیب نبینه.👍9
بزرگ ترین تغییر ۳.۱۲ نسبت به ۳.۱۱ که بنظرم صدرا اشاره نکرد بهش PEP 684 بود
A Per-Interpreter GIL
که البته فعلا تو سطح پایتون نیست و python api نداره.
ولی این تغییر تو ۳.۱۳ خودشو خیلی بیشتر نشون میده. جایی که API python اش میاد. طبق PEP 554.
https://peps.python.org/pep-0554/
جایی که ما میتونیم حالا از این تغییراتی که تو ۳.۱۲ انجام شده و API پایتونیش تو ۳.۱۳ هست استفاده کنیم:)
اینکه چیه و چیکار میکنه تو این پست نمیگنجه. توصیه میکنم حتما این دو PEP رو وقت بذارین و بخونید که از بقیه جلوتر باشید تا وقتی ۳.۱۳ اومد بدونید چی باید یاد بگیرید 😁 فقط یک مقایسه میکنم بین sub Interpreter و مولتی پروسس
True Parallelism -> Multiprocess: YES | Subinterpreters: Potential
Isolation -> Multiprocess: HIGH | Subinterpreters: MEDIUM
Overhead -> Multiprocess: HIGH | Subinterpreters: LOW
و توی theory حداقل باید Subinterpreters یک مموری ایزوله و هندل CPU Bound task به صورت بهینه تر رو به ما بدن که باعث میشه پایتون با استفاده از این مفهوم جدید برای real-time processing و streaming data بسیار مناسب تر شه. چرا؟چون میتونید یک subinterpreter داشته باشید که دیتا رو بگیره و یک subinterpreter داشته باشید که دیتا رو پروسس کنه که این ایزوله سازی باعث استفاده بهتر و بهینه تر از ریسورستون میشه و latency رو هم کاهش میده
@ManiFoldsPython
A Per-Interpreter GIL
که البته فعلا تو سطح پایتون نیست و python api نداره.
ولی این تغییر تو ۳.۱۳ خودشو خیلی بیشتر نشون میده. جایی که API python اش میاد. طبق PEP 554.
https://peps.python.org/pep-0554/
جایی که ما میتونیم حالا از این تغییراتی که تو ۳.۱۲ انجام شده و API پایتونیش تو ۳.۱۳ هست استفاده کنیم:)
اینکه چیه و چیکار میکنه تو این پست نمیگنجه. توصیه میکنم حتما این دو PEP رو وقت بذارین و بخونید که از بقیه جلوتر باشید تا وقتی ۳.۱۳ اومد بدونید چی باید یاد بگیرید 😁 فقط یک مقایسه میکنم بین sub Interpreter و مولتی پروسس
True Parallelism -> Multiprocess: YES | Subinterpreters: Potential
Isolation -> Multiprocess: HIGH | Subinterpreters: MEDIUM
Overhead -> Multiprocess: HIGH | Subinterpreters: LOW
و توی theory حداقل باید Subinterpreters یک مموری ایزوله و هندل CPU Bound task به صورت بهینه تر رو به ما بدن که باعث میشه پایتون با استفاده از این مفهوم جدید برای real-time processing و streaming data بسیار مناسب تر شه. چرا؟چون میتونید یک subinterpreter داشته باشید که دیتا رو بگیره و یک subinterpreter داشته باشید که دیتا رو پروسس کنه که این ایزوله سازی باعث استفاده بهتر و بهینه تر از ریسورستون میشه و latency رو هم کاهش میده
@ManiFoldsPython
Python Enhancement Proposals (PEPs)
PEP 554 – Multiple Interpreters in the Stdlib | peps.python.org
CPython has supported multiple interpreters in the same process (AKA “subinterpreters”) since version 1.5 (1997). The feature has been available via the C-API. [c-api] Multiple interpreters operate in relative isolation from one another, which facilit...
👍8
<خرافاتی و دروغ هایی که برنامه نویس ها بهش باور دارن>
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
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
Space Ninja
Falsehoods Programmers Believe
I'm in love with these lists of "Falsehoods Programmers Believe About…," so I've collected all the ones I know of here.
👍3😁2
https://www.sequoiacap.com/article/sebastian-ramirez-spotlight/
مصاحبه (زندگی نامه) سباستین رامیرز رو چند ساعت پیش خوندم و واقعا WOW!
شخصا این نکاتو حداقل برداشت کردم:
۱. برای موفق نشدن دلایل خیلی بیشتری داشت تا موفق شدن، ولی جا نزد!
۲. نشون میده شما مدرک دانشگاه نداشته باشید دنیا به اخر نمیرسه. سباستین حتی دیپلم هم نداره!
۳. به برنامه نویسی به عنوان درامد زایی نگاه نمیکرد بلکه لذت میبرد.
۴. خلاقیت و ترکیب و استفاده از برنامه نویسی برای حل چالش های شخصیش
۵. پافشاری رو اهدافش
حتماا بخونید توصیه میشه
@ManiFoldsPython
مصاحبه (زندگی نامه) سباستین رامیرز رو چند ساعت پیش خوندم و واقعا WOW!
شخصا این نکاتو حداقل برداشت کردم:
۱. برای موفق نشدن دلایل خیلی بیشتری داشت تا موفق شدن، ولی جا نزد!
۲. نشون میده شما مدرک دانشگاه نداشته باشید دنیا به اخر نمیرسه. سباستین حتی دیپلم هم نداره!
۳. به برنامه نویسی به عنوان درامد زایی نگاه نمیکرد بلکه لذت میبرد.
۴. خلاقیت و ترکیب و استفاده از برنامه نویسی برای حل چالش های شخصیش
۵. پافشاری رو اهدافش
حتماا بخونید توصیه میشه
@ManiFoldsPython
Sequoia Capital
Keeping an Open-Source Mind
Sebastián Ramírez is building open-source tools to make coding more accessible for anyone, anywhere.
👍18
یک تمپلیت SOLID ببینید از FastAPI
https://github.com/Tishka17/fastapi-template
خیلی حال کردم باهاش 👍
چند پروژه و معماری دیگه که اینا هم خوب بودن
https://github.com/iam-abbas/FastAPI-Production-Boilerplate
https://github.com/SamWarden/user_service
https://github.com/bomzheg/Shvatka
@ManiFoldsPython
https://github.com/Tishka17/fastapi-template
خیلی حال کردم باهاش 👍
چند پروژه و معماری دیگه که اینا هم خوب بودن
https://github.com/iam-abbas/FastAPI-Production-Boilerplate
https://github.com/SamWarden/user_service
https://github.com/bomzheg/Shvatka
@ManiFoldsPython
GitHub
GitHub - Tishka17/fastapi-template
Contribute to Tishka17/fastapi-template development by creating an account on GitHub.
👍6
آموزش ماگریشن نویسی با 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
آلمبیک یک 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
۱. لایه بندی و جدا سازی هر دیتابیس تو معماری 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
GitHub
GitHub - schireson/pytest-alembic: Pytest plugin to test alembic migrations (with default tests) and which enables you to write…
Pytest plugin to test alembic migrations (with default tests) and which enables you to write tests specific to your migrations. - schireson/pytest-alembic
👍6
Forwarded from TorhamDev | تورهام 😳
این دو روز داشتم رو این کار میکردم. کد چلنج یکی از شرکتها که براشون رزومه فرستاده بودم. یک سیستم خرید کریپتو. این طوری خریدها رو میگیره داخل ردیس ذخیره میکنه ایونت و رکورد خرید رو. بعد یک تسک هر چند وقت یکبار اجرا میشه و اون خریدها رو نهایی میکنه و ایونتش رو از ردیس پاک میکنه.
این روش درست پیاده سازی همچین چیزی نیست چون یک تایم (اینجا ۳۰ ثانیه) طول میکشه ک اون تسک نهایی کردن خریدها ران بشه. درستش پیاده سازی با آپاچی کاکفا و من چون بلد نبودم با سلری و ... زدمش :)
ستاره بدید خوشحال شم 🫠
https://github.com/TorhamDev/buy-cryptocurrency
این روش درست پیاده سازی همچین چیزی نیست چون یک تایم (اینجا ۳۰ ثانیه) طول میکشه ک اون تسک نهایی کردن خریدها ران بشه. درستش پیاده سازی با آپاچی کاکفا و من چون بلد نبودم با سلری و ... زدمش :)
ستاره بدید خوشحال شم 🫠
https://github.com/TorhamDev/buy-cryptocurrency
GitHub
GitHub - TorhamDev/buy-cryptocurrency: A simple cryptocurrency purchase system :)
A simple cryptocurrency purchase system :). Contribute to TorhamDev/buy-cryptocurrency development by creating an account on GitHub.
TorhamDev | تورهام 😳
این دو روز داشتم رو این کار میکردم. کد چلنج یکی از شرکتها که براشون رزومه فرستاده بودم. یک سیستم خرید کریپتو. این طوری خریدها رو میگیره داخل ردیس ذخیره میکنه ایونت و رکورد خرید رو. بعد یک تسک هر چند وقت یکبار اجرا میشه و اون خریدها رو نهایی میکنه و ایونتش…
چلنج این تسکی که به تورهام داده بودن رو خیلی دوست داشتم(صرافی کریپتو). برای همین خواستم ایراداتشو تکمیل کنم.
این ریپو رو تو ۴ ساعت کد زدم. که درواقع تمرکز رو EDD کردن بود با داینامیک کردن لاجیک بیزنس که کریپتو های جدید و api های جدید (جهت تحویل خودکار اوردر) و کلا فیچر های جدید خیلی راحت اضافه شن.
https://github.com/ManiMozaffar/edd-exchange
یک proto type برای دو سرویس exchange کریپو به سبک event driven هست
با ردیس استریم هم هندلش کردم که یکم ردیسم قوی تر شه.
نظرتون رو بگید راجب دیزاینش .
پ.ن: تست و ران و دیباگ نکردمش صرفا prototype بود جهت تمرین
@ManiFoldsPython
این ریپو رو تو ۴ ساعت کد زدم. که درواقع تمرکز رو EDD کردن بود با داینامیک کردن لاجیک بیزنس که کریپتو های جدید و api های جدید (جهت تحویل خودکار اوردر) و کلا فیچر های جدید خیلی راحت اضافه شن.
https://github.com/ManiMozaffar/edd-exchange
یک proto type برای دو سرویس exchange کریپو به سبک event driven هست
با ردیس استریم هم هندلش کردم که یکم ردیسم قوی تر شه.
نظرتون رو بگید راجب دیزاینش .
پ.ن: تست و ران و دیباگ نکردمش صرفا prototype بود جهت تمرین
@ManiFoldsPython
GitHub
GitHub - ManiMozaffar/edd-exchange: OOP Exchange EDD Service prototype with SOA pattern with dynamic feature integration
OOP Exchange EDD Service prototype with SOA pattern with dynamic feature integration - ManiMozaffar/edd-exchange
👍7👎2
یک پلاگین pytest نوشتم برای integration test که ممکنه به دردتون بخوره
تو اینتگریشن تست بعضا fixture هایی که استفاده میکنیم بسیار سنگین هستند. مثل مرورگر. برای ریست کردن اون fixture شما یک راه حلی که دارین اینه که اسکوپ تستون رو به فانکشن تغییر بدید که سر هر تست یک بار fixture تون مجدد نصب شه. ولی واقعا کاربردی نیست. چون fixture باید به اون استیت برسه دوباره که بتونه اون تست رو پرفوم کنه. مثلا میخواین چک ۱۰ تا اکشن تو یک صفحه view فرانتتون رو تست کنید. پس باید ۱۰ بار مروگر بالا بیارین و هر بار مرورگر بالا اوردن ۴ ثانیه طول میکشه. تستون ۴۰ ثانیه میشه فقط setup اش!
راه حل دوم چیه؟اینه که تو هر فایل شما کلی تست وابسطه به هم بنویسید. بعد با استفاده از پلاگین من اگه یکی از تستاتون fail شد بقیا تستای اون فایل رو xfail میکنه و اسکیپشون میکنه.
یعنی شما ۴ ثانیه یک مرورگر بالا میاری. بعد تو اون فایل واسه هر اکشن یک تست مینوسید. بعد مرورگر رو تو تست اول میبرین تو view ای که باید بره. بعد اکشن هارو تست میکنید. هرجایی هم fail شد مشکلی نداره دیباگ میکنیم فرانتو و دوباره تستو ران میکنیم. اینطوری ران تایم تست به شدت کاسته میشه.
البته این تو unit test اصلا توصیه نمیشه. تو unit test تو یک فایل نباید تستاتون به هم دیگه dependency داشته باشن.
کد پلاگین(تو conftest باید بره):
@ManiFoldsPython
تو اینتگریشن تست بعضا 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
خیلی ویدیو خوبیه
https://www.youtube.com/watch?v=OqcUrQnbulM
به عنوان developer حتما ببینید. رو فلسک pen test داره انجام میده
@ManiFoldsPython
https://www.youtube.com/watch?v=OqcUrQnbulM
به عنوان developer حتما ببینید. رو فلسک pen test داره انجام میده
@ManiFoldsPython
YouTube
HackTheBox Agile | Detailed Walkthrough
Hello again.
Another video to guide how to pwn Agile machine with Nima Dabbaghi From Nova Group.
!! Hope enjoy and dont forget to Subscribe !!
-------------------------------------------------------------------------
* SubDomain Enumeration
* CI/CD
* Flask…
Another video to guide how to pwn Agile machine with Nima Dabbaghi From Nova Group.
!! Hope enjoy and dont forget to Subscribe !!
-------------------------------------------------------------------------
* SubDomain Enumeration
* CI/CD
* Flask…
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
راجب معماری 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
GitHub
edd-exchange/shared/shared at main · ManiMozaffar/edd-exchange
OOP Exchange EDD Service prototype with SOA pattern with dynamic feature integration - ManiMozaffar/edd-exchange
👏6👍3
نکته دومی که رعایت شده و اکثرا میبینم بین دوستان کم تجربه تر رعایت نمیکنن استفاده از دیزاین پترنه!
اینکه دیزاین پترن رو بلد باشیم خوبه. ولی بلد بودن دیزاین پترن هیچ کمکی بهتون نمیکنه. صرفا قدرت خوانایی کدتون میره بالا. باید یاد بگیرید از کدوم دیزاین پترن کجا و چطوری باید استفاده کنید.
من تو کدم از strategy pattern و factory pattern به همراه interface استفاده کردم.
اینترفیس هام یا abstract بودن یا protocol بسته به سطح حساسیت interface و کلس هایی که باید از روش ساخته میشد. (اگه این جمله رو متوجه نشدین حتما این ویدیو رو ببینید)
من crypto و API Integration ام رو استراتژی پترن زدم. که البته با Enum هم یک مپر ساختم و هر کلسی که ساختم مپ کردم به یک Enum . مثلا کریپتو آبان و تتر تو این مثال:
بعد از همون enum ها برای ورودی API استفاده کردم به جای استرینگ. اینطوری ارتباطمو با تیم فرانت به حداقل ترین حالت ممکن رسوندم و تیم فرانت میتونه از json خود سواگر بیاد تمام دیفالت ها و enum ها و آپشن هارو بگیره. تو سطح API هم دیگه نیازی نیست ولیدیشن بنویسم چون دارم از enum استفاده میکنم.
بعد تو قسمت Currency که در واقع واحد های پول بود از پترن فکتوری استفاده کردم که راحت کارنسی جدید اضافه کنم.
در نتیجه با این دیزاین پترن هایی که استفاده کردم خیلی راحت میتونم یک API جدید اضافه کنم, یک currency جدید اضافه کنم, یک کریپتو حذف کنم یا اضافه کنم, و کاملا دستم بازه تو سمت لاجیک بیزنس.
@ManiFoldsPython
اینکه دیزاین پترن رو بلد باشیم خوبه. ولی بلد بودن دیزاین پترن هیچ کمکی بهتون نمیکنه. صرفا قدرت خوانایی کدتون میره بالا. باید یاد بگیرید از کدوم دیزاین پترن کجا و چطوری باید استفاده کنید.
من تو کدم از 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
YouTube
Protocol Or ABC In Python - When to Use Which One?
💡 Learn how to design great software in 7 steps: https://arjan.codes/designguide.
When should you use protocol classes vs abstract base classes? Here's an example where I use both, talk about the trade-offs, and give you a suggestion of when to use each…
When should you use protocol classes vs abstract base classes? Here's an example where I use both, talk about the trade-offs, and give you a suggestion of when to use each…
👍5🔥4
نهایتا API این شکلی شد
توی تسک اشاره شده برای مثال کریپتو آبآن پیاده سازی شه. و این یکم نکته داره.
چون که گفته شده برای مثال کریپتو آبان پیاده سازی شه دلیل نمیشه شما به داینامیک نبودن این دقت نکنید.
یا گفته شده فرض کنید صرافی سفارشات زیر ۱۰ دلار نمیگیره. (API Integration). چون گفته شده فرض کنید اینطوره دلیل نمیشه همه صرافی ها اینطور باشه.
موقع زدن تسک:
۱. به بیزنس لاجیک خیلی دقت کنید و سعی کنید داینامیک باشه
۲. تمام edge case هارو در نظر بگیرید.
۳. موقع دیزاین کردن اصلا به فرضیات دقت نکنید. موقع کد زدن به فرضیات بچسبید.
۴. .وقتتون رو سره چیزایی که ارزش گذاری نشده تو تسک تلف نکنید
@ManiFoldsPython
توی تسک اشاره شده برای مثال کریپتو آبآن پیاده سازی شه. و این یکم نکته داره.
چون که گفته شده برای مثال کریپتو آبان پیاده سازی شه دلیل نمیشه شما به داینامیک نبودن این دقت نکنید.
یا گفته شده فرض کنید صرافی سفارشات زیر ۱۰ دلار نمیگیره. (API Integration). چون گفته شده فرض کنید اینطوره دلیل نمیشه همه صرافی ها اینطور باشه.
موقع زدن تسک:
۱. به بیزنس لاجیک خیلی دقت کنید و سعی کنید داینامیک باشه
۲. تمام edge case هارو در نظر بگیرید.
۳. موقع دیزاین کردن اصلا به فرضیات دقت نکنید. موقع کد زدن به فرضیات بچسبید.
۴. .وقتتون رو سره چیزایی که ارزش گذاری نشده تو تسک تلف نکنید
@ManiFoldsPython
👍6
من این تسکو خیلی دوست داشتم ولی چیزی که اصلا دوست نداشتم راجب این تسک زمانش بود! این تسک فقط ۴۸ ساعت فرصت داشت که روی تست نویسی, سالید, معماری تمیز, کلین کد و داکرایز مانور رفته بود. همچنین جایی اشاره نشده بود که مثلا سیستم احراز هویت ننویسید یا فلان چیزو ننویسید که حجم تسک کمتر شه.
تو خود تسکم گفته شده بود <تراکنش کریپتویی یوزر باید بلافاصله انجام شه> که نشون میده دیزاین سیستم باید real time و event driven باشه.
من تو تجربه خودم با شرکت های خارجی تسک خیلی ساده تر میگرفتم و یک هفته هم زمان میدادن, که مشخصا وقت کافی بود برای پیاده سازیش تو یک هفته. ولی بعد پیاده سازی اصطلاحا مو رو از ماست میکشیدن 🙂
"The only way to go fast is to go well." - Uncle bob
@ManiFoldsPython
تو خود تسکم گفته شده بود <تراکنش کریپتویی یوزر باید بلافاصله انجام شه> که نشون میده دیزاین سیستم باید real time و event driven باشه.
من تو تجربه خودم با شرکت های خارجی تسک خیلی ساده تر میگرفتم و یک هفته هم زمان میدادن, که مشخصا وقت کافی بود برای پیاده سازیش تو یک هفته. ولی بعد پیاده سازی اصطلاحا مو رو از ماست میکشیدن 🙂
"The only way to go fast is to go well." - Uncle bob
@ManiFoldsPython
👏10❤3👍1
یک توصیه به دوستانی که دارن یادگیری fastapi/flask رو شروع میکنن:
خواهشا از tortoise استفاده نکنید. در مقابل sqlalchemy جوکه. استفاده از sqlalchemy باعث میشه کمی از سینتکس orm django فاصله بگیرین و SQLتون قوی تر شه. مخصوصا اگه از جنگو دارین شیفت میکنید احتمال خیلی زیاد پایه SQLتون ضعیفه و ابتدای کار دستتون کند باشه تو نوشتن query و دیباگش.
همینطور ORM کاملا shit عی هست. از تعداد ایشو هاش نسبت به ستارش فکر کنم مشخص باشه. پختگی و mature بودن sqlalchemy به کنار. من ۲ ماه تو مارکت آلمان و هلند دنبال کار بودم یک آگهی ندیدم نوشته باشه باید مسلط باشین رو tortoise orm. ولی تا دلتون بخواد sqlalchemy بود.
@ManiFoldsPython
خواهشا از tortoise استفاده نکنید. در مقابل sqlalchemy جوکه. استفاده از sqlalchemy باعث میشه کمی از سینتکس orm django فاصله بگیرین و SQLتون قوی تر شه. مخصوصا اگه از جنگو دارین شیفت میکنید احتمال خیلی زیاد پایه SQLتون ضعیفه و ابتدای کار دستتون کند باشه تو نوشتن query و دیباگش.
همینطور ORM کاملا shit عی هست. از تعداد ایشو هاش نسبت به ستارش فکر کنم مشخص باشه. پختگی و mature بودن sqlalchemy به کنار. من ۲ ماه تو مارکت آلمان و هلند دنبال کار بودم یک آگهی ندیدم نوشته باشه باید مسلط باشین رو tortoise orm. ولی تا دلتون بخواد sqlalchemy بود.
@ManiFoldsPython
👍26