<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های سید مرتضی موسوی</title>
        <link>https://virgool.io/feed/@se.mo.moosavi</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-07-06 15:53:44</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/7673/avatar/avatar.png?height=120&amp;width=120</url>
            <title>سید مرتضی موسوی</title>
            <link>https://virgool.io/@se.mo.moosavi</link>
        </image>

                    <item>
                <title>چگونه نیازمندی‌های پروژه‌ی rust رو به روز کنیم</title>
                <link>https://virgool.io/@se.mo.moosavi/%DA%86%DA%AF%D9%88%D9%86%D9%87-%D9%86%DB%8C%D8%A7%D8%B2%D9%85%D9%86%D8%AF%DB%8C-%D9%87%D8%A7%DB%8C-%D9%BE%D8%B1%D9%88%DA%98%D9%87-%DB%8C-rust-%D8%B1%D9%88-%D8%A8%D9%87-%D8%B1%D9%88%D8%B2-%DA%A9%D9%86%DB%8C%D9%85-vm3lkpedwkqh</link>
                <description>در دنیای امروز وقتی یه پروژه می‌زنیم، به طور معمول از چندین نیازمندی dependency استفاده می‌کنیم. زبان‌های مختلف روش‌های مختلفی برای نصب نیازمندی‌ها دارند. به طور مثال برای node js از npm یا yarn یا pnpm استفاده می‌کنیم. در زبان rust این موضوع بر عهده‌ی cargo می‌باشد.بسیاری از این نیازمندی‌هایی که نصب کردیم، خودشون کتاب‌خونه‌های زنده‌ای هستند که طی زمان به روز می‌شوند و امکانات جدید اضافه می‌کنند یا اشکالات قبلی رو رفع می‌کنند. پس لازمه در پروژه‌ی ما به روز بشوند.خب این کار رو چطور انجام بدیم؟ اول لازمه که لیست نیازمندی‌هایی که به روز شده‌اند رو داشته باشیم. برای این کار از cargo outdated استفاده می‌کنیم. این cargo outdated خودش یه کتاب‌خونه هستش که باید جدا نصبش کنیم روی سیستمcargo install --locked cargo-outdatedبعد از نصب، در داخل پروژه مون دستور زیر رو اجرا می‌کنیمcargo outdated -Rکه چنین خروجی به ما می‌ده:my-project
================
Name   Project  Compat  Latest  Kind    Platform
----   -------  ------  ------  ----    --------
regex  1.5.5    ---     1.5.6   Normal  ---بر اساس این لیست می‌تونیم نیازمندی‌هایی که باید به روز بشوند رو پیدا کنیم و با دستور زیر، اون‌ها رو به روز کنیم:cargo update -p regex</description>
                <category>سید مرتضی موسوی</category>
                <author>سید مرتضی موسوی</author>
                <pubDate>Tue, 21 Jun 2022 13:27:45 +0430</pubDate>
            </item>
                    <item>
                <title>ساخت API مدرن با GraphQL، بخش سوم</title>
                <link>https://virgool.io/SahabPardaz/%D8%B3%D8%A7%D8%AE%D8%AA-api-%D9%85%D8%AF%D8%B1%D9%86-%D8%A8%D8%A7-graphql-%D8%A8%D8%AE%D8%B4-%D8%B3%D9%88%D9%85-ggmcmby8syxc</link>
                <description>در بخش‌های قبل (۱ و ۲) گرف‌کیوال رو معرفی کردیم و به کمک جنگو گرافین یک ای‌پی‌آی ساده ساختیم تا با مفاهیم اولیه گرف‌کیوال و گرافین آشنا بشیم. در این بخش توضیح می‌دم چگونه کدها رو لایه بندی کنیم که پروژه‌ی تمیزتر و قابل نگه‌داری داشته باشیم.قبل از شروع این بخش لازمه مستندات graphql و مستندات graphene رو مطالعه کرده باشید و با مفاهیم‌شون آشنا باشید.این پروژه در این آدرس در دسترس عموم قرار دارد.لایه بندی و تفکیک وظایفاگه بخوایم بی‌خیال و کثیف کد بزنیم، چی کار باید بکنیم؟ یه تابع می‌نویسیم که همه کار توش انجام بشه. ریکوئست توش گرفته می‌شه، جیسون توش پارس می‌شه، هدر خونده می‌شه و تشخیص می‌ده که کاربر لاگین هست یا نه، چند تا شرط رو چک می‌کنه که ببینه کاربر دسترسی داره یا نه، یه چند تا کوئری هم به دیتا بیس می‌زنه، شاید یه چهار خط اون وسط چند تا منطق کسب و کار (Business logic) هم اعمال کنه، آبجکت جیسون رو سریالایز کنه و بنویسه در جواب ریکوئست، ناقابل چهارصد خط، تست هم که نداره، اصلا ما اهل این سوسول بازی‌ها نیستیم، تازه بخوایم تست هم بنویسیم نمی‌شه، پس به جد بی‌خیال تست.برای اینکه این اتفاق نیفته، لازمه که کدها لایه بندی مناسب داشته باشند، لایه بندی کد به ما کمک می‌کنه تا هر لایه رو بتونیم به طور مستقل مورد توجه قرار بدیم و در هر لایه تنها دغدغه‌های همون لایه رو داشته باشیم و حداکثر لازمه که interface لایه‌های دیگه رو مد نظر قرار بدیدم.یه لایه بندی خوب، برای ما تعریف می‌کنه که هر لایه چه وظایفی داره، چه فرضیاتی داره و مهم‌تر از اون چه فرضیاتی نداره، چه لایه‌ای رو می‌شناسه و چه لایه‌ای رو نباید بشناسه.لایه‌های جنگو و گرافینوقتی داریم با گرفین یک ای‌پی‌آی گرف‌کیوال پیاده می‌کنیم، اکثر کدهای ما در این دو دسته می‌گنجه: کدهای تعریف تایپ و کدهای تعریف resolver. کدهای تعریف تایپ به صورت اعلامی (declarative) هستند و اکثر کدهای دارای منطق ما در بخش resolver ها اجرا می‌شن. خوبه قبل از اینکه بریم و بخوایم لایه بندی‌های کد خودمون رو مشخص کنیم، ببینیم در اطرافمون و در جنگو و گرافین چه لایه‌هایی وجود داره و به چه لایه‌هایی دسترسی داریم.وقتی یه درخواست از کاربر به اپ جنگوی ما می‌رسه، ابتدا جنگو مواردی مثل پارس کردن ورودی رو انجام می‌ده. البته جنگو صرفا مواردی مثل json و query param و form data رو می‌شناسه و گرف‌کیوال رو نمی‌شناسه. همچنین مواردی مثل اینکه درخواست دهنده چه کاربری هستش رو از روی مواردی مثل کوکی‌ها تشخیص داده و از طریق request.user در اختیار ما قرار داده. خود این کارهای در داخل جنگو در چندین لایه مجزا انجام می‌شه، ولی فعلا همین که بدونیم به صورت کلی این کارها قبل از رسیدن درخواست کاربر به دست ما توسط جنگو انجام می‌شه، کافیه در لایه‌ی بعدی، گرفین وجود داره که موضوعات مربوط به گرف‌کیوال رو می‌شناسه. بلده کوئری گرف‌کیوال رو پارس بکنه، ورودی‌های کوئری بگیره و صحت‌سنجی و تبدیل کنه و resolver متناسب با کوئری رو صدا بزنه و در ادامه خروجی رو بگیره و صحت سنجی کنه و بدست جنگو بسپاره تا به عنوان جواب درخواست به کاربر برگردونده بشه.لایه‌ی دیگه که جنگو در اختیار ما قرار داده، لایه ORM هستش که به ما کمک می‌کنه بتونیم داده‌ها رو در پایگاه‌داده ذخیره و بازیابی کنیم.احراز هویت و مجاز شمارییکی از مسائلی که تقریبا تمام سرویس‌ها با اون مواجه هستند، دو مسئله‌ی «احراز هویت» و «مجاز شماری» است. خوبه اول این دو مورد رو تعریف کنیم:احراز هویت: احراز هویت یا Authentication قراره این سوال رو جواب بده، کاربر چه کسی هستش؟مجاز شماری: مجاز شماری یا Authorization قراره این سوال رو جواب بده که کاربر حق داره چه کارهایی انجام بده؟این دو موضوع رو کجای کد باید اعمال کنیم؟همون‌طور که قبل‌تر گفته شده، احراز هویت توسط جنگو انجام شده. ولی منطق مربوط به مجاز شماری، کاملا به کسب و کار ما بر می‌گرده و این ما هستیم که باید کدش رو بزنیم. کدهای مجاز شماری رو کجا بزنیم؟ وسط کدهای resolver گرف‌کیوال خوبه؟ نه.فرض کنیم ما بجز گرف‌کیوال ممکن است روش‌های ارتباطی دیگه‌ای مثل rest یا cli یا grpc یا تمپلیت‌های جنگو داریم. اگه ما کدهای مجاز شماری رو داخل resolver گرف‌کیوال بنویسیم، این منطق مجاز شماری تنها روی گرف‌کیوال اعمال می‌شه و مثلا روی کدهای رِست اعمال نمی‌شه. یا اگه بخوای اعمال بشه، لازمه کدهای مشابه زده بشه و معلوم هم نیست با چه مکانیسمی قراره این منطق‌ها با هم سینک بمونند و احتمالا بعد از یه مدت می‌بینیم منطق اعمال مجاز شماری بین روش‌های ارتباطی مختلف، فرق کرده و تفاوت رفتار دارند. مثلا کاربر از طریق گرف‌کیوال تنها پست‌های منتشر شده رو می‌تونه ببینه، ولی از طریق رِست همه‌ی پست‌ها رو می‌بینه در حالی که نباید این اتفاق می‌افتاد.اینکه یه کاربر حق داره چه کارهایی بکنه و چه چیزهایی رو ببینه ربطی به این نداره که این کاربر از چه طریقی به اپ ما وصل شده.روش نامناسب اعمال مجاز شماری منبعخب پس باید چی کار کنیم؟لایه منطق کسب و کارجواب اینه که باید یه لایه داشته باشیم که منطق کسب و کار ما بر عهده‌ی اون لایه باشه و بخشی از وظایف لایه کسب و کار، اعمال قواعد مجاز شماری هستش. به این ترتیب در لایه‌ی گرف‌کیوال و در کدهای resolver که ما می‌نویسیم، نباید اثری از کدهای مجازشماری و کدهای منطق کسب و کار وجود داشته باشه.در غیر این صورت مجبور می‌شیم که این کدها رو در روش‌های ارتباطی دیگه مثل رِست هم کپی کنیم.روش مناسب اعمال مجاز شماری منبعلایه کسب و کار قرار نیست ذره‌ای در مورد پروتکل‌های http و گرف‌کیوال و ... بدونه، این لایه باید منطق خالص باشه. و تنها حق داره لایه‌ی داده رو بشناسه. خود من وقتی با جنگو کد می‌زنم، اجازه می‌دم لایه کسب و کار، ORM جنگو رو به عنوان لایه‌ی دیتا بشناسه و از اون استفاده کنه، ولی به هیچ وجه مواردی مثل http توی کدهای این لایه نیست.سوالی که اینجا پیش می‌آد اینه که پس لایه گرف‌کیوال اینجا چی کار می‌کنه؟ با این روش، لایه گرف‌کیوال یه لایه‌ی بسیار نازک می‌شه که یه وظایف بیشتر نداره: صدا کردن تابع مناسب از لایه‌ی کسب و کار و پاس دادن ورودی‌های گرفته شده از کاربر به لایه‌ی کسب و کار. در صورت لزوم ممکن است برای این که ورودی‌ها مناسب لایه‌ی کسب و کار بشه، یه تبدیل روی ورودی‌ها انجام بده. ولی باید مراقب باشیم هیچ بخشی از مجاز شماری و یا منطق کسب و کار در لایه گرف‌کیوال نباشه. در حالت ایده‌آل هیچ عبارت شرطی مثل if در لایه‌ی گرف‌کیوال و  resolver ها وجود ندار.در ادامه یه کم دست به کد می‌شیم.مثال عملیفرض بگیریم یه تعداد پست داریم، که برخی از این‌ها در وضعیت پیش‌نویس قرار دارند و برخی هم منتشر شده‌اند. قرار است همه‌ی کاربران بتوانند پست‌های منتشر شده را ببینند ولی پست‌های پیش‌نویس تنها توسط نویسنده قابل مشاهده می‌باشد.منطق کسب و کار داخل resolverدر نگاه اول، این کد داره کار می‌کنه و همه چی خوبه، ولی نکته اینجا است که ممکنه کد مشابهی هم در بخش‌های مربوط به رِست و یا view های جنگو زده شده باشه. ولی اگه فردا روزی لازم بشه این منطق عوض بشه،‌ اون وقت لازمه که بریم چند جا رو به صورت مشابه تغییر بدیم و حتی ممکنه بعضی موارد رو فراموش کنیم و رفتار رِست و گرف‌کیوال متفاوت بشه.برای اصلاح، همون طور که بالاتر بحث شد، یک لایه‌ی جدید باید ایجاد کنیم که منطق‌های مخصوص کسب و کار در اون بخش نوشته شده باشه. من اسم این لایه رو interactor گذاشتم. رویه‌ی من در جنگو این طور بوده که interactor ها تنها حق دارن آبجکت‌های مربوط به مدل رو بشناسن و از مواردی مثل http و graphql نباید خبر داشته باشن. یک interactor می‌تونه یک تابع و یا یک کلاس باشه. در این مورد ساده، من یک تابع تعریف می‌کنم. (اسم interactor از این ارائه‌ی uncle bob گرفته شده)تابع interactorتعریف resolver با استفاده از interactor و بدون پیاده‌سازی مستقیم منطق کسب و کاردر لایه‌ی گرف‌کیوال و کد resolver دیگه اثری از کدهای مربوط به منطق کسب و کار ما وجود نداره و در کد resolver تنها تابع interactor استفاده شده. این تابع interactor می‌تونه به صورت مشترک بین رِست و دیگر روش‌های ارتباطی به صورت مشترک استفاده بشه و در صورتی که لازم شد منطق کسب و کار ما تغییر کنه، فقط اون تابع interactor تغییر می‌کنه.چرا به جای user متغییر info ویا info.context رو به عنوان ورودی به تابع interactor پاس ندیم؟ چون info یه آبجکت مربوط به graphql هستش و info.context هم یک آبجکت مربوط به http هستش و قرار نیست لایه منطق کسب و کار ما از این موضوعات خبر داشته باشند. مثلا اگه info ورودی بود، دیگه بخش مربوط به رِست نمی‌تونست از این تابع استفاده کنه. اگه info.context رو پاس می‌دادیم، بخش مربوط به rpc دیگه نمی‌تونست از این تابع استفاده کنه. ولی user مربوط به لایه‌ی ORM هستش و بنابر این interactor حق داره درباره‌اش بدونه.تغییر شاید کوچک به نظر برسه، ولی به شدت در تمیزی کد و نگه‌داشت‌پذیری کد (maintainability) کمک کننده هستش، مخصوصا اگه چند کانال ارتباطی مثل رِست و گرف‌کیوال به صورت همزمان وجود داشته باشه و یا اینکه منطق‌های کسب و کار پیچیده باشه، این موضوع بیشتر آشکار می‌شه. در این آدرس می‌تونید نمونه‌ی interactor ها رو در یک پروژه‌ی واقعی ببینید که به نسبت پیچیده‌تر هستند و تعدادشون هم اون‌قدر زیاد هستش که به جای یک فایل، یک پوشه interactors داریم.نکته‌ی جذاب دیگه این هستش که می‌تونیم کدهای مربوط به منطق کسب و کار رو مستقل از بقیه لایه‌ها تست کنیم:تست منطق کسب و کارجمع بندیدر این بخش بررسی کردیم که با اضافه کردن یک لایه‌ی کسب و کار می‌تونیم کد را تمیزتر کنیم و نگه‌داشت‌پذیری کد را افزایش بدیم.در بخش بعدی در این مورد صحبت خواهیم کرد که چطور می‌تونیم تا جای ممکن اپ‌های جنگو رو از هم مستقل نگه داریم تا قابلیت استفاده‌ی مجدد از اون‌ها بالا بره.</description>
                <category>سید مرتضی موسوی</category>
                <author>سید مرتضی موسوی</author>
                <pubDate>Sat, 21 Aug 2021 15:39:11 +0430</pubDate>
            </item>
                    <item>
                <title>ساخت API مدرن با GraphQL، بخش دوم</title>
                <link>https://virgool.io/SahabPardaz/%D8%B3%D8%A7%D8%AE%D8%AA-api-%D9%85%D8%AF%D8%B1%D9%86-%D8%A8%D8%A7-graphql-%D8%A8%D8%AE%D8%B4-%D8%AF%D9%88%D9%85-ewxcofo288mz</link>
                <description>در بخش قبل گرف‌کیوال رو معرفی کردیم و گفتیم که چه مشکلاتی رو حل می‌کنه، در این بخش با استفاده از Django و Graphene یک ای‌پی‌آی گرف‌کیوال خواهیم ساخت. البته بیشتر توجه روی بخش گرف‌کیوال خواهد بود و فرض می‌کنیم شما با Django آشنایی دارید.این پروژه در این آدرس در دسترس عموم قرار دارد.راه‌اندازی ای‌پی‌آی گرف‌کیوالنصب grapheneابتدا با استفاده از دستور زیر کتاب‌خانه‌ی graphene-django را نصب می‌کنیم:pip install graphene-djangoو در فایل settings.py تغییرات زیر را اعمال می‌کنیم:در قسمت INSTALLED_APPS اپ graphene_django را اضافه کردیم.در انتهای فایل، خط‌های زیر را اضافه می‌کنیم. این چند خط به گرافین می‌گه از کجا ساختار اسکیما رو بخونه.تعریف اسکیماگرافین در پکیج graphql_api.schema دنبال متغیر schema خواهد گشت، مشابه ایمپورت‌ها در پایتون. بنابر این پوشه‌ی graphql_api/schema رو ایجاد می‌کنیم و توش چند تا فایل زیر رو می‌سازیم:تا به اینجا یه کوئری خیلی ساده تعریف کردیم. توی این کوئری تعریف کردیم که یه فیلد وجود داره به نام hello که تایپش String هستش، بعدش هم گفتیم که هر وقت کسی مقدار این فیلد رو خواست، در جواب رشته‌ی world رو برگردونه.روش کار graphene به این صورت است که برای هر فیلدی که تعریف می‌کنیم به دنبال تابعی می‌گردد که با resolve شروع شود و در ادامه نام فیلد بیاید. به طور مثال برای فیلد hello به دنبال تابع resolve_hello می‌گردد و هنگامی که بخواهد کوئری گرف‌کیوال را اجرا کند و مقدار hello را بداند این تابع را صدا می‌کند.افزودن graphql به routingحالا لازمه که یه url تعریف کنیم تا بتونیم به ای‌پی‌ای گرف‌کیوال دسترسی داشته باشیم. فایل urls رو به شکل زیر تغییر می‌دیم تا ای‌پی‌آی graphql در آدرس /gaphql/ دیده بشه:سرور رو اجرا می‌کنیم و به آدرس localhost:8000/graphql می‌ریم تا ببینیم ای‌پی‌آی چطور کار می‌کنه. توی قسمت سمت چپ کوئری graphql رو که می‌خوایم اجرا بشه رو می‌نویسیم و جواب سرور رو دریافت می‌کنیم.سمت راست: جواب سرور، سمت چپ: درخواستبرای اینکه اسکیمای گرف‌کیوال رو به صورت فایل داشته باشیم دستور زیر رو اجرا می‌کنیم:python manage.py graphql_schema --out schema.graphqlو فایل schema.graphql ایجاد می‌شه، و فایل اسکیمای ساخته شده رو در اختیار تیم‌های دیگه قرار می‌دیم که قراره از این ای‌پی‌ای استفاده کنند.اسکیمای hello worldتعریف ای‌پی‌آی مربوط به مدلتا به اینجای کار یه اسکیمای خیلی ساده ساختیم، در ادامه چندتا مدل می‌سازیم و براشون تایپ‌های گرف‌کیوال را تعریف می‌کنیم.تعریف مدل‌های Post و Commentدو تا مدل Post و Comment را به این شکل تعریف می‌کنیم:مدل پست و کامنتتعریف تایپ Postحالا می‌خوایم Post رو به گرف‌کیوال اضافه کنیم، برای این کار لازمه دو تا کار انجام بشه:تعریف تایپ متناظر با مدل Post.تعریف کوئری که بتونیم یک پست رو با آی‌دی بگیریم.تعریف تایپ متناظر با مدل postاین چند خط داره می‌گه که متناظر مدل Post یک تایپ گرف‌کیوال وجود داره و فیلد‌های id و title و body یک پست قابل کوئری کردن هستند. گرفین به صورت اتوماتیک خودش تایپ‌های مدل رو بررسی می‌کنه و تایپ‌های متناظر رو در گرف‌کیوال برای این فیلد‌ها تعیین می‌کنه.حالا باید به کوئری اصلی یه فیلد post اضافه کنیم که id رو ورودی می‌گیره و در صورتی که پست متناظر با این آی‌دی وجود داشت، مقدار پست رو بر می‌گردونه. برای این کار یه کلاس جدید تعریف می‌کنیم:تعریف کوئری مربوط به پستدر این چند خط یک کلاس PostQuery تعریف کرده‌ایم. در این کلاس گفتیم که یک فیلد پست وجود دارد که یک آرگیومنت از نوع ID ورودی می‌گیرد و در خروجی PostType بر می‌گرداند (تایپ گرف‌کیوال متناظر با مدل Post) و سپس تابع resolve_post را تعریف کرده‌ایم این تابع از ورودی id رو می‌خونه و با استفاده از امکانات مدل جنگو، پست رو پیدا می‌کنه و بر می‌گردونه.حالا باید به کوئری اصل اضافه بشه:اضافه کردن کوئری مربوط به پست به کوئری اصلیبا اضافه کردن PostQuery به کلاس‌های پدر Query اصلی، فیلد post به Query اصلی اضافه می‌شود.حال ای‌پی‌آی رو تست می‌کنیم:در این حالت اسکیمای جدید ما به این شکل می‌باشد:یه تایپ جدید به نام PostType اضافه شده است، هم‌چنین فیلد post به کوئری اصلی اضافه شده است.تعریف رابطه‌هاتا به اینجای کار یک تایپ جدید با فیلد‌های ساده ایجاد کردیم، اما در بسیاری از موارد فیلدهای پیچیده نیاز داریم. به طور مثال یک پست، فیلد نویسنده دارد. هم‌چنین لازم است بتوانیم لیست کامنت‌های مربوط به پست را نیز بگیریم. در ادامه این نوع فیلد‌ها را بررسی می‌کنیم.ابتدا دو تایپ گرف‌کیوال برای یوزر و کامنت تعریف می‌کنیم:حال نویسنده و لیست کامنت‌ها رو به پست اضافه می‌کنیم:مقدار self در تابع resolve_comments یک پست است که از مدل Post ایجاد شده است (در این مثال دقیقا همان پستی است که از تابع resolve_post در PostQuery برگردانده شده است). بنابر این می‌توانیم از تمام امکاناتی که مدل جنگو در اختیار ما قرار می‌دهد استفاده کنیم، مثلا لیست کامنت‌ها رو بگیریم و حتی در صورت نیاز، فیلتر کنیم.حالا می‌توانیم دیتای مربوط به کامنت‌ها و نویسنده را از پست بگیریم:تا به اینجا اسکیمای ما شامل تایپ کامنت، یوزر و پست می‌باشد:پیشنهاد می‌کنم در ادامه مستندات graphql و مستندات graphene رو مطالعه کنید تا برای بخش‌های بعدی آماده باشید. جمع بندیتا به اینجای کار یک ای‌پی‌آی ساده‌ی گرف‌کیوال رو راه‌اندازی کردیم و چند تا تایپ هم توش تعریف کردیم و با مفاهیم اولیه گرف‌کیو ال آشنا شدیم. در بخش‌های بعدی مفاهیم پیشرفته‌تری رو توضیح خواهم داد.</description>
                <category>سید مرتضی موسوی</category>
                <author>سید مرتضی موسوی</author>
                <pubDate>Mon, 22 Feb 2021 16:30:12 +0330</pubDate>
            </item>
                    <item>
                <title>ساخت API مدرن با GraphQL، بخش اول</title>
                <link>https://virgool.io/SahabPardaz/%D8%B3%D8%A7%D8%AE%D8%AA-api-%D9%85%D8%AF%D8%B1%D9%86-%D8%A8%D8%A7-graphql-%D8%A8%D8%AE%D8%B4-%D8%A7%D9%88%D9%84-hgz8kp3pjcbw</link>
                <description>تا حالا شده وسط پیاده‌سازی کد، اعضای تیم مجبور بشن چندین بار از هم بپرسند که جزئیات رِست (Rest) ای‌پی‌آی چیه؟ و مجبور بشید برید وسط کدها بگردید تا پارامترهای ای‌پی‌آی رو پیدا کنید تا به هم‌تیمی‌تون بگید چجوری باید درخواست بده؟ یا اینکه کد ای‌پی‌آی عوض شده و هماهنگی‌ها به درستی انجام نشده و محصول به مشکل خورده؟ گرف‌کیوال می‌تونه بسیاری از این مشکلات رو کم کنه و به شما کمک کنه با اطمینان محصول توسعه پیدا کنه و تجربه‌ی توسعه (DX، Developer Experience) و حتی تجربه‌ی کاربری (UX) بهتری داشته باشید. در ادامه به بررسی گرف‌کیوال خواهیم پرداخت.گرف‌کیوال چیست؟گرف‌کیوال، یک استاندارد است که یک زبان کوئری تعریف می‌کنه. یک اسکیما برای یک ای‌پی‌آی گرف‌کیوال تعریف می‌شه و بر اساس اون اسکیما کوئری‌ها به سرور زده می‌شه و جواب کوئری‌ها بر می‌گرده. اسکیما شامل همه‌ی اطلاعات لازم برای توصیف ای‌پی‌آی هستش: انواع تایپ‌ها، نام و تایپ فیلد‌ها، و حتی مستندات و توضیحات مناسب برای انسان. برای نمونه یه اسکیما این شکلی هستش:اسکیمای نمونهچرا گرف‌کیوال؟در ابتدا تعدادی از مشکلاتی که ای‌پی‌ای‌های رِست (Rest) داشتند رو توضیح می‌دم، بعدش می‌گم که گرف‌کیوال چجوری این مشکلات رو حل می‌کنه.مشکل over-fetchingدر هنگام استفاده از ای‌پی‌آی‌های رِست خیلی وقت‌ها سرور دیتای اضافه به ما بر می‌گردونه که هم میزان مصرف شبکه رو زیاد می‌کنه و هم بار اضافی روی سرور داره، مثلا شما لیست کتاب‌ها رو از سرور می‌گیرید، اطلاعات عنوان کتاب و نام نویسنده رو نیاز دارید، ولی سرور اطلاعت اضافه زیادی برای شما می‌فرسته که هیچ وقت استفاده نمی‌کنید، مثلا سال چاپ، آی‌دی انتشارات و حتی متن پشت جلد!در گرف‌کیوال، کلاینت دقیقا می‌گه چه فیلدهایی رو نیاز داره و سرور تنها اون اطلاعت رو ارسال می‌کنه. مثلا در صفحه‌ی لیست کتاب‌ها فقط به عنوان نیاز دارید و در صفحه جزئیات کتاب، اکثر فیلدها رو درخواست می‌دید و در هر صفحه تنها به اندازی کافی دیتا دریافت می‌کنید.مشکل under-fetchingدر هنگام استفاده از ای‌پی‌آی‌های رِست خیلی وقت‌ها سرور دیتای کافی به ما بر نمی‌گردونه، مثلا دیتای لیست کتاب‌ها رو فرستاده، ولی نام نویسنده رو نداده و صرفا آی‌دی نویسنده رو برای ما ارسال کرده، در این صورت ما مجبوریم دوباره یه درخواست جدید بدیم و جزئیات اطلاعات نویسنده رو بگیریم و از توش نام نویسنده رو پیدا کنیم تا بتونیم به درستی نمایش بدیم. این باعث می‌شه برای نمایش کامل اطلاعات چندین درخواست به سرور ارسال بشه.در گرف‌کیوال، امکان کوئری زدن دیتا‌های مرتبط وجود داره، یعنی کلاینت می‌گه عنوان کتاب و نام نویسنده رو نیاز دارم و کل دیتا در یک درخواست به دست کلاینت می‌رسه:کوئری نمونهپاسخ سرورمشکل حدس زدن و عدم اطمینانفرض بگیرید یک ای‌پی‌آی رِستی وجود دارد که اطلاعات مربوط به پست‌ها و کامنت‌های یک بلاگ رو در اختیار شما قرار می‌ده. و شما قصد دارید لیست پست‌ها رو بگیرید، دقیقا باید به کجا درخواست بدید؟ احتمالا درخواست باید به ‎/api/posts  زده بشه، اگه بخواید یه تک پست رو دریافت کنید چطور؟ ‎/posts/45 هستش یا ‎/post/45 و لیست کامنت‌های یک پست از کجا می‌آد؟ ‎/posts/45/comments و یا یه روش دیگه؟الان یه پست چه مقادیری رو به من بر می‌گردونه؟ عنوان در چه فیلدی هستش؟ title یا post_title یا postTitle یا ... آیا متن پست در پاسخ سرور هستش یا صرفا خلاصه پست اومده؟ آیا تعداد کامنت رو هم می‌ده؟اگه در آینده یکی از این فرضیات عوض بشه چی؟ چه زمانی و به چه طریقی قراره بفهمیم، آیا توسعه‌دهنده‌ی backend شخصا به توسعه‌دهندگان frontend باید خبر بده؟البته برخی از این مشکلات با روش‌هایی مثل استفاده از swagger قابل حل هستند، ولی هم زحمت پیاده‌سازی‌اش وجود داره، و خیلی وقت‌ها هم واقعا کسی همت نکرده و کلا وجود نداره.اما در گرف‌کیوال همه‌ی درخواست‌ها به یک end-point می‌ره، هم‌چنین از ابتدا مفهوم اسکیما (schema) وجود داشته که می‌گفته دقیقا چه تایپ‌هایی وجود داره، هر تایپ چه فیلد‌هایی داره و تایپ هر فیلد چیه و این امکان وجود داره که برای هر فیلد مستندات و توضیحاتی اضافه کنید. دیگه لازم نیست اسم فیلد‌ها حدس زده بشه.حتی ابزارهای مختلفی وجود داره که در هنگام توسعه بر اساس اسکیما راهنمایی می‌کنند که چه فیلد‌هایی وجود داره. هم‌چنین می‌شه در زمان کامپایل و قبل از اجرای برنامه صحت کوئری‌ها بررسی بشه. و برای زبان‌هایی مثل typescript و یا kotlin که تایپ رو پشتیبانی می‌کنند، تایپ‌های متناظر با کوئری ساخته می‌شه و هنگام استفاده از پاسخ سرور با اطمینان کامل کد می‌زنیم.هم در سرور و هم در کلاینت کاملا مطمئن هستیم تایپ ورودی‌های سرور و پاسخ سرور مطابق اسکیما هستش و از این نظر توسط کتاب‌خانه‌های گرف‌کیوال تایپ‌ها اعتبار سنجی شده‌اند و با خیال راحت می‌تونیم وقت برای منطق اختصاصی برنامه خودمون صرف کنیم.با قدرت و اقتدار کد بزنیدجمع‌بندیتا به اینجا گرف‌کیوال رو معرفی کردیم و برخی از فواید و مشکلاتی رو که حل می‌کنه رو بیان کردیم. در بخش بعد با استفاده از Django و Graphene یه ای‌پی‌آی ساده گرف‌کیوال رو پیاده سازی خواهیم کرد.</description>
                <category>سید مرتضی موسوی</category>
                <author>سید مرتضی موسوی</author>
                <pubDate>Mon, 22 Feb 2021 16:28:57 +0330</pubDate>
            </item>
                    <item>
                <title>جنگ استیت، recoil یا react-wire، مسئله این نیست!!</title>
                <link>https://virgool.io/@se.mo.moosavi/%D8%AC%D9%86%DA%AF-%D8%A7%D8%B3%D8%AA%DB%8C%D8%AA-recoil-%DB%8C%D8%A7-react-wire-%D9%85%D8%B3%D8%A6%D9%84%D9%87-%D8%A7%DB%8C%D9%86-%D9%86%DB%8C%D8%B3%D8%AA-gykii2rmeqhg</link>
                <description>یک هفته پیش، یکی از دوستان برام این پیام رو ارسال کرد:اومدم ریکویل رو برات بفرستم لینکشو بگم احتمالا علاقه‌مند باشی بهش، دیدم به اشتراک گذاشتی تو کانالت :)اون کتابخونه‌ت رو فکر کنم باید deprecate کنی ؛)داستان از چه قرار بود؟ هفت ماه پیش، در نوامبر ۲۰۱۹، کتاب‌خانه‌ای منتشر کردم به نام react-wire تا یکی از مشکلات مدیریت استیت در ری‌اکت رو حل کنم. تقریبا دو هفته پیش، می ۲۰۲۰، فیس‌بوک-اکسپریمنتال کتاب‌خانه‌ای رو منتشر کرد به نام recoil تا دقیقا همین مشکل را با روشی مشابه حل کنند. ری‌کویل توجه بسیاری رو به خودش جلب کرد. و طی همین مدت کوتاه بیش از ۵ هزار استار گرفته، و خود من هم شاید در پروژه‌های آینده به جای ری‌اکت-وایر از ری‌کویل استفاده کنم.ارائه‌ی ری‌کویل توسط دیویدقطعا مسئله این نیست که ری‌کویل استفاده کنیم، یا ری‌اکت-وایر؟ جواب واضحا برای اکثر افراد ری‌کویل هستش. جنگی در کار نیست، پیروز میدان ری‌کویل است. حتی بعید نیست در آینده‌ای نزدیک ری‌کویل، کتاب‌خانه پر طرفدار ری‌داکس رو هم از میدان به در کند.موضوعی که می‌خوام الان مطرح کنم، مسئله‌ی نحوه‌ی ارائه است. شاید در فرصتی دیگه به این موضوعات فنی بپردازم.مسئله ارائه است!من به درستی مشکل رو تشخیص دادم و راه حلی هم ارائه کردم، راه حل هم به نسبت خوب بود. به تجربه فهمیده بودم که باید فایل README خوبی داشته باشم. سعی کردم در این فایل، API رو به خوبی توضیح بدم. ولی دیگه فرصت نشد یک مثال کامل کاربردی ارائه کنم، سایت براش بسازم یا ویديو براش تولید کنم. و از همه مهم‌تر فرصت نشد به درستی مشکل و فلسفه قضیه رو مکتوب کنم. برای برخی دوستان شفاهی مشکل رو توضیح دادم و بحث کردیم، اما مکتوب نشد. وقتی چند ماه پیش برای دوستان توضیح می‌دادم که چرا ری‌اکت-وایر لازم است، دقیقا همین هفت دقیقه‌ی اول این ویدیو مربوط به ری‌کویل رو بیان می‌کردم.من از نظر فنی مسیر رو درست تشخیص داده بودم و راه‌کار ارائه کردم. ولی نتونستم در ارائه به جامعه به خوبی عمل کنم. این کتاب‌خونه رو صرفا کسانی که شفاهی براشون توضیح داده بودم می‌شناختند و تعداد کم‌تری هم استفاده می‌کردند.شاید لازم باشه در دفعات بعد در نحوه‌ی ارائه راه‌کارها بهتر عمل کنم. کم‌تر در بعد فنی سخت‌گیری کنم و زودتر به تبلیغات و ارائه‌ی عمومی پروژه‌ها بپردازم و حتی ویدیو درست کنم.اگر شما هم پیشنهاد، راهکار یا تجربه‌ای برای این موضوع «نحوه‌ی ارائه‌ی» دارید در کامنت‌ها به اشتراک بگذارید.</description>
                <category>سید مرتضی موسوی</category>
                <author>سید مرتضی موسوی</author>
                <pubDate>Sat, 23 May 2020 01:40:28 +0430</pubDate>
            </item>
                    <item>
                <title>پرینت فایل پی‌دی‌اف از ترمینال</title>
                <link>https://virgool.io/@se.mo.moosavi/%D9%BE%DB%8C%D8%B1%DB%8C%D9%86%D8%AA-%D9%81%D8%A7%DB%8C%D9%84-%D9%BE%DB%8C%D8%AF%DB%8C%D8%A7%D9%81-%D8%A7%D8%B2-%D8%AA%D8%B1%D9%85%DB%8C%D9%86%D8%A7%D9%84-qm1rmkwwqruu</link>
                <description>امروز می‌خواستم ۱۲ تا فایل پی‌دی‌اف رو پرینت کنم و حال نداشتم که دستی و یکی یکی فایل‌ها رو باز کنم و پرینت کنم. برای همین یه تحقیق کوچیک کردم که چجوری می‌شه از ترمینال دستور پیرینت رو ارسال کرد و بعد از اینکه فاز تحقیقات تموم شد، پرینت کردن فایل‌های تنها چند ثانیه طول کشید و البته بدون خطا.مرحله اول: پیدا کردن پرینتر مورد نظرتوی محیطی که من حضور داشتم چندتا پرینتر وجود داشت. برای اینکه لیست پرینترها رو ببینم دستور زیر رو اجرا کردمlpstat -sبا اجرای این دستور لیست پرینترها به همراه آدرس آی‌پی نمایش داده شد و من اسم پرینتر مورد نظرم رو از روی آی‌پی پیدا کردم.مرحله دوم: لیست کردن فایل‌های مورد نظرتمام فایل‌هایی که می‌خواستم پرینت کنم در یک پوشه و در چند زیرپوشه قرار داشت. برای همین از دستور find استفاده کردمcd my-directory
find . | grep pdfلیست کل فایل‌ها پی‌دی‌اف در این پوشه نمایش داده شد و من لیست این فایل‌ها رو کپی کردم در vscode تا برای مراحل بعد آماده‌اش کنممرحله سوم: پرینت فایل‌هایدر نهایت با دستور زیر تمام فایل‌ها رو پرینت گرفتمlp -d MY_PRINTER dir/my-file1.pdf
lp -d MY_PRINTER dir/my-file2.pdf
lp -d MY_PRINTER dir/my-file3.pdfبرای این‌که دستورات رو هم بنویسم از امکان Multi cursor ویرایش‌گر vscode استفاده کردمامیدوارم این تجربه برای شما هم مفید باشه. تا می‌توانید تنبل باشد.مراجع:http://man7.org/linux/man-pages/man1/find.1.htmlhttp://man7.org/linux/man-pages/man1/lpstat.1.htmlhttp://man7.org/linux/man-pages/man1/lp.1.htmlhttps://code.visualstudio.com/docs/getstarted/tips-and-tricks#_multi-cursor-selection</description>
                <category>سید مرتضی موسوی</category>
                <author>سید مرتضی موسوی</author>
                <pubDate>Sun, 13 Oct 2019 23:24:48 +0330</pubDate>
            </item>
                    <item>
                <title>دسترسی آسان به ذخیره‌سازی ابری با rclone</title>
                <link>https://virgool.io/@se.mo.moosavi/%D8%AF%D8%B3%D8%AA%D8%B1%D8%B3%DB%8C-%D8%A2%D8%B3%D8%A7%D9%86-%D8%A8%D9%87-%D8%B0%D8%AE%DB%8C%D8%B1%D9%87%D8%B3%D8%A7%D8%B2%DB%8C-%D8%A7%D8%A8%D8%B1%DB%8C-%D8%A8%D8%A7-rclone-yrethtaa7bqu</link>
                <description>خیلی از ما با خدمات ذخیره‌سازی ابری مثل google drive و یا dropbox آشنا هستیم و احتمالا از اپ یا وب اون‌ها استفاده کردیم.اما اگه از دوستان لینوکس کار باشید که زمان زیادی رو در ترمینال سر می‌کنید، بدتون نمی‌آد به جای اپ و یو‌آی بتونید از ترمینال فایل‌هاتون در فضای ابری ذخیره کنید. امروز با ابزاری آشنا شدم که این کار رو به خوبی انجام می‌ده و تعداد زیادی از سرویس‌ها رو پشتیبانی می‌کنه rclone. در ادامه با نصب، راه‌اندازی و استفاده از این ابزار آشنا می‌شیم.قدم اول، نصبساده‌ترین روش نصب استفاده از دستور زیر هستش که از اینجا کپی کردم:curl https://rclone.org/install.sh | sudo bashخب الان دیگه باید بتونید دستور rclone رو اجرا کنید.قدم دیم، راه‌اندازیبرای راه اندازی خیلی ساده باید دستور rclone config رو اجرا کنید و به سوالاتی که می‌پرسه پاسخ بدید. برای مثال ما در این نوشته یه دسترسی به google drive رو ایجاد می‌کنیم.در قدم اول از شما می‌پرسه که می‌خواید چه کار انجام بدید. ما هم با زدن دکمه‌ی n می‌گیم که می‌خوایم یه کانفیگ جدید ایجاد کنیم.در قدم بعد از شما می‌پرسه که اسم کانفیگ جدید چی باشه. مثلا می‌نویسیم driveبعد یه لیست بلند و بالا به شما نشون می‌ده و از شما می‌خواید سرویس ذخیره‌سازی مورد نظرتون رو انتخاب کنید. ما شماره‌ی ۱۱ رو تایپ می‌کنیم که مربوط به google drive هستش.بعد از شما چندتا سوال در باره کلاینت آی‌دی و کلاینت سکرت می‌پرسه که می‌تونیم خالی رهاشون کنیم و معمولا هم همین کار رو می‌کنیمبعد یه سوال مهم می‌پرسه: دسترسی برنامه چقدر باشه؟۱- دسترسی کامل۲- دسترسی فقط خواندنی۳- دسترسی ایجاد فایل (یعنی دسترسی به فایل‌های قدیمی شما نداره)۴ و ۵ - هم احتمالا به درد خیلی‌ها نمی‌خورهمن در این قدم ۳ رو انتخاب کردم.بعد دوباره یه سوال می‌پرسه درباره‌ی روت فلدر آی‌دی که می‌تونیم خالی رهاش کنیم.بعد از شما درباره‌ی کانفیگ خودکار می‌پرسه که با زدن دکمه‌ی y مرورگر شما باز می‌شه و شما به گوگل منتقل می‌شید و اونجا اجازه‌ی دسترسی رو به rclone می‌دید. یکی از خوبی‌های این ابزار اینه که برای کانفیگ از یه سایت سوم استفاده نمی‌کنه و کانفیگ فقط روی خود لوکال‌هاست اتفاق می‌افته.بعد از این به ترمینال بر می‌گردید. در این  مرحله می‌پرسه که می‌خواید تیم-درایو باشه که من چون نمی‌دونستم چیه زدم n به معنی نه و ادامه دادم.در نهایت یه خلاصه‌ای از کانفیگ نمایش می‌ده که شما با تاییدش کار رو به اتمام می‌رسوندتا به اینجا پیکربندی انجام شده.استفادهاستفاده از rclone خیلی ساده هستش. مثلا با اجرای دستور زیر می‌تونید یه فایل رو به گوگل درایو منتقل کنید:rclone copy myfile.png drive:imagesهمچنین با اجرای دستور rclone --help می‌تونید اطلاعات بیشتری درباره‌ی این ابزار بگیرید. دستورات مختلفی مثل mkdir و md5sum و cat و touch و rm و ... در این ابزار وجود داره که می‌تونید استفاده کنید.امیدوارم از استفاده از این ابزار لذت ببریدپس نوشتبرای فعال‌سازی اوتوکامپلیت می‌تونید از دستور زیر استفاده کنید. بعد از اجرای این دستور یه بار لازمه ترمینال رو ببنید و دوباره بازکنیدrclone genautocomplete zsh ~/.zsh/completion/_rclone</description>
                <category>سید مرتضی موسوی</category>
                <author>سید مرتضی موسوی</author>
                <pubDate>Wed, 23 May 2018 23:34:38 +0430</pubDate>
            </item>
                    <item>
                <title>اصلاح زمان بندی زیر نویس فیلم</title>
                <link>https://virgool.io/@se.mo.moosavi/%D8%A7%D8%B5%D9%84%D8%A7%D8%AD-%D8%B2%D9%85%D8%A7%D9%86-%D8%A8%D9%86%D8%AF%DB%8C-%D8%B2%DB%8C%D8%B1-%D9%86%D9%88%DB%8C%D8%B3-%D9%81%DB%8C%D9%84%D9%85-oelblabn0p8t</link>
                <description>گاهی اوقات زیر نویس فایل‌ها جلو و عقب هستند و این باعث اذیت شدن شما می‌شه. در این نوشته می‌خوایم یکی دو روش برای حل این مشکل رو معرفی کنیم.رفع اشکالات کوچیکاگر از vlc استفاده می‌کنید برای رفع مشکلات کوچیک مثل تاخیر کمتر از یک ثانیه می‌تونید با استفاده از دکمه‌های g و یا h زیرنویس‌ها رو در حد ۱۰۰ میلی‌ثانیه جابه‌جا کنید.رفع مشکلات اساسیگاهی اوقات مشکلات زیر نویس اساسی هستند. مثلا ۱۰ ثانیه جابه‌جا هستند. در این موارد می‌تونید از بسته‌ی نرم افزاری subsync استفاده کنید.پیش‌نیاز: نصب node و yarnنصب subsyncyarn global add subsyncاجرای دستور subsync با پارامتر‌های مناسبsubsync @+10 &lt; input.srt &gt; output.srtفایل جدید شما با ۱۰ ثانیه شیفت آماده‌ی استفاده است.دستور subsync قابلیت‌های بیشتر و پیچیده‌تری هم داره که این‌جا معرفی‌اش نمی‌کنیم</description>
                <category>سید مرتضی موسوی</category>
                <author>سید مرتضی موسوی</author>
                <pubDate>Wed, 16 May 2018 22:49:23 +0430</pubDate>
            </item>
            </channel>
</rss>