<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>پست‌های انتشارات اسنپ مارکت</title>
        <link>https://virgool.io/snappmarket/feed</link>
        <description>تجربیات تیم تولید و توسعه فنی اسنپ مارکت</description>
        <language>fa</language>
        <pubDate>2026-04-14 18:36:51</pubDate>
        <image>
            <url>https://files.virgool.io/upload/publication/tmmb9pvbfcks/iaponu.png</url>
            <title>اسنپ مارکت</title>
            <link>https://virgool.io/snappmarket</link>
        </image>

                    <item>
                <title>چرا به Command Schedule تو Laravel نمیشه اعتماد کرد؟</title>
                <link>https://virgool.io/snappmarket/%DA%86%D8%B1%D8%A7-%D8%A8%D9%87-command-schedule-%D8%AA%D9%88-laravel-%D9%86%D9%85%DB%8C%D8%B4%D9%87-%D8%A7%D8%B9%D8%AA%D9%85%D8%A7%D8%AF-%DA%A9%D8%B1%D8%AF-unuulrzttm1l</link>
                <description>لاراول یکی از معروف ترین و محبوب ترین فریم ورک های PHP و PHP یکی از پر استفاده ترین زبان های برنامه نویسی تو ایران و خیلی از کشور هاست.همونطور که میدونید هر فریم ورک، تسهیلاتی در اختیار توسعه دهندش قرار میده که سرعت کار رو بیشتر کنه و یکی از کاربردی ترینِ اونها تو لاراول، امکان Command Schedule یا زمان بندی دستوراته. خیلی وقت ها نیاز داریم تا در زمان های مشخصی، دستور یا کد خاصی اجرا بشه. قبل تر این کار با کمک crontab انجام می شد. اما در جهت شفاف سازی بیشتر و احتمالا به خاطر تبعیت از قاعده Everything as code (EaC)، این امکان تو چنین فریم ورک هایی به وجود اومد تا صرفن با اجرا کردن دستور ساده ای مثل php artisan schedule:run خیلی از کارهایی که نیاز به زمان بندی دارند رو بشه انجام داد.اتفاقن این کار خیلی راحت تر هم قابل انجامه و نیاز به حفظ کردن فرمت crontab هم نیست و با متد های ساده ای مثل daily، everyMinute، hourly و ... میشه این زمان بندی رو انجام داد. هر چند که فرمت crontab رو هم ساپورت می کنه.اما کجا ممکنه که مشکل به وجود بیاد؟قبل از اینکه به مشکل احتمالی این فیچر بپردازیم، لازمه قبلش بدونیم این زمان بندی چطور کار می کنه. شاید تو ذهن بعضی ها اینطور جا افتاده باشه که وقتی ما دستوری رو everyThirtyMinutes قراره اجرا بکنیم، احتمالا یک زمانی رو خود سیستم به عنوان مبدا در نظر می گیره و جایی ذخیرش می کنه و شمارش های بعدی رو نسبت به اون میسنجه. خب این دیدگاه غلطه. چون هم پیچیدگی رو زیاد تر می کنه و هم قابل track کردن نیست و در عمل هم اینطور ساخته نشده.زمان بندی command scheduler لاراول دقیقن مثل crontab عمل می کنه. یعنی تمام متد ها در نهایت تفسیر میشن به یه عبارت با فرمت crontab. برای مثل everyThirtyMinutes تفسیر میشه به 0,30 * * * * و این اتفاق برای تمام متدهاش میفته. خود دستور php artisan schedule:run هم باید به کمک ابزاری مثل supervisor یا crontab هر دقیقه یک بار اجرا بشه و با اجرای هر بار این دستور، دقیقه ای که سیستم توش قرار داره مقایسه میشه با cron expression و در صورت تطبیق، دستور مورد نظر اجرا میشه.نکته ای که ممکنه از ذهن ها پنهان بمونه و سرمنشأ مشکل بشه، synchronous بودن کل فرایند schedule:run هست و این ابزار به خودی خود امکانی برای اجرای multi process یا multi thread فراهم نمی کنه. فرض کنید چنین عبارتی رو تو فایل Console/Kernel.php دارید:$schedule-&gt;command(&#039;job1&#039;)-&gt;everyFiveMinutes();
$schedule-&gt;command(&#039;job2&#039;)-&gt;everyTenMinutes();زمانی که هر کدوم از این جاب ها زمان کوتاهی برای اجرا نیاز داشته باشن، همه چیز به خوبی کار می کنه و مشکلی به وجود نمیاد. اما وقتی که از حد معمول بیشتر طول بکشن چه اتفاقی میفته؟فرض کنید الان ساعت ۱۰:۰۵ هست و schedule:run اجرا میشه. طبق کد job1 که قراره هر ۵ دقیقه یک بار اجرا بشه، شروع می کنه به اجرا شدن و مثلا تو ۴ دقیقه (یعنی ۱۰:۰۹ دقیقه) تموم میشه. در این اجرا شرط زمانی job2 صدق نمی کنه و اجرا نمیشه. ساعت ۱۰:۰۶ تا ۱۰:۰۹ هم با اجرا شدن دستور  schedule:run اتفاقی نمیفته چون شرط زمانی هیچ کدوم از دو تا جاب meet نمیشه. ولی ساعت ۱۰:۱۰ هر دو جاب باید اجرا بشن. اما اگه job1 بیشتر از ۱ دقیقه طول بکشه، زمانی که interpreter پی اچ پی به خط بعد می رسه، ساعت ۱۰:۱۱ شده و دیگه شرط everyTenMinutes براش صدق نمی کنه (چون با زمان حال مقایسه میشه) و اون دور اجرای این دستور کنسل میشه و اگه جاب مهمی باشه، احتمالا ساید افکت های اجرا نشدنش توی پروژه خودش رو نشون میده. اینجا دقیقن جاییه که درک سطحی از این ابزار ممکنه کار دست دولوپر بده و اون رو وارد یه پروسه debugging طولانی و گاهن بی نتیجه بکنه.چیکار میشه کرد که این مشکل به وجود نیاد؟اولین و احتمالن ساده ترین راه حل که الزامن راه درستی هم نیست، منتقل کردن این جاب ها به crontab واقعی سیستم هست که خب با هدف ساختن این فیچر و فلسفه Everything as code (EaC) در تناقضه و Debugging و Maintenance رو هم میتونه سخت تر کنه. ولی به خاطر ماهیت Multi Process بودنش دیگه این دغدغه ها رو به همراه نخواهد داشت.دومین و احتمالا راه حل سخت تر (و پیشنهاد شده) برای حل این مسئله، تبدیل این کامند ها به Job های async هست که میتونه با کمک Queue و یا روش های دیگه انجام بشه که روند اجرای این دستورات رو از حالت خطی و synchronous در میاره و میتونه به ازای هر دستور یک process یا thread جداگونه ای داشته باشه و به صورت parallel تمامی این دستورات رو سر وقت انجام بده.سومین راه و راه حل خیلی خیلی سخت تر برای حل این مشکل، احتمالا modify کردن سورس کد لاراول و اضافه کردن sub process به scheduler و یا اصلاح زمان مورد مقایسه برای اجرای هر کامند به زمان آغاز schedule:run به جای زمان حاله که خب کسی حالشو نداره! ولی اگه کسی انجامش داد لطفن pull request بزنه به لاراول بلکه تایید شه و به درد بقیه هم بخوره.توصیه من به کسانی که از این قابلیت استفاده می کنند اینه که مشکلات مربوط به همزمانی و یا miss شدن جاب ها رو همیشه مدنظر داشته باشن و گول راحتی استفاده از این ابزار رو نخورن. با توجه به اینکه امکان وارد کردن لاجیک به این scheduler وجود داره، میتونه ابزار خیلی قدرتمند تری از crontab سیستم عامل باشه ولی به همون میزان به دلیل عدم پشتیبانی از multi threading میتونه خطرناک باشه.اگه شما هم راه حل دیگه ای برای برنخوردن به این مشکل دارید، حتما با ما به اشتراک بذارید.</description>
                <category>اسنپ مارکت</category>
                <author>میلاد کیانی</author>
                <pubDate>Thu, 22 Apr 2021 01:22:22 +0430</pubDate>
            </item>
                    <item>
                <title>چرا داکیومنت نویسی در شرکت های نرم افزاری جدی گرفته نمی شود ؟!</title>
                <link>https://virgool.io/snappmarket/%DA%86%D8%B1%D8%A7-%D8%AF%D8%A7%DA%A9%DB%8C%D9%88%D9%85%D9%86%D8%AA-%D9%86%D9%88%DB%8C%D8%B3%DB%8C-%D8%AF%D8%B1-%D8%B4%D8%B1%DA%A9%D8%AA-%D9%87%D8%A7%DB%8C-%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1%DB%8C-%D8%AC%D8%AF%DB%8C-%DA%AF%D8%B1%D9%81%D8%AA%D9%87-%D9%86%D9%85%DB%8C-%D8%B4%D9%88%D8%AF-guteayevchdv</link>
                <description>به جرأت می توان گفت در شرکت های نرم افزاری ایران , اکثر افراد فعال در حوزه ی فنی , مستند سازی و داکیومنت نویسی را یک کابوس تلقی می کنند و همیشه از انجام و یا مشارکت در این مورد سر باز می زنند . در این مقاله نظر شخصی ام را در مورد چرایی این اتفاق توضیح خواهم داد .  حتما بارها در آگهی های استخدام دیده ایم و یا در شعارهای سازمانی شنیده ایم که روی &quot; توانایی مستند سازی  &quot; چقدر تاکید می شود و مقالات بسیاری درباره ی تاثیر مثبت آن برای فرد و تیم در دسترس می باشد . ولی آیا در عمل هم افراد و تیم ها توجه و مشارکت لازم را به خرج می دهند ؟ برای پاسخ به این سوال باید به ریشه ی این حس تنبلی و مقاومت درونی در برابر مستند سازی رجوع کنیم . از روانشناسی شنیدم که تقریبا همه ی رفتارهایی که نادرست تعبیر می شوند گذشته ای دارد و تاثیر مستقیم از مواردی مثل آموزش غلط , تصمیم های نادرست و فضای نامناسب می گیرد . می توانم ادعا کنم که این استدلال در مورد موضوع این مقاله نیز صدق می کند . در کنار تمام پیشرفت هایی که در صنعت نرم افزار کشور صورت گرفته و تلاش های بسیاری که در جهت حرفه ای شدن انجام می شود , هنوز هم تفکر غالب همان توصیه هایی هست که در ذهن ما نهادینه شده و پشت تمامشان نوعی &quot; خساست در اشتراک گذاری &quot;,  &quot; تملک دانستنی ها &quot;  و از همه مهمتر &quot; ترس از دست دادن موقعیت &quot; نهفته است . از طرفی سازمان ها هم صرفا به پیشبرد اهداف اقتصادی بسنده می کنند و اقدامات لازم برای فرهنگ سازی را انجام نمی دهند .بیایید با خودمان صادق باشیم و توجیهاتی مثل تنبلی و کمبود زمان در مستند سازی و داکیومنت نویسی را کنار بگذاریم و ببینیم چقدر به اینکه از عدم انجام این کار به عنوان ابزار وابستگی سازمان به خودمان استفاده کنیم , فکر کرده ایم ؟ اشتباه فاحشی که در ذهن ما صورت می گیرد و متاسفانه در اکثر سازمانها نیز برای رفع آن تلاشی نمی شود . نقطه ی قوت یک فرد در جایگاه شغلی اش استفاده ی ابزاری از آموخته هایش نیست بلکه ويژگی های شخصیتی و رفتاری منحصر به فردش هست که باعث شکوفایی خودش و تحقق روحیه تیمی می شود.متاسفانه ما معلم های خوبی در قبال چیزهایی که آموخته ایم نیستیم چون معلم های خوبی نداشته ایم .ما همیشه تحت تاثیر عوامل بیرونی قرار گرفته ایم و احساس ناامنی شغلی را لمس کرده ایم در صورتی که برای حرفه ای شدن باید روی توانمندیها تمرکز کرد نه ابزار . اعتقاد دارم راه حل فقط و فقط تغییر نگرشمان هست.از دیگر دلایل این کم کاری می تواند ایده آل گرایی باشد . تصویری که از یک داکیومنت تکنیکال در ذهن ما وجود دارد پر از زرق و برق و توجه بیش از حد به جزییات می باشد . فکر می کنیم که اگر داکیومنت ما از استاندارد بسیار بالایی برخوردار نباشد ارزنده نیست و به همین دلیل قدمی بر نمی داریم . شکی نیست که سلیقه و خلاقیت احساس خوبی به خود شخص و افراد تیم منتقل می کند ولی توجه بیش از حد به این مورد باعث تعلل در قدم اول می شود . نباید فراموش کنیم که مستند ما صرفا استفاده ی درون سازمانی دارد . در پایان امیدوارم این مقاله برای افرادی که به هر نحوی با این موارد مواجه شده اند تاثیرگذاری مثبتی داشته باشد و سعی کنیم با دید روشن تری به سمت حرفه ای شدن حرکت کنیم . </description>
                <category>اسنپ مارکت</category>
                <author>آرین صابری</author>
                <pubDate>Tue, 01 Dec 2020 15:13:43 +0330</pubDate>
            </item>
                    <item>
                <title>یه باگ بد و یک طومار حرف جاواسکریپتی - حکایتی از اسنپ مارکت</title>
                <link>https://virgool.io/snappmarket/%DB%8C%D9%87-%D8%A8%D8%A7%DA%AF-%D8%A8%D8%AF-%D9%88-%DB%8C%DA%A9-%D8%B7%D9%88%D9%85%D8%A7%D8%B1-%D8%AD%D8%B1%D9%81-%D8%AC%D8%A7%D9%88%D8%A7%D8%B3%DA%A9%D8%B1%DB%8C%D9%BE%D8%AA%DB%8C-%D8%AD%DA%A9%D8%A7%DB%8C%D8%AA%DB%8C-%D8%A7%D8%B2-%D8%A7%D8%B3%D9%86%D9%BE-%D9%85%D8%A7%D8%B1%DA%A9%D8%AA-whkb1iyhqmib</link>
                <description>سلام ، من جعفر رضائی هستم، یکی از بچه‌های تیم فرانت‌اند توی اسنپ‌مارکت.این پست رو دارم ساعت ۳:۴۴ دقیقه بامداد می‌نویسیم و الان نصف شب بعد همون روزی هست که یه مشکلاتی روی مدیریت کوکی‌های nodejs‌ برای server side rendering پروژه نیوسایت پیش اومد.ذره بین و عکساگه در جریان مشکلی که پیش اومد نیستین، بزارین اول بگم که مشکل چی بود... این مشکل که حدودا ۲ ساعت و ۲۷ دقیقه روی production و برای ۱۰ درصد از ترافیک سایت اصلی که به صورت A/B تست به سایت جدید منتقل میشدن، رخ داد و باعث می‌شد کاربرایی که در لحظه بازکردن سایت همزمانی زیادی داشتن توکن jwtشون با داده کاربر دیگه‌ای پر بشه و بعد از لود شدن صفحه بجای پنل خودشون، پنل یه فرد دیگه رو ببینن.البته طبق سفارشات ثبت شده، این مورد برای موارد کمی رخ داده و ۸۷ درصد سفارشات این بازه با آدرس صحیح خودشون ثبت شدن که مشخص می‌کنه داشتن با پنل خودشون کار می‌کردن.خب تا اینجای صحبتم سکانس اول بود که مشکل پیش اومده رو توصیف می‌کرد، سکانس دوم رو مسائل فنی، دلیل بروز این مشکل و راهکاری که برای حل سریعش انجام دادیم رو میگم.اول از همه می‌خوام یه سوال بپرسم، اگه به هر دلیلی یهو این مشکل در وب‌سایت شما پیش بیاد چیکار می‌کنین؟ من امروز این سوال رو چند بار از خودم پرسیدم که در اون لحظه چطوری می‌تونستم با کمترین زمان دقیق‌ترین تصمیم رو بگیرم! البته واقعیتشو بگم قیافه‌م بعد دیدن باگ این شکلی شد:حالت‌های چهره - از چپ به راستخب اولین کاری که کردم و احتمالا شما هم می‌کردین این بود که دیپلوی اخیر که ممکن بود مشکل از اون بوده رو revert کردم و دوباره فرستادم بالا... مشکل حل نشد! چون تغییرات قبل از اون هم مربوط به چیزی نبود که فکر کنم مشکلی ایجاد کرده باشه، پس رفتیم کدها رو بخونیم.چند تا مسئله‌ای که ممکن بود مشکل از اونا باشه رو در آوردیم.وجود باگ در سرویس authenticationاشتباه بودن jwt توکن و وجود باگ توی توکنی که refresh توکن می‌کنهرندر شدن markup جابجا برای کاربران توی expressکوکی‌های روی سرور nodejs۲ تا تئوری اول با یه بررسی ساده رد شدن. مورد سوم اصلا امکان پذیر نبود و بیشتر حاصل تفکر عجولانه توی اون لحظه بود و تنها مورد باقی مونده cookie بود...یه بررسی کوتاه بچه‌های تیم روی کوکی، بی نتیجه‌ بود و خبری از وجود باگ نداشت، بعلاوه روی استیج این مشکل رو نداشتیم. آقای سوباساالبته در نظر بگیرین که کارتون سوباسا پخش نمی‌شد و هر لحظه که بررسی‌ها بیشتر طول می‌کشید خطا روی پروداکشن بیشتر در جریان بود. پس باید هر چه سریع‌تر تصمیمی گرفته می‌شد، توی اون لحظات، دو راه وجود داشت:یه روش پیدا کنیم که سریع جلوی مشکل رو بگیریم و بعدا یه فیکس دقیق روش بزنیمبشینیم کامل بررسی کنیم مشکل رو و اساسی باگ رو حل کنیمقطعا راه اول رو باید انتخاب می‌‌‌کردیم، ولی خب چه‌جوری باید مشکل رو فیکس کنیم؟! دقیقا چی باعث این مشکل میشه!اینجا یه لحظه به stream شدن و امکان ایجاد خطا بوسیله Readable stream توی nodejs فکر کردم. قبلا توی گیت‌هاب یه صحبتی با سازنده Preact آقای developit داشتم(لینک) که از یکی از پکیج‌هاشون توی نیوسایت و با stream استفاده کنیم ولی پاسخ خیلی طولانی ایشون خیلی از مسائل رو برای من شفاف کرده بود.https://github.com/GoogleChromeLabs/critters/issues/53یه issue ، یه کلاس درس!یکی از نکته‌های خوب این صحبت، تشریح نحوه stream شدن توی nodejs بود. برای مثال اینکه nodejs هر سایز از دیتا برای stream که داشته باشیم میاد توی بلاک‌های 16 کیلوبایتی به کلاینت ارسال می‌کنه، یعنی اگر شما ۶۰ کیلوبایت html می‌خوایید stream کنید این اتفاق توی 4 بلاک انجام میشه.پس فکر به اینکه نکنه داریم یه مشکلی رو با stream کردن بوجود می‌آریم پیش اومد. با توجه به معماری منعطفی که برای server side rendering روی نیوسایت ایجاد کردیم(که احتمالا در قالب یه پست دیگه توضیح میدم یا به شکل open source منتشر میشه) اولین و راحت‌ترین کار تبدیل کردن نحوه رندر از stream به string و دیپلوی کردنش بود.خوشبختانه بعد از این دیپلوی خطا روی سیستم بچه‌ها دیده نشد و گویا مشکل حل شده بود، ولی مسئله این بود که یه مشکل دیگه‌ای هنوز وجود داشت!کاربرایی که قبلا لاگین کردن باید از حساب فردی که خودشون نیستن خارج میشدن... برای این موضوع هم یه پچ نوشته شد و مرحله اول یعنی جلوگیری از وقوع بیشتر خطا انجام شد. ولی خب تا اینجا فقط تونسته بودیم بدون متوجه شدن دلیل اصلی رخدادن باگ، از رخ دادن بیشتر اون جلوگیری کنیم.حالا سکانس سوم: یه کمی اوضاع آرومتره و می‌خواییم مشکل اصلی رو پیدا و حل کنیم... مشکل دقیقا چی بوده؟! یعنی استریم نباید انجام بدیم؟! مگه میشه!اگه دقت کرده بودین یه بخشی از صحبت‌هام گفته شد که ساختار منعطفی برای SSR فراهم کردیم. این ساختار که کلا به شکل ماژولار داره کار می‌کنه و سعی شده حتی بدون تغییر کد بتونه CSR بشه و از lazy و suspense روی ssr پشتیبانی می‌کنه و کلا حتی نحوه درخواست api هم per component هست نه per route و کلی ویژگی‌های متفاوت دیگه.(میدونم فعلا رو خود ری‌اکت هم suspense برای سرور نیومده ولی ssr-prepass از kitten می‌تونه امکان suspense رو node رو بهتون بده :) )https://github.com/kittenاین معماری متفاوت باعث میشه ما یه سری چالش‌های متفاوت‌تر داشته باشیم، یکی از اون چالش‌ها که در راستای ماژولار بودن سیستم پیش اومده بود، نحوه مدیریت کوکی‌ها بوده. خب میدونیم که روی سرور اگه با express داریم کار می‌کنیم می‌تونیم به ازای هر درخواست روی res.cookie برای کلاینت کوکی بفرستیم.ولی اگه ما برای درخواست‌های httpها یه ماژول داشته باشیم که با یه ماژول دیگه که jwt توکن رو مدیریت می‌کنه ارتباط برقرار می‌کنه، چطوری می‌تونیم res رو توی اون context داشته باشیم؟! شاید بپرسین چرا به res نیاز داریم؟ چون مثلا با فرض اینکه شما jwt توکن دارین و اون توکن منقضی شده ما باید بدون اینکه شما در جریان تعویض توکن باشین یه توکن جدید براتون درست کنیم، اون موقع چون می‌تونه درخواست روی سرور باشه پس لازمه توکن شما روی کوکی نوشته بشه...خب ما برای اینکه یه storage به شکل isolated برای هر request داشته باشیم که مدیریتش هم راحت باشه و نیاز به maintain کردن کانتینر و... مثل redis نباشه. اومدیم از یه پکیج مشهور به اسم node-continuation-local-storage استفاده کردیمhttps://github.com/othiym23/node-continuation-local-storageبا این پکیج میشه یه namespace منحصر به فرد برای هر درخواست ایجاد کرد و بهمون اجازه میده یه‌ سری متغیر رو توی یه session نگهداری کنیم و هرجایی از برنامه بهش دسترسی داشته باشیم. یعنی به شکل یه gateway برای تبادل داده عمل می‌کنه. پس می‌تونه برامون res و req رو توی کل ماژول‌ها قابل دسترس کنه. اما مشکل زمانی پیش میاد که استریم انجام میشه و پکیج‌های 16kb ارسال میشن به مرورگر. توی این حالت اگر concurrent در حال stream باشیم، nodejs میاد برای بهینه بودن اجرای برنامه، از context موجود بین درخواست‌ها به شکل مشترک استفاده می‌کنه و انگار تغییرات یه جا داره انجام میشه. پس توی یه بلاک از استریم دیتا درسته،pipe انجام میشه و توی بلاک بعدی از محل نادرستی از حافظه خونده میشه! پس باگ ایجاد میشه.الان که ما دیگه رو renderToString هستیم ولی از اون سمت نحوه مدیریت شدن داده بین ماژول‌ها رو تغییر دادیم و بجای کار روی محوریت کوکی، دیتا رو به شکل ساده‌تر توی closure مربوط به همون ماژول مدیریت می‌کنیم.با توجه به اینکه با رفرش شدن صفحه امکان داشت کوکی شما از middleware احراز هویت رد نشه و نیاز به رفرش داشته باشه و این مورد بدتر باعث میشد که توکن شما مجددا عوض بشه. البته توی این سناریو در بدترین حالت، با توجه به میزان همزمانی کاربران، یه کاربر فعال در اون بازه زمانی اطلاعات ۷ نفر(نفرات ثابت) دیگه رو رفرش کرده و دیده.امیدوارم توضیحاتم کافی و شفاف بوده باشه، اگه جایی سوالی داشتین خوشحال میشم بپرسین. امیدوارم فرهنگ بیان دلیل رخدادن باگ‌ها و قبول کردن اینکه سیستم‌ها به باگ می‌خورن و هنر ما توسعه‌دهنده‌ها رفع کردن اونا با کمترین هزینه هستش جا بیفته. مورد بعدی اینکه، ما توی پروژه وب‌سایت جدید اسنپ مارکت بخش زیادی از سورس رو به صورت open source جلو بردیم و توی گیت‌هابمون موجوده ، خوشحال می‌شم به گیت‌هاب‌‌مون هم مراجعه کنین و اگه نظری دارین بهمون بگین :) و کلام آخر ، امیدوارم فرهنگ open source بودن رو بیشتر و بیشتر جا بندازیمhttps://github.com/snappmarket</description>
                <category>اسنپ مارکت</category>
                <author>Jafar Rezaei</author>
                <pubDate>Tue, 21 Jul 2020 17:32:06 +0430</pubDate>
            </item>
                    <item>
                <title>تجربه ساخت تیم محصول در اسنپ مارکت</title>
                <link>https://virgool.io/snappmarket/snappmarket-product-team-zeinhnrigpoh</link>
                <description>سلام!ایده اسنپ مارکت حدودا از زمستان ۹۶ شروع شد و من این شانس رو داشتم که از بهار ۹۷ به تیم اضافه بشم تا در تجربه شکل گیری و بزرگ شدن اسنپ مارکت شریک باشم.بخشی از تیم ما در آخرین روز حضورمبه پیشنهاد دوستان، این متن رو نوشتم که هم مروری برای خودم باشه که چه کردم و کارها چطور انجام شده و هم بقیه، خطاهای من رو کمتر تکرار کنند. طبیعتا در این متن بیشتر به تیم محصول می پردازم و خیلی به بقیه افراد و بخش هایی که باهاشون در ارتباط بودیم، اشاره نمی کنم و تا جای ممکن برای عدم ایجاد حاشیه اسم نمی برم. بیشتر عملکرد خودم و تاریخچه تیم را نقل می کنم.بطور کلی در شروع کار، خیلی مشخص نبود که باید چه کاری انجام بدم. برای همین ماه اول سرم خلوت بود. بعدش یه مدت در مورد بیزینس پلن، یه مدت در مورد پشتیبانی و یه مدت برای بازاریابی طرح می نوشتم و پیگیری می کردم. ولی خب همه اینها در بهار ۹۷ بود. یعنی زمانی که هنوز چیزی لانچ نشده بود و این بخش ها همه بعد از ارائه نسخه اولیه معنی پیدا می کنند.ساختار اولیهبه مرور و با توجه نیازهایی که هر روزبیشتر مشخص می شد به سمت تیم فنی رفتم. حقیقتا اون زمان اصطلاح مدیرمحصول را خیلی  نشنیده بودم. نقشی هم که داشتم چیزی بین مدیر محصول و product owner بود. دقیقتر بخوام بگم، ما یک مدیر فنی داشتیم که ساختار تیم فنی رو شکل می داد و نیروهای مرتبط را استخدام می کرد. من واسط بقیه تیم ها با تیم فنی . حالا این واسط شدن بعضی اوقات ترجمه حرفهای طرفین بود، گاهی پیگیری از دو طرف و گاهی هم تعریف محصول یا فیچر مورد نیاز. طبیعتا گاهی وزن قسمت های مختلف تغییر می کرد. همچنین در تعریف مدیرمحصول بعضی جاها مدیریت روندهای بازاریابی و توسعه کسب و کار و چیزهای دیگه هم  هست که در مورد کار ما صدق نمی کرد.به هر صورت بعد از ماه های اول فعالیت به این نتیجه رسیدیم که نیاز هست فرد تمام وقتی برای این ارتباط داشته باشیم. برای همین عملا کار تمام وقت من این شد که درگیر شکل دهی تیم محصول بشم. نکته دیگه فراگیر شدن مدل اسپاتیفای بود. که الان مدل معروفی محسوب می شود و قبل از آن زمان هم توسط چندجا مثل کافه بازار مورد استفاده بود. در مورد جزییات مدل اسپاتیفای طبیعتا اینجا نمی شه توضیح داد.برای پیاده سازی این مدل ما دو چالش اصلی داشتیم. اولا نیاز به تعداد بیشتری نیروی دولوپر داشتیم. دوما بحثهای فرهنگ سازمانی را باید هم داخل و هم بیرون تیم درست می کردیم.روند به این صورت جلو می رفت که علیرضا به عنوان مدیرفنی مصاحبه های استخدامی رو جلو می برد و از حدود مرداد یا شهریور من هم درگیر مصاحبه ها و تصمیم گیری برای نیروی جدید شدم. مصاحبه های استخدامی هم به این صورت بود که علیرضا از نظر فنی و من از نظر کالچری و مهارت های عمومی مصاحبه می کردیم. طبیعتا یکی از مهم ترین موضوعاتی که برام مطرح بود میزان تطبیق فرد با ساختار مدل اسپاتیفای بود. مثلا میزان تمایل به  شرکت در بحث درمورد فیچرهای جدید، یا میزان تمایل به همکاری با افرادی از تخصص های دیگه و میزان کارایی در ساختارهای بدون سلسله مراتب و یا با سلسله مراتب کم.بطور کلی روندی که ما داشتیم اینطوری بود:· بهار ۹۷: جمع شدن اولیه تیم و شناخت محصول و تلاش های اولیه برای ایجاد محصول و تیم.· تابستان ۹۷: انتشار نسخه های اولیه اسنپ مارکت، کامل شدن فرآیندهای بیزینسی، تعریف محصولات· پاییز ۹۷: بلوغ اولیه تیم، ایجاد ساختار بلند مدت و تلاش برای خارج شدن از نسخه های آزمایشی· زمستان ۹۷: تثبیت تیم اصلی، stable شدن محصولات، شفاف شدن مسئولیتها و عدم تمرکز روی فرد یا افراد خاص· بهار ۹۸: شکستن تیم محصول به ۳ یا ۴ تیم زیرمجموعه، پیاده کردن اولیه مدل تیم های محصول محور· تابستان ۹۸: تلاش برای تقویت و توسعه هر تیم محصول و تلاش برای کیفیت بخشی به جنبه فنی محصولات برای رشد و توسعه بیشترطبیعتا بعد از این زمان من از تیم جدا شدم و بعدش رو باید بقیه دوستان بگن.این روند فصل ها یک روند مشخص شده و برنامه ریزی شده نبود. بنابر شرایط جلو رفتند. طبیعتا هر تیم چالش های خاصی داره. برای ما دو موضوع اصلی وجود داشت. چالش اول سرعت توسعه محصول و اولویتها بود. اولا توسعه یک محصول جدید در گروه اسنپ یا کنار اسنپ فود، کار پرفشاری هست. همه (از داخل و خارج مجموعه) از اولین روزها انتظار یک کار با کیفیت که به تعداد زیادی مشتری سرویس می دهد را دارند. دوما، فرهنگ درستی که در مجموعه بود، بیزینس اولویت همه موضوعات را مشخص می کند. واقعیتی که وجود دارد و درس مهمی برای من بود، اگه قرار هست یک مجموعه استارتاپی یا تجاری بزنید، قرار است یک تجارت یا بیزینس را راه اندازی کنید. همه ابعاد دیگه از جمله فنی، بازاریابی، پشتیبانی یا لاجستیک همه باید در خدمت توسعه بیزینس باشند. برای همین خیلی اوقات ما کیفیت فنی، یا طراحی محصول را فدای اولویت و فوریت های کل بیزینس می کردیم. شاید برای من و خیلی از بچه های تیم این کار دردناک بود ولی لازم بود انجام بشه.چالش دوم، پیدا کردن یک تیم فنی بود. مسلما برای همه مشخص هست که پیدا کردن برنامه نویس یا دیگر تخصص های فنی توسعه سرویس مثل DevOps، تست یا تحلیل داده چه کار سختی است. بخصوص ما بخاطر تازه کار بودن و یا مباحث دیگه محدودیت رنج حقوقی هم داشتیم. البته در مقابل، برند و سابقه برند اسنپفود و گروه اسنپ را هم داشتیم که جذابیت ایجاد می کرد.روند توسعه محصولخلاصه روند محصولی ایی که ما جلو رفتیم به این شکل بود:یک نسخه اندروید از تیرماه ۹۷، بعدش آیفون، وب سایت که در این مرحله بیشتر یه لندینگ برای دانلود اپلیکیشن ها بود.از حدود تیرماه هم یک سیستمی برای جمع آوری و تحلیل داده های کاربران در کنار سیستم موبایلمان ایجاد کردیم.اسنپ فود یک پنل مدیریتی داشت که ما همون رو برای نیازهای خودمون تغییر می دادیم و عملا از این پنل را از روزهای اولیه داشتیم.کل backend را هم از اسنپ فود گرفته بودیم و تغییراتی که می خواستیم اعمال می کردیم تا زمستان ۹۷ که عمده این بخش با نسخه ریفکتور شده ما جایگزین شد.وب سایت هم از حدود شهریور در دسترس بود.همزمان برای مدیریت سفارش ها داخل فروشگاه یک اپلیکیشن برای کسانی که سفارشات را جمع می کردند و یک اپلیکیشن برای کسانی که موجودی کالاها را گزارش کردند توسعه دادیم که هر دو در پاییز قابل استفاده بودند.یعنی در انتهای پاییز ما ۷ محصول داشتیم که بخش های مختلف باهاشون کار میکردند. همه این بخش ها نیازمند رفع باگ ها و توسعه قابلیتهای جدید بودند. برای کاهش زمان توسعه هم خیلی از کارها در کنار سیستم های اصلی بصورت دستی انجام می شد که طبیعتا این بخش ها هم با سرعت کمتری باید بصورت اتوماتیک تبدیل می شدند.در بازه هایی هم در کنار حجم زیادی از تقاضاهای جدید موضوع ریفکتور و بازنویسی بخش های مختلف را داشتیم.تقریبا در تابستان و پاییز ۹۷ هر روز قبل ساعت ۹ با این پیغام مواجه می شدم که سیستم از دسترس خارج شده و مشکلی پیش آمده. در کنار این موضوعات فنی داخلی، بخاطر بحث های اقتصادی از جمله دلار و واردات، ما مشکل جدی تهیه سرور داشتیم. حتی سرورهایی که خریداری می شدند مشکلات جدی سخت افزاری مثل هارد معیوب یا رم مشکل دار داشتند.توسعه تیمبرگردیم به تیم. از خرداد ما تعداد بیشتری مصاحبه و تمرکز برای توسعه تیم داشتیم. ولی بخاطر مشخص نبودن روندها، فشار و سرعت اولیه زیاد و عدم تطبیق بین واقعیت و تصورات بچه ها میزان زیادی رفت و آمد در تیم داشتیم. البته بودند بچه هایی مثل سیامک، که قبل از من بودند و حداقل تا ۹۸ همراه بودند ولی تقریبا عمده تیم فنی که تابستان جذب شدند پاییز از تیم جدا شدند. این جدا شدن شامل علیرضا که مدیرفنی ما هم بود می شد. داخل تیم طبیعتا افرادی با سطح مهارتی مختلف داشتیم ولی مشکلی که وجود داشت فرهنگ متفاوت افراد و انگیزه هاشون بود. البته این مشکل دوطرفه بود و از سمت شرکت هم سیاست های شفافی هنوز شکل نگرفته بود، بیشتر ایده پردازی هایی بود که از سمت شرکت، بطور مشخص من و علیرضا بود که این دیدگاه ها باهم تضادهایی هم داشتند.تابستان و پاییز ۹۷، به شدت تحت فشار بودم که تیم را هرچه زودتر بزرگ کنم تا در مقابل سرعت توسعه بتونیم بهتر عمل کنیم. شخصا با این دیدگاه مخالف بودم و فکر می کردم که اضافه کردن افراد بخصوص در تیم محصول باعث دوباره کاری های بیشتر و کم شدن انگیزه بچه های موثرتر می شود.البته در مقابل، متوجه مشکلات و فشارها هم بودم. بطور مثال در شهریور ۹۷، ما یک تلاش ناموفق برای تقسیم تیم محصول به دو تیم محصول محور (بجای تخصص محور) داشتیم که به سرعت شکست خورد چون یک تعداد از بچه ها از تیم جدا شدند و عملا برگشتیم به حالت قبلی.موضوع دیگری که تست کردیم، ما سعی می کردیم با ساختارهای اسکرام کار کنیم. ولی عملا اسپرینت های موفقی نداشتیم. همچنین کارها به شدت به اشخاص و نه به تیم وابسته بود. برای همین از آبان ماه سیستم را به کانبان تغییر دادیم. این کار باعث شد انعطاف بیشتری برای برنامه ریزی های کوتاه مدت داشته باشیم و عملا برنامه های بلند مدت را تا حدودی از دست بدیم. برای همین یکی از کارهای اصلی عملا در کنار این موضوع اتفاق افتاد. برای هر نفر سعی می کردیم یک روند کاری جداگانه روی بخش های محصول داشته باشیم و بسته به توانمندیش درگیر بخش های دیگه هم بشه. در این بازه، برای تعریف هر تسک، عین کار عموما به بچه ها گفته نمی شد، و یک موضوع کلی با مشارکت خودشون تعریف می شد. البته این به معنی ایده پردازی نبود. خیلی مواقع ایده ها از قبل مشخص شده بودند یا باگ های سیستم بود. ولی نحوه پیاده سازی و جزییات بیشتر فیچرها موضوعی بود که باید بچه ها عمدتا خودشون را درگیر می کردند. گاهی این کار تکی و گاهی گروهی بود. حالت مطلوب این بود که ما طراح گرافیکی یا فردی از جنبه دیگه بیزینس هم داشته باشیم که درکنار دولوپرها باهم این جزییات را مشخص کنند که خب نداشتیم.این روش یک خوبی داشت، باعث می شد بچه ها با جزییات بیشتری درگیر بشند، حس مالکیت کنند و البته برای مدل اسپاتیفای هم آماده بشند. در مقابل چند بدی داشت. اولا کار به شدت به چند نفر وابسته بود که باید تسک ها را تشریح می کردند، با ذینفعان صحبت می کردند و همه را همراستا نگه می داشتند. و چون مدل کانبان بود، هر روز و بلکه هر نصفه روز این سوال مطرح می شد که خب الان روی چه چیزی کار کنم؟نکته دیگه ایی که در تقسیم کارها سعی کردیم رعایت کنیم، نحوه تقسیم بندی بچه ها بود. بالاخره همه اینکارها برای رسیدن به اون ساختار محصول محور بود. از حدود بهمن این موضوع جدی شد. ما دو فرآیند روند کاربر داشتیم. یکی از زمان آشنایی کاربر با اسنپ مارکت تا زمان سفارش گذاری، یو دیگری از زمان پس از پرداخت تا دریافت کالا. دو تیم دیگه هم داشتیم که یکی مسئول زیرساخت بود و یکی تحلیل داده. کارهای بچه ها و جای نشستن افراد طوری تعریف شده بود که بدون تیم بندی این چهار قسمت بوجود بیایند.بزرگترین چالش برای من در اسفند پیدا کردن آدم های به درد بخور، برای اولا مسئولیت هر تیم دوما آدم های تخصصی داخل هر تیم بود. داخل تیم پوریا و میلاد را داشتیم. فرزاد را هم بطور اتفاقی داخل یک رویداد دیدم. یکی از تجربیات جالب هم مدل جذبی بود که برای افراد با تجربه داشتیم. مصاحبه با فرزاد با فردی که کلا نمی شناسید یا تجربه کاری محدودی دارد تفاوتهایی دارد. طبیعتا میزان تخصص این افراد را می توان از همکارهای قدیمی شان پرسید. ولی بحث فرهنگ کاری و دغدغه ها موضوع متفاوتی هستند که حتی از جلسه مصاحبه هم به سختی می شود نتیجه گرفت. چرا این موضوع برای افراد با تجربه مهم تر هست؟ چون طبیعتا شما این افراد را به تیم اضافه می کنید تا جریان سازی کنند. اگه تعارض جدی بین افراد و خواسته های شما باشد خیلی بعید است که فرصت جبران داشته باشید. نکته مهم بعدی، متقاعد کردن همین افراد هست. به نظرم اگه شما تیمی دارید که برای بقیه جذابه که توش کار کنند، چی بهتر از تجربه کردن اون؟ برای چند نفر از بچه ها، این تجربه را داشتیم که گفتیم بیا، چند روز داخل تیم باش و کارهای خودت را انجام بده. لپتاپ از تو، میز و اینترنت از ما. ببین ما چه می کنیم؟ چطور برخورد می کنیم و چالش ها چیه؟ اگه خوب بود بمون اگه بد بود برو. طبیعتا این روش ریسک زیادی دارد. از المان هایی که می خواهید داخل تیم محرمانه بماند بگیرید تا بعضی روزها که روزهای بد سازمان هست و بعضی روزهای خوب. ولی از این موضوع شخصا نتیجه خوبی گرفتم. بخصوص برای افرادی که می دونستم یا احتمال می دادم تیم براشون از تکنولوژی و برند و ... مهم تره، از این روش استفاده کردیم.خدا رو شکر با مجموعه اتفاقات، ما یک مدیر فنی، دو مدیر محصول، و برای هر موقعیت فنی تخصصی حداقل دو نفر پیدا کردیم که حداقل یک ماه در تیم فعال بودند. در جلسه پایان سال ۹۷، رسما ساختار جدید اعلام شد و بچه ها از اولین روز کاری ۹۸ داخل تیم های جدید فعالیتشون را شروع کردند. بخاطر همه مقدماتی که فراهم شده بود، قبل از جلسه ساختار به کسی اعلام نشده بود ولی فکر نمی کنم کسی هم از چیدمان جدید تعجب کرده باشد. به بیان دیگه، به هرکس دیگری از داخل تیم می گفتیم برای این ساختار تیم ها را مشخص کن، به همین صورت مشخص می کرد.اشتباهاتمدر ماه های اول طبیعتا چالش ها و تعارض ها بیشتر بود. ولی به مرور و بخاطر کاراکتر خود بچه ها، کارها واگذار شد و من درحد تعارضات دخالت داشتم. مسئولیت پذیری برای عموم بچه ها به معنی واقعی وجود داشت.یکی از مشکلات مجموعه اصلی ما، عدم رشد افراد داخل سازمان بود. این از اشتباهات من بود که روی این موضوع تمرکز نکردم. یعنی در عمده موارد که می خواستیم ساختاری ایجاد کنیم، برای موقعیت بالاتر و با مسئولیت بالاتر افرادی خارج از مجموعه وارد می کردیم. این موضوع را خیلی دیر متوجه شدم و اگر برگردیم حتما خیلی بیشتر روش سرمایه گذاری می کنم.اشتباه دیگه ما، تمرکز کم روی هویت بخشی به فرد فرد بچه ها بود. داخل سازمان این مشکل نبود. هر کدوم از بچه ها که درگیر موضوعی بود، سعی می کردیم حتما خودش درگیر ارائه موضوع باشد. ولی همین روند باید برای افراد بیرون سازمان هم میبود. یعنی برای بچه ها از حضور در داخل تیم، برندی ایجاد شود. ولی مسیر این برند باید از آموزش و ارتقای سواد و تخصص افراد انجام می شد.موضوع دیگه، اینکه اگر از اول این مسیر را طی کنم، روی خواسته هام و تشکیل تیم محصول محور، که داخل اون نه فقط افراد فنی، بلکه افراد دیگه هم حاضر باشند اصرار بیشتری می کردم. مثلا تیم محصول صفحه اول موبایل و وب با حضور حداقل یک نفر از تیم مارکتینگ. یا مثال های دیگه.به هر صورت، اسنپ مارکت در طول حدود ۱۸ ماهی که در اون مشغول به کار بودم، ۷ محصول مختلف توسعه داد که بعدا همه این محصولات به روزرسانی و ارتقا داشتند. تیم از ساختار پراکنده و ۳-۴ نفره به ۲۲ نفر رسید و قطعا نقاط ضعف فراوانی داشت.خوشبختانه روزی که مجموعه جدا شدم، افراد توانمندی در تیم بودند و وابستگی تیم به من حداقلی بود. امیدوارم، هر روز از اسنپ مارکت و بخصوص بچه هایی که باهاشون همکاری داشتم بیشتر بشنونم و موفقیت های بیشتری ازشون ببینیم.</description>
                <category>اسنپ مارکت</category>
                <author>Mahmoud Pourmand</author>
                <pubDate>Sun, 01 Dec 2019 11:29:06 +0330</pubDate>
            </item>
                    <item>
                <title>با Redux دوست باشیم (بخش اول)</title>
                <link>https://virgool.io/snappmarket/%D8%A8%D8%A7-redux-%D8%AF%D9%88%D8%B3%D8%AA-%D8%A8%D8%A7%D8%B4%DB%8C%D9%85-%D8%A8%D8%AE%D8%B4-%D8%A7%D9%88%D9%84-uta7oow1ahif</link>
                <description>لوگوی reduxوقت صحبت کردن با یه برنامه‌نویس FrontEnd در مورد React، یاد گرفتن و استفاده از Redux یکی از نقاط تاریک بوده و هست. ما معمولا، با کمی مطالعه، شروع به پیاده‌سازی می‌کنیم و دقیقا نمی‌دونیم که Redux برای چی و کجا باید استفاده بشه. یا چطور می‌شه بهترین استفاده رو ازش داشت. توی این مقاله می‌خوام از مشکلاتی که خودم تو این راه باهاشون رو به رو بودم بگم.اولین نکته‌ای که لازم بود بدونم این بود که Redux برای چی به وجود اومده و قراره کدوم مشکل ما رو حل کنه. مشکل از جایی شروع می‌شه که هرکامپوننت توی React , Vue، یا Angular به صورت داخلی state خودشون رو مدیریت می‌کنن. تا یه مرحله‌ای این مشکل به چشم نمیاد و حتی خیلی هم خوب کار می‌کنه. ولی وقتی برنامه به سمت بزرگتر شدن میره و ارتباط بین کامپوننت‌ها بیشتر می‌شه، مدیریت state ها سخت و سخت‌تر می‌شه.بعضی از کامپوننت‌ها از یه سری state مشترک استفاده می‌کنن. به طور مثال، تو یه سیستم فروشگاهی تعداد کالاهای خریداری شده ممکنه بین تعداد زیادی کامپوننت به اشتراک گذاشته بشه. یا توی route های مختلف بهش نیاز باشه. پیدا کردن اینکه این state از کجا اومده می‌تونه واقعا گیج‌کننده باشه.از طرفی، یه دلیل معروف هم هست که بیشتر ما توی صحبتهامون از این دلیل برای استفاده از Redux استفاده میکنیم؛ «وقتی می‌خوام یه state رو از یه کامپوننت به یه کامپوننت دیگه بفرستم، باید اون رو تا نزدیک‌ترین parent مشترک lift up کنم و درنهایت به عنوان props به کامپوننت مورد نظر pass down بشه&quot;.تفاوت جابه‌جایی state با redux  و بدون اونحالا می‌دونیم که مشکل کجاست. اما Redux چطور این مشکلات رو حل میکنه؟طبق تعریفی که توی سایت خودش وجود داره، Redux عزیز ما با سه تا ویژگی شاخص به ما کمک می‌کنه؛Preditctable State Updates&quot;Pure&quot; reducer functionCentralizing the Stateخب این ویژگی‌ها یعنی چی؟ از اولی شروع میکنیم. برای خود من هم سوال بود که این عبارت دقیقا یعنی چی. بعد از گشتن‌های فراوان، توی یه فروم جوابی از خود Dan Abramov پیدا کردم؛ «این عبارت از دوتا بخش تشکیل شده؛ state container و predictable . بخش اول یعنی این که Redux وظیفه داره state برنامه شما رو نگه داره و شما هم نمی‌تونید مستقیما مقدارش رو تغییر بدید. پس مجبورید تغییرتون رو در قالب یه action بهش تحویل بدید. از اونجایی که action ها می‌تونن ضبط و تکرار بشن، Redux میتونه predictable باشه. با همون action و با همون ترتیب فراخوانی، state شما باید مقدار یکسانی داشته باشه.ویژگی دومی که توی تعریف به چشم میخوره pure بودن reducer هاست. ما اینجا قصد نداریم بگیم pure function یعنی چی. اما اگه نمی‌دونید چی هست، می‌تونید با مطالعه صفحه ویکی پدیا یه اطلاعات مختصر به دست بیارید. pure بودن به ما این کمک رو میکنه که به ازای هر ورودی، خروجی مشخصی داشته باشیم که هیچ عامل بیرونی روش تاثیر نداره. بنابراین تست کردنش و حتی پیاده‌سازی یه سیستم logging برای تغییرات داده‌ها ساده‌تر خواهد بود.ویژگی سوم متمرکز شدن state ها در یک نقطه است. تمام state هایی که بین کامپوننت‌های مختلف مشترک هستن توی یک نقطه، اونم داخل RAM، ذخیره می‌شن. تنها مشکلی که به نظر می‌رسه داشته باشیم persist شدن یا همون موندگاریه. چون با هر رفرش، ما دیگه مقدار قبلی store رو نداریم.فعلا فهمیدیم که مشکل از کجاست و Redux چطور قراره کمکمون کنه. توی نوشته‌های بعدی اجزای مختلفش رو بررسی میکنیم.</description>
                <category>اسنپ مارکت</category>
                <author>امین آشتیانی</author>
                <pubDate>Sat, 28 Sep 2019 11:43:11 +0330</pubDate>
            </item>
                    <item>
                <title>تأثیر کاخ سفید در افزایش دوستی بین توسعه‌دهنده‌های یک تیم</title>
                <link>https://virgool.io/snappmarket/whitehouse-standrads-e3toksrmtsrv</link>
                <description>عنوان عجیبیه، ولی واقعیه. برای این که بتونیم این عنوان عجیب رو با هم درک کنیم می‌خوام از یه خاطره‌ی مشترک شروع کنم. من، و شاید خیلی از شما، توی تیم‌هایی کار کردیم که توسعه‌دهنده‌های قسمت‌های مختلفش با هم اختلافاتی در مورد نحوه‌ی پیاده‌سازی داشته‌ن. این اختلافات معمولن مسائل مرگ‌باری نیستن و به راحتی حل می‌شن. اما اگه یه کم توی روند حل شدن این اختلافات ریز بشیم متوجه می‌شیم جایی که این اختلافات شروع به حل شدن می‌کنن دقیقن همون جاییه که یه سری قرارداد نانوشته بین اعضا تصویب می‌شه. قراردادهایی که همه، یا لااقل بیشتر افراد، باهاش موافقن. این اتفاق می‌تونه دقیقن معنی تعریف شدن یک «استاندارد» در تیم باشه. خب. تا اینجا که همه چیز خیلی طبیعیه. اما یه زمانی سفر کردن با شتر هم طبیعی بوده. منظورم اینه که همه‌ی تغییراتی که بشر در طول تاریخ ایجاد کرده لزومن برای حل کردن مشکلات نبوده. خیلی از این تغییرات ایجاد شده‌ن که تا کاری که قبلن انجام می‌شده رو راحت‌تر کنن.استانداردهای عمومی (در مقابل استانداردهای درون‌سازمانی) یکی از همین تغییراته. من به عنوان یک توسعه‌دهنده خیلی خوشحال‌تر خواهم بود اگر با دونستن یک یا چند استاندارد بتونم با تیم‌های مختلف کار کنم. با همین استانداردها بعد از هر جا‌به‌جایی بتونم به زودی به تیم جدیدم اضافه بشم. با همین استانداردها بتونم آموزش‌های بهتری رو منتشر یا دریافت کنم. امیدوارم تا الان برای همه‌مون به اندازه‌ی کافی مشخص شده باشه که وجود داشتن استانداردها در عالم برنامه‌نویسی چقدر می‌تونه به راحت‌تر شدن روابط بین توسعه‌دهنده‌ها کمک کنه.استاندارد کاخ سفید مجوعه‌ای از پیشنهادهاست که برای API ها و بر پایه‌ی REST تعریف شده. این استاندارد تمام حالت‌هایی که من و هم‌تیمی‌هام تا الان باهاش برخورد داشتیم رو پوشش می‌ده. از طرفی تعریفش خیلی ساده‌ست و توی چند جمله می‌شه برای هر آدم جدیدی توضیحش داد.اما بعد از تجربه‌ی خوب اولین پروژه‌ای که با این استاندارد کار کردم، رقص‌کنان رفتم سراغ پیاده‌سازیش روی پروژه‌ی بعدی. اینجا بود که دیدم ای دل غافل. توی پروژه‌ی قبلی کلی کد نوشته بودم که پیاده‌سازی این استاندارد رو راحت کنم. حالا باید همه رو از اونجا کپی کنم و توی پروژه‌ی جدید استفاده کنم. اگر شما هم مثل من از کپی کردن کد متنفر باشید حتمن متوجه می‌شید که در اون لحظه چه غمی رو روی شونه‌هام حس کردم. طبیعتن سعی کردم بگردم ببینم آیا همکاران مهربونم در گوشه‌ای از این کره‌ی خاکی چرخی رو اختراع کرده‌ن که من روی دوچرخه‌م نصب کنم یا نه. بعد از کلی تلاش، لاقل برای ابزارهایی که خودم ازشون استفاده می‌کردم کتابخونه‌ای پیدا نکردم که پیاده‌سازی این استاندارد رو برام انجام بده. این شد که کمر همت رو بستم و دو تا کتابخونه برای این کار نوشتم. اولیش یه کتابخونه‌ برای پیاده‌سازی استاندارد کاخ سفید با زبان PHP بود. که اون رو از اینجا می‌تونید پیدا کنید. بعد هم یه کتابخونه‌ی دیگه برای همین کار روی فریم‌ورک لاراول که از اینجا در دسترسه. خودم و همکاران خوبم در اسنپ‌مارکت اولین استفاده‌کننده‌های این کتابخونه‌ها بودیم. برای استفاده از این کتابخونه‌ها چیزی بیشتر از راهنمای خودشون ندارم که اینجا بنویسم. ولی اگر هر کدوم از شما خواستید ازشون استفاده کنید و هر چیزی برای بهتر شدنشون به ذهنتون رسید، من خیلی خوشحال می‌شم که بهم بگید.</description>
                <category>اسنپ مارکت</category>
                <author>امی‌تیس یوسفی</author>
                <pubDate>Wed, 21 Aug 2019 17:05:44 +0430</pubDate>
            </item>
                    <item>
                <title>۱۰ دقیقه برای شروع یادگیری ماشین</title>
                <link>https://virgool.io/snappmarket/%DB%B1%DB%B0-%D8%AF%D9%82%DB%8C%D9%82%D9%87-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%B4%D8%B1%D9%88%D8%B9-%DB%8C%D8%A7%D8%AF%DA%AF%DB%8C%D8%B1%DB%8C-%D9%85%D8%A7%D8%B4%DB%8C%D9%86-yhbms92soslk</link>
                <description> مقدمهدر این مقاله سعی میکنیم مسیر یک پروژه یادگیری ماشین رو با هم مرور کنیم . این موارد شامل کلیه مراحل پروژه های یادگیر ماشین از ابتدا تا انتهاست. همچنین مراحلی مثل پیش پردازش و مرتب کردن داده ها، اکتشاف و مهندسی ویژگی ها و تاثیر همه ی این موارد بر عملکرد و کارایی مدل نهایی را بررسی خواهیم کرد. احتمالا برای پیاده سازی با پایتون به کتابخانه های زیر نیاز خواهیم داشت:NumpyPandasSci-kit LearnMatplotliنحوه یادگیری ماشین در یک نگاهمرور مراحل یادگیری ماشین مراحل زیر ۵ گام اصلی برای یادگیری ماشین می باشد:جمع آوری داده مورد نیازپیش پردازش داده هاپیداکردن مناسب ترین مدل (به نسبت داده اولیه)آموزش و تست مدلارزیابی نهاییدر اینجا بهتره به اصول اولیه یادگیری ماشین بپردازیم.مدل در یادگیری ماشین چیست؟در حقیقت مدل هیچ چیز خاصی جز یک قطعه کد نیست که مهندسی مثل شما آن را با آموزش، به مرور هوشمند و هوشمند تر کرده است. واضح است که اگر آموزش غلط بدهیم یا با داده غلط آموزش بدهیم نتیجه دلخواه به دست نخواهد آمد. درست مثل یک دانش آموزش دبستانی که اگر جمع یا تفریق را به درستی به او یاد ندهیم نباید منتظر پاسخ گویی صحیح او باشیم.۱- جمع آوری دادهروند جمع آوری داده بسیار به نوع پروژه ای که میخواهیم انجام دهیم وابسته است. اگر بخواهیم یک پروژه یادگیری ماشین real-time (یا به عبارت دیگر در لحظه پاسخ دهنده :) داشته باشیم باید از یک سیستم IOT یا همان اینترنت اشیا که از تعدادی سنسور برای درک محیط اطراف استفاده میکند، بهره بگیریم. و اگر نه میتوانیم از  تصاویر ، پایگاه های داده و یا هر مدل داده ورودی دیگری استفاده کنیم. اما نکته مهم این است که نمیتوانیم هر داده ای را مستقیم برای یادگیری مدل خود استفاده کنید. چرا؟ دلیل این موضوع نسبتا واضح است چون ممکن است داده ی اولیه شامل مقادیر زیادی نویز، داده های از دست رفته و مقادیر بسیار بزرگ تر از حد پیشبینی شده و ... باشد که برای این کار نیاز به آماده سازی داده داریم.ما همچنین می توانیم از برخی مجموعه داده های رایگان که در اینترنت موجود هستند استفاده کنیم. مخزن یادگیری Kaggle و UCI  مخازنی هستند که بیشترین استفاده را برای ساخت مدلهای یادگیری ماشینی دارند. Kaggle یکی از پر بازدید ترین وب سایت هایی است که برای تمرین الگوریتم های یادگیری ماشین استفاده می شود.۲- پیش پردازش داده هاپیش پردازش داده ها یکی از مهم ترین مرحله ها برای یادگیری ماشین می باشد. دلیل این اهمیت اثرگذاری بسیار زیاد این مرحله بر دقت ساخت مدل مورد نیاز است. در یادگیری ماشین قانون ۸۰-۲۰ حکم فرماست به این نحو که ما باید ۸۰ درصد زمان خود را صرف پیش پردازش  و فقط ۲۰ درصد زمان را صرف تجزیه و تحلیل داده کنیم.پیش پردازش داده چیست؟پیش پردازش داده ها مرحله ای برای مرتب کردن داده های خام است.  به عبارت دیگر ، هر زمان که داده ها از منابع مختلفی جمع آوری شوند ، به صورت خام جمع آوری می شوند و این داده ها برای تجزیه و تحلیل مناسب نیست.بنابراین ، مراحل خاصی برای تبدیل داده ها به مجموعه داده های منظم و نرمال انجام میدهیم که به مرحله پیش پردازش داده ها گفته می شود.چه مواردی را باید انجام دهیم؟همانطور که میدونیم پیش پردازش داده ها داده های خام را به داده های مرتب تبدیل میکند حالا از این داده ها باید برای آموزش مدل خود استفاده کنیم. چیزی که باید بدونیم اینه که برای رسیدن به یک مدل یادگیری ماشین یا یادگیری عمیق خوب ما حتما به پیش پردازش داده ها نیاز خواهیم داشت.اغلب داده های دنیای واقعی مرتب نیست. بعضی از موارد نامرتب بودن داده ها را با هم مرور کنیم:۱- داده های ناقص : این داده ها زمانی به وجود میایند که سیستم به طور منظم داده را ذخیره نکرده باشد و یا به واسطه برخی مشکلات تکنیکی و نرم افزاری۲- داده های نویز : این نوع داده که  outliners نیز نامیده می‌شود، می‌تواند ناشی از اشتباهات انسانی (جمع‌آوری دستی داده‌ها) یا برخی از مشکلات فنی دستگاه در زمان جمع‌آوری داده‌ها باشد.۳- داده‌های Inconsistent یا ناهمخوان : این نوع از داده‌ها ممکن است به دلیل اشتباهات انسانی (اشتباه در نامگذاری یا مقدار دهی) یا داده های تکراری ایجاد شود.سه نوع اصلی داده ها ۱- عددی (Numeric) به عنوان مثال درآمد ، سن۲- طبقه ای (Categorical) به عنوان مثال جنسیت ، ملیت۳- معمولی (Ordinal) به عنوان مثال کم متوسط زیادچگونه پیش پردازش داده را انجام دهیم؟برخی از تکنیک‌های اولیه پیش‌پردازش داده که می‌توانیم برای تبدیل داده‌های خام استفاده کنیم:۱- تبدیل داده ها: از آنجا که می دانیم که مدل های یادگیری ماشین فقط می توانند ویژگی های عددی را استفاده کنند ، بنابراین سایر داده ها باید به نوعی به ویژگی های عددی تبدیل شوند.۲- نادیده گرفتن مقادیر ناقص: هر زمان که در مجموعه داده ها با داده های ناقص مواجه می شویم ، می توانیم بسته به نیاز خود ، ردیف یا ستون داده ها را حذف کنیم. این روش کارآمد است اما اگر مقادیر زیادی داده های ناقص در مجموعه وجود داشته باشد ، نباید انجام شود.۳- پر کردن مقادیر ناقص: هر زمان که در مجموعه داده ها با داده های ناقص مواجه می شویم ، می توانیم داده های ناقص را به صورت دستی پر کنیم ، معمولاً از میانگین ، متوسط ​​یا بالاترین مقدار فرکانس استفاده می شود.۴- یادگیری ماشین: اگر برخی از اطلاعات ناقص را داشته باشیم ، می توانیم با استفاده از داده های موجود ، پیش بینی کنیم که چه داده هایی باید در جای خالی قرار بگیرند.۵- شناسایی Outliers: در برخی از داده های مقادیر از حد تصور و بازه قطعی بسیار بیشتر یا کمتر است به نحوی که خطا بود آن کاملا واضح است در این موارد میتوانیم این داده ها را در صورت داشتن راه حل اصلاح نماییم. [مثال: وزن انسان = ۸۰۰ کیلوگرم؛ به دلیل ۰ اضافه]۳- پیداکردن متناسب ترین مدل برای نوع داده هاهدف اصلی ما یافتن بهترین مدل ممکن با استفاده از داده های از پیش پردازش شده است.  یادگیری با نظارت:در یادگیری نظارت شده ، سیستم هوش مصنوعی با داده هایی مدل می شود که دارای برچسب هستند ، به این معنی که هر داده دارای برچسب صحیح است.یادگیری نظارت شده شامل دو دسته &quot;Classification&quot; و &quot;Regression&quot; می باشد.- طبقه بندی یا Classification:طبقه بندی زمانی مورد نیاز است که داده ها دارای دسته بندی مشخص باشند به نحوی که داده جدید را بتوان در دسته A یا B قرار داد. مانند &quot;قرمز&quot; یا &quot;آبی&quot; ، &quot;بیماری&quot; یا &quot;عدم بیماری&quot; یا &quot;اسپم&quot; یا &quot;عدم اسپم&quot; .طبقه بندی | GIF: www.cs.toronto.eduهمانطور که در شکل فوق نشان داده شده است ، ما 2 کلاس داریم که بر روی نمودار رسم شده اند یعنی قرمز و آبی که می توانند به عنوان &quot;گل setosa&quot; و &quot;گل versicolor&quot; نمایش داده شوند ، محور X برای عرض کاسبرگ و و محور Y برای طول کاسبرگ در نظر گرفته شده است.حالا ما سعی می کنیم بهترین خط  برای جدا کردن دو نوع گل را پیدا کنیم. بدیهی است برای دسته بندی داده های جدید این خط خط معیار ما می باشد.برخی از رایج ترین الگوریتم های دسته بندی عبارت است از : K-Nearest NeighborNaive BayesDecision Trees/Random ForestSupport Vector MachineLogistic Regression- رگرسیون : مدل سازی بر پایه رگرسیون زمانی استفاده میشود که متغیر ها پیوسته باشند:رگرسیون | GIF: techburst.ioهمانطور که در شکل فوق نشان داده شده است ،  محور X نمودار &quot;نمرات آزمون&quot; است و محور Y نشان دهنده &quot;IQ&quot; است. بنابراین ما سعی می کنیم در نمودار مورد نظر بهترین خط را ایجاد کنیم تا بتوانیم از آن خط برای پیش بینی نمره تقریبی هر ضریب هوشی که در داده ها وجود ندارد استفاده کنیم.برخی از رایج ترین الگوریتم های رگرسیون عبارت است از : Linear RegressionSupport Vector RegressionDecision Tress/Random ForestGaussian Progresses RegressionEnsemble Methodsیادگیری بدون نظارت:در یادگیری بدون نظارت یک سیستم هوش مصنوعی باید با داده بدون برچسب و طبقه بندی نشده مدل شود و الگوریتم ها بدون آموزش قبلی روی داده ها عمل می کنند. یادگیری بدون نظارت شده شامل دو دسته &quot;Clustering&quot; و &quot;Association&quot; می باشد.خوشه بندی یا Clusteringدر این روش داده ها به گروه هایی تقسیم می شوند. برخلاف طبقه بندی ، گروه ها از قبل مشخص نیستند ، و این کار معمولاً یک کار غیرقابل نظارت است.برخی از رایج ترین الگوریتم های خوشه بندی عبارت است از : Gaussian mixturesK-Means ClusteringBoostingHierarchical ClusteringK-Means ClusteringSpectral Clusteringنمایی از مدل های گفته شده۴- آموزش و تست مدلبرای آموزش یک مدل ، ابتدا داده ها را به ۳ بخش تقسیم می کنیم که عبارتند از &quot;داده های آموزشی&quot; ، &quot;داده های اعتبارسنجی&quot; و &quot;داده های آزمایش یا تست&quot;.ما مدل سازی را با استفاده از &quot;مجموعه داده های آموزشی&quot; آموزش می دهیم ، پارامترها را با استفاده از &quot;مجموعه اعتبارسنجی&quot; تنظیم می کنید و سپس عملکرد مدل خود را بر روی &quot;مجموعه داده های آزمون&quot; آزمایش می کنید. نکته مهمی که باید به آن توجه داشته باشید این است که در حین آموزش طبقه بندی کننده فقط مجموعه آموزش و یا اعتبار سنجی در دسترس است. از مجموعه داده های آزمون نباید هنگام آموزش طبقه بندی استفاده شود. مجموعه تست فقط هنگام تست طبقه بندی در دسترس خواهد بود.مجموعه آموزشی: مجموعه داده ای که برای یادگیری مدل مورد نیازاعتبار سنجی: مجموعه داده ای دیده نشده برای اعتبار سنجی و تنظیم بهتر پارامترهای مدل.مجموعه تست: مجموعه‌ای از داده‌های دیده نشده برای ارزیابی عملکرد نهایی مدلپس از تقسیم داده ها به 3 بخش می توانیم فرایند آموزش را شروع کنیم.معمولا پس از حذف دیتای تست از دیتای آموزش  چندین مرحله برای ساخت مدل استفاده میکنیم. به این نحو که در هر مرحله دیتای باقی مانده را به دوقسمت آموزش و اعتبار سنجی تفکیک میکنیم و کار آمورش را در اندازه کوچک تر انجام میدهیم. تا مدل نهایی ساخته شود. پس از آموزش مدل می توانیم از همان مدل آموزش دیده استفاده کنیم تا با استفاده از داده های تست یعنی داده های دیده نشده پیش بینی نهایی انجام شود. هنگامی که این کار انجام شد می توانیم یک ماتریس پراکندگی ایجاد کنیم ، این به ما می گوید که مدل ما چقدر خوب آموزش داده شده است. یک ماتریس پراکندگی دارای 4 پارامتر است که عبارتند از &quot;مثبت صحیح&quot; ، &quot;منفی صحیح&quot; ، &quot;مثبت غلط&quot; و &quot;منفی غلط&quot;. ما ترجیح می دهیم که منفی و مثبت های صحیح بیشتری را کسب کنیم تا یک الگوی دقیق تر دریافت کنیم.مثبت های صحیح:  مواردی است که ما  آن را TRUE پیش بینی کردیم و  پیش بینی ما صحیح است.منفی های صحیح: ما FALSE  پیش بینی کردیم و  پیش بینی ما صحیح است.مثبت های غلط: ما TRUE پیش بینی کردیم ، اما خروجی واقعی FALSE است.منفی های غلط: ما FALSE را پیش بینی کردیم ، اما خروجی واقعی  TRUE است.در نهایت ما می توان با استفاده از ماتریس پراکندگی دقت مدل را خود را بفهمیم.Accuracy = (True Positives +True Negatives) / (Total number of classes)برای مثال بالا:Accuracy = (100 + 50) / 165 = 0.9090 (90.9% accuracy)۵- ارزیابیارزیابی مدل بخشی جدایی‌ناپذیر از فرآیند توسعه مدل است.که به پیدا کردن بهترین مدل کمک می‌کند و نحوه کارکرد آینده مدل را مشخص خواهد کرد.برای بهبود مدل ممکن است پارامترهای بالا  را  بار ها و بار ها تغییر دهیم و سعی در بهبود دقت مدل داشته باشیم و همچنین  با محاسبه به ماتریس پراکندگی  تعداد مثبت‌های صحیح و منفی‌های صحیح را افزایش دهیم.۶- نتیجه گیریدر این مقاله فقط دورنمایی از نحوه یک پروژه یادگیری ماشین را با هم مرور کردیم که در هر قسمت نیاز به عمق و یادگیری بیشتری داریم. به طور مثال هر کدام از الگوریتم هایی که در این مقاله نام بردیم نیاز به بررسی جزییات ، نحوه عمکرد و ... دارد که در آینده بررسی خواهیم کرد. اکثر مطالب این مقاله از این لینک برداشت شد به جز مواردی که نیاز به کمی توضیح بیشتر و یا حتی ساده تر بیان کردن موضوعات داشت که در این موارد تغییرات اندکی داشتیم. در ضمن پروژه سمپلی با موارد یاد شده در این مقاله در این لینک گیت هاب قرارداده شده که قابل دسترس شما میباشد.</description>
                <category>اسنپ مارکت</category>
                <author>محمدرضا زندی</author>
                <pubDate>Sun, 11 Aug 2019 15:30:32 +0430</pubDate>
            </item>
                    <item>
                <title>گام اول</title>
                <link>https://virgool.io/snappmarket/%DA%AF%D8%A7%D9%85-%D8%A7%D9%88%D9%84-nclboeufpxot</link>
                <description>یاد گرفتن و یاد دادن چرخه ای هست که میلیون ها سال وجود داشته و به لطف اون دنیا به جایی رسیده که توش قرار داریم. ما هم از این چرخه مستثنی نیستیم. میخوایم یاد بگیریم و یاد بدیم. تجربیاتمون از موفقیت ها و شکست ها، پیشرفت ها و پسرفت ها، دلگرمی ها و دلسردی ها رو ثبت می کنیم تا یادمون بمونه چه مسیری رو طی کردیم و از کجا به کجا رسیدیم. میخوایم بذری رو بکاریم و رشدش بدیم تا به بلوغ خودش برسه. تو هر سازمان مجموعه ای از آدم ها با افکار، استعداد ها، علایق و اهداف مختلف دور هم جمع شدن تا با هم به یه هدف فکر کنن و چیزی رو بسازن که تا قبل از این وجود نداشته. ما دوست داریم بستر رشد رو برای همدیگه هموار کنیم و به هم کمک کنیم تا بلندپرواز باشیم و به چیزهای دست نیافتنی و دور از دسترس بیشتر فکر کنیم. تمام تلاشمون رو می کنیم تا کسایی که در کنار ما کار می کنن، چیز هایی رو تجربه کنن که دوستشون دارن و احساس می کنن اونها رو تبدیل به آدم های بهتری می کنه و خیلی دوست داریم کمکی هر چند کوچیک بکنیم به تمام کسانی که مشتاق و علاقه مند به این حوزه هستند. یاد گرفتیم که به بی نهایت فکر کنیم و سقفی برای خودمون نذاریم و راهی رو انتخاب کنیم که ما رو سمت این میل ذاتی می بره.سعی می کنیم هر آنچه که در بخش فنی اسنپ مارکت اتفاق میفته که شاید خوندنشون برای دیگران جالب باشه (یا دردی رو از کسی یا جایی دوا کنه!)، منتشر کنیم. امیدوارم تلاش ما جبران و ادای دِینی باشه به کسایی که تو حوزه تکنولوژی تأثیر گذار بودن و دنیا رو به جای بهتری تبدیل کردن.</description>
                <category>اسنپ مارکت</category>
                <author>میلاد کیانی</author>
                <pubDate>Mon, 29 Jul 2019 12:28:13 +0430</pubDate>
            </item>
                    <item>
                <title>توسعه REST API با استفاده از GoLang, Echo, MySql, JWT Token با معماری MVC</title>
                <link>https://virgool.io/snappmarket/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-rest-api-%D8%A8%D8%A7-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-golang-echo-mysql-jwt-token-%D8%A8%D8%A7-%D9%85%D8%B9%D9%85%D8%A7%D8%B1%DB%8C-mvc-eeaplh2u5k7h</link>
                <description>GoLang REST API using Echo, MySql, JWT Tokenدر این آموزش ساخت REST API در زبان GoLang و با استفاده از فریمورک Echo و دیتابیس MySql را فراخواهید گرفت. فرض بر این است که شما اصول و مبانی ابتدایی دیتابیس MySql را دانسته و با Querying در این دیتابیس آشنایی دارید.مراحل کار به این صورت خواهد بود :  ایجاد یک API ساده با استفاده از Echo  اتصال GoLang به دیتابیس MySql اضافه کردن یک کاربر  جدید در دیتابیس و دریافت JWT Token ایجاد یک REST API ساده با استفاده از Echo در این مرحله ابتدا فایلی با نام main.go ایجاد کرده و با دستور زیر فریمورک Echo را به ‍پروژه اضافه میکنیم.    $ go get &quot;github.com/labstack/echo&quot;main.go file in project root همانطور که مشاهده میشود در این فایل و در بلاک import از پکیج utils که مربوط به همین پروژه است استفاده شده است. این پکیج مربوط به دایرکتوری utils همین پروژه است که شامل سه فایل response.go, translator.go و constants.go  است که در ادامه بررسی خواهد شد.response.go file inside utils directory خطوط ۵ تا ۱۰ فایل response.go ساختار کلی یک response که در پاسخ به یک request ارسال میشود قرار گرفته است. Result از نوع string بوده و میتواند هر مقدار دلخواهی داشته باشد. در این پروژه مقادیر SUCCESS و ERROR برای این آیتم در نظر گرفته شده است که نمایانگر موفقیت آمیز بودن یا نبودن response  است. آیتم StatusCode از نوع int است که درواقع همان HTTP Status Code  است که در بدنه response  نیز ارسال شده است. آیتم Messages  مربوط به پیغامی است که نمایش داده میشود و خود شامل آرایه ای از MessageItemهاست. MessageItem نیز ساختاری است که شامل یک یا چند string است. آیتم Data ساختاری است که محتوی آرایه ای از آبجکتها است و برای برگرداندن اطلاعات در response (به عنوان مثال لیست کاربران) استفاده میشود.در فایل main.go و در خط ۱۳ متدی با نام GetMessageByKey وجود دارد. این متد در فایل translator.go در دایرکتوری utils قرار دارد که با دریافت یک key پیغام مربوط به آن را در قالب MessageItem در زبانهای مختلف برمیگرداند.translator.go file inside utils directory  در این فایل ثابتی با نام NotFoundErrorMessageKey قرار دارد. این ثابت نیز در فایل constants.go و در دایرکتوری utils تعریف شده است. این فایل جهت نگهداری ثوابت استفاده میشود که در ادامه ثوابت دیگری نیز به آن اضافه خواهد شد.constants.go file in utils directory با اجرای کد زیر در خط فرمان REST API بسیار ساده ای بدون هیچ rout تعریف شده ای خواهیم داشت. این سرویس در پاسخ به هر request پیغام not found را ارسال میکند که در خطوط ۱۱ تا ۱۴ فایل main.go تعریف کرده ایم. این API روی آدرس لوکال هاست و پورت دلخواه تعریف شده ۱۳۲۳ اجرا خواهد شد.$ go run main.goحال اگر در مرورگر یا نرم افزارهایی مثل PostMan آدرس localhost:1323 را فراخوانی کنیم در پاسخ response زیر را دریافت خواهیم کرد.not found response for first requestاتصال GoLang به دیتابیس MySqlجهت اتصال به دیتابیس MySql نیاز است تا ابتدا پکیج درایور آن را به پروژه اضافه کنیم. این پکیج با استفاده از اجرای دستور زیر در خط فرمان امکان پذیر است.$ go get &quot;github.com/go-sql-driver/mysql&quot;پس از اضافه نمودن این پکیج به پروژه در دایرکتوری utils فایلی با نام db.go اضافه میکنیم.db.go file inside utils directory  در این فایل username, password, host, port, db_name به ترتیب نام کاربری و رمز عبور و هاست و پورت و نام دیتابیس است. اضافه کردن یک کاربر  جدید در دیتابیس و دریافت JWT Token پس از ایجاد کانکشن بین دیتابیس و Echo شروع به ساخت مدل و کنترلر خواهیم کرد. مدل ها در دایرکتوری models و کنترلرها در دایرکتوری controllers ایجاد خواهند شد. مدل User  را در فایل user.go و در دایرکتوری models ایجاد میکنیم.user.go file inside models directory  پس از ساخت مدل User کنترلر مربوط به اکشنهای این مدل را در قالب فایل userController.go و در دایرکتوری controllers  ایجاد میکنیم.قبل از ایجاد این فایل پکیج های زیر را بصورت زیر نصب میکنیم : $ go get github.com/dgrijalva/jwt-go$ go get golang.org/x/crypto/bcrypt$ go get gopkg.in/go-playground/validator.v9اولین پکیج جهت ساخت توکن برای کاربر ثبت نام شده , پکیج دوم جهت رمزنگاری رمزعبور وارد شده توسط کاربر و پکیج سوم جهت کنترل مقادیر ورودی توسط کاربر است.userController.go file inside controller directory  در این مرحله نیاز است تا route مخصوص به ایجاد کاربر جدید را در فایل main.go ایجاد کنیم. فایل main.go جدید بصورت زیر خواد بود.modified main.go file in project root  خط ۲۰ از این فایل نشان می دهد که یک route group  برای کاربرها ایجاد شده است. همانطور که در فایل userController.go مشخص است یک ثابت جدید نیز به فایل constants.go اضافه شده است.modified constants.go file inside utils directory  فایل translator.go نیز بصورت زیر تغییر خواهد کرد.modified translator.go file inside utils directory  پس از اتمام کار با ارسال یک request  از نوع POST به /users و ارسال request body  بصورت زیر میتوان کاربر را ثبت نام کرده و یک توکن در response برگرداند. request body to register user and get tokenresponse body with tokenهمچنین میتوانید کدهای این آموزش را از آدرس گیت هاب پروژه مشاهده نمایید.  </description>
                <category>اسنپ مارکت</category>
                <author>علیرضا جنگی</author>
                <pubDate>Wed, 29 May 2019 16:49:58 +0430</pubDate>
            </item>
            </channel>
</rss>