Syntax | سینتکس @syntax_fa Channel on Telegram

Syntax | سینتکس

@syntax_fa


Focus: Web
Lan: Python & Go

Group:
https://t.me/Syntax_fa_group

Syntax | سینتکس (Persian)

با کانال سینتکس آشنا شوید وارد دنیای جذاب توسعه نرم افزار شوید. این کانال به منظور ارائه اطلاعات و محتوای مفید در زمینه توسعه وب برای مهندسین نرم افزار در زبانهای Python و Go تاسیس شده است. در اینجا شما می توانید از تجربیات و دانش تخصصی توسعه دهندگان حرفه ای در این حوزه بهره ببرید و به روزرسانی های جدید در دنیای توسعه نرم افزار دسترسی پیدا کنید. کانال سینتکس یک جامعه آموزشی برای اشتراک تجربیات و ایده های نوین در زمینه توسعه وب است. اگر علاقه‌مند به افزودن ابزارهای جدید به دسته‌بندی سبز خود هستید، حتما به این کانال بپیوندید. علاوه بحض وبینار‌های آموزشی، گروه تلگرامی معتبری نیز برای بحث و گفتگو در این حوزه وجود دارد. برای استفاده از این امکان به لینک گروه زیر مراجعه کنید: https://t.me/Syntax_fa_group

Syntax | سینتکس

11 Jan, 06:30


داکیومنت داکر اینو میگه:
internal
By default, Compose provides external connectivity to networks. internal, when set to true, lets you create an externally isolated network.


برای حل این مسئله، می‌توانیم از شبکه‌های داخلی (internal network) در Docker Compose استفاده کنیم. شبکه داخلی یک شبکه‌ای است که داکر فراهم می‌کند و ارتباط سرویس‌ها فقط در داخل همان شبکه امکان‌پذیر است. به این ترتیب، سرویس‌ها کاملاً ایزوله می‌شوند و هیچ ارتباطی با خارج از شبکه داکر (مانند هاست یا اینترنت) برقرار نمی‌کنند، حتی اگر به اشتباه پورت‌هایی در فایل Compose تعریف شود.

1. ایجاد شبکه داخلی در فایل `docker-compose.yml`:

در فایل Docker Compose، می‌توانید یک شبکه داخلی تعریف کنید. در این شبکه، سرویس‌ها فقط می‌توانند با یکدیگر ارتباط برقرار کنند و هیچ ارتباطی با شبکه هاست یا اینترنت ندارند.

مثال:

   version: '3.9'
services:
service1:
image: my-image-1
networks:
- internal_network
service2:
image: my-image-2
networks:
- internal_network

networks:
internal_network:
internal: true


توضیحات:
- در بخش networks`، یک شبکه به نام `internal_network تعریف شده و ویژگی internal: true به آن اضافه شده است.
- این شبکه فقط برای ارتباط داخلی بین سرویس‌های تعریف‌شده در Docker Compose در دسترس است.
- هیچ پورت خارجی (حتی اگر در بخش ports تعریف شده باشد) از خارج شبکه داکر قابل دسترسی نخواهد بود.

#docker #docker_compose

@Syntax_fa

Syntax | سینتکس

11 Jan, 06:15


سوال درباره داکر و داکر کمپوز

سوال:

فرض کنید ما چند سرویس داریم که در یک پروژه با استفاده از Docker Compose مدیریت می‌شوند. این سرویس‌ها نیازی به ارتباط با خارج از شبکه داخلی داکر (مانند شبکه هاست یا اینترنت) ندارند و فقط باید به‌صورت داخلی با یکدیگر ارتباط برقرار کنند. حتی اگر به اشتباه پورت‌هایی برای آن‌ها در فایل Docker Compose تعریف شود (مانند ports)، نباید این پورت‌ها از بیرون شبکه داکر در دسترس باشند.

چگونه می‌توانیم چنین محدودیتی اعمال کنیم و اطمینان حاصل کنیم که سرویس‌ها کاملاً ایزوله هستند و فقط در شبکه داخلی داکر قابل دسترسی‌اند؟
(جواب و راه حلی پیشنهادی پست بعدی گذاشته میشه)

#docker #docker_compose

@Syntax_fa

Syntax | سینتکس

10 Jan, 06:57


چند نکته درباره Dockerfile

۱. بدون دسترسی روت:
- اجرای کانتینر با کاربر غیر روت برای امنیت بیشتر

۲. ساخت چند مرحله‌ای (Multistage Build):
- کاهش حجم نهایی ایمیج
- جداسازی محیط build از محیط اجرا
مثال:
FROM golang:1.23 AS build
WORKDIR /src
COPY main.go .
RUN go build -o /bin/hello ./main.go

FROM scratch
COPY --from=build /bin/hello /bin/hello

CMD ["/bin/hello"]


۳. استفاده از Distroless یا From Scratch:
- حذف ابزارهای غیرضروری برای کاهش سطح حمله
- استفاده از ایمیج‌های پایه حداقلی
مثال:
FROM gcr.io/distroless/nodejs
COPY --from=builder /app/dist .
CMD ["app.js"]


۴. استفاده از ایمیج‌های مطمئن:
- استفاده از ایمیج‌های رسمی از Docker Hub
- بررسی منبع و تاریخچه ایمیج‌ها

۵. به‌روزرسانی منظم ایمیج:
- به‌روزرسانی مرتب پایه ایمیج برای دریافت پچ‌های امنیتی
- استفاده از CI/CD برای ساخت خودکار ایمیج‌های جدید

۶. پورت‌های در معرض (Exposed Ports):
- فقط پورت‌های ضروری را expose کنید
- مستندسازی پورت‌های مورد نیاز
مثال:
EXPOSE 8080


۷. عدم قرار دادن کلیدها و رمزها در Dockerfile
- استفاده از secrets یا متغیرهای محیطی
مثال:
# bad idea
ENV DB_PASSWORD=secretpass

# recommended
ARG DB_PASSWORD


۸. مدیریت لایه‌ها (Layer Sanity):
- ترکیب دستورات مرتبط برای کاهش تعداد لایه‌ها
- حذف فایل‌های موقت در همان لایه
مثال:
RUN apt-get update && \
apt-get install -y package1 package2 && \
rm -rf /var/lib/apt/lists/*


۹. برچسب‌های متادیتا:
- افزودن اطلاعات مفید درباره ایمیج
مثال:
LABEL maintainer="[email protected]"
LABEL version="1.0"
LABEL description="Application description"


نکات تکمیلی:
- همیشه از .dockerignore برای ایگنور شدن فایل‌های غیرضروری استفاده کنید
- دستورات را به ترتیب بهینه قرار دهید (از کمترین تغییر به بیشترین)
- از کش Docker به درستی استفاده کنید

#docker

@Syntax_fa

Syntax | سینتکس

09 Jan, 07:30


این ویدیو از آتیش سوزی لس آنجلس رو اگه از یه کانال اطلاع رسانی بازی میدیدیم فک میکردم با آنریل انجین برای سری جدید Resident Evil ساختن

@normal_developer

Syntax | سینتکس

06 Jan, 00:01


در وینوز خبیث چگونه داکر که یک linux container هستش اجرا میشه؟

قبل از 2016:

در ابتدا، Docker فقط برای Linux طراحی شده بود و روی Windows قابل اجرا نبود🫠. در آن زمان، توسعه‌دهندگان Windows برای استفاده از Docker مجبور بودند:
1. یا از یک ماشین مجازی Linux جداگانه استفاده کنند
2. یا از ابزارهایی مثل VirtualBox استفاده کنند
3. یا تصمیم عاقلانه میگرفتن لینوکسی میشدن

2016 - معرفی Docker for Windows:
در سال 2016، Docker یک راهکار رسمی برای Windows ارائه کرد که شامل دو بخش اصلی بود:

1. Docker Desktop for Windows:
- یک نرم‌افزار یکپارچه که شامل تمام اجزای مورد نیاز برای اجرای Docker بود
- از Hyper-V (مجازی‌ساز رسمی Microsoft) استفاده می‌کرد
- یک Moby VM (ماشین مجازی سبک Linux) را به صورت خودکار مدیریت می‌کرد

2. معماری دو لایه:
- لایه Windows: شامل Docker Client که رابط کاربری و CLI را در اختیار کاربر قرار می‌داد
- لایه Linux (Moby VM): شامل Docker Daemon که مسئول اصلی مدیریت کانتینرها بود

نحوه کار:
1. کاربر در Windows دستورات Docker را اجرا می‌کند
2. Docker Client
این دستورات را به Moby VM منتقل می‌کند
3. Docker Daemon
در Moby VM دستورات را پردازش کرده و کانتینرها را مدیریت می‌کند
4. تمام کانتینرهای Linux در این VM اجرا می‌شوند و از kernel آن استفاده می‌کنند

مزایای این معماری:
- کانتینرهای Linux دقیقاً مثل Linux اصلی کار می‌کنند
- مدیریت منابع بهتر و کارایی بالاتر نسبت به استفاده از VirtualBox
- یکپارچگی بهتر با Windows
- نصب و راه‌اندازی ساده‌تر

تغییرات بعدی:
بعد از 2016، Docker قابلیت‌های جدیدی اضافه کرد:
1. Windows Containers:
امکان اجرای کانتینرهای native ویندوزی
2. WSL2 Integration:
یکپارچگی با Windows Subsystem for Linux نسخه 2
3. Hyper-V Isolation:
لایه امنیتی اضافه برای جداسازی بهتر کانتینرها

در نمودار بالا هم دقیقاً همین معماری نشان داده شده:
- سمت چپ: محیط Windows که Docker Client در آن قرار دارد
- سمت راست: Moby VM که Docker Daemon و کانتینرهای Linux را میزبانی می‌کند
- ارتباط بین این دو از طریق یک پروتکل شبکه انجام می‌شود

توضیحات مایکروسافت خبیث

#docker

@Syntax_fa

Syntax | سینتکس

05 Jan, 16:07


توی پایتون بجای isinstance از singledispatch استفاده کن!

۱. ابتدا دو کلاس با استفاده از @dataclass تعریف میکنیم:
@dataclass
class UserCanceledSubscription:
username: str

@dataclass
class UserSubscribed:
username: str

این‌ها دو نوع ایونت هستند: یکی برای زمانی که کاربر مشترک می‌شود و دیگری برای زمانی که اشتراکش را لغو می‌کند.

۲. روش اول با استفاده از isinstance:
def process(event):
if isinstance(event, UserSubscribed):
print(f"Enable access to user {event.username}")
elif isinstance(event, UserCanceledSubscription):
print(f"Disable access to user {event.username}")

در این روش، برای هر نوع رویداد یک شرط if نوشته شده که نوع رویداد را چک می‌کند.

۳. روش دوم با استفاده از singledispatch:
@singledispatch
def process(event):
pass

@process.register(UserCanceledSubscription)
def _(event):
print(f"Disable access to user {event.username}")

@process.register(UserSubscribed)
def _(event):
print(f"Enable access to user {event.username}")

در این روش، برای هر نوع رویداد یک تابع جداگانه تعریف می‌شود که فقط برای آن نوع خاص اجرا می‌شود.

مزایای استفاده از singledispatch:

۱. کد تمیزتر: به جای زنجیره‌ای از `if/elif`، هر منطق در یک تابع جداگانه قرار می‌گیرد.

۲. قابلیت توسعه بهتر: اضافه کردن نوع جدید فقط نیاز به اضافه کردن یک تابع جدید دارد، نه تغییر کد موجود.

۳. جداسازی مسئولیت‌ها: هر تابع فقط مسئول پردازش یک نوع خاص است.

۴. کاهش پیچیدگی: به جای یک تابع بزرگ با شرط‌های متعدد، چندین تابع کوچک و ساده داریم.

نحوه کار:
- @singledispatch
یک تابع پایه تعریف می‌کند
- @process.register()
توابع مختلف را برای انواع مختلف ورودی ثبت می‌کند
- در زمان اجرا، بر اساس نوع ورودی، تابع مناسب فراخوانی می‌شود

کاربرد این الگو در مواردی مثل:
- پردازش انواع مختلف پیام‌ها یا رویدادها
- تبدیل داده‌ها بین فرمت‌های مختلف
- اعمال عملیات‌های متفاوت روی انواع مختلف داده
- پیاده‌سازی الگوی Observer یا Event Handler

نمونه استفاده نهایی:
events = [
UserSubscribed(username="johndoe"),
UserCanceledSubscription(username="johndoe"),
]

for event in events:
process(event)


این کد به طور خودکار تابع مناسب را برای هر نوع رویداد فراخوانی می‌کند.

#python #singledispatch

@Syntax_fa

Syntax | سینتکس

03 Jan, 03:26


سوال مصاحبه ای درباره ذاکر با توضیح کامل

چرا وقتی یک کانتینر از یک ایمیجی رو بالا میاریم، نمیتونیم اون ایمیج رو پاک کنیم؟

زمانی که شما یک کانتینر را از یک ایمیج (Image) در Docker بالا می‌آورید، امکان حذف آن ایمیج تا زمانی که کانتینر مرتبط با آن در حال اجرا یا وجود داشته باشد امکان پذیر نیست. این رفتار به دلیل معماری Docker و نحوه مدیریت داده‌ها از طریق مکانیزم‌هایی مانند Copy-on-Write (COW) و UnionFS اتفاق می‌افتد.

در Docker، ایمیج‌ها به‌عنوان قالب‌های فقط خواندنی (Read-Only) عمل می‌کنند که شامل تمام فایل‌ها، نرم‌افزارها و تنظیمات مورد نیاز برای اجرای یک برنامه هستند. وقتی یک کانتینر از یک ایمیج بالا می‌آید:

- ایمیج به‌عنوان پایه (Base) عمل می‌کند.
- کانتینر یک لایه نوشتنی (Writable Layer) به بالای ایمیج اضافه می‌کند.

این لایه نوشتنی به کانتینر اجازه می‌دهد تغییراتی مانند ایجاد فایل‌ها یا تغییر تنظیمات را انجام دهد، بدون اینکه لایه‌های فقط خواندنی ایمیج اصلی تغییر کنند.

Copy-on-Write (COW)
داکر برای مدیریت تغییرات کانتینر از مکانیزم Copy-on-Write (COW) استفاده می‌کند. به این معنا که:

- تا زمانی که نیازی به تغییر داده‌ها نباشد، کانتینر از لایه‌های موجود در ایمیج به‌صورت مستقیم استفاده می‌کند.
- وقتی تغییری در یک فایل لازم باشد، آن فایل از لایه فقط خواندنی ایمیج به لایه نوشتنی کانتینر کپی می‌شود و سپس تغییرات اعمال می‌گردد.

این روش باعث صرفه‌جویی در منابع می‌شود، زیرا تا زمانی که نیازی به تغییر نباشد، ایمیج و کانتینر از همان نسخه داده‌ها استفاده می‌کنند.

UnionFS
سیستم فایل UnionFS (Union File System) برای ترکیب چندین لایه سیستم فایل در یک نمای واحد (Single View) استفاده می‌شود. Docker از UnionFS برای ساخت ایمیج‌ها و کانتینرها استفاده می‌کند. نحوه کار به این صورت است:

- ایمیج‌ها از چندین لایه تشکیل شده‌اند.
- این لایه‌ها فقط خواندنی هستند و هر لایه تغییرات و افزوده‌هایی نسبت به لایه قبلی دارد.
- وقتی یک کانتینر ایجاد می‌شود، یک لایه نوشتنی به بالای این لایه‌های فقط خواندنی اضافه می‌شود.

بنابراین، از دید کانتینر، تمام این لایه‌ها به‌صورت یک سیستم فایل یکپارچه دیده می‌شوند. اما در واقعیت، لایه نوشتنی و لایه‌های فقط خواندنی جدا از هم هستند.
https://en.wikipedia.org/wiki/UnionFS

چرا ایمیج حذف نمی‌شود؟
وقتی یک کانتینر از یک ایمیج ایجاد می‌شود، آن کانتینر به لایه‌های ایمیج وابسته است. به همین دلیل، تا زمانی که کانتینر وجود دارد (حتی اگر متوقف شده باشد):

- لایه‌های فقط خواندنی ایمیج در حال استفاده هستند.
- اگر ایمیج حذف شود، کانتینر نمی‌تواند به لایه‌های مورد نیاز خود دسترسی پیدا کند و در نتیجه خراب می‌شود.

Docker برای جلوگیری از این مشکل، اجازه حذف ایمیج‌هایی که در حال استفاده هستند را نمی‌دهد و در نهایت فقط میتوانید تگ آن را حذف کنید نه بادی ایمیج را.


ارتباط Copy-on-Write و UnionFS
- UnionFS امکان استفاده از چندین لایه سیستم فایل را فراهم می‌کند و باعث می‌شود ایمیج‌ها و کانتینرها به‌صورت مؤثری مدیریت شوند.
- Copy-on-Write تضمین می‌کند که تنها زمانی تغییرات در داده‌ها ایجاد شوند که واقعاً لازم باشد، بدون تغییر لایه‌های اصلی (فقط خواندنی) ایمیج.

این دو مکانیزم با هم کار می‌کنند تا Docker بتواند ایمیج‌ها و کانتینرها را به‌صورت کارآمد مدیریت کند.

چگونه ایمیج را حذف کنیم؟
اگر بخواهید یک ایمیج را حذف کنید، ابتدا باید تمام کانتینرهای وابسته به آن را حذف کنید. مراحل کلی عبارتند از:

1. لیست کانتینرهای وابسته به ایمیج:


   docker ps -a --filter ancestor=<image_name_or_id>

2. حذف کانتینرهای وابسته:


   docker rm <container_id>

3. حذف ایمیج:


   docker rmi <image_name_or_id>


#docker #copy_on_write #union_file_system

@Syntax_fa

Syntax | سینتکس

02 Jan, 13:43


استاد سنیور فول استک دولوپر میفرماید:
هر کی تو گیتهاب فعاله برنامه نویس نیست
حالا تو هعی پروژه بزن بذار تو گیتهاب

#fun

@Syntax_fa

Syntax | سینتکس

01 Jan, 11:55


دوستان اگه اپلیکیشن رو بصورت مونولیت مینیوسید، کار خوبی میکنید، اما aggregation pattern رو جدی بگیرید، کمک بزرگی میکنه به حفظ loosely coupled بودن ماژول و سرویس هاتون.

یه اشتباه رایجی که باعث میشه خیلی راحت همه چیز در هم تنیده و coupled بشه نیازهای بیزینسی ای هست که دیتای aggregate شده از چند domain مختلف رو میخواد از شما. تو حالت مونولیت خیلی ساده ست که شما در هر domain به دیتابیس یه domain دیگه درخواست بزنی و یا حتی تو interactor/service دیگه یه متد جدید تعریف کنی که دیتای مد نظر رو بده. که معمولا باعث در هم تنیده شدن و چاق شدن سرویس هاتون میشه.

بهتره سرویس یا همون interactorهاتون کارهای خیلی کوچیک و well-definedی رو انجام بدن و اگه نیازمندی های aggregationطور دارید، یه سری service دیگه بسازید که وابستگی خواهد داشت به سرویس های مختلف و دیتاهای raw رو میگیره و پردازش میکنه که دیتای نهایی رو آماده کنه.

بعضی وقت ها از طریق gateway هم ممکنه بتونید aggregate کنید. بعضی وقت ها ممکنه تو همون لایه دلیوری (کنترلر) تون بتونید دو تا سرویس رو فراخوانی کنید و کار رو در بیارید، گاهی هم پیچیده تر میشه و لازمه یه سرویس(interactor) بنویسید که کار aggregation رو انجام بده
https://learn.microsoft.com/en-us/azure/architecture/patterns/gateway-aggregation

باز خود aggregate کردن حالت های مختلفی داره، اینجا میتونید بیشتر بخونید در موردش
https://medium.com/geekculture/design-patterns-for-microservices-aggregation-pattern-1b8994516fa2

Source:
https://t.me/gocasts

@Syntax_fa

Syntax | سینتکس

30 Dec, 09:51


6 الگوی برتر معماری نرم‌افزار

معماری مونولیتیک (Monolithic Architecture)


در معماری مونولیتیک، تمام اجزای یک برنامه در یک کدبیس واحد و یکپارچه ترکیب می‌شوند. این رویکرد، فرآیند استقرار (Deployment) را ساده کرده و برای برنامه‌های کوچک مدیریت آن آسان‌تر است. با این حال، با رشد برنامه، این معماری می‌تواند سنگین و پیچیده شود، به طوری که مقیاس‌پذیری و نگهداری آن دشوار می‌گردد. هر تغییری در بخشی از برنامه ممکن است نیازمند استقرار دوباره کل سیستم باشد.

این معماری برای پروژه‌های کوچک و تیم‌های کوچک مناسب است، اما برای پروژه‌های بزرگ‌تر، به دلیل وابستگی‌های زیاد میان اجزاء، مدیریت تغییرات بسیار دشوار می‌شود.


الگوی (Controller-Worker Pattern)

این الگو منطق کنترل (Control Logic) را از منطق پردازش (Processing Logic) جدا می‌کند. کنترلر وظیفه مدیریت درخواست‌های ورودی، جریان داده‌ها و تخصیص وظایف به اجزای کارگر (Worker) را بر عهده دارد. اجزای کارگر وظایف پردازشی واقعی را انجام می‌دهند. این الگو برای مدیریت وظایف غیرهمزمان (Asynchronous Tasks) مفید است و می‌تواند مقیاس‌پذیری را با امکان اجرای همزمان چندین نمونه از اجزای کارگر بهبود بخشد.

مناسب برای سیستم‌هایی است که بار پردازشی غیرهمزمان دارند، مانند پردازش صف‌ها (Queues) یا مدیریت درخواست‌های سنگین.

معماری میکروسرویس‌ها (Microservices Architecture)

معماری میکروسرویس‌ها برنامه را به سرویس‌های کوچک و مستقل تقسیم می‌کند که از طریق APIهای مشخص با یکدیگر ارتباط برقرار می‌کنند. هر سرویس مسئول یک قابلیت خاص از کسب‌وکار است و می‌تواند به‌طور مستقل توسعه، استقرار و مقیاس‌پذیری شود. این معماری انعطاف‌پذیری بیشتری فراهم می‌کند و امکان استفاده از فناوری‌های مختلف برای سرویس‌های مختلف را می‌دهد. اما مدیریت سرویس‌ها و ارتباط بین آن‌ها می‌تواند پیچیدگی‌هایی به همراه داشته باشد.

این معماری مناسب سازمان‌هایی است که نیاز به توسعه سریع و مقیاس‌پذیری خدمات دارند. اما نیازمند ابزارهای مناسب برای نظارت، هماهنگی و مدیریت ارتباطات میان سرویس‌ها است.


مدل (Model-View-Controller یا MVC)

الگوی MVC یک برنامه را به سه بخش مرتبط تقسیم می‌کند:
- مدل (Model): وظیفه مدیریت داده‌ها و منطق کسب‌وکار را دارد.
- نما (View): داده‌ها را به کاربر نمایش می‌دهد.
- کنترلر (Controller): ورودی کاربر را مدیریت کرده و با مدل تعامل دارد.

این جداسازی باعث سازماندهی بهتر کد می‌شود و مدیریت و مقیاس‌پذیری برنامه، به‌ویژه در توسعه وب، را آسان‌تر می‌کند.

این الگو در اکثر فریم‌ورک‌های وب مانند Django و Ruby on Rails استفاده می‌شود و برای پروژه‌هایی که نیاز به تعامل زیاد با کاربر دارند، ایده‌آل است.


معماری رویداد-محور (Event-Driven Architecture)

در معماری رویداد-محور، اجزا از طریق تولید و مصرف رویدادها با یکدیگر ارتباط برقرار می‌کنند. هنگامی که یک رویداد رخ می‌دهد (مانند یک اقدام کاربر یا تغییری در سیستم)، رویداد های خاصی در سیستم ایجاد می‌شود و دیگر اجزای سیستم نسبت به رویداد ها اکشن مناسبی که نیاز دارند را انجام می دهند. این معماری بسیار جدا از هم (Decoupled) است و مقیاس‌پذیری و انعطاف‌پذیری بیشتری فراهم می‌کند، چرا که اجزا می‌توانند به‌طور مستقل تکامل یابند.

این معماری در سیستم‌های توزیع‌شده بسیار مفید است.


معماری لایه‌ای (Layered Architecture)

در معماری لایه‌ای، برنامه به لایه‌های مجزا با وظایف مشخص تقسیم می‌شود. لایه‌های رایج شامل موارد زیر هستند:
- لایه ارائه (Presentation Layer): وظیفه نمایش داده به کاربر.
- لایه منطق کسب‌وکار (Business Logic Layer): مدیریت منطق اصلی برنامه.
- لایه دسترسی به داده (Data Access Layer): مدیریت تعامل با پایگاه داده.

هر لایه تنها با لایه مجاور خود ارتباط برقرار می‌کند که باعث جداسازی وظایف (Separation of Concerns) می‌شود. این الگو نگهداری را آسان کرده و به تیم‌ها اجازه می‌دهد به‌طور مستقل روی لایه‌های مختلف کار کنند. با این حال، وجود لایه‌های متعدد ممکن است باعث کاهش عملکرد به دلیل سربار ناشی از ارتباط میان لایه‌ها شود.

این معماری برای سیستم‌های بزرگ و تیم‌های توسعه که به تفکیک وظایف نیاز دارند، مناسب است. اما باید بهینه‌سازی لازم برای جلوگیری از کاهش عملکرد انجام شود.

source

@Syntax_fa

Syntax | سینتکس

28 Dec, 05:03


مقاله زیر به ما آموزش میده چطور 1,000,000 رکورد دیتا رو در 4 ثانیه در PostgreSQL ذخیره کنیم!

https://www.timescale.com/learn/testing-postgres-ingest-insert-vs-batch-insert-vs-copy?ref=timescale.com

#postgresql
#database

source

@Syntax_fa

Syntax | سینتکس

24 Dec, 09:15


یه مدتی هست دارم سعی میکنم ترید کردن یاد بگیرم و پوزیشن های خیلی کوچیک باز میکنم و الان حدودا ۱۰ دلار تو اکانتم دارم. البته با ۱۵ دلار شروع کرده بودم :(
میخوام یه کانال سیگنال دهی بزنم و برعکس هرکاری خودم کردمو بذارم اونجا ملت استفاده کنن.

@normal_developer

Syntax | سینتکس

23 Dec, 15:49


آشنایی با File and Directory Permissions در لینوکس یکبار برای همیشه

در لینوکس، هر فایل و دایرکتوری دارای سطوح دسترسی (Permissions) است که مشخص می‌کند چه کسی می‌تواند به فایل یا دایرکتوری دسترسی داشته باشد و چه کاری با آن انجام دهد. این سطوح دسترسی برای سه دسته اصلی تعریف می‌شوند:

1. Owner (مالک فایل یا دایرکتوری)
2. Group (گروهی که فایل یا دایرکتوری به آن تعلق دارد)
3. Others (سایر کاربران سیستم)

ساختار دسترسی‌ها

در ابتدای هر فایل یا دایرکتوری در خروجی دستور ls -l، سطح دسترسی آن به صورت زیر نمایش داده می‌شود:

drwxrwxrwx


این سطح دسترسی از 10 کاراکتر تشکیل شده است:

1. اولین کاراکتر: نوع فایل را مشخص می‌کند:
- - : فایل معمولی
- d : دایرکتوری
- l : لینک سمبلیک

2. 9 کاراکتر بعدی (سه گروه سه‌تایی): سطح دسترسی برای مالک، گروه و سایرین را نشان می‌دهد:
- r : اجازه خواندن (Read)
- w : اجازه نوشتن (Write)
- x : اجازه اجرا (Execute)

جدول باینری و مقادیر اعداد


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

| مقدار عددی | سطح دسترسی | باینری |

|------------|------------|---------|
| 7 | rwx | 111 |
| 6 | rw- | 110 |
| 5 | r-x | 101 |
| 4 | r-- | 100 |
| 3 | -wx | 011 |
| 2 | -w- | 010 |
| 1 | --x | 001 |
| 0 | --- | 000


مثال: chmod 777


دستور chmod برای تغییر سطح دسترسی فایل‌ها و دایرکتوری‌ها استفاده می‌شود. در مثال chmod 777:

- اولین عدد 7: سطح دسترسی مالک (Owner) است.
- دومین عدد 7: سطح دسترسی گروه (Group) است.
- سومین عدد 7: سطح دسترسی سایرین (Others) است.

سطح دسترسی هر عدد به صورت زیر تعریف می‌شود:

rwx | rwx | rwx


این به این معناست که:
- مالک: می‌تواند بخواند، بنویسد و اجرا کند.
- گروه: می‌تواند بخواند، بنویسد و اجرا کند.
- سایرین: می‌توانند بخوانند، بنویسند و اجرا کنند.

دسترسی‌های محدودتر


حال اگر بخواهیم دسترسی محدودتری تعریف کنیم، می‌توانیم از مقادیر پایین‌تر استفاده کنیم:

- chmod 644:
- مالک: rw- (خواندن و نوشتن)
- گروه: r-- (فقط خواندن)
- سایرین: r-- (فقط خواندن)

- chmod 755:
- مالک: rwx (خواندن، نوشتن و اجرا)
- گروه: r-x (خواندن و اجرا)
- سایرین: r-x (خواندن و اجرا)



- chmod +x:
دسترسی execute به مالک و گروه و دیگر کاربران

- chmod -r:
دسترسی read رو از مالک و گروه و دیگر کاربران میگیریم

نکته درباره دایرکتوری‌ها


برای دایرکتوری‌ها:
- r:
به کاربر اجازه می‌دهد محتویات دایرکتوری را مشاهده کند.
- w:
به کاربر اجازه می‌دهد فایل‌ها را حذف یا اضافه کند.
- x:
اجازه ورود به دایرکتوری را می‌دهد.

#file_and_directory_permission

@Syntax_fa

Syntax | سینتکس

17 Dec, 04:30


📢 معرفی CONN_MAX_AGE در Django

متغیر CONN_MAX_AGE یکی از تنظیمات مهم Django است که برای مدیریت اتصالات پایدار (Persistent Connections) به پایگاه داده استفاده می‌شود. این تنظیم مشخص می‌کند که یک اتصال به پایگاه داده برای چه مدت زمان زنده بماند و پس از آن بسته شود.

🔍 CONN_MAX_AGE چیست و چگونه عمل می‌کند؟

- مقدار CONN_MAX_AGE نشان‌دهنده مدت زمان (بر حسب ثانیه) است که یک اتصال به پایگاه داده در حالت باز باقی می‌ماند.
- اگر مقدار آن روی ۰ تنظیم شود، اتصال به پایگاه داده پس از هر درخواست بسته می‌شود (رفتار پیش‌فرض).
- اگر مقدار CONN_MAX_AGE روی `None` تنظیم شود، اتصال به پایگاه داده هرگز بسته نمی‌شود و دائماً زنده می‌ماند (تا زمانی که فرآیند Worker یا برنامه بسته شود).

⚙️ مقدار پیش‌فرض CONN_MAX_AGE

به صورت پیش‌فرض، مقدار CONN_MAX_AGE برابر با ۰ است. یعنی Django پس از پایان هر درخواست، اتصال به پایگاه داده را می‌بندد و برای درخواست جدید، اتصال دیگری باز می‌کند. این رفتار برای پروژه‌های کوچک یا آزمایشی مناسب است ولی در محیط تولید (Production) ممکن است باعث کاهش عملکرد شود.

✏️ نحوه تنظیم CONN_MAX_AGE

مقدار CONN_MAX_AGE در تنظیمات پایگاه داده تعریف می‌شود. مثال زیر نحوه استفاده از آن را نشان می‌دهد:

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'your_database',
'USER': 'your_user',
'PASSWORD': 'your_password',
'HOST': 'your_host',
'PORT': 'your_port',
'CONN_MAX_AGE': 600, # 600 seconds
}
}



چند سناریو برای تنظیم CONN_MAX_AGE

1. پروژه کوچک یا محیط توسعه
- سناریو: اگر پروژه شما تعداد کمی از درخواست‌ها را مدیریت می‌کند یا در حال توسعه هستید.
- مقدار پیشنهادی:

     'CONN_MAX_AGE': 0

- توضیح: اتصال پس از هر درخواست بسته می‌شود. این کار به شما کمک می‌کند که رفتار واقعی برنامه را در محیط توسعه مشاهده کنید.

2. پروژه با بار متوسط
- سناریو: اگر برنامه شما درخواست‌های متوسطی (نه کم، نه زیاد) دارد و پایگاه داده شما برای تعداد اتصالات زیاد محدودیت خاصی ندارد.
- مقدار پیشنهادی:

     'CONN_MAX_AGE': 300  # 5 minutes

- توضیح: این تنظیم باعث می‌شود که اتصالات برای چندین درخواست استفاده شوند و هزینه باز و بسته کردن اتصال کاهش یابد.

3. پروژه با بار زیاد (High Traffic)
- سناریو: اگر برنامه شما تعداد زیادی درخواست دارد و می‌خواهید عملکرد را بهینه کنید.
- مقدار پیشنهادی:

     'CONN_MAX_AGE': 600  # 10 minutes

- توضیح: این مقدار کمک می‌کند که هزینه باز و بسته کردن مکرر اتصالات کاهش یابد، اما همچنان اتصالات پس از مدتی بسته می‌شوند تا از مشکلات احتمالی جلوگیری شود.

4. پروژه‌های با درخواست‌های خیلی کم
- سناریو: اگر برنامه شما به ندرت به پایگاه داده متصل می‌شود (مثلاً به دلیل استفاده از کش یا تعامل کم با پایگاه داده).
- مقدار پیشنهادی:

     'CONN_MAX_AGE': 0  # each http request

- توضیح: نگه‌داشتن اتصال در این موارد منطقی نیست و بهتر است اتصال پس از هر درخواست بسته شود.

5. استفاده از Connection Pooling خارجی
- سناریو: اگر از ابزارهای خارجی مدیریت اتصال مانند pgbouncer (برای PostgreSQL) یا ProxySQL (برای MySQL) استفاده می‌کنید.
- مقدار پیشنهادی:

     'CONN_MAX_AGE': None

- توضیح: در این حالت، مدیریت اتصالات به ابزارهای خارجی سپرده شده است و Django نیازی به بستن اتصالات ندارد.

⚠️ نکات مهم:

1. مراقب تعداد اتصالات باشید:
اگر مقدار CONN_MAX_AGE را روی مقدار زیاد یا None تنظیم کنید، مطمئن شوید که سرور پایگاه داده شما می‌تواند تعداد زیادی اتصال همزمان را مدیریت کند. در غیر این صورت ممکن است با خطای "too many connections" مواجه شوید.

2. محیط production:
در محیط تولید، معمولاً مقدار CONN_MAX_AGE روی چند دقیقه (مثلاً ۵ تا ۱۰ دقیقه) تنظیم می‌شود تا عملکرد بهینه باشد و اتصالات مکرر ایجاد نشوند.

3. ابزارهای خارجی مدیریت اتصال:
اگر از Connection Pooling خارجی استفاده می‌کنید، مقدار CONN_MAX_AGE را روی None تنظیم کنید تا Django اتصال را مدیریت نکند.

conn_max_age

#database #django

@Syntax_fa

Syntax | سینتکس

16 Dec, 21:44


📊 رشد چشمگیر داده‌های بدون ساختار

در دنیای امروز، داده‌های بدون ساختار (Unstructured Data) به بخش عظیمی از تولید و ذخیره‌سازی اطلاعات تبدیل شده‌اند. این داده‌ها شامل انواع محتوای دیجیتال مانند فیلم‌ها، تصاویر، صداها، متون غیرساختاریافته (مانند پیام‌های شبکه‌های اجتماعی) و حتی داده‌های حسگرهای اینترنت اشیا (IoT) هستند. برخلاف داده‌های ساختاریافته که در قالب‌های منظم (مانند جداول پایگاه داده) ذخیره می‌شوند، داده‌های بدون ساختار از تنوع و پیچیدگی بالایی برخوردارند، اما مدیریت و تحلیل آن‌ها چالش‌برانگیز است.

افزایش حجم داده‌های بدون ساختار: یک روند بی‌سابقه
گزارش‌ها و تحقیقات نشان می‌دهند که حجم داده‌های بدون ساختار سالانه با نرخ متوسطی در حدود ۳۰ تا ۴۰ درصد رشد می‌کند. این میزان رشد در برخی صنایع، مانند رسانه‌های دیجیتال، شبکه‌های اجتماعی و فناوری‌های مبتنی بر IoT، حتی از این رقم هم فراتر می‌رود. این افزایش به دلایل متعددی رخ می‌دهد.

چالش‌های مدیریت داده‌های بدون ساختار
با وجود ارزش بالقوه این داده‌ها، مدیریت و پردازش آن‌ها چالش‌های خاص خود را دارد:
 
- حجم بالا
  داده‌های بدون ساختار معمولاً حجیم‌تر از داده‌های ساختاریافته هستند؛ مثلاً یک ویدئوی باکیفیت یا مجموعه‌ای از تصاویر می‌تواند صدها گیگابایت فضا اشغال کند.

- تنوع داده‌ها:
این داده‌ها از نظر فرمت و نوع بسیار متنوع هستند. مدیریت داده‌های متنی، صوتی، تصویری و ویدئویی نیازمند ابزارها و الگوریتم‌های متفاوت است.

- تحلیل پیچیده
  برخلاف داده‌های ساختاریافته که به راحتی قابل جستجو و تحلیل هستند، داده‌های بدون ساختار نیازمند فناوری‌های پیشرفته‌ای مانند پردازش زبان طبیعی (NLP)، بینایی کامپیوتر (Computer Vision) و تحلیل صوت هستند.

تأثیر بلندمدت داده‌های بدون ساختار
رشد سریع داده‌های بدون ساختار نشان‌دهنده تغییر چشمگیر در نحوه تولید، ذخیره و استفاده از اطلاعات در دنیای دیجیتال است. با توجه به این‌که این داده‌ها بیش از ۸۰ درصد کل داده‌های جهان را تشکیل می‌دهند، سازمان‌ها و کسب‌وکارها ناگزیرند که به ابزارها و راهکارهای پیشرفته برای مدیریت و تحلیل آن‌ها روی بیاورند.

#unstructured_data

@Syntax_fa

Syntax | سینتکس

12 Dec, 06:02


تایپ‌های مختلف DNS رکورد و کاربردهای آن‌ها

1. A Record (Address Record)


کاربرد:
این رکورد، نام دامنه را به آدرس IPv4 تبدیل می‌کند. این نوع رکورد یکی از رایج‌ترین و مهم‌ترین رکوردها در DNS است.

مثال:
اگر کاربری آدرس example.com را وارد کند، DNS با استفاده از رکورد A، آدرس IP مربوط به آن (مثلاً 93.184.216.34) را برمی‌گرداند.

موارد استفاده:
- اتصال نام دامنه به آدرس IPv4 سرور

2. AAAA Record


کاربرد:
مشابه رکورد A است، اما برای آدرس‌های IPv6 استفاده می‌شود.

مثال:
اگر نام دامنه example.com از رکورد AAAA استفاده کند، ممکن است به آدرس IPv6 مانند 2606:2800:220:1:248:1893:25c8:1946 اشاره کند.

موارد استفاده:
- اتصال دامنه به آدرس IPv6

3. CNAME Record (Canonical Name Record)

کاربرد:
این رکورد نام یک دامنه را به دامنه دیگری اشاره می‌دهد. به جای ذخیره مستقیم آدرس IP، از این رکورد برای هدایت به نام دامنه‌ای دیگر استفاده می‌شود.

مثال:
اگر www.example.com یک رکورد CNAME داشته باشد که به example.com اشاره کند، تمامی درخواست‌ها به www.example.com به آدرس example.com هدایت می‌شوند.

موارد استفاده:
- تغییر مسیر زیردامنه‌ها.
- ساده‌سازی مدیریت DNS در صورت تغییر آدرس IP.

4. MX Record (Mail Exchange Record)

کاربرد:
این رکورد برای مشخص کردن سرورهای ایمیل دامنه استفاده می‌شود. رکورد MX مشخص می‌کند که ایمیل‌های ارسالی به دامنه باید به کدام سرور ارسال شوند.

مثال:
اگر رکورد MX برای example.com به mail.example.com اشاره کند، تمامی ایمیل‌ها به سرور mail.example.com ارسال می‌شوند.

موارد استفاده:
- تنظیم سرور ایمیل.
- مدیریت اولویت ارسال ایمیل (اولویت‌ها با اعداد مشخص می‌شوند).

5. TXT Record


کاربرد:
این رکورد برای ذخیره اطلاعات متنی استفاده می‌شود. معمولاً از آن برای تأیید مالکیت دامنه و اطلاعات امنیتی استفاده می‌شود.

مثال:
- تأیید مالکیت دامنه برای Google Search Console.
- پیاده‌سازی پروتکل‌های امنیتی مانند SPF، DKIM، و DMARC.

موارد استفاده:
- جلوگیری از اسپم و جعل هویت ایمیل.
- تأیید سرویس‌های خارجی.

6. NS Record (Name Server Record)


کاربرد:
این رکورد مشخص می‌کند که کدام سرورهای DNS مسئول مدیریت رکوردهای دامنه هستند.

مثال:
برای دامنه example.com، رکورد NS ممکن است به ns1.example.com و ns2.example.com اشاره کند.

موارد استفاده:
- تعیین سرورهای DNS اصلی یک دامنه.
- مدیریت و نگهداری رکوردهای دامنه.

7. SOA Record (Start of Authority)


کاربرد:
این رکورد اطلاعات پایه‌ای درباره دامنه و سرور DNS اولیه ارائه می‌دهد. SOA رکورد شامل اطلاعاتی مانند آدرس ایمیل مدیر دامنه و زمان به‌روزرسانی رکوردها است.

موارد استفاده:
- مشخص کردن سرور اصلی DNS.
- مدیریت به‌روزرسانی رکوردهای DNS.

8. PTR Record (Pointer Record)

کاربرد:
این رکورد برای جستجوی معکوس DNS استفاده می‌شود (تبدیل آدرس IP به نام دامنه). برخلاف رکورد A که دامنه را به IP تبدیل می‌کند، PTR آدرس IP را به نام دامنه تبدیل می‌کند.

موارد استفاده:
- تأیید هویت سرورها.
- جلوگیری از ارسال ایمیل‌های اسپم.

#DNS_records

@Syntax_fa

Syntax | سینتکس

12 Dec, 04:40


قبل از DNS

بذارید یه نگاه به دوران قبل از DNS بندازیم. اون زمان خبری از این راحتی‌ای که الان داریم نبود. اینترنت بود، ولی به جای اینکه اسم سایت‌ها رو وارد کنید، باید با یه مشت عدد و رقم سر و کله می‌زدید. حالا ببینیم اون روزا مردم چطوری با اینترنت کار می‌کردن:

1. حفظ کردن آدرس‌های IP
قبل از DNS، شما برای باز کردن سایت‌ها مجبور بودید آدرس‌های IP مثل 192.168.1.1 یا 216.58.214.14 رو تایپ کنید. مثلاً اگه می‌خواستید به یه سایت خاص برید، باید آدرس IP اون رو از جایی پیدا می‌کردید و دستی وارد می‌کردید. کاملاً منطقیه که خیلی‌ها دفترچه‌ای کنار دست‌شون داشتن و توش آدرس‌های IP مهم رو می‌نوشتن، چون حفظ کردن این اعداد اصلاً کار ساده‌ای نبود.

2. فایل HOSTS
کامپیوترها اون زمان یه فایل به اسم `hosts` داشتن که مثل دفترچه تلفن عمل می‌کرد. تو این فایل، آدرس IP‌ها به اسم‌های خاصی (اگه وجود داشت) نگاشت می‌شدن. مثلاً نوشته می‌شد:
93.184.216.34 example.com
216.58.214.14 google.com

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

3. کشف سایت‌ها؟ یه چالش واقعی!
یادمون باشه که اون زمان خبری از موتورهای جستجو مثل گوگل یا یاهو نبود. شما یا باید آدرس IP یه سایت رو از کسی می‌شنیدید، یا توی یه مجله یا کتاب می‌دیدید. اگه یه سایت جدید می‌خواستید پیدا کنید، باید امیدوار می‌بودید که کسی آدرسش رو بهتون بده.


4. مشکل هماهنگی
هر شبکه‌ای نسخه خودش از فایل hosts رو داشت. حالا اگه یه سایت جدید اضافه می‌شد یا تغییری توی یه آدرس IP رخ می‌داد، باید اون تغییر رو دستی به همه شبکه‌ها اطلاع می‌دادید. این هماهنگی برای شبکه‌های بزرگ‌تر شبیه یه کابوس بود.

#fun

@Syntax_fa

Syntax | سینتکس

11 Dec, 04:42


ادمینتون از این کارام میکنه
کسی خواست بخره با تخفیف سینتکسی در خدمتم 🍸

Syntax | سینتکس

11 Dec, 04:41


قبل اینکه روشن بشه بگو کدوم نقاشیه 😏

اینم یکی از خاص ترین تابلو لومن هامون، شب پر ستاره ون‌گوگ

ــــــــــــــــــــــــــــــــ

همچنین عکس و طرح دلخواه خودتونم می‌زنیم 😀

سفارش از طریق آیدی زیر:
@ayeef

#محصول@kereshme_tel
#تابلو_لومن@kereshme_tel

@Kereshme_tel

Syntax | سینتکس

09 Dec, 04:59


ساختار پروژه های جنگویی تیم سینتکس‌فا

در پروژه‌های نرم‌افزاری، به ویژه پروژه‌های بزرگ، ساختار مناسب کد نقش کلیدی داره. ساختار پروژه تأثیر مستقیمی به خوانایی، قابلیت نگهداری، و مقیاس‌پذیری کد داره.

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

تیم سینتکس در حال حاضر از ساختاری که توی این ریپو بصورت پابلیک قرار دادیم استفاده میکنه.

امیدوارم براتون مفید باشه 🙏

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

همچنین به مرور زمان داکیومنت رو هم اضافه میکنیم و سعی میکنیم همیشه آپدیت باشه.

برای حمایت از ما ستاره فراموش نشه 🍸

https://github.com/syntaxfa/django-structure

#django #structure

@Syntax_fa

Syntax | سینتکس

08 Dec, 16:01


برنامه نویسا تو هند، چجوری کار پیدا میکنن

#fun

@Syntax_fa

Syntax | سینتکس

27 Nov, 10:05


نمونه‌هایی از وب‌سایت‌ها و شرکت‌های بزرگ که استانداردهای مشخص‌شده را رعایت نکرده‌اند

1. Dropbox
- مشکل: استفاده از یک متد HTTP (POST) برای همه درخواست‌ها
- توضیح:
در نسخه‌های اولیه API خود، تقریباً همه درخواست‌ها (حتی موارد مربوط به خواندن داده‌ها) را با متد POST انجام می‌داد. این در حالی است که طبق استاندارد HTTP، متدهای GET باید برای دریافت داده‌ها استفاده شوند و نیازی به ارسال داده در بدنه (Body) نیست.

2. Twitter
- مشکل: استفاده از Query String برای ارسال اطلاعات حساس
- توضیح:
  در نسخه‌های اولیه API توییتر، برخی از درخواست‌های احراز هویت (مانند ارسال کلید API یا Access Token) از طریق Query String انجام می‌شد. این روش باعث می‌شد که اطلاعات حساس در URL ذخیره شوند و در لاگ‌های سرور یا مرورگر ثبت شوند.

  چرا استاندارد نیست؟
  طبق اصول امنیتی، اطلاعات حساس باید در بدنه درخواست (Body) یا هدر (Header) ارسال شوند، نه در Query String.

3. GitHub
- مشکل: استفاده از Status Code 404 برای پنهان کردن اطلاعات
- توضیح:
گیت هاب در برخی از APIهای خود، وقتی کاربری به یک منبع غیرمجاز دسترسی پیدا می‌کند (مثلاً یک ریپازیتوری خصوصی)، به جای استفاده از کد وضعیت 403 Forbidden، کد 404 Not Found را برمی‌گرداند. این کار برای جلوگیری از افشای وجود منابعی که کاربر به آن‌ها دسترسی ندارد انجام می‌شود.

4. Facebook
- مشکل: عدم استفاده صحیح از محدودیت نرخ (Rate Limit) در برخی نسخه‌های اولیه API
- توضیح:
  در نسخه‌های اولیه API فیس‌بوک، محدودیت نرخ (Rate Limit) به صورت یکنواخت برای همه کاربران اعمال نمی‌شد و رفتار مشخصی برای درخواست‌های بیش از حد وجود نداشت. گاهی درخواست‌های اضافی به صورت موفقیت‌آمیز پاسخ داده می‌شدند، اما در برخی موارد دیگر خطای غیرشفاف بازگردانده می‌شد.

5. Instagram
- مشکل: استفاده از کد وضعیت 200 برای خطاها
- توضیح:
  در API اینستاگرام، در برخی از نسخه‌های قدیمی، خطاها (مانند درخواست‌های نامعتبر) با کد وضعیت 200 OK بازگشت داده می‌شدند و جزئیات خطا در بدنه پاسخ قرار می‌گرفت.

6. PayPal
- مشکل: استفاده از کدهای وضعیت غیررایج
- توضیح:
  در برخی پاسخ‌های APIهای قدیمی PayPal، کدهای وضعیت غیررایج یا غیرمستند (مانند 490) ارسال می‌شدند. این کدها در مستندات HTTP تعریف نشده‌اند و کلاینت‌ها نمی‌توانند به درستی آن‌ها را پردازش کنند.

7. Amazon S3
- مشکل: استفاده از کد وضعیت 200 برای پاسخ‌های جزئی
- توضیح:
  در برخی از عملیات S3 (مانند لیست کردن اشیاء در یک باکت بزرگ)، اگر پاسخ به دلیل محدودیت اندازه به صورت چندبخشی باشد (Partial Response)، همچنان کد وضعیت 200 OK بازگردانده می‌شود.

  چرا استاندارد نیست؟
  برای پاسخ‌هایی که تنها بخشی از داده‌ها را شامل می‌شوند، استاندارد HTTP کد 206 Partial Content را پیشنهاد می‌کند.

8. LinkedIn
- مشکل: ساختار غیریکسان در پاسخ‌های JSON
- توضیح:
در برخی از نسخه‌های قدیمی APIهای لینکدین، ساختار پاسخ‌های JSON در درخواست‌های مختلف یکنواخت نبود. مثلاً کلیدها در یک پاسخ به صورت snake_case و در پاسخ دیگر به صورت camelCase بودند.

چرا استاندارد نیست؟
یکی از اصول طراحی API این است که ساختار پاسخ‌ها باید یکنواخت باشد تا توسعه‌دهندگان بتوانند به راحتی آن‌ها را پردازش کنند.

9. Google Maps API
مشکل: ارسال داده‌های غیرضروری در پاسخ‌ها
- توضیح:

در برخی پاسخ‌های Google Maps API، مقادیر غیرضروری و اضافی که گاهی هیچ ارتباطی با درخواست کاربر ندارند، بازگردانده می‌شدند. این می‌تواند باعث افزایش حجم داده و تأخیر در پردازش شود.

@Syntax_fa

Syntax | سینتکس

25 Nov, 14:11


Hard Coding

به معنای استفاده از مقادیر ثابت و تعریف‌شده درون کد یک برنامه، به‌جای استفاده از ورودی‌های داینامیک، متغیرها یا منابع خارجی (مثل فایل‌های کانفیگ یا پایگاه‌های داده). در این روش، مقادیر به‌صورت مستقیم در کد قرار می‌گیرند و برای تغییر آنها نیاز به ویرایش دستی کد است.

مثال ساده:
# Hard coded example
deposit = 0.1
price = 100
final_price = price + (price * deposit)
print(final_price)


مزایای Hard Coding

1. سادگی اولیه: کدنویسی سریع‌تر و آسان‌تر است، زیرا نیازی به ایجاد ساختارهای پیچیده برای مدیریت مقادیر نیست.
2. کاهش پیچیدگی در پروژه‌های کوچک: در برنامه‌های کوچک و ساده، ممکن است نیازی به طراحی سیستم‌های دینامیک برای مدیریت مقادیر نباشد.
3. کاهش وابستگی به منابع خارجی: در صورت hard coding، نیازی به مدیریت فایل‌های پیکربندی، پایگاه داده یا ورودی‌های خارجی وجود ندارد.

معایب Hard Coding

1. کاهش انعطاف‌پذیری: تغییر مقادیر ثابت نیازمند تغییر کد منبع و بازنویسی یا بازسازی برنامه است، که می‌تواند زمان‌بر باشد.
2. نگهداری سخت‌تر: در برنامه‌های بزرگ، مدیریت مقادیر hard coded دشوار است و می‌تواند باعث افزایش احتمال بروز خطا شود.
3. محدودیت در تنظیمات داینامیک: برنامه‌های مبتنی بر hard coding نمی‌توانند به راحتی خود را با شرایط یا محیط‌های مختلف سازگار کنند.

جایگزین‌ها برای Hard Coding
1. استفاده از فایل‌های تنظیمات (Config Files): ذخیره مقادیر در فایل‌های خارجی مانند JSON`، `YAML`، یا `INI.
2. دیتابیس: استفاده از دیتابیس برای مدیریت مقادیر پویا.
3. متغیرهای محیطی (Environment Variables): استفاده از متغیرهای سیستم‌عامل برای ذخیره مقادیر حساس مانند secret key.
4. ورودی‌های پویا از کاربر: گرفتن مقادیر از کاربر به‌صورت runtime.

متغیر هایی که حساس نیستند بهتره براشون fallback تعریف کنیم.
برای مثال اول چک بشه اگه بصورت دستی داخل کانفیگ مقداری براشون ست شده، از اونجا بخونه ولی اگه نبود با مقدار پیشفرض کار کنه و اروری نده. تا برناممون برای استفاده راحت تر باشه و برای شخصی سازی هم دستمون رو باز بذاره.

#hard_coding

@Syntax_fa

Syntax | سینتکس

23 Nov, 15:25


مشکل خود سنیور پنداری!

جدیدا خیلیا رو میبینم که قبل از تخصصشون عنوان سنیور رو وصل میکنن. ولی واقعیت امر اینه که سنیور بودن یه لقب نیست. به زمان هم خیلی بستگی نداره که بعد از فعالیت n ساله در یک زمینه شما به این مرحله برسید.
کسی که خودش رو سنیور خطاب میکنه در واقع مهارت های خیلی زیادی رو باید داشته باشه که یکیشون برنامه نویسیه!
مهارت های نرم، مهارت یادگیری چیزهای جدید، طرز فکر و راهکار یابی و ... بخشی از پیشنیاز این صفت میشه.
تو فرایند جذب نیروی جدید برای شرکتمون رزومه های زیادی رو چک کردم و واقعا همه دوست دارن این عنوان رو قبل اسمشون داشته باشن.
عجیب ترین چیزی که دیدم هم مربوط میشه به یه فردی که بعد از یه بوت کمپ با یه شرکت شروع به همکاری چند ماهه کرده بود و عنوان شغلی خودش تو اون شرکت رو نوشته بود "Senior Django Developer"!
یعنی در فاصله کمتر از چند ماه به این درجه از عرفان رسیده بوده!


@normal_developer

Syntax | سینتکس

20 Nov, 06:33


برنامه نویسا روزی یبار به چی فکر می کنن:

#fun

@Syntax_fa

Syntax | سینتکس

18 Nov, 20:42


یه تنوعی بدین به خودتون😂🔥

VsCode Extention : power mode

Syntax | سینتکس

18 Nov, 16:02


وقتی به جای سیستم‌ها، انسان‌ها هک می‌شوند!

طبق تحقیقات و گزارش‌ها، تخمین زده می‌شود که حدود 70 تا 90 درصد از حملات سایبری موفق، به نوعی از تکنیک‌های مهندسی اجتماعی استفاده می‌کنند. این آمار نشان‌دهنده اهمیت آموزش و آگاهی‌بخشی به کاربران برای کاهش ریسک این گونه حملات است.

https://youtu.be/Z_S9jFkdCjY

@Syntax_fa

Syntax | سینتکس

16 Nov, 15:19


Backpressure

تو این پست با چند مثال Backpressure رو بررسی میکنیم.

مثال اول:‌کارخانه شکلات
در برنامه تلویزیونی "I Love Lucy" قسمتی وجود دارد که Lucy در یک کارخانه بسته‌بندی شیرینی کار می‌کند. وظیفه او برداشتن شیرینی از نوار نقاله و بسته‌بندی هر کدام در کاغذ است.
او با این مشکل مواجه می شود که تعداد شیرینی هایی که در نوار نقاله می أید بیشتر از توان او در بسته بندی است.

او دو روش مختلف برای مقابله با آن را امتحان می‌کند: کنار گذاشتن برخی تا بعدا بهشون رسیدگی کنه (buffering)، و در نهایت شروع به خوردن و پنهان کردن آنها در کلاهش می‌کند (dropping). با این حال، در مورد یک کارخانه شکلات، هیچ یک از این استراتژی‌های Backpressure عملی نیستند. در عوض، او نیاز داشت که نوار نقاله را آهسته‌تر کنند؛ به عبارت دیگر، او نیاز به کنترل سرعت producer دارد.

مثال دوم: خواندن و نوشتن از فایل:
حالا درباره Backpressure مرتبط با نرم‌افزار صحبت می‌کنیم. رایج‌ترین حالت هنگام کار با file system است.

نوشتن در فایل کندتر از خواندن فایل است. تصور کنید یک hard drive که سرعت موثر خواندن ۱۵۰ مگابایت بر ثانیه و سرعت نوشتن ۱۰۰ مگابایت بر ثانیه را ارائه می‌دهد. اگر بخواهید فایلی را با حداکثر سرعت ممکن به memory بخوانید، در حالی که همزمان آن را با حداکثر سرعت ممکن به دیسک بنویسید - باید هر ثانیه ۵۰ مگابایت را buffer کنید. در هر ثانیه 50 مگابایت را باید بافر کنید!

شما نمی‌توانید به بافر رسیدگی کنید تا زمانی که خواندن فایل ورودی کاملاً به پایان برسد.

حالا تصور کنید این کار را با یک فایل ۶ گیگابایتی انجام می‌دهید. تا زمانی که فایل را کاملاً خوانده‌اید، یک buffer ۲ گیگابایتی خواهید داشت که هنوز باید نوشتن آن را تمام کنید.

6 GB / 150 MB = 40 seconds
150 MB - 100 MB = 50 MB deficit
50 MB x 40 = 2 GB !!!


مقدار زیادی memory هدر رفته است. در برخی سیستم‌ها این ممکن است حتی از مقدار memory موجود فراتر رود.

نگران نباشید، راه‌حل ساده است: فقط به همان سرعتی بخوانید که می‌توانید بنویسید. تقریباً تمام I/O library ها abstraction هایی را برای انجام خودکار این کار برای شما ارائه می‌دهند.

مثال سوم: ارتباط Server
مثال بعدی ارتباط بین server ها است. امروزه استفاده از معماری microservice که در آن مسئولیت‌ها بین چندین server تقسیم می‌شود بسیار رایج است.

Backpressure
معمولاً این سناریو زمانی رخ می‌دهد که یک server درخواست‌ها را سریع‌تر از آنچه server دیگر می‌تواند پردازش کند، ارسال می‌کند.

اگر server A، ۱۰۰ rps (requests per second) به server B بفرستد، اما server B فقط بتواند ۷۵ rps را پردازش کند، شما یک کسری ۲۵ rps دارید.

در هر صورت، server B باید به نوعی با Backpressure مقابله کند. Buffer کردن آن کسری ۲۵ rps یک گزینه است، اما اگر آن افزایش ثابت بماند، به زودی memory تمام می‌شود و از کار می‌افتد. Drop کردن درخواست‌ها گزینه دیگری است که در اکثر سناریو ها قابل قبول نیست.

گزینه ایده‌آل این است که server B نرخ ارسال درخواست‌های server A را کنترل کند، اما باز هم این همیشه عملی نیست - اگر server A به نمایندگی از یک کاربر درخواست می‌کند، شما نمی‌توانید کاربر ها را کنترل کنید که آهسته‌تر شوند، اغلب بهتر است که server درخواست کننده buffer داشته باشد، تا بتوانید بار memory را در downstream، جایی که استرس وجود دارد، بهتر توزیع کنید و بر سایر درخواست کنندگان تأثیر نگذارید.

به عنوان مثال، اگر سه نوع مختلف سرویس (A, B, C) همگی به یک سرویس downstream مشترک (Z) درخواست بدهند، و یکی از آنها (A) تحت بار بالا باشد، سرویس Z می‌تواند به طور موثر به سرویس A بگوید "آهسته‌تر شو" (کنترل producer) که باعث می‌شود سرویس A درخواست‌ها را buffer کند. اگر این ادامه پیدا کند، در نهایت سرویس A با کمبود memory مواجه می‌شود، با این حال، دو سرویس دیگر (B, C) همچنان فعال می‌مانند، همانطور که سرویس downstream Z نیز فعال می‌ماند زیرا اجازه نمی‌دهد یک سرویس بدرفتار از دسترسی برابر برای دیگران جلوگیری کند. در این مورد ممکن است قطعی اجتناب‌ناپذیر باشد، اما ما محدوده را محدود کردیم و از Denial of Service زنجیره‌ای جلوگیری کردیم.

مثال ها:
https://medium.com/@jayphelps/backpressure-explained-the-flow-of-data-through-software-2350b3e77ce7

#Backpressure

@Syntax_fa

Syntax | سینتکس

15 Nov, 05:05


در برنامه‌نویسی، اصطلاح "Idiomatic" به معنای استفاده از الگوها و روش‌هایی است که در یک زبان برنامه‌نویسی خاص به عنوان استاندارد و رایج شناخته می‌شوند. این موضوع اهمیت زیادی دارد و چندین دلیل برای آن وجود دارد:

1. خوانایی کد: کدی که به صورت idiomatic نوشته شده باشد، برای سایر برنامه‌نویسانی که با آن زبان آشنا هستند، راحت‌تر قابل درک است. این باعث می‌شود که تیم‌ها به راحتی بتوانند با یکدیگر همکاری کنند.

2. نگهداری آسان‌تر: کدی که از الگوهای استاندارد پیروی می‌کند، به راحتی قابل نگهداری و اصلاح است. این امر به‌ویژه در پروژه‌های بزرگتر که افراد مختلفی روی آن کار می‌کنند، بسیار مهم است.

3. عملکرد بهتر: در بسیاری از موارد، استفاده از روش‌های idiomatic به بهبود عملکرد کمک می‌کند، زیرا این روش‌ها اغلب بهترین شیوه‌های بهینه‌سازی شده برای زبان مربوطه هستند.

4. کاهش خطاها: پیروی از الگوهای رایج به کاهش خطاها و باگ‌ها کمک می‌کند، زیرا این الگوها معمولاً توسط جامعه توسعه‌دهندگان آزمایش شده‌اند و مطمئن‌تر هستند.

#idiomatic

@Syntax_fa

Syntax | سینتکس

13 Nov, 07:08


گفتگو شنیدنی GoCasts با مهندس کیانوش مختاریان، مهندس نرم افزار، رهبر فنی سابق در گوگل. 

https://gocasts.ir/talk-with-kain

@Syntax_fa

Syntax | سینتکس

11 Nov, 08:49


ادعای هک اطلاعات یکونیم میلیون کاربران بلو بانک.
دیگه فکر کنم برای ملت فرقی نمیکنه چون کل ایران اپن سورسه.

https://youtu.be/iaMeC798mdI?si=uN3oCDuAuIHUjRY6

@Syntax_fa

Syntax | سینتکس

09 Nov, 15:00


تست Canary: راز پشت پرده تغییرات گوگل

چند وقت پیش داشتم ایمیل‌هایم را در گوگل چک می‌کردم که یک ویژگی جدید توجه من را جلب کرد؛ دکمه‌ای مخصوص پرسش از هوش مصنوعی درباره‌ی محتوای ایمیل‌ها. فکر کردم این یک تغییر جذاب است و سری به بقیه ایمیل‌هایم زدم تا از این فیچر استفاده کنم. اما جالب بود که این ویژگی فقط در یک ایمیل فعال شده بود! چرا همه کاربران این ویژگی را ندارند؟ مگر این همان گوگل نیست که وقتی چیزی اضافه می‌کند برای همه فعال می‌شود؟

با کمی تحقیق و کنجکاوی، به یک واژه رسیدم:
Canary Test

چرا تست Canary؟
تصور کنید گوگل می‌خواهد ویژگی جدیدی را به سرویس ایمیل خود اضافه کند. اگر این ویژگی به‌درستی کار نکند، ممکن است کل سیستم ایمیل دچار مشکل شود. اما به کمک Canary Test، ابتدا این تغییرات را برای گروه کوچکی از کاربران فعال می‌کنند. اگر همه‌چیز درست کار کرد، این تغییر را برای کاربران بیشتری اجرا می‌کنند؛ و اگر مشکلی رخ داد، به‌سرعت به نسخه قبلی برمی‌گردند، بدون این‌که کسی متوجه شود.

فواید این تست
این تست مثل نگهبانی است که با فداکاری جلوی آسیب‌های بزرگ را می‌گیرد
ریسک کم‌تر: ابتدا در شرایط محدود بررسی می‌شود که ویژگی جدید مشکلی ایجاد نکند.
شناسایی مشکلات: قبل از اینکه همه کاربران با باگ‌ها روبرو شوند، تیم توسعه آن‌ها را شناسایی و رفع می‌کند.
تجربه‌ی کاربری بهتر: بدون اختلال و با اطمینان بالا، کاربران از قابلیت‌های جدید لذت می‌برند.

گوگل، فیس‌بوک و سایر غول‌ها چطور از Canary Test استفاده می‌کنند؟
در این روش، غول‌های فناوری مثل گوگل و فیس‌بوک ابتدا تغییرات را به درصد کوچکی از کاربران عرضه می‌کنند. این کاربران به‌عنوان "قناری‌های" سیستم انتخاب می‌شوند تا در صورت شناسایی خطر، باقی کاربران در امان بمانند. اگر همه‌چیز خوب پیش رفت، تغییرات به همه عرضه می‌شود؛ و اگر نه، به‌راحتی تغییرات را متوقف می‌کنند.

پس اگر روزی دیدید که شما یک قابلیت خاص در یک اپلیکیشن دارید و دوستانتان نه، بدانید شاید شما هم یکی از «قناری‌ها»ی سیستم باشید! 🐤

Source

@Syntax_fa

Syntax | سینتکس

06 Nov, 02:39


شما در این ویدئو یک CPU آیفون را در زیر میکروسکوپ در کنار یک تار مو بعنوان مقایسه اندازه آن مشاهده می‌کنید.

@Syntax_fa

Syntax | سینتکس

30 Oct, 14:14


~> چالش‌های یادگیری Go برای برنامه‌نویس‌های تازه‌کار 🥰

یکی از مهم‌ترین چالش‌هایی که برنامه‌نویس‌های جدید موقع یادگیری Go باهاش روبرو می‌شن، درک مفهوم کانکارنسی هستش. Go با معرفی goroutines و channels سعی می‌کنه مدل ساده‌ای برای برنامه‌نویسی همروند ارائه بده، اما درک عمیق این مفاهیم برای افرادی که تازه شروع کردن سخت می‌شه.

ارور هندلینگ در Go هم چالش دیگه‌ای هستش که برنامه‌نویس‌های جدید باهاش درگیر می‌شن. برخلاف زبان‌هایی مثل Java که از try-catch استفاده می‌کنن، Go از یک پترن ساده‌تر با استفاده از مقادیر error استفاده می‌کنه. این روش باعث می‌شه کد تمیزتر بشه، اما نیاز به چک کردن مکرر خطاها داره که می‌تونه برای تازه‌کارها گیج‌کننده باشه.

درک سیستم تایپ‌های Go برای برنامه‌نویس‌هایی که از زبان‌های شی‌گرا میان می‌تونه چالش‌برانگیز باشه. Go اصلاً یک زبان شی‌گرا نیست و به جای کلاس و آبجکت، از type برای تعریف struct‌ها و interface‌ها استفاده می‌کنه. این struct‌ها و interface‌ها صرفاً تایپ هستن و برای داک تایپینگ استفاده می‌شن. این تفاوت پارادایم برای کسایی که با OOP آشنا هستن می‌تونه گیج‌کننده باشه.

پوینترها توی Go یکی دیگه از نقاط چالش‌برانگیز هستن. اگرچه Go نسبت به C مدیریت حافظه رو ساده‌تر کرده، اما هنوز هم درک اینکه کی باید از پوینتر استفاده کرد و کی نباید، برای برنامه‌نویس‌های جدید سخت می‌شه.

سیستم پکیج‌های Go و نحوه مدیریت dependency‌ها هم می‌تونه گیج‌کننده باشه. از Go 1.11 به بعد، سیستم module معرفی شد که اگرچه مشکلات قبلی GOPATH رو حل کرده، اما یادگیری نحوه کار با go.mod و go.sum برای تازه‌کارها زمان‌بر هستش.

یکی از ویژگی‌های خاص Go که درکش برای برنامه‌نویس‌های جدید سخت می‌شه، interface‌ها هستن. Go از implicit interface implementation استفاده می‌کنه که با زبان‌های دیگه متفاوت هستش و نیاز به تغییر دیدگاه داره.

نکته دیگه‌ای که برای برنامه‌نویس‌های تازه‌کار چالش‌برانگیز می‌شه، عدم وجود جنریک‌ها تا قبل از Go 1.18 بود. حالا که جنریک‌ها اضافه شدن، یادگیری syntax و best practice‌های مربوط به اون‌ها خودش یه چالش جدید محسوب می‌شه.

همچنین، Go یه سری قوانین سخت‌گیرانه در مورد code formatting و نام‌گذاری داره. مثلاً اگه یه متغیر exported تعریف کنی، حتماً باید با حرف بزرگ شروع بشه، یا اینکه هر statement باید با semicolon تموم بشه (که البته کامپایلر خودش اضافه می‌کنه). این قوانین اگرچه به خوانایی کد کمک می‌کنن، اما رعایت کردنشون برای تازه‌کارها می‌تونه سخت باشه.

Source

@Syntax_fa

Syntax | سینتکس

30 Oct, 07:19


کمی دور از انتظار باشه این رو به عنوان کسی دارم میگم که سالها ظهور و ناپدید شدن تکنولوژی ها و نوع تفکر قالب بر نرم افزار رو لمس کردم و در این فضا کار کردم به عنوان کسی که وقتی #ویژوال بیسیک کار میکردم فکر نمیکردم روزی از بازار حذف بشه یا فکر نمیکردم دات نت با یک تغییر در ساختار و رفتن سراغ #netcore بتونه با جاوا رقابت کنه و باز هم برام قابل تعریف نبود که زبان تازه به دنیا اومده ای مثل #گولنگ و #راست چنین با اقتدار قد علم کنن و مرزهای پرفورمنس رو به لرزه دربیارن و شاید تصور اینکه روزی در دنیای وب رقیبهایی به این قدرت رو برای #php متصور بشم سخت بود اما امروز با توجه به تمام تغیرات چه در نگرش به نرم افزار و معماری نرم افزار و همچنین پیش اومدن هوش مصنوعی در این حوزه به ناچار باید بگم دنیای #شی گرایی و #معماریهای شی گرا کم کم دارن کوله بارشون رو میبندن و زبانهای شی گرا باید جاشون رو به زبانهای جوانتر مثل همین #گولنگ و #راست بدن حرف من کنار رفتن زبانهای جاوا یا سی شارپ نیست دوستان موضوع کم رنگ شدن و قدرت گرفتن تفکر جدید هست تغییر نگرش زمانبر و طولانی مدت خواهد بود ولی #ساده سازی نوع #تفکر در برنامه نویسی و گذار از روش های سنتی و معماریهای سنتی در حال انجامه برای همین شما اسم #ورتیکال یا معماریهای مدرن دیگه رو میشنوید #مراقب جا موندن از قطار پر سرعت تغییرات باشید

Source

@Syntax_fa

Syntax | سینتکس

29 Oct, 08:41


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

اما قسمت دارک ماجرا زمانیه که محتویات کانتریبیوتش رو میبینیم که کلا یدونه کلمه از کامنت رو تغییر داده

واقعا لینکدین خیلی عجیبه

#fun

@Syntax_fa

Syntax | سینتکس

28 Oct, 13:31


😂😔
#fun

Syntax | سینتکس

23 Oct, 05:45


تایید می کنید؟

#fun

@Syntax_fa

Syntax | سینتکس

20 Oct, 10:25


📱 زندگی برنامه‌نویس‌ها قبل و بعد از چت‌بات‌های هوش مصنوعی:

قبل:
- گوگل: بهترین دوست
- Stack Overflow: خونه دوم
- کپی-پیست: مهارت اصلی

بعد:
- چت‌جی‌پی‌تی: رفیق فابریک
- پرامپت مهندسی: تخصص جدید
- هوش مصنوعی: همکار جدید

دنیای برنامه‌نویسی قبل از عصر هوش مصنوعی


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

جستجو: هنر اصلی برنامه‌نویسی


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

Stack Overflow: ناجی برنامه‌نویسان


سایت Stack Overflow نقش حیاتی در زندگی برنامه‌نویسان داشت. بسیاری از مشکلات با جستجو در این سایت و خواندن پاسخ‌های دیگران حل می‌شد. البته پیدا کردن پاسخ مناسب در میان انبوه نظرات، خود چالشی بزرگ بود.(هنوزم ناجی برنامه نویساس)

دیباگ: کابوس شبانه


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

#fun

@Syntax_fa

Syntax | سینتکس

20 Oct, 10:01


یه شخصی تو لینکدین این پست رو گذاشته که قراره با هم بررسیش کنیم:
چرا نباید از Signals ها در جنگو استفاده کنیم؟

اگر تجربه کار با Django را داشته باشید، احتمالاً با Signals آشنا هستید. سیگنال‌ها به شما این امکان را می‌دهند که بعد از رخ دادن یک رویداد خاص، مانند ذخیره یا حذف یک شی، کدی را اجرا کنید. اما آیا همیشه بهترین انتخاب هستند؟ بیایید با هم بررسی کنیم.

کاربرد سیگنال‌ها
سیگنال‌ها در Django برای مواردی مانند ارسال ایمیل بعد از ایجاد یک شی یا به‌روزرسانی داده‌های مرتبط، استفاده می‌شوند. به این معنی که وقتی یک تغییر در دیتابیس رخ میده، میتونیم با استفاده از سیگنال‌ها به آن پاسخ دهیم. این رویکرد به ما کمک می‌کند تا وابستگی‌ها را کاهش بدیم و بین بخش‌های مختلف برنامه ارتباط برقرار کنیم.

چرا نباید از سیگنال‌ها استفاده کنیم؟
با وجود کاربردهای سیگنال‌ها، استفاده از آن‌ها معایب خودشون رو هم دارن. یکی از مشکلات اساسی سیگنال‌ها این است که پیچیدگی و عدم پیش‌بینی‌پذیری را افزایش میدن. کدهایی که به‌وسیله سیگنال اجرا می‌شوند، ممکن است در جریان اصلی کد ما نباشند و ما به‌راحتی متوجه نشیم که چه زمانی و چرا آن‌ها فراخوانی می‌شوند. این موضوع نه تنها کار دیباگ کردن رو سخت میکنه، بلکه ممکنه رفتار ناخواسته‌ای هم که ازش انتظار نداریم رو هم داشته باشه.

یکی دیگه از مشکل های سیگنال‌ها اینه که همگام (Synchronous) اجرا میشن. برخلاف تصوری که ممکنه داشته باشیم، سیگنال‌ها به‌صورت غیرهمگام اجرا نمیشن و هیچ پروسه پس‌زمینه‌ای برای آن‌ها وجود ندارد. این موضوع باعث میشه که اگر سیگنال با خطا مواجه بشن، این خطا مستقیما در جریان اصلی کد شما بروز کند و حتی ممکن است رفتارهای ناخواسته به وجود بیاد.

به‌عنوان مثال، فرض کنید شما در حال توسعه کدی هستید که تعداد فروش یک نوع تاپینگ پیتزا را هنگام ایجاد پیتزای جدید به‌روزرسانی می‌کند. اگر از سیگنال استفاده کنید، ممکن است در مواردی که از متدهای bulk مانند bulk_create یا .update() استفاده می‌کنید، این سیگنال فراخوانی نشود و این به داده‌های ناهماهنگ منجر شود.

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

چه چیزی می‌تواند جایگزین باشد؟
به جای استفاده از سیگنال‌ها، یکی از راهکارهای بهتر استفاده از متدهای مدل مثل save() هست. زمانی که بیزینس لاجیک خود را درون متد save() مدل قرار می‌دهید، همه چیز شفاف‌تر و قابل پیش‌بینی‌تر خواهد بود. به این ترتیب، کد جلو چشم شما قرار دارد و نیازی نیست نگران اجرا شدن یا نشدن سیگنال‌ها باشید. این کار باعث می‌شود کد تمیزتر و خواناتر باشد و همچنین به‌راحتی قابل تست و نگهداری شود.

برای مثال، می‌توانید یک متد در مدل خود تعریف کنید که منطق به‌روزرسانی را مدیریت کند و سپس این متد را در متد save() فراخوانی کنید. این روش نه تنها ساختار کد شما را ساده‌تر می‌کند، بلکه به توسعه‌دهندگان آینده هم کمک می‌کند تا به‌راحتی جریان کد را دنبال کنند.
————————————-

نظر من راجب این پست:
استفاده از سیگنال ها تو برخی شرایط بنظرم خیلیم مفید هستش.

برای مثال میتونیم با استفاده از سیگنال ها، سرویس ها و اجزای مختلف رو از هم decouple تر کنیم.
فرض کنید موقعی که یک یوزر جدید ساخته میشه، چند تا سرویس دیگه هم یه سری عملیات انجام میدن. مثلا نوتیف خوش آمد گویی ارسال میکنیم.
ساختار پروژمونم یکپارچه هستش.

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

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

الگوی observer:
سیگنال ها درواقع پیاده سازی الگوی observer هستن که برای ارتباط بین اجزای مخنلف سیستم خیلی مفیده.

فقط چند تا نکته باقی میمونه اینکه از سیگنال ها هوشمندانه استفاده کنیم، تو استفاده ازشون زیاده روی نکنیم و حتما داکیومنت کنیم تا باعث سردرگمی نشه

#django #Signals

@Syntax_fa

Syntax | سینتکس

20 Oct, 05:38


اگه کانفیگ های v2ray که پول هم دادی براش کار نمیکنه این پست رو چک کن:

https://t.me/normal_developer/25

@syntax_fa

Syntax | سینتکس

18 Oct, 12:53


میبینید که یه سایت ساده لیارا بنچ C گرفته
در مقابل یه سایت که تصویر هم زیاد داره روی هتزنر بنچ A گرفته!

@Normal_Developer

Syntax | سینتکس

18 Oct, 12:53


ممکنه شما هم برای هاستینگ سایت یا اپلیکیشنتون از لیارا (liara.ir) استفاده کنید.
حدودا از سال ۱۴۰۰ سرویسای دم دستی که لازم داشتم رو میبردم روی لیارا یا حداقل نسخه اولیه رو اونجا ران میکردم.
سایت شخصی خودم رو هم اونجا ران کردم چون میخواستم از قابلیت های آماده ش استفاده کنم و زیاد روی تنظیم زیرساخت زمان نذارم و بیشتر روی توسعه تمرکز کنم.
ولی تو چند ماه اخیر واقعا با لیارا مشکل پیدا کردم و برام نه صرفه داره که ازش استفاده کنم و نه کیفیتشون مثل قبل خوبه.
تو ماه های جدید برای هر قابلیتی دارن یه قیمتی میدن.
فرض کنید یه سایت ساده با مثلا پایتون با کمترین منابع ران کنید روی لیارا. ببینیم چقد در میاد:

هزینه PaaS ماهانه: ۹۹ هزار تومن (512 مگابایت رم - ۰.۵ هسته پردازنده- ۵ گیگ حافظه)
هزینه بسته امکاناتی: ۷۴ هزار تومن (برنزی)
هزینه دیتابیس پستگرس: ۹۹ هزار تومن (۵۱۲ مگابایت رم - ۰.۵ هسته پردازنده - ۵ گیگ فضای ذخیره سازی)

جمعا: ۲۷۲ هزار تومن ماهانه معادل حدود 4.5 دلار در ماه
حالا اگه شما بخواید یه سرور مجازی بگیرید از یه دیتاسنتر خوب مث هتزنر یا OVH هم حدود ۵ دلار در ماه هزینه داره.
ولی منابعی که مثلا هتزنر دراختیارتون قرار میده میشه ۴ گیگابایت رم، ۲ هسته پردازنده، ۴۰ گیگ فضا!
به اضافه اینکه کیفیت زیرساختی خیلی بهتری داره.
در ادامه بنچمارک GTMetrics از یه سرویس نسبتا پرتصویر و عکس که روی هتزنر دارم و سایت شخصی خودم که هیچی نداره رو میذارم.

@Normal_Developer

Syntax | سینتکس

18 Oct, 09:06


#fun

@syntax_fa

Syntax | سینتکس

16 Oct, 04:23


Docker in Docker (DinD)

به اجرای Docker در داخل یک کانتینر اشاره دارد.

یک مثال کاربردی اش پایپ‌لاین CI/CD است:

- در برخی مواقع ممکن است پروژه ما برای اجرا و تست نیاز به یک سری backing service ها مثل redis و ... داشته باشد. در این صورت ترفندی که می زنیم را می توان اینطور بیان کرد که داخل کانتینر، کانتینر های مورد نیاز پروژه مان را آپ می کنیم.

مثال:
ci.yml
name: CI

on:
pull_request:
types: [opened, edited, reopened, synchronize, ready_for_review]
branches: [main]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements/test.txt

- name: dockerUp
run: sudo make docker-test-up

- name: Test
run: make test

- name: dockerDown
run: sudo make docker-test-down


و داخل فایل Makefile:
.PHONY: test

ROOT=$(realpath $(dir $(lastword $(MAKEFILE_LIST))))

test:
python manage.py test

docker-test-up:
docker compose -f $(ROOT)/docker-compose-test.yml up -d

docker-test-down:
docker compose -f $(ROOT)/docker-compose-test.yml down


چالش DinD در موارد بیشتر

1. امنیت:
- اجرای Docker در Docker می‌تواند خطرات امنیتی به همراه داشته باشد، زیرا کانتینر داخلی به Docker Host دسترسی دارد.

2. پیچیدگی شبکه:
- کانفیگ شبکه می‌تواند پیچیده شود، به ویژه اگر نیاز به ارتباط بین کانتینرهای داخلی و خارجی باشد.

3. عملکرد:
- ممکن است عملکرد ضعیف‌تری نسبت به اجرای Docker به صورت مستقیم روی سرور داشته باشد.

نحوه استفاده

برای استفاده از Docker in Docker، می‌توانید از ایمیجی مانند docker:dind استفاده کنید. یک نمونه ساده از اجرای DinD به صورت زیر است:

docker run --privileged --name dind-container -d docker:dind


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

جایگزین‌ها

در بسیاری از موارد، استفاده از روش‌های جایگزین مانند Docker خارج از کانتینر یا استفاده از ابزارهایی مانند Kubernetes می‌تواند مشکلات مربوط به DinD را حل کند و امنیت بیشتری فراهم کند.

#DinD

@Syntax_fa

Syntax | سینتکس

14 Oct, 22:36


Linter & pylint

لینتر ابزاری است که برای تحلیل کد استفاده می‌شود تا مشکلات احتمالی در کد را شناسایی کند. این ابزارها به توسعه‌دهندگان کمک می‌کنند تا با شناسایی خطاهای سینتکس، استانداردهای کدنویسی و مسائلی مانند memory leak و ... را شناسایی کنند و کیفیت کد را بهبود بخشند.

کاربردهای Linter


1. شناسایی خطاهای سینتکسی:
لینتر می‌توانند خطاهای سینتکسی را قبل از اجرای کد شناسایی کنند.

2. بهبود خوانایی کد:
با پیشنهادهایی برای رعایت استانداردهای کدنویسی می دهد، خوانایی کد را افزایش می‌دهند.

3. کاهش باگ‌ها:
با شناسایی مسائل بالقوه، به کاهش تعداد باگ‌ها کمک می‌کنند.

4. یکنواختی کد:
با اطمینان از رعایت استانداردهای یکسان در سراسر پروژه، یکنواختی کد را حفظ می‌کنند.

معرفی Pylint

پای لینت یک ابزار Linter برای زبان Python است که به تحلیل کد Python می‌پردازد تا مشکلات مختلفی مانند خطاهای سینتکسی عدم رعایت استانداردهای PEP 8 و مسائل منطقی را شناسایی کند.

ویژگی‌های Pylint


- شناسایی خطاهای نحوی و منطقی:
Pylint می‌تواند خطاهای نحوی و منطقی را در کد شناسایی کند.

- پیشنهاد برای بهبود کد:
با ارائه پیشنهادهایی برای بهبود کد، توسعه‌دهندگان را در نوشتن کدهای تمیزتر و بهینه‌تر یاری می‌دهد.

- پشتیبانی از استانداردهای PEP 8:
با بررسی کد نسبت به استانداردهای PEP 8، به رعایت بهترین شیوه‌های کدنویسی کمک می‌کند.

- گزارش‌دهی جامع:
گزارش‌های کاملی از مشکلات موجود در کد ارائه می‌دهد که شامل امتیازدهی به کیفیت کد نیز می‌باشد.

مثال نحوه استفاده از pylint:
pip install pylint

بعد از نصب کردن با دستور
pylint .

تمامی کد های پروژه را بررسی می کند.
خیلی مواقع نیاز است که لینتر ها و تنظیماتشان را تغییر بدهیم. برای اینکار دستور زیر را میزنیم تا فایل کانفیگ لینتر ساخته شود:
pylint --generate-rcfile > .pylintrc

در فایل .pylintrc می توانید بر حسب نیاز خودتان برخی از لینتر هارا غیر فعال کنید یا تنظیماتشان را تغییر دهید.

نحوه استفاده کاربردی از لینتر:
میتوانید در github workflow از لینتر استفاده کنید و اگر مشکلی شناسایی شد اکشن با خطا مواجه شود. همچنین می توانید از ابزار pre commit استفاده کنید و لینتر را تعریف کنید تا هر زمانی که کامیت جدیدی زده میشود بررسی کند اگر خطایی وجود دارد جلوی کامیت را بگیرد.

#linter #pylint #python

@Syntax_fa

Syntax | سینتکس

14 Oct, 08:59


شرکت SpaceX در موفقیتی تاریخی، تونسته بوستر Super Heavy رو روی برجی که از اون پرتاب شده بود، روی دو بازوی مکانیکی این برج با دقت فوق العاده ای فرود بیاره!

@normal_developer

Syntax | سینتکس

13 Oct, 13:34


🔍 بررسی استراتژی جداسازی عملیات چک کردن وجود و بازیابی اطلاعات از دیتابیس

دو رویکرد اصلی در این زمینه در نظر داریم:

1️⃣ جداسازی مسئولیت‌ها:
در این روش، دو متد جداگانه داریم:
- check_user_exists(user_id)
- get_user_by_id(user_id)

مزایا:
رعایت Single responsibility(SRP)
خوانایی و وضوح بیشتر کد
امکان استفاده مجدد از هر متد به صورت مستقل

معایب:
افزایش تعداد کوئری‌های ارسالی به دیتابیس

2️⃣ ترکیب عملیات در یک متد:
در این روش، یک متد واحد داریم:
- get_user(user_id)

مزایا:
کاهش تعداد کوئری‌های ارسالی به دیتابیس
بهبود کارایی

معایب:
احتمال نقض اصل Single responsibility
کاهش خوانایی و وضوح کد

🤔 حالا سوال این است: کدام رویکرد بهتر است؟

پاسخ: بستگی دارد!

باید فاکتورهایی مانند نیازهای پروژه، الگوهای استفاده، و اولویت‌های تیم را در نظر گرفت. اما یک راه حل میانه هم وجود دارد:

3️⃣ رویکرد میانه:
در این روش، یک متد اصلی داریم که می‌تواند مبنای سایر عملیات باشد:

class UserService:
@staticmethod
def get_user(user_id: int) -> Optional[User]:
try:
return User.objects.get(id=user_id)
except User.DoesNotExist:
return None

@staticmethod
def check_user_exists(user_id: int) -> bool:
return UserService.get_user(user_id) is not None

@staticmethod
def get_user_or_raise(user_id: int) -> User:
user = UserService.get_user(user_id)
if user is None:
raise ObjectDoesNotExist(f"User with id {user_id} does not exist")
return user


این رویکرد مزایای هر دو روش را ترکیب می‌کند:
تنها یک کوئری به دیتابیس زده می‌شود
اصل مسئولیت تکی تا حد زیادی رعایت می‌شود
انعطاف‌پذیری بیشتری در استفاده داریم
کد خوانا و قابل نگهداری است

شما کدام رویکرد را ترجیح می‌دهید؟

@Syntax_fa

Syntax | سینتکس

07 Oct, 13:25


کتاب django in production رو دادم به notebook llm و یه پادکست ساخته برامون که این کتاب درمورد چیا صحبت میکنه و یه دید کلی میده نسبت به کتاب.


پ.ن: سرویس notebook llm خلاصه مقاله یا کتابی که بهش دادید رو مثل یه پاکست که دو نفر دارن درمورد اون مقاله صحبت میکنن درمیاره!

SOURCE

@Syntax_Fa

Syntax | سینتکس

06 Oct, 05:39


⭐️ بنیاد دیسترو | حامی جهان اپن سورس

دیسترو یک بنیاد برای حمایت از دنیای متن‌باز است که به تولید و نظارت بر پروژه‌های مفید برای جوامع توسعه‌دهنده در سراسر جهان می‌پردازد. با ایجاد ایده‌های جدید، پیاده‌سازی ایده‌های مختلف، و انتشار رایگان آن‌ها در جهان، دیسترو گامی در جهت توسعه جوامع متن‌باز ایران برداشته است.

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

@DistroFDN
github.com/distrofdn/distrofdn

#open_source

@Syntax_fa

Syntax | سینتکس

03 Oct, 22:42


Syntax | سینتکس pinned «شب همگی سینتکسیا خوش باشه😉 بطور خیلی خلاصه اول ازتون میخوام که با دقت از این دو تا ویدیو فرانت اند وبسایت syntax دیدن کنید و انتخاب خودتون بهمون بگید که کدوم یکی از لحاظ تناسب و سایز ویجت ها و فونت ها به نسبت desktop بردیگری برتری داره؟ (جزئیات هر فرانت…»

Syntax | سینتکس

03 Oct, 22:29


فرانت اند (۲):

توضیحات :
Design size: 1440 x 1024
Desktop size : 1366 x 738

توی این دیزاین هم برخی آیتم هارو scale کردیم اما تفاوت قابل توجه در فونت ها و ویجت هایی که parent فونت ها هستن وجود داره .
ما تو این دیزاین size فونت هارو برای تمام desktop size ها ثابت قرار دادیم و مقدار ویجت والد رو بر اساس padding فونت ها بدست آوریم که خروجی شده این ویدیو

Syntax | سینتکس

03 Oct, 22:24


فرانت اند (۱)

توضیحات :
رفقا دیزاین سایز هر دو فرانت اند 1440 در 1024 هست ، اندازه desktop که فرانت اند نشون میده ۱۳۶۶ در ۷۳۸ هست .
اینجا برای اینکه آیتم ها ظاهر خودشون رو در هر نوع desktop حفظ کنه از scale کردن استفاده کردیم (بعضی جاها کل آیتم scale شده ، بعضی جاها برخی قسمت ها) .

طراحی فونت ها براساس متریال دیزاین هست و چون desktop ما از design size کوچیک تره ،برای اینکه ظاهر مینیمال و جذاب خودشو حفظ کنه از تمام فونت ها 2px کم کردیم و خروجی نهایی این شده

Syntax | سینتکس

03 Oct, 22:17


شب همگی سینتکسیا خوش باشه😉

بطور خیلی خلاصه اول ازتون میخوام که با دقت از این دو تا ویدیو فرانت اند وبسایت syntax دیدن کنید و انتخاب خودتون بهمون بگید که کدوم یکی از لحاظ تناسب و سایز ویجت ها و فونت ها به نسبت desktop بردیگری برتری داره؟

(جزئیات هر فرانت رو زیر ویدیو درج میکنم)

Syntax | سینتکس

23 Sep, 12:42


نکات مهم اجرای جنگو با Gunicorn

توضیح درباره Gunicorn
نمیخوام توضیحات زیادی بدم حوصلتون سر بره پس همون سه خط معرفی که تو وب سایت gunicorn نوشته رو براتون یکم شفافش میکنم:
اسمش مخفف green unicorn هستش
جی یونیکورن یک http سرور هستش که از استاندارد WSGI(Web server gateway interface) برای اجرای برنامه های وب پایتون استفاده میکنه.
استاندارد WSGI برای این بوجود اومد تا هر فریم ورک وب پایتونی روش خودشو واسه ارتباط پیاده نکنه و همه از یه استاندارد مشخص استفاده کنن.

در ادامه میگه gunicorn برای unix هستش و برای سیستم عامل هایی مثل مک و لینوکس طراحی شده.

بعدش میگه که جی یونیکورن از مدل pre-fork worker استفاده میکنه حالا این به چه معنیه؟
جی یونیکورن کاری که میکنه اینه قبل اینکه شروع به پردازش درخواست ها کنه، میاد و به اندازه ای که تنظیم کردید worker ایجاد میکنه که هر worker درخواست هارو بطور مستقل پردازش میکنه.

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

قسمت آخرشم میگه light resource هستش و منابع کمی مصرف میکنه همچنین برای ترافیک بالا عملکرد خوبی داره.

خب جی یونیکورن این ادعا هارو میکنه اما بیاید با چند تا مثال شرایطی رو بررسی کنیم که شما به غلط دارید از جی یونیکورن استفاده میکنید:

مثال اول
gunicorn --chdir config config.wsgi:application -b 0.0.0.0:8000

اگه با این دستور جی یونیکورن رو اجرا کنید باید به این نکته دقت کنید بصورت پیشفرض براتون فقط یدونه worker میسازه که این اصلا خوب نیست. خود جی یونیکورن پیشنهاد میده حتی اگه یدونه core دارید 4 تا ورکر بسازید و یه فرمولی هم داده که میگه«تعداد هسته های سی پی یو رو ضربدر 2 به علاوه یک کنید»
همچنین به شما اطمینان داده همین تعداد ورکر هزاران ریکوئست رو میتونن پاسخ بدن پس تعداد ورکر هارو الکی زیادش نکنید.
البته به کیس شما هم بستگی داره.
دستور بهتر برای اجرا اینه تعداد ورکر هارو مشخص کنیم:
gunicorn --workers 5 --chdir config config.wsgi:application -b 0.0.0.0:8000


مثال دوم:
فرض کنید کاربر ها تو اپلیکیشن شما فایل هایی رو آپلود میکنن. شما پنج تا ورکر دارید.
وقتی پنج تا کاربر همزمان فایل آپلود کنن بنظرتون چه اتفاقی میوفته؟
پنج تا ورکر شما گیر یه io افتادن و مشغولن و درخواست های دیگه کاربرا انجام نمیشه. خب این وضعیتی نیست که باب میلیتون باشه!
برای حل این مشکل کافیه از gevent توی جی یونیکرون استفاده گنید؛
gunicorn --workers 1 -k gevent --chdir config config.wsgi:application -b 0.0.0.0:8000

با فلگ -k نوع کلاس ورکر رو مشخص میکنیم. حالا چرا از gevent استفاده میکنیم؟
کتابخونه gevent برای مدریریت همزمانی طراحی شده. میشه گفت یک نمونه lightweight thread هستش که این مدل موقع عملیات های IO سوئیچینگ انجام میده و در این صورت اگه به io خوردید براتون هندل میکنه.

کلی نکات دیگه هم قطعا هست که تو یه پست جا نمیشه
امیدوارم براتون مفید باشه

#python #django #gunicorn #gevent

@Syntax_fa

Syntax | سینتکس

23 Sep, 09:03


Django Serializers: Related Fields in Serializer


وقتی با مدل‌های مرتبط در Django کار می‌کنیم، نمایش اطلاعات کامل آن‌ها در سریالایزرها می‌تواند چالش‌برانگیز باشد. خوشبختانه، Django REST Framework (DRF) ابزارهای قدرتمندی برای این کار در اختیار ما قرار می‌دهد.

سریالایزر DRF به‌طور پیش‌فرض برای فیلدهای مرتبط در هنگام سریال‌سازی داده‌ها از مقدار primary key استفاده می‌کند. به عنوان مثال:

class Author(models.Model):
name = models.CharField()
last_name = models.CharField()

class Blog(models.Model):
title = models.CharField()
author = models.ForeignKey(Author, on_delete=models.CASCADE)

class BlogSerializer(serializers.ModelSerializer):
class Meta:
model = Blog
fields = "__all__"


خروجی BlogSerializer به شکل زیر خواهد بود:

{
"title": "black python",
"author": 3
}


حالا اگر بخواهیم به جای PK، اطلاعات اضافی از Author نمایش دهیم، چند راه حل وجود دارد:

1. استفاده از depth:
با تنظیم پارامتر 1 = depth در Meta کلاس سریالایزر، می‌توانید مشخص کنید که تا چه عمقی از روابط مدل‌ها سریالایز شوند. این روش ساده و سریع است، اما کنترل کمتری بر روی داده‌های خروجی به شما می‌دهد.

class BlogSerializer(serializers.ModelSerializer):
class Meta:
model = Blog
depth = 1


خروجی BlogSerializer به شکل زیر خواهد بود:

{
"title": "python black",
"author": { "name": "amirhossein", "id": 1, "last_name": "some last name" }
}


2. استفاده از Nested Serializers:
با تعریف سریالایزرهای تو در تو، می‌توانید کنترل کاملی بر روی فیلدهایی که می‌خواهید از مدل‌های مرتبط نمایش دهید داشته باشید. این روش انعطاف‌پذیرتر است، اما نیاز به نوشتن کد بیشتری دارد , مثال:

class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields = ("name",)

class BlogSerializer(serializers.ModelSerializer):
author = AuthorSerializer()

class Meta:
model = Blog
fields = "__all__"


خروجی به شکل زیر خواهد بود:

{
"title": "black python",
"author": { "name": "amirhossein" }
}


مشکل N + 1 در هنگام استفاده از Depth یا Nested Serializer:
حتما باید در queryset خود از select_related یا prefetch_related استفاده کنید تا از بروز مشکل N + 1 جلوگیری کنید!

Django Serializers: Validators

1 : field level validators
برای اعتبار سنجی داده ها در سطح فیلد در drf باید از دستور زیر پیروی کنید:
class BlogSerializer(serializers.ModelSerializer):
....
def validate_<field name>(self, value): # validate_email
if vlaue in "_" :
serializers.ValidationError("some error")
return value

2 : object level validator

class BlogSerializer(serializers.ModelSerializer):
....
def validate(self, attrs):
if attrs.name == attrs.title :
serializers.ValidationError("name and title can not be same")
return value


Django Serializers: to_internal_value
متود to_internal_value در ModelSerializer قبل از اجرای اعتبارسنجی داده ها به داده های خام دسترسی دارد و میتوانید برای تغییر داده ها یا اضافه کردن داده ها قبل از اعتبارسنجی از اون استفاده کنید:
class BlogSerializer(serializers.ModelSerializer):
....
def to_internal_value(self, data):
data["user"] = self.context["user"] # افزودن شی user به data
return super().to_internal_value(data)

نکته:
اقا حتما موقع return از super().to_internal_value(data) استفاده کنید و return data استفاده نکنید ; چون اینطوری باعث میشه تمام validatorهای modelSerializer که از روی مدل شما بطور پیشفرض ساخته شده , غیرفعال بشن!

Django Serializers: to_representation

ما میتوانیم این رو ش را override کنیم تا قبل از داده های سریالی که نمونه سریالسازبر میگرداند،
دستکاری داده ها را انجام دهیم , مثال:
class BlogSerializer(serializers.ModelSerializer):
....
def to_representation(self, instance):
resp = super().to_representation(instance)
resp['title'] = resp['title'].upper()
return resp


برای اطلاعات بیشتر به کتاب :django in production مراجعه کنید.

Syntax | سینتکس

22 Sep, 09:47


📊 Raw Queries and Connection Proxy in Django

🔍 How to Get Raw Queries in ORM

در جنگو، اگر ویژگی .query یک QuerySet را چک کنیم، می‌توانیم پرس‌وجو SQL مربوطه را دریافت کنیم. به عنوان مثال:

from author import models
all_authors = models.Author.objects.filter(email__endswith='@gmail.com').values_list('name').query


خروجی:

SELECT "author_author"."name" FROM "author_author" WHERE "author_author"."email"::text LIKE '%@gmail.com'



⚠️ چالش!

در جستجوهای ORM جنگو، دستورهایی داریم که غیر از QuerySet هستند و استفاده از .query باعث ایجاد خطا می‌شود. به عنوان مثال:

from author import models
author_count = models.Author.objects.filter(email='a').count().queries


خطا:

Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'int' object has no attribute 'query'



🛠 راه‌حل با استفاده از Connection Proxy

برای حل این مشکل، از connection در django.db استفاده می‌کنیم:

from django.db import connection
from author import models

author_count = models.Author.objects.filter(email='a').count()
connection.queries[-1]


خروجی:

{'sql': 'SELECT COUNT(*) AS "__count" FROM "author_author" WHERE "author_author"."email" = \'a\'', 'time': '0.166'}



📌 توجه!

شی connection فقط زمانی نتیجه می‌دهد که سرور جنگو در حالت DEBUG=True در حال اجرا باشد!

📝 نوشتن Debug Queries برای درک Connection Proxy

from django.db import connection
from django.db import reset_queries

def database_debug(func):
def inner_func(*args, **kwargs):
reset_queries()
results = func(*args, **kwargs)
query_info = connection.queries
print(f'function_name: {func.__name__}')
print(f'query_count: {len(query_info)}')
queries = [f'{query["sql"]}\n' for query in query_info]
print(f'queries: \n{"".join(queries)}')
return results
return inner_func


📌 توجه! تابع reset_queries تمام پرس‌وجوهای ذخیره شده در connection را پاک می‌کند!

🔧 استفاده از کد:

@database_debug
def regular_query():
blogs = models.Blog.objects.all()
return [blog.author.name for blog in blogs]


خروجی:

function_name: regular_query
query_count: 4
queries:
SELECT "blog_blog"."id", "blog_blog"."title", "blog_blog"."content", "blog_blog"."author_id"



💡 توضیح کد:

با استفاده از دستور reset_queries تمام پرس‌وجوهای ذخیره شده در connection را حذف می‌کنیم تا فقط کوئری‌های خواسته شده دیباگ شوند. سپس کوئری‌های داخل inner_function که دکوراتور شده‌اند اجرا می‌شوند و شی connection حاوی لیست از پرس‌وجوها می‌شود. بعد از آن، تمام پرس‌وجوها را از connection.queries بازیابی می‌کنیم.


🔗 منبع : کتاب django in productions

Syntax | سینتکس

18 Sep, 22:14


زمانی که داشتم این کدارو میزدم فقط منو خدا میدونستیم چی به چیه
ولی الان فقط خدا میدونه🥹

پ.ن:
وقتی بعد چند وقت رو پروژه های قدیمت برمیگردی

#fun

@Syntax_fa

Syntax | سینتکس

13 Sep, 15:54


برای آشنایی بیشتر یه مثال هم اضافه کنم:

اگر از rich error استفاده نکنیم، برای هندل کردن ارور های مختلف مجبور بودیم از یک سولوشن دیگه بجز exception استفاده کنیم و یا اینکه بیایم و برای هر ارور به این صورت exceptionبنویسیم:
class UserNotFoundErr(Exception):
    pass


class IpBlockedErr(Exception):
    pass


class TooManyRequestErr(Exception):
    pass


class UserConflictErr(Exception):
    pass

در handler هم باید این کار رو میکردیم:

from examples.without_rich_error.service import get_user_service
from examples.without_rich_error.exception import UserNotFoundErr, UserConflictErr, TooManyRequestErr, IpBlockedErr


def get_user_handler(user_id: int):
    try:
        print(service.get_user_by_id(user_id=user_id))
    except UserNotFoundErr as err:
        print("user not found code is 404", err)
    except UserConflictErr as err:
        print("user conflict code is 409", err)
    except TooManyRequestErr as err:
        print("too many request code is 429", err)
    except IpBlockedErr as err:
        print("ip blocked code is 403", err)

در این صورت هرچقدر تعداد exceptionها بیشتر شود مدیریت کردن آنها نیز سخت تر خواهد شد. همچنین قدرت مشاهده گری سیستم با استفاده از exception ها نیز پایین می آید در صورتی که ما در rich error تمامی ارور هایی که در لایه های مختلف رخ داده باشند رو داشتیم.

اگه کد رو با rich error جایگزین کنیم:

from examples.with_rich_error.api import base_response_with_error, base_response


def get_user_handler(user_id: int):
    try:
        ...
    except Exception as err:
        return base_response_with_error(error=err)

از آنجا که ما یک ارور غنی داریم و از کد ها استفاده کردیم به راحتی میدانیم که این ارور به چه معنی است و حتی به سادگی http error مناسب را برگردانیم.

#rich_error #python

@Syntax_fa