pybackendhub | Unsorted

Telegram-канал pybackendhub - Python BackendHub

-

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 لینک گروه: https://t.me/PythonFellow

Subscribe to a channel

Python BackendHub

آنچه خواهید دید

@BenDevelop

Читать полностью…

Python BackendHub

من تازه فهمیدم که میشه تو sqlalchemy با انجین هم transaction باز کرد. و حتی یک سری متود هایی که Session داره رو نداره. مثل add. همه متود هایی که رفتار عجیب غریب و ORM طور اضافه میکردن به sqlalchemy
حالا کنجکاو شدم بدونم ایا انجین sqlalchemy اون رفتار های implicit سشن رو داره یا نه؟ با توجه به اینترفیسش بنظر نمیاد داشته باشه. ولی هیچی بعید نیست از sqlalchemy 😅

@PyBackendHub

Читать полностью…

Python BackendHub

Unpopular opinion

خیلی دیدم جامعه رو <سخت کار کردن> مانور رفته. سخت کار کن. موفق میشی. و ...
ولی حقیقتا اصلا مهم نیست چقدر سخت کار میکنید. مهم خروجیه. ممکنه من ۷ صبح کار کنم تا ۷ شب. ولی خروجیم کمتر از کسی باشه که ۱۱ صبح کار میکنه تا ۴.

پس مهم نیست چقدر سخت کار میکنی. مهم اینه که کارآمد و بهینه کار میکنی.
@PyBackendHub

Читать полностью…

Python BackendHub

Monad چیه؟

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

What is a Monad? A monad is an algebraic structure in category theory, and in Haskell it is used to describe computations as sequences of steps, and to handle side effects such as state and IO. Monads are abstract, and they have many useful concrete instances. Monads provide a way to structure a program.

یک مقاله قشنگ که تو پایتون این پترن رو پیاده کرده

https://dev.to/hamzzak/mastering-monad-design-patterns-simplify-your-python-code-and-boost-efficiency-kal

@PyBackendHub

Читать полностью…

Python BackendHub

نمیدونم چرا ولی روند توسعه یک فیچر ۹۹درصد مواقع اینطوریه که شما اول under engineer میکنی. همه یوزکیس هارو کاور نمیکنی. بعدش اورانجینر میکنی. یک سیستم پیچیده تحویل میدی، که maintain اش یکم سخت تره. و باره سوم، درست انجامش میدی 😁

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

@PyBackendHub

Читать полностью…

Python BackendHub

این شاید مهم ترین پست sqlalchemy بود که تا امروز گذاشتم (و خواهم گذاشت). 👆

Читать полностью…

Python BackendHub

مشکل روتر درست شد. فقط یک مشکل ریز داشت اونم این بود که وای فای تقریبا هر ۲-۳ دقیقه یک بار قطع میشه و یک bash script نوشتم که اگه قطع بود وای فای سعی کنه دوباره وصل شه :))

@PyBackendHub

Читать полностью…

Python BackendHub

#توصیه
وقتی دارین از SQLAlchemy استفاده میکنید و دارین یک چیزی سلکت میکنید
بهتره select from رو بنویسید
چون امروز یک ساعت درگیر یک باگی‌بودم، که یک آبجکت cte نسبتا پیچیده چند بار استفاده شده بود، و تو یکی از این دفعات sqlalchemy نمیتونست به درستی متوجه شه رو کدوم مدل باید سلکت from کنه (مدل اشتباهی رو داشت سلکت میکرد) با وجود اینکه فقط یک چیزو داشتم سلکت میکردم.
یعنی به جای
sa.select(Model)
بنویسید
sa.select(Model).select_from(Model)

کلا هرچی لاجیک compile کوئری رو بیرون تر بکشید و explicit تر باشه و به خوده SQL نزدیک تر باشه، بهتره، خیلی edge case وجود داره همیشه.

@PyBackendHub

Читать полностью…

Python BackendHub

Correlation is not causation
اشتباهی که به عنوان انسان و برنامه نویس زیاد انجام میدیم

تو این سایت همش رو نوشته. تازه نکته جالب اینجاست که خیلیاش ریسرچ و پیپیره.
https://www.tylervigen.com/spurious-correlations

@PyBackendHub

Читать полностью…

Python BackendHub

اما جوابش:
بحث ساب تایپ تو پایتونه (چه تو mypy چه تو pyright). که دو روش وجود داره
nominal typing
و
structural typing
وقتی من تو پایتون مینویسم
var = 2
طبق nominal typing خود تایپ چکر میفهمه تایپ var درواقع int هست. (یا حتی دقیقتر Literal 2)
و همیشه nominal به صورت strict بر پایه class hierarchy هست. و غلبه میکنه به structural type به شرطی که تو hierarchy tree اش اون تایپ رو داشته باشه. اگه نداشته باشه ارور میده (تو عکس ببین bar دقیقا همین کیسه)

برای همین شما بنویسی:
foo: int = 2

درواقع تایپ چکر به شما میگه تایپ foo اینت نیست. بلکه Literal 2 هست. تایپ چکر هم ایرادی به شما نمیگیره چون میگه int درواقع Literal 2 رو satisfy میکنه. ولی برعکسش درست نیست. یعنی ساده تر بگم literal 2 همیشه int هست. ولی int همیشه literal 2 نیست.

این موضوع رو تو عکس واضح تر نشون دادم با ۲ تایپی که خودم ساختم.

این رفتار که ایا این دو تایپینگ باید باشن یا فقط یکیش باشه یا چطوری هم دیگه رو satisfy میکنن ممکنه تو زبونا ممکنه فرق کنه ولی کانسپت language design هست.
@PyBackendHub

Читать полностью…

Python BackendHub

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

@PyBackendHub

Читать полностью…

Python BackendHub

اینم برای reproduce کردنش.

@PyBackendHub

Читать полностью…

Python BackendHub

کدو اول توضیح میدم چون خیلیا درک نکردن, این کد درواقع داره اینکارو میکنه
SELECT 1

شما وقتی تو sqlalchemy چیزی رو سلکت میکنی خودکار تبدیل به تاپلی از اون چیز میشه. مثلا من اگه 1 رو سلکت کنم میشه Select[Tuple[int]]
پس درواقع تایپ چیزی که دو تا فانکشن دارن ریترن میکنن تاپلی هست که فقط یک int هست.
ولی تو من signature فانکشن گفتم تاپلی از string عه. که خب تایپ اشتباهه.

حالا برگردیم به باگ:
تو فانکشن اول که correct هست تایپ چکر داره این موضوعو به من نشون میده. چون من گفتم q = ... و بعد q رو ریترن کردم.
ولی وقتی خوده فانکشن رو ریترن میکنم مستقیما تایپ چکر تشخیص نمیده. که خیلیی باگ عجیبیه 😂

@PyBackendHub

Читать полностью…

Python BackendHub

کسایی از chatgpt یک سوال میپرسن، یا یک کدی از استک اورفلو کپی پیست میکنن، توضیه میکنم بهشون حتما این مقاله زیر رو بخونید.
https://archive.ph/jRvwx

خلاصه بخوام بگم، کدشون رو داشتن از تایپ اسکریپت میبردن پایتون. مدل های دیتابیس رو دادن chatgpt از پریسما تبدیلش کنه به sqlalchemy. این وسط chatgpt برای یکی از مدل ها برای id مدل، به جای اینکه از دیفالت فکتوری استفاده کنه، از دیفالت استفاده میکرد. و اینطوری بود که اون مدل هروقت instance ای ازش ساخته میشد آیدی تکراری میشد. و دیتابیس ارور میداد. و این باگ باعث ضرر ۱۰ هزار دلاری به این شرکت شد. صرفا برای اینکه یکی‌نمیدونست دیتاکلس توپایتون چطور کار میکنه و به جای خوندن داک از chatgpt پرسید 🙂

@PyBackendHub

Читать полностью…

Python BackendHub

نسخه بعدی aioclock منتشر شد 👀

تغییرات این نسخه:
اضافه شدن تریگر Cron - با سینتکس cron میتونید راحت تریگر بنویسید.

اضافه شدن OrTrigger - میتونید تریگری بنویسید که شامل تریگر های دیگه میشه و هرکدوم زودتر نوبتشون شد اجرا میشن.

داکیومنت
گیتهاب

ممنون میشم استار بدید یا contribute کنید.

@PyBackendHub

Читать полностью…

Python BackendHub

یک پست خیلی خوب از بنیامین تو گروه👌

یه مقاله ای دیدم
https://dev.to/stripe/common-design-patterns-at-stripe-1hb4
که نویسندش توسعه دهنده توی استرایپه

4 بخشه و نکاتی رو در مورد توسعه API میگه که به نظرم خوندنش خالی از لطف نیست. بخش مهم ترش به نظرم بخش آخره.

یه قسمتش یه حرفی رو میزنه:
Prefer enums over booleans

و میگه وقتی شما یه چیزی رو میخواید با مقدار bool بذارید مثلا:

Subscription.canceled={true, false}

ممکنه پس فردا نیاز به یه چیز دیگه داشته باشید و یه فیلد دیگه به API اضافه کنید:
Subscription.canceled={true, false}
Subscription.paused={true, false}

میگه به جای این کار، بهتره بیاید از enum استفاده کنید:
Subscription.status={"active", "canceled"}


که پس فردا اگه به جز canceled وضعیت دیگه ای هم داشتید، نیاز به تغییر اونطوری نباشه.
Subscription.status={"active", "canceled", "paused"}


دوست دارم نظر شما رو هم در مورد این کار بدونم که این کار، کار خوبیه یا باید بیشتر روش فکر کرد..؟

با همین فرمون میگه کلی boolean رو میشه جا به جا کرد
post.published = true, false
post.status = PUBLISHED, NOT_PUBLISHED

و یا
product.in_stock = true, false
product.availability = IN_STOCK, OUT_OF_STOCK



@PyBackendHub

Читать полностью…

Python BackendHub

ولی یک فکتی رو هم در نظر بگیرین, که شیب خروجی با حقوقتون ۱ نیست. یعنی چی؟

یعنی بیاین تصور کنیم که من ساعتی n دلار میگیرم.و در روز ۴ ساعت کار میکنم. و بیایم تصور کنیم من هر ساعت بیشتر کار کنم به همون میزان خروجیم هم بیشتره (تو بهترین حالت ممکن).

بنابراین درآمد من در روز باید 4n باشه اگه ۴ ساعت کار کنم.
و 8n باشه اگه ۸ ساعت کار کنم.
و 10n باشه اگه ۱۰ ساعت کار کنم.
ولی تو واقعیت اینطوری نیست. وقتی شما خروجی بیشتری دارین,اونوقت پروموشن میگیرید. این پروموشن رو کل حقوقتون تاثیر میذاره. بعد اینطوری تو ۱۰ ساعت به جای 10n حقوقه من میشه 16n.

یک نکته دیگه هم بنظرم خیلی مهمه تو پروموشن گرفتن و این حالت.
اینکه شما اگه یک وظیفه رو به بهترین حالت ممکن انجام بدید, پروموشن نمیگیرین. (یا خیلی نمیگیرین). چون صرفا دارین کارتونو انجام میدید. ولی اگه چند وظیفه که حتی خارج از وظایف خودتونه انجام بدید و ownership اشو دستتون بگیرین خیلی پروموشن بیشتری میگیرین. چون دارین چند تا کار انجام میدین. و جا به جا کردن شما با یک نفر دیگه تقریبا خیلی سخت و پر هزینه میشه. و نیازی هم ندارین اون وظایف رو پرفکت انجام بدید. به حد کافی (و در حد انتظار) خوب انجام بدید کافیه.

@PyBackendHub

Читать полностью…

Python BackendHub

دلیل ناکافی بودن unit test به تنهایی:

@PyBackendHub

Читать полностью…

Python BackendHub

توییت آخر امروز 😁

قبلا فکر میکردم مصاحبه هایی هست که میرم توش و مشکل شرکت رو میذارن جلوم و صرفا هدفشون <حل کردن مشکله>. ولی الان که فکر میکنم بهش امکان نداره همچین چیزی. صرفا یک مشکل خیلی ساده بود که خودشون قطعا حل کرده بودن. یا خیلی ساده حلش میکردن خودشون.
چون فکر کنید بهش: شما یک مشکلی دارین. یک نفر از بیرون میاد و تو ۲۰ دقیقه بهش توضیح میدین و میخواین تو ۱-۲ ساعت براتون حل کنه. بدون اینکه هیچ context ای از نرم افزار شما داشته باشه. سولوشنی که طرف میده هم پرفکت سولوشنه و تمام مشکلاتشونو حل میکنه.
اگه واقعا همچین سناریویی رخ بده خب اون مشکل خیلی احمقانست 😅 یا اینکه یک سری دوره هم جمع شدن که هیچ کدومشون اصلا نمیدونن چیکار دارن میکنن. که ۹۹ درصد مواقع بنظرم این نیست. صرفا سوء برداشت شماست.

@PyBackendHub

Читать полностью…

Python BackendHub

ادامه پست دیروز
من یک سری فکت های خیلی ترسناک امروز راجب sqlalchemy پیدا کردم....

ببینید ما یک آبجکت session داریم که session maker میاد. (یا session factory). که درواقع کانکشن پول این آبجکت رو میسازه و به ما میده. این Session نسبت به همه آبجکت هایی که از query میاد آگاهه. و آبجکت هارو به صورت خیلی implicit داره mutate میکنه.

مثلا مثال زیر رو در نظر بگیرین. من یک کانکشن باز کردم به دیتابیس. یک یوزر گرفتم. name رو گذاشتم مانی. بعد یک transaction زدم. به session این transaction گفتم که user رو track کن. همون یوزر, اسمش رو تغییر دادم به عباس.
حالا اگه transaction رو من بیام rollback کنم sqlalchemy به صورت خودکار میاد اون تغییری که من دادم رو تو سطح memory میاد revert میکنه. یعنی الان پراپرتی name یوزر مانیه!


async with session_maker() as session:
query = sa.select(User).where(User.id == 1).limit(1)
user = await session.scalar(query)
user.name = "Mani"
async with session.begin() as transaction:
transaction.add(user)
user.name = "Abbas"
await transaction.rollback()
print(user.name) # This is mani! not abbas 🙂


چطوری اینکارو انجام میده؟ از آبجکت قبل از اینکه بره تو transaction داره snapshot میگیره. و اگه transaction به هر دلیلی rollback شه این snapshot رو ریکاور میکنه. یعنی درواقع داره رفتار rollback رو تو لایه مموری پایتون شبیه سازی میکنه 🤦‍♂️
WHAT THE FUCK
یک عمر فکر میکردم میشد با sqlalchemy جوری کد زد که همه چی explicit باشه. ولی ظاهرا توهمی بیش نبوده.

البته همه اینا قابل فیکسه. کل این رفتار های عجیب و غریب از Session نشات میگیره.و هیچ کدومش هم قابل تنظیم نیست. احتمالا یک لایبری بنویسم یک آبجکت Session ای بسازم که هیچ ساید افکت implicit و رفتار عجیب غریبی نداشته باشه.

@PyBackendHub

Читать полностью…

Python BackendHub

یکی از دلایلی که از ORM بدم میاد اینه که خیلی وقتا خیلی implicit میشه. و یکی از دلایلی که خوشم میاد از SQLAlchemy اینه که نسبت به ORM های دیگه تا حد زیادی میشه ازش به عنوان query builder استفاده کرد با کمی چاشنی orm. که همون چاشنی یک وقتا مشکل ایجاد میکنه :)) وقتی دارین با SQLAlchemy کار میکنید باید حواستون باشه به state آبجکت. یعنی چی؟


async with session_maker.begin() as transaction:
query = sa.select(User).where(User.id == 1).limit(1)
user = await session.scalar(query)
user.name = "Mani"
await transaction.rollback()

print(user.name) # Mani ?

وقتی دارم آبجکت ORM رو mutate میکنم و بعد session رو فلاش میکنم درواقع میاد یک query میزنه و فقط اون تغییری که دادم رو تو دیتابیس اعمال میکنه. (به این کار میگن dirty tracking و تو orm های دیگه مثل جنگو میاد کل state آبجکت رو اعمال میکنه تو دیتابیس. نمیاد بگه فقط name رو تغییر بده).

اولین مشکل اینجاست که وقتی به پراپرتی name تو خط آخر برای user دارم دسترسی پیدا میکنم, ران تایم ارور میخورم. خوده sqlalchemy یک ستینگی داره که آبجکت هارو وقتی session بسته میشه expire میکنه. این expire کردن یعنی دیگه اون آبجکت اون property رو نداره. که البته میشه گفت expire_on_commit=False. یعنی اگه من کامیت کردم شما این آبجکت رو اکسپایر نکن. دیگه نباید ران تایم ارور بخورم.
اما نه , همچنان ران تایم ارور میخورم. چرا؟ چون rollback دارم میکنم transaction رو. درواقع ستینگی وجود نداره تو sqlalchemy که بگه expire_on_rollback. اگه رول بک نمیکردم مشکلی نداشت.
این دقیقا برعکس کانسپت type stateعه. تایپینگ داره به من میگه مشکلی نداره از این پراپرتی استفاده کنی. ولی ران تایم یک جور دیگه داره به من میگه.

که خیلیم منطقیه! چون شما فکر کنید من دارم میگم name رو بذار Mani. بعد بهش میگم رول بک کن. خب طبیعتا تو دیتابیس name دیگه mani نیست. نیم همون چیزیه که قبل از مانی بوده. پس تو درستی رفتارش شکی نیست. ولی با یک جمله موافقم
ORM is conceptually wrong
چرا اینقدر پیچیده کردم سناریو رو؟ و تبدیلش کردم به یک محیط implicit که درک و دیباگش اینقدر سخته؟ چرا نمیشد سادش کرد و آپدیت کردن state آبجکت رو گذاشت به عهده برنامه نویس؟ چرا اصلا یک دیتاکلس باید استیت داشته باشه؟

راه حل خودم چیه؟ راه حل خیلی منطقی ندارم ولی:
۱. سعی میکنم هیچوقت آبجکتی رو mutate نکنم. به جاش یک query میزنم که هم UPDATE کنه و هم RETURNING میکنم با خوده SQL آبجکت جدید رو.
۲. خوده transaction یک متودی داره به اسم expunge_all(). من begin رو overwrite کردم و اونو همیشه صدا زدم. اینطوری بهم گارانتی میده که اون آبجکت همیشه قابل دسترسیه. متاسفانه تنظیماتی نداره sqlalchemy که همیشه بای دیفالت اینکارو انجام بده. ولی میتونید اون کانتکس منیجر رو اوررایت کنید که همیشه اون expunge انجام شه.




@asynccontextmanager
async def my_begin(session_maker):
async with session_maker() as transaction:
try:
yield transaction
except Exception as exc:
transaction.expunge_all()
raise exc

async with my_begin() as transaction:
query = sa.select(User).where(User.id == 1).limit(1)
user = await session.scalar(query)
user = sa.update(User).where(User.id == user.id).values({User.name: "Mani"}).returning(User)
await transaction.rollback()

print(user.name) # No runtime issue -> Mani


@PyBackendHub

Читать полностью…

Python BackendHub

چهار روزه تو خونه نت ندارم، نت گوشیم کار میکنه، که خب شارژ گوشیم تموم میشه و فقط تو بالکن آنتن میده، برای همین دو سوم تایمی که میخوام کد بزنم نه استک اورفلویی هست نه داکیومنت آنلاینی نه گوگلی 😂

اولش سخت بود مخصوصا برای من که زیاد سرچ میکنم، ولی الان عادت کردم خیلی بهتر شده و دستم سریعتر شده :))

@PyBackendHub

Читать полностью…

Python BackendHub

برخی از مطالبی که در خصوص رزومه نویسی تهیه کردم

دوره رزومه نویسی و رشد در مسیر شغلی

چند درصد آگهی رو خوب بلدیم رزومه بفرستیم؟‌راهنما عملکرد بهتر در مصاحبه ها

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

ریپازیتوری آموزش رزومه نویسی با بیش از ۲۰۰ استار

معرفی ریسورس برای مصاحبه و بهتر کردن رزومه

@PyBackendHub

Читать полностью…

Python BackendHub

Same question, different places 😂
@PyBackendHub

Читать полностью…

Python BackendHub

بنظره من دونستن type interface خیلی به دانش شما کمک میکنه و تو نحوه کد زدتون تاثیر میذاره وقتی شروع میکنید بهش فکر میکنید.

حالا quiz امروز:‌ این جفت variable ها درواقع تایپ annotation اشون یکیه. جفتشون Mapping[str,str] هستن. بنظرتون pylance (یا pyright که میشه تایپ چکر vscode من) چطور تشخیص میده که بالایی mutable هست ولی پایینی mutable نیست؟

هینت:‌این سوال لزوما مربوط به پایتون نمیشه. یک قاعده کلی تو کامپیوتر ساینس هست.
@PyBackendHub

Читать полностью…

Python BackendHub

مصاحبه فنی سنیور با مانی

@BenDevelop
@PyBackendHub


https://www.youtube.com/watch?v=rh3acuXS3xw&amp;t=633s

Читать полностью…

Python BackendHub

ایشو زده بودم تو pyright درواقع فهمیدم که باگ نیست. درواقع دیزاین اینطوریه.
ما روش های مختلفی برای resolve کردن تایپینگ داریم. طوری که pyright کار میکنه bidirectional type inference هست. یعنی چی؟
Constructors are typed by inheritance, and so the name is available when resolving the constructor, whereas variables are typed by synthesis, and so each variable must have a unique type.

دقیقا اتفاقی که تو select افتاده . تو sqlalchemy سلکت ۹ تا اورلود داره. یعنی برای ۹ اینپوت مختلف, تایپینگ مختلف داره.
یکی از این overload ها درواقع داره تایپینگ رو satisfy میکنه. یعنی این مسیر رو برعکس میره. درواقع داره چک میکنه که آیا Select[tuple[str]] با تایپ ریترن شده از اون فانکشن satisfy میشه یا نه. و چون یکی از این اورلود ها این satisfy میکنه بنابراین تایپ چکر ارور نمیده.

ولی وقتی assign اش میکنی به یک مقدار و بعد اون مقدار رو ریترن میکنی دیگه نمیره با همه constructor ها (که میشن همون overload ها) چک کنه تایپ satisfy میشه یا نه. داره دو تا تایپ رو باهم مقایسه میکنه.

پس هر موقع شما یک constructor داشتین که بر اساس ورودی ممکن بود تایپ های مختلف بده, باید حواستون باشه که حتما assign اش کنید به یک مقدار تا bidirectional نشه.

@PyBackendHub

Читать полностью…

Python BackendHub

یک باگ خیلی عجیب
فهمیدین چیه؟
@PyBackendHub

Читать полностью…

Python BackendHub

اگه از FastAPI استفاده می‌کنید و سعی دارید MVP بیارید بالا (درحدی که منابع زیادی مورد نیاز نباشه) پلتفورم‌های زیر Free Trial دارن و بدون پرداخت می‌تونید سرویس بک‌اندتون رو روشون بالا بیارید. داکیومنت و بلاگ هم در دسترس هست کافیه سرچ کنید.


1️⃣ - https://render.com/

2️⃣ - https://www.cyclic.sh/

3️⃣ - https://fly.io/

4️⃣ - https://leapcell.io/

5️⃣ - https://vercel.com/

Читать полностью…

Python BackendHub

نسخه جدید aioclock هم منتشر شد 🔥

تغییرات این نسخه:
- اضافه شدن پشتیبانی برای تسک های sync . هر فانکشن sync توسط aioclock تو تردپول با anyio ران میشه. ولی این رو خوده فانکشنی که دکوریت کردین تاثیر نمیذاره و تبدیل به کوروتین نمیشه و همونطور که استفاده کردین میتونید انجام بدید.

- بهتر شدن داکیومنت. همراه با پشتیبانی از چند نسخه


داکیومنت
گیتهاب

ممنون میشم استار بدید یا contribute کنید.

@PyBackendHub

Читать полностью…
Subscribe to a channel