<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های shayan hoseini</title>
        <link>https://virgool.io/feed/@shayanadc</link>
        <description>back-end developer</description>
        <language>fa</language>
        <pubDate>2026-04-15 10:38:25</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/30627/avatar/avatar.png?height=120&amp;width=120</url>
            <title>shayan hoseini</title>
            <link>https://virgool.io/@shayanadc</link>
        </image>

                    <item>
                <title>توسعه دادن را به حال خودش رها نکن!</title>
                <link>https://virgool.io/@shayanadc/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%AF%D8%A7%D8%AF%D9%86-%D8%B1%D8%A7-%D8%A8%D9%87-%D8%AD%D8%A7%D9%84-%D8%AE%D9%88%D8%AF%D8%B4-%D8%B1%D9%87%D8%A7-%D9%86%DA%A9%D9%86-g2qqurnykffn</link>
                <description>پزشکان معتقدند بر اساس کتاب مقدس، خدا حوا را از بطن آدم ساخته پس  جراحی قدیمی ترین حرفه است در حالیکه مهندسان مدعی اند قبل از آدم و حوا، خداوند دنیا و بهشت را از نظم دادن به یک حرج و مرج مطلق بوجود آورده، پس ساخت و ساز اولین حرفه شناخته شده در هستی است. در این بین برنامه نویس ها به صندلی خودشون با اعتماد به نفس تکیه میزنند و با تمسخر به هر دوی اونها میگویند: هیچ با خودتون فکر کردید که اون هرج و مرج رو چه کسی بوجود آورده؟؟بله خنده دار بود اما حتما پیش اومده که بخواهید کد شخص دیگری رو ادامه بدهید اما بدلیل سردرگمی موفق نشده باشید و یا حتی ادامه پروژه ای که خودتون توسعه اش دادید غیر ممکن شده باشه. در واقع انتظار میره پروژه طوری توسعه شده باشه که اضافه کردن ویژگی جدید به اون و یا رفع باگ به راحتی قابل انجام باشه اما این اتفاق جز با ساختار دادن به روندهای انجام پروژه قابل کنترل نیست.ساختار :‌ 1 - چگونگی ساختمان چیزی. 2 - ترتیب اجزا و بخش های یک جسم.اینجا قصد ندارم چیزی رو آموزش بدم فقط میخوام ساختاری که برای پیاده سازی Backend پروژه هام در نظر میگیرم رو باهاتون به اشتراک بذارم و اینکه شما هم روشهای خودتون رو با توی کامنت ها یا توییتر به اشتراک بذارید خیلی خوشحالم میکنه.اول خوب فکر کنیدWeeks of coding can save you hours of planning.کد زدن و توسعه محصول کار پرهزینه ایست پس قبل از کد زدن باید مطمئن شد دقیقا برای همون چیزی کد میزنید که واقعا مورد نیاز مشتری است و از طرفی ساده ترین روش رو برای پیاده سازی پیدا کرد. برای این کار باید مسئله رو تا جایی که میشه کوچک و قابل تعریف کرد و طراحی هر چیزی که بعدا هم میتونه به سیستم اضافه بشه رو به همون بعد موکول کرد. البته این کاری نیست که به تنهایی انجام بدهید، در واقع در تعامل با مالک محصول به این ويژگی ها از محصول خواهید رسید و از اونجا که اون چیزی که در فکر شما میگذره الزاما با فکر شخص دیگر یکسان نیست باید به اون نظم داد. نوشتن هر ویژگی از محصول در قالب جمله زیر شما رو به نقطه ی مشترکی از انتظارات ذهنی با مالک محصول میرسونه.“As a &lt;role or persona&gt;, I can &lt;goal/need&gt; so that &lt;why&gt;”این دوره میتونه برای پیدا کردن نیاز واقعی مشتری میتونه بهتون ایده بده و برای خودتون و مشتری بهتره که ویژگی های توافق شده رو به طور مصور هم داشته باشید.قرارداد کنیدمن برای پیاده سازی روی وب، اغلب از API و استاندارد REST استفاده میکنم و برای اینکه فرمت استانداری  برای فرستادن ورودی و گرفتن خروجی در این روش داشته باشم از JsonApi تبعیت میکنم و بر همین اساس مشخصه های API رو قرارداد میکنم:حالا برای ثبت این قرارداد باید اون رو داکیومنت کرد ولی همیشه نوشتن داکیومنت (هم برای نویسنده و هم خواننده) کار سختیه. البته به کمک swagger ، نوشتن داکیومنت نه تنها سریع بلکه قابل خوندن هم میشه. به این شکل که فایلی با پسوند .yaml رو با رعایت استاندارد OpenApi Specification به شکل زیر مینویسیم:openapi: 3.0.1
info:
  title: ProductAPI
  version: 1.0.0
  servers:
      - url: https://localhost.com/v
paths:
  /products:
    post:
     requestBody:
     content:
     application/json:
       schema:
           required:
               - meta
               type: object
               properties:
                meta:
                type: object
                properties:
                title:
                type: string
                price : integer 
                required: false
        responses:
        200:
        description: invitation issued successfully
        content:
        application/json:
        schema:
        required:
          - meta
                  type: object
                  properties:
                      meta:
                        type: object
                          properties:
                            message:
                            type: string
        400:
        description: invitation failed
        content:
        application/json:
        schema:
        required:
        - errors
            type: object
             properties:
             errors:
             type: array
                 items:
                 type: object
                  properties:
                      title:
                         type: stringو به جای متن های طولانی، یک نمونه قابل اجرا از داکیومنت خواهدید داشت که میتونید نمونه در اینجا امتحان کنید.به قرارداد پایبند شویدهر توسعه دهنده نرم افزار باید ساختار و رفتار سیستم را در توسعه در نظر داشته باشد. در واقع قراردادی موفق خواهد بود که ابزاری برای متعهد بودن به انجامش هم پیدا کنید. با استفاده از تست های رفتاری BDD ، میتوان رفتار سیستم را بر مبنای انتظار مشتری مورد تست قرار داد این تست ها که با زبان gherkin قابل پیاده سازی است تضمین میکند که  بعد از پیاده سازی سیستم [به هر نحوی] رفتار آن همانی خواهد بود که از ابتدا برای آن قرارداد کرده بودیم.همینطور که در تصویر میبیند در این تست وارد جزییات عملکرد نمیشویم و در واقع رفتار سیستم را بر اساس سناریو تست میکنیم. چیزی که توسعه میدهیم، در نهایت باید این تست را پاس کند و با این کار به نتیجه نهایی رفتار سیستم متعهد خواهیم شد.نمونه اولیه بسازیدهمیشه مشتری ها برای دریافت محصول عجله دارند پس با ساختن یک نمونه از API، به تیم frontend اجازه دهید پیش از تمام شدن کار توسعه backend، کار خود را پیش ببرند و محصول نهایی را آماده ارائه کنند.ابزارهای مثل https://app.mocklab.io این امکان رو میدهند تا روی سرور اونها مشخصه های api رو داکیومنت کنید و هر بار که بر اساس اون مشخصه درخواست بدهید به شما پاسخی مطابق با داکیومنت بدهند. دست نگه داریدتصور اینکه اول توسعه دهیم و بعد ریفکتور کنیم تفکر درستی نیست!! قبل از شروع به کد زدن باید مکانیسمی برای ایجاد کدها در نظر بگیرید. برای این کار باید دیدی توامان از معماری و طراحی داشت. و مثلا تصمیم بگیرید میخواهید از معماری مایکروسرویس استفاده کنید یا یکپارچه. این کتاب تا حدی میتونه بهتون ایده بده. بنظرم داشتن ایده ای در معماری سیستم که حتی خیلی هم دقیق نباشه بهتر از نداشتن اونه. قطعه های لگو را به هم وصل کنیدحالا نوبت به انجام قسمت های درونی است. قطعا کنترل بخش های کوچک، کار ساده تری است پس روش تقسیم و غلبه رو تا جای ممکن پیاده سازی کنید و یونیت تست بنویسید و در نهایت هم اینتگریشن تست. اما خود تست ها هم نیاز به کنترل و ساختاردهی دارند. sandi mentz روشی رو ارائه پیشنهاد میده که سیستم با تبادل پیام بین متدها کار میکند(خروجی یک متد، ورودی متد دیگری است) و عملکرد متدها به دو نوع دسته بندی میشه:کوئری Query : مقداری را برمیگردانند اما چیزی را نباید تغییر دهند.دستوری Command : مقداری را تغییر میدهند اما نباید چیزی را تغییر دهند.البته بعضی اوقات رعایت این تقسیم بندی هم ممکن نیست. جدول زیر نشان میدهد که لازم نیست همه چیز را تست کنیم:کنترل کنیدبه پروژه، سیستم کنترل ورژن مثل گیتهاب رو اضافه کنید و هر issue یا مسئله ای رو روی یک branch جداگانه ببرید و هر نسخه stable (وقتی مطمئن هستید سیستم دقیق و مطابق قرارداد کار میکنه) از master رو تگ بزنید تا بتونید بر روی چیزی که توسعه میدهید کنترل داشته باشید.دستها را بالا بگیردفرستادن کد بر روی سرور دقیقا قسمت رنج آور ماجرا است. اول اینکه کد شما ممکن است بر روی سرور لوکال خودتون کار کنه اما دلیل نمیشه روی هر سرور دیگری هم کار کنه چرا که کانفیگ ها با هم متفاوت هستند و هم اینکه نیازمندیهای پروژه شما روی سرور مقصد نصب نشده باشه. برای یکبار از شر این مشکل با داکر کردن پروژه تون خلاص بشید.حالا میتونید نسخه تگ خورده از گیت (یا هر کنترل ورژن دیگه ای) رو روی سروس pull کنید. اما صبر کنید!! قبل از اون باید همه تست ها پاس بشن.ابزارهای CI/CD به شما این امکان رو میدهند تا از شر کار تکراری تست کردن قبل از هر pull ریکوئست هم خودتون رو خلاص کنید. من از drone استفاده میکنم و احتمال خطای انسانی موقع deploy رو کم میکنم. اینطوری که هر وقت من تگی به گیت میزنم و push میکنم drone به گوش نشسته و وقتی متوجه تغییرات شد، بصورت اتوماتیک تستها رو اجرا میکنه و در صورت پاس شدن، اخرین تگ رو رو سرور pull میکنه.از وقتی که برای خوندن این مطلب گذاشتید سپاسگزارم. این روش من بود و فکر میکنم مثل هر شغل دیگه ای کار برنامه نویسی هم نیاز به مدون شدن داره تا بشه اون رو کنترل کرد ولی این روش ها میتونه متفاوت باشه و هدف پیدا کردن این روش ها بر اساس نیاز و توانایی همگام شدن با اون هاست. پس شما هم روش های خودتون رو کامنت بذارید یا به توییتر من پیام بدید.</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Thu, 17 Oct 2019 12:49:58 +0330</pubDate>
            </item>
                    <item>
                <title>احراز هویت به کدام روش؟</title>
                <link>https://virgool.io/@shayanadc/%D8%A7%D8%AD%D8%B1%D8%A7%D8%B2-%D9%87%D9%88%DB%8C%D8%AA-%D8%A8%D9%87-%DA%A9%D8%AF%D8%A7%D9%85-%D8%B1%D9%88%D8%B4-chyks5nzzxdq</link>
                <description>در اینجا میخوام دو استراتژی پیاده سازی authentication رو مورد بررسی قرار بدم.زمانی که کاربری احراز هویت شد (به هر روشی) نیاز دارد توکنی را دریافت و برای خود نگه دارد و تا زمانی که این توکن منقضی نشده بتواند به منابع  - بدون نیاز به احراز هویت دوباره - دسترسی داشته باشد.در روش stateful شما وضعیت را نگه میدارید و هر زمانی که بخواهید میتوانید آنرا باطل کنید و یا از بین ببرید. و در مقابل، روش stateless  اینگونه است که شما وضعیت را کنترل نمیکنید و زمانی که برای توکن مشخص کرده اید باطل کننده آن خواهد بود.وقتی سرور وضعیت کاربر احراز هویت شده را نگه میدارد یا stateful:در این روش توکن صادر شده را در همان backend صادر و به ازای آن اطلاعات کاربر را بر روی session ذخیره میکنید و مقدار session را به client میدهیم. حال هر بار client بخواهد به backend دسترسی پیدا کند خود backend میداند که در session کدام کاربر درخواست دهنده است. و بدین ترتیب هر بار که session ها در سمت سرور پاک یا دستکاری شوند دیگر مقداری که به client داده بودیم بی معنی خواهد شد.در این روش شما میتوانید در هر زمانی که بخواهید مقدار session را پاک کنید و البته پیاده سازی راحتی هم دارد. اما این روش علاوه بر مصرف زیاد حافظه، برای scale کردن مناسب نیست چرا که اگر کاربر A رو روی سرور ۱ احراز هویت کنیم پس مقدار توکن را در این سرور ذخیره کرده ایم و از این به بعد تنها سرور ۱ میتواند به درخواست های کاربر A پاسخ دهد.مشکل دیگر این است که فرض کنید سرویس شما هم بر روی هم بر روی مرورگر و هم اپلیکیشن اندروید قابل استفاده است. در این حالت اگر کاربر دستور logout بر روی اپلیکیشن اندروید را بدهد، backend مقدار session را پاک خواهد کرد و در واقع درخواست های شما از اپلیکیشن اندروید هم دیگر بی معنی است و احراز هویت باید دوباره صورت بگیرد.وقتی سرور از وضعیت کاربر احراز هویت شده هیچ اطلاعی ندارد یا stateless:این روش برای رفع مشکلاتی که در بالا گفتیم ارائه شده است. در این روش backend مقدار توکن را پیش خود نگه نمیدارد و آنرا پس از ذخیره در پایگاه داده، فقط یکبار به client میسپارد.واضخ است که در این روش دیگر نگران حافظه نخواهید بود و برای scale کردن مشکلی پیش نخواهد آمد چرا که backend تنها وظیفه اعتبارسنجی مقدار توکن را دارد و بر روی سرور ذخیره ای صورت نمیگیرد. واضح است که اگر شما از روی مرورگر logout کنید حساب کاربری شما بر روی اپلیکیشن اندروید همچنان کار خواهد زیرا شما فقط مقدار توکن ذخیره شده بر روی مرورگر را پاک کرده اید و تغییر وضعیتی در backend پیش نیامده است.البته بر اساس این روش که کمی پیچیده تر است، شما بعنوان backend باید کاملا پایبند به توکنی که صادر کرده اید باشید چرا که نمیتوانید آنرا یکطرفه باطل کنید.کاملا مشخص است که روش دوم کارایی بیشتری دارد اما محدودیت هایی را برای توسعه ایجاد میکند که برای بهبود آنها چند توصیه زیر عملکرد را بهتر خواهد کرد:برای تولید هر توکن، زمانی را بعنوان انقضا مشخص کنید و به client اجازه دهید همراه با درخواست ایجاد توکن این زمان را مشخص کند.مقداری را برای از نوسازی توکن و تمدید مدت آن در نظر بگیرید. (Refresh Token)</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Sun, 29 Sep 2019 22:46:46 +0330</pubDate>
            </item>
                    <item>
                <title>احراز هویت با استفاده از github در express</title>
                <link>https://virgool.io/apieco/%D8%A7%D8%AD%D8%B1%D8%A7%D8%B2-%D9%87%D9%88%DB%8C%D8%AA-%D8%A8%D8%A7-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-github-%D8%AF%D8%B1-express-t9ajhvwkgvnx</link>
                <description>در این پست میخوام authentication رو با استفاده از github  در backend  پیاده سازی کنم. برای این موضوع بهتره کمی عقب تر بریم و درک عمیق تری از شیوه ی authentication داشته باشیم.ما در اینجا میخواهیم از oauth2 استفاده کنیم که یک استاندارد برای احراز هویت کاربران برای دسترسی به منابع یا داده ها در api است.در RFC اون شکل زیر اومده که شاید خوندنش کمی پیچیده باشه اما به زبان ساده تر و خلاصه:استراتژی این استاندارد اینطوریه که برای جلوگیری از دسترسی مخرب به داده یا منبع، باید ابتدا یک درخواست با نام کاربری و رمز عبور برای احراز هویت به سرویس دهنده فرستاده شود و برای این درخواست clientID ای مشخص به اون درخواست رو دریافت کرد و در ازای ارسال این clientID به سرویس دهنده یک رشته ( string ) رمزگذاری شده بعنوان توکن (token) ساخت و برگردانده شود که حالا این توکن نشان اجازه دسترسی ما به داده یا منبع مورد نظر خواهد شد چرا که هم client و هم server از اون خبر دارند.ما میتونیم مراحل رو خودمون پیاده سازی کنیم یعنی یه رشته منحصر بفرد بر اساس clientID برای نام کاربری درخواست داده شده ایجاد کنیم و عملیات بالا رو برای احراز هویت کاربر انجام بدیم اما از اونجایی که سایتهایی مثل گیت هاب و توییتر و فیسبوک و گوگل و ... [که اینجا به اونها provider میگیم ] هم از این روش (oauth) استفاده میکنند و ما به اونها اعتماد داریم میتونیم این مراحل رو به اونا بسپریم و تنها کاری که انجام باید بدهیم این است که کاربر را به سمت انها بفرستیم و انتظار داشته باشیم توکن منحصر بفرد تولید شده را از اون provider دریافت و ذخیره کنیم و در هر درخواست از مقدار توکن، کاربر متناظرش رو تشخیص بدهیم.خب حالا که کمی با تئوری ماجرای oauth authentication آشنا شدیم بریم سراغ پیاده سازی:من برای پیاده سازی از passportjs استفاده کردم که شاید کامل ترین پیکیجی بود که دیدم.بعد از نصب باید بخاطر داشته باشید که باید با استفاده از passport.initialize به برنامه خودتون بفهمونید که از این پکیج بعنوان middleware استفاده کنه اما حواستون باشه که ما اینجا نمیخوایم از session استفاده کنیم پس از passport.session استفاده نخواهیم کرد.اما چرا از session استفاده نکردم؟ تصور کنید توکن کاربر احراز هویت شده رو دارید. با اون چه باید بکنید تا در درخواست های بعدی این اطلاعات از دست نره و مجبور نباشید هر بار احراز هویت کنید. درسته که میتونیم این اطلاعات رو در session ذخیره کنیم اما تصور کنید میخواهید با استفاده از توکن بدست آمده هم روی مرورگر و هم روی یک اپلیکشین موبایل لاگین کنید. اگر نمیخواهید کاربر مجبور به احراز هویت مجدد شود باید توکن رو به درخواست دهنده بدهید تا در هر کجا که خواست از اون استفاده کنه و برای شما این مهم باشه که این توکن در دیتابیس شما اعتبار دارد و یا خیر. البته اشکال این کار اینه که اگر توکن به دست هرکسی بیفته میتونه با اون درخواست بده ولی باید ببینید کدوم برای شما اولویت دارهپکیج passport دارای استراتژی های مختلف هستش که ما میخواهیم از گیت هاب استفاده کنیم. پس از اینجا اون استراتژی رو به پروژه تون اضافه کنید. حالا میتونید از اون استراتژی در برنامه تون استفاده کنید اما چطوری؟const passport = require(&#039;passport&#039;);
​
var GitHubStrategy = require(&#039;passport-github2&#039;).Strategy;
​
passport.use(new GitHubStrategy({
    clientID: &#039;clientIDFromGithub&#039;,
    clientSecret: &#039;clientSecretFromGithub&#039;,
    scope: [&#039;user:email&#039;],
    callbackURL: &amp;quothttp://127.0.0.1:3000/auth/github/callback&amp;quot,
  },
  async function(accessToken, refreshToken, profile, done) {
    let user = // save or update user with accessToken and profile items
    return done(null, user);
  }
));همونطور که متوجه شده اید این استراتژی ( استفاده از provider ) نیاز به clientID و clientSecret داره که براساس توضیحی که دادم همون نقش سرویس دهنده ایجاد کننده توکن رو برای ما دارند که باید اونها رو از گیت هاب بگیرید. اینجا میتونید یک اپ بسازید و کلیدهای مورد نظر اون رو دریافت کنید.گیت هاب کاربر شما رو پس از احراز هویت به لینکی به نام callbackURL میفرسته تا شما از موفقیت آمیز بودن احراز هویت و اون رشته توکن مطلع کنه. پس از این اتفاق شما با استفاده از done() کاربر رو بر میگردونید.در صورتیکه اطلاعات غلط بود میتونید اینطوری جلوی اون رو بگیرید:return done(null, false, { message: &#039;Incorrect credential.&#039; });خب پس تا اینجا متوجه شده ایم که به دو Route نیاز داریم: اول فرستادن کاربر به گیتهاب برای احراز هویت و دریافت توکن و اطلاعات کاربر در callback پس :router.get(&#039;/auth/github&#039;,
  passport.authenticate(&#039;github&#039;));
​
router.get(&#039;/auth/github/callback&#039;, 
  passport.authenticate(&#039;github&#039;, {session: false}), function(req, res) {
    res.json({email : req.user.email, access_token : req.user.access_token});
  });
​در صورتیکه احراز هویت به درستی انجام بشه شما  accessToken و اطلاعات کاربر احراز هویت شده رو دریافت خواهید کرد.مقدار توکن میتونه نشون دهنده این باشه که کدام کاربر در حال درخواست دادنه. یعنی از این به بعد کاربر مقدار توکن خودش رو به همراه ریکوئست میفرسته ( مثلا توی header ) و ما توی دیتابیس کاربر متناظر اون توکن رو پیدا میکنیم و برمیگردونیم.من توی express این بررسی کردن رو اینطوری نوشتم:async function ensureAuthenticated(req, res, next) {
 var Htoken = req.headers.access_token
 user  = await //find user based on token in db
 if(!user) res.status(401).json({err: &amp;quotInvalid Request&amp;quot})
 if(user) {
   req.user = user
   next()
 }
}و از اون در جاهایی که میخوام دسترسی رو محدود به احراز هویت کنم بعنوان middleware استفاده میکنم:router.get(&#039;/profile&#039;, ensureAuthenticated, function(req, res, next) {
  res.json({message: &amp;quotsuceess&amp;quot})
});</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Sun, 29 Sep 2019 14:53:09 +0330</pubDate>
            </item>
                    <item>
                <title>چرا انتخاب Myisam و Innodb از آنچه فکر میکنیم مهم تر هستند؟</title>
                <link>https://virgool.io/@shayanadc/%DA%86%D8%B1%D8%A7-%D8%A7%D9%86%D8%AA%D8%AE%D8%A7%D8%A8-myisam-%D9%88-inoodb-%D8%A7%D8%B2-%D8%A2%D9%86%DA%86%D9%87-%D9%81%DA%A9%D8%B1-%D9%85%DB%8C%DA%A9%D9%86%DB%8C%D9%85-%D9%85%D9%87%D9%85-%D8%AA%D8%B1-%D9%87%D8%B3%D8%AA%D9%86%D8%AF-bdkngnligm4d</link>
                <description>اگر از MySQL استفاده میکنید حتما باید بدونید که چه نوع انجینی رو برای ذخیره کردن داده ها استفاده کنید.قبل از اینکه از بدونید چرا باید به انتخاب Innodb و یا MyIsam اهمیت بدهیم بهتره در مورد نحوه ایجاد تغییر  و دستکاری در جدول‌ (table) ها چیزهایی بدونیم.برای اینکه دو کوئری با هدف تغییر به طور همزمان به سراغ یک سطر نروند باید اجازه دسترسی از کوئری های دیگر گرفته شود.فرض کنید در یک پایگاه داده، چندین تراکنش با یکدیگر در حال اجرا هستند. خاصیت isolation به ما میگوید تراکنش ها نباید از اجرای یک دیگر مطلع شوند. یعنی تراکنش ها باید طوری اجرا شوند که انگار، فقط همین تراکنش در حال اجرا در کل پایگاه داده است. برای این عمل فرایندها باید اجازه اتصال و تغییر را از بقیه بگیرند به این عمل قفل (lock) شدن میگویند. این عمل قفل شدن به دو صورت میتواند ایجاد شود.قفل شدن جدول Table Locking:زمانیکه برای یک یا چند سطر از جدول درخواست تغییر (update , delete) فرستاده میشود کل آن جدول تا زمان انجام تغییرات قفل میشود. این روش تنها اجازه یک کوئری تغییر در یک زمان را میدهد و بقیه درخواست های تغییر منتظر میمانند تا کار تغییر قبلی تمام و جدول مورد نظر آزاد شود که بیشتر مناسب برای دیتابیس هایی است که بیشتر عمل خواندن (select) از آنها صورت میگیرد. MyIsam از این روش استفاده میکند.این قفل شدن و آزادسازی جداول به شیوه ی زیر انجام میشود:دو صف درخواست قفل شدن برای تغییر (update , delete) و خواندن (select) در نظر بگیرید.اگر میخواهید برای نوشتن در جدول آنرا قفل کنید:اگر جدول از قبل به حالت قفل در نیامده درخواست قفل جدول برای نوشتن را اعمال میکند و کوئری را اعمال کن،در غیر اینصورت در صف قفل برای نوشتن قرار میگیرد.اگر میخواهید برای خواندن در جدول آنرا قفل کنید:اگر قفل نوشتن روی جدول مورد نظر نیست قفل خواندن را اعمال کن و آن کوئری را بخوان،در غیر اینصورت در صف قفل خواندن قرار بگیر.توجه کنید که ابتدا صف نوشتن بعد از هر بار آزادسازی خوانده میشود چرا که به آن اولویت بالاتری داده شده.برای اینکه نسبت قفل شدن به منتظر ماندن در صف را ببنید میتوانید:SHOW STATUS LIKE &#039;Table%&#039;+-----------------------+---------+
| Variable_name         | Value   |
+-----------------------+---------+
| Table_locks_immediate | 150 |
| Table_locks_waited    | 11   |
+-----------------------+---------+در این روش اگر از Group By استفاده میکنید میتواند سریع تر عمل کند.قفل شدن سطر Row-level locking:این روش که innodb از آن برای کارایی حداک‍ثری دیتابیس استفاده میکند و همزمانی بالا و چندکاربره بودن را پشتیبانی میکند عمل قفل شدن به صورت سطر به سطر اتفاق میفتد.دو کانکشن را در نظر بگیرید که هر کدام روی یک سطر میخواهند تغییر ایجاد کنند:UPDATE customers SET name = NEW NAME WHERE id=1; 
DELETE FROM customers WHERE id=1;کوئری دوم منتظر جواب یا خطایی از کوئری اول میماند تا بتواند اعمال شود. متغیر innodb_lock_wait_timeout  منتظر ماندن برای اعمال کوئری تغییر و سپس برگرداندن transaction به حالت اولیه را تنظیم میکند.برای جلوگیری از اینکه دو کوئری یک سطر را قفل کنند و منتظر آزادسازی یکدیگر شوند و بن بست (deadlock) پیش بیاید هر کوئری تغییر قبل از اضافه شدن به صف، لیست همه ی قفل شده ها را چک میکند و این انتظار روند را کند میکند.همینطور با غیر فعال کردن  innodb_deadlock_detect   در سیستم های که همزمانی بالایی دارند میتواند از تشخیص جلوگیری کند. و از همان  innodb_lock_wait_timeout  برای آزاد سازی کوئری ها استفاده کنیم.برای تغییر این دو متغیر میتوانید :SET GLOBAL innodb_deadlock_detect = 1000;همچنین برای دیدن وضعیت و جزییات بیشتر از قفل شدن :SHOW ENGINE INNODB STATUS;روش MyIsam از transaction پشتیبانی نمیکند یعنی اگر در بین کوئری مشکلی پیش بیاد تا آنجایی که مشکلی پیش آمده تغییر  را اعمال میکند ولی در InnoDB خاصیت تجزیه ناپذیری یا atomicity برقرار است یعنی بعد از پیش آمدن خطا در میانه اعمال کوئری همه چیز به حالت قبل برمیگردد.اما InnoDB از خواص Relational پیروی میکند و update و delete آبشاری شما را در بین جداول پشتیبانی میکند. از طرفی در InnoDB همه داده های جداول (از جمله index) رو بر روی cache ذخیره میکند و به مموری زیادی احتیاج دارد در حالیکه MyIsam فقط index ها را ذخیره میکند.اما Myisam عملکردی درخشان تر از innodb خواهد داشت چرا که وقتی تغییرات زیاد نیست قفل شدن کل جدول سرعت بالاتری نسبت به هر سطر برای تغییرات زیاد دارد. و اگر تغییرات سرعت بالاتری از خواندن داشته باشند innodb عملکرد بهتری دارد زیرا میتواند زودتر تغییرات را واگذار فرایند بعدی کند.</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Wed, 11 Sep 2019 09:18:26 +0430</pubDate>
            </item>
                    <item>
                <title>وقتی تست ها انعطاف دارند...</title>
                <link>https://virgool.io/@shayanadc/%D9%88%D9%82%D8%AA%DB%8C-%D8%AA%D8%B3%D8%AA-%D9%87%D8%A7-%D8%A7%D9%86%D8%B9%D8%B7%D8%A7%D9%81-%D8%AF%D8%A7%D8%B1%D9%86%D8%AF-ywrkgzcv34dy</link>
                <description>پروژه ای رو فرض کنید که نسبتا بزرگ محسوب میشه و دارای تست unit است. در واقع برای عملکرد هر قسمت و متد از سیستم تست unit متناظری نیز وجود داشته باشه.بعد از مدتی نیازمندی مشتری در قسمتی از پروژه تغییر میکنه. اگر فرض را براین بگیریم که به روش ابتدا تست سپس کد (TDD) پایبند هستیم. خب حالا کدام تست ها را باید مطابق با ویژگی جدید محصول تغییر بدهیم؟از آنجایی که تست های unit بر نحوه پیاده سازی کد تمرکز دارد نیاز به refator مداوم دارند و با این حال بدست آوردن خط مشی مشخصی از تست های شده ی مربوط به هر Feature بعد از مدتی کار ساده ای نخواهد بود.اما راه حل؟ بله درسته!‌ میتونیم تست ها را با دید مشتری و براساس نیازمندیهای او بنویسیم.خب برای این کار برگردیم به نحوه بیان مشتری از نیازهاش. مشتری ها عموما اینطوری نیازشون رو بیان میکنن:وقتی کاربر لاگین نکرده کالایی را به سبد خرید اضافه کرد پیغام ابتدا ثبت نام کنید بر روی صفحه نمایش داده شود برای تبدیل این جمله به سراغ زبان gherkin میریم. این زبان از چند قاعده کلی پیروی میکنه که اگه اون ها رو بدونیم میتونیم کارمون رو شروع کنیم ( برای بیشتر دونستن اینجا رو ببنید )Feature, Scenario, Given, When, Thenتوجه کنید که در gherkin فقط این کلمات کلیدی هستند و جملاتی که در مقابل آنها قرار میگیرد در واقع نام متدی است که قرار است تبدیل به تست در زبان مورد نظر شما شود. کافیه یه فایل با پسوند feature ایجاد کنیم.در هر فایل میتوانید یک بار از کلمه Feature استفاده کنید:Feature: add product to cardIn order to add product in cardAs an userI want to get right messageو به ازای هر Feature میتونید Scenario های متعددی بنویسید:Scenario: add product as unauthorized userمفروضات (چیزهایی که برای انجام این تست نیاز داریم داشته باشیم مثل کاربری با مشخصات معین) تست:Given unathorized userحالا رخدادی که کاربر سیستم آنرا انجام میدهد تا نتیجه لازم را بدست بیاورد:When I add product to cardو در پایان نتیجه ای که انتظار داریم:Then I should get message &amp;quotlogin PLZ!!&amp;quotحالا با توجه به زبانی که از اون استفاده میکنید باید **ابزاری** پیدا کنید تا تست gherkin رو به زبان مورد نظرتون تبدیل کنه:من برای php از behat و در python از behave  استفاده میکنم و توصیه شون میکنمدر جاوا اسکریپت هم از cucumber استفاده کردم و توصیه ش نمیکنم :)حالا کافیه فایل با پسوند feature به زبان gherkin رو با ابزار مورد نظرتون اجرا کنید:npm run cucumber firsttest.featureخروجی ترمینال شما باید چیزی شبیه به این (مثال javascript) خواهد بود:? Given unathorized userUndefined. Implement with the following snippet:Given(&#039;unathorized user&#039;, function () {// Write code here that turns the phrase above into concrete actionsreturn &#039;pending&#039;;});? When I add product to cardUndefined. Implement with the following snippet:When(&#039;I add product to card&#039;, function () {// Write code here that turns the phrase above into concrete actionsreturn &#039;pending&#039;;});? Then I should get message &amp;quotlogin PLZ!!&amp;quotUndefined. Implement with the following snippet:Then(&#039;I should get message {string}&#039;, function (string) {// Write code here that turns the phrase above into concrete actionsreturn &#039;pending&#039;;});فراموش نکنید که دو شیوه Unit Test و BDD رو در مقابل هم قرار ندید چرا که برای تکمیل یک پروژه هم به نظر مشتری و مدیر محصول نیاز دارید تا بدونید محصول شما در نهایت باید چگونه کار کند؟ و هم برای اینکه دولوپر سنیور شما از قابل نگهداری نوشته شدن تست ها مطمئن بشه به تست های unit نیاز خواهید داشت.احتمالا الان راحت تر میتونید تشخیص بدهید که چطور نوشتن تست BDD ما رو در مقابل تغییر نیاز مشتری ایمن نگه میداره.</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Sat, 07 Sep 2019 23:09:22 +0430</pubDate>
            </item>
                    <item>
                <title>بازی بولینگ و چالش های برنامه نویسی</title>
                <link>https://virgool.io/fboard/%D8%A8%D8%A7%D8%B2%DB%8C-%D8%A8%D9%88%D9%84%DB%8C%D9%86%DA%AF-%D9%88-%DA%86%D8%A7%D9%84%D8%B4-%D9%87%D8%A7%DB%8C-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%86%D9%88%DB%8C%D8%B3%DB%8C-qnouxwipipej</link>
                <description>بازی بولینگ و نحوه امتیاز دهی در این بازی میتواند برای یک برنامه نویس بسیار جالب باشد چراکه برای تبدیل قوانین بازی به کد تقریبا اکثر پارادایم های برنامه نویسی را لازم خواهید داشت.بولینگ همان بازی پرتاب یک توپ گرد از مسیری باریک به سمت ۱۰ پین کاشته شده است که هدف انداختن بیشترین پین در هر پرتاب است. این بازی در ۱۰ فریم انجام میشود. به طوری که در ابتدای هر فریم هر ۱۰ توپ کاشته میشود و در هر فریم به بازی کننده اجازه داده میشود تا ۲ بار توپ را به سمت پین ها پرتاب کند.اگر در همان پرتاب اول همه ی پین ها انداخته شود به این حالت ( strike ) گفته میشود و این فریم در همینجا تمام میشود ولی اگر این اتفاق نیفتاد و در پرتاب دوم موفق به انداختن همه پین ها شدیم به این حالت ( spare ) گفته میشود.بعد از پرتاب دوم حتی اگر همه ی پین ها نیفتاده باشد، فریم بسته میشود و به فریم بعدی خواهیم رفت.فریمی که درآن استرایک ( افتادن همه پین ها در پرتاب اول ) اتفاق افتاده به این صورت محاسبه میشود:تعداد پین های انداخته شده این فریم (که ۱۰ تا است) به اضافه ی تعداد پین های انداخته شده در دو پرتاب بعدی به اضافه ی امتیاز فریم قبلی خواهد بود.در صورتیکه در قاب یا فریم دهم strike اتفاق بیفتد ‌به بازی کننده اجازه داده میشود که دو پرتاب دیگر برای اتمام بازی انجام دهد و سپس امتیاز فریم آخر محاسبه خواهد شد.فریمی که درآن اسپیر ( افتادن همه پین ها در پرتاب دوم ) اتفاق افتاده به این صورت محاسبه میشود:تعداد پین های انداخته شده این فریم (که ۱۰ تا است) به اضافه ی تعداد پین های انداخته شده در یک پرتاب بعدی به اضافه ی امتیاز فریم قبلی خواهد بود.باز هم در صورتیکه در قاب یا فریم دهم spare اتفاق بیفتد ‌به بازی کننده اجازه داده میشود که یک پرتاب دیگر برای اتمام بازی انجام دهد.در واقع فریم آخر میتواند به جای دو پرتاب، سه پرتاب داشته باشد. در غیراینصورت از جمع امیتاز فریم قبلی  با تعداد پین های انداخته شده در این فریم امیتاز فریم حاضر بدست خواهد آمد.حالا یک مثال:در فریم اول با پرتاب اول فقط ۱ پین را انداخته و در پرتاب دوم ۴ پین را. پس امتیاز فریم از جمع تعداد پین های انداخته شد عدد ۵ میشود.در فریم دوم با پرتاب اول ۴ پین و در پرتاب دوم ۵ پین انداخته شده. پس جمع امیتاز فریم قبلی (۵) با تعداد پین های انداخته شده (۹) امتیاز این فریم را به  ۱۴ می رساند.در فریم سوم با پرتاب اول ۶ پین و در پرتاب دوم همه ی پین های باقی مانده(۴) انداخته میشود. در اینجا حالت spare رخ داده است. پس یک پرتاب دیگر برای محاسبه امتیاز این فریم نیاز داریم.در فریم چهارم با پرتاب اول ۵ پین را انداخته ایم. اجازه دهید ابتدا امتیاز فریم قبل را محاسبه کنیم.۱۰ عدد پین اندخته شده در فریم سوم با ۵ پین انداخته شده در فریم (چهارم) بعلاوه ی امتیاز فریم قبلی ( فریم دوم - ۱۴) جمع امتیاز فریم سوم را به ۲۹ میرساند. در پرتاب دوم از فریم ۴ همه پین ها انداخته میشود. پس برای محسابه امتیاز این فریم باز هم منتظر یک پرتاب دیگر خواهیم بود.در فریم پنجم حالت strike رخ داده است. ابتدا محاسبه فریم چهارم:۱۰ پین انداخته شده در پرتاب اضافه + ۱۰ پین انداخته شده در فریم چهارم + امتیاز فریم سوم = ۴۹و برای محاسبه امتیاز فریم پنجم به دو پرتاب دیگر لازم داریمدر مجموع دو پرتاب فریم ششم کلا ۱ پین انداخته میشود و بعلاوه پین های انداخته شده در فریم پینج و امتیاز فریم چهارم، جمع امتیاز چهارم به ۶۰ میرسد.حالا باید بتونید بقیه فریم ها رو خودتون محاسبه کنید. من هم تصمیم دارم توی چند پست به روش test-frist این مثال رو به زبان های php یا پایتون کد بزنم...- این مثال خوب و پر چالش در کتاب  Agile Software Development آورده شده و در صورتیکه میخواهید خودتون رو محک بزنید میتونه واستون بسیار مفید باشه.</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Sat, 03 Aug 2019 17:16:18 +0430</pubDate>
            </item>
                    <item>
                <title>۵ لکه سیاه در رزومه برنامه نویسان</title>
                <link>https://virgool.io/@shayanadc/%DB%B4-%D9%84%DA%A9%D9%87-%D8%B3%DB%8C%D8%A7%D9%87-%D8%AF%D8%B1-%D8%B1%D8%B2%D9%88%D9%85%D9%87-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%86%D9%88%DB%8C%D8%B3%D8%A7%D9%86-fizhshwcys8s</link>
                <description>برای هر برنامه نویسی حتما پیش آمده که توسط شرکتی که برای انجام یک پروژه سراغ آنها آمده رد شده باشد. دلیل: منطبق نبودن دانش شخص با نیازمندیهای پیاده سازی پروژه - بدون در نظر گرفتن قدرت یادگیری و توانایی همگام شدن -. پس باید در آنچه که یاد میگیرید و همینطور آنطوری که خود را معرفی میکنید توجه کنید چرا که بسیاری از تکنولوژی ها -حتی شاید بدون هیچ دلیل درستی- شما را فاقد صلاحیت نشان دهد. بله کاملا ناعادلانه است اما: باید مراقب زبان اصلی خود که میخواهید در رزومه بر آن تکیه کنید، باشید. ممکن است این زبان از پس کارهای شما و بسیاری بربیاید و حتی یادگیری آن به سختی یا آسانی دیگر زبانها باشد اما توجه کنید تکیه بر  اغلب زبانهایی که برای توسعه Enterprise شناخته میشوند از جمله VB و .NET میتواند شما را یک برنامه نویس غیر حرفه ای جلوه دهد.توجه بیش از اندازه به یادگیری زبان و قید کردن همه آنها در رزومه میتواند نکته منفی برای شما باشد. زیرا شما را به عنوان فردی با عمق کم که با مفاهیم برنامه نویسی آشنایی ندارد نشان میدهد.جمع کردن مدارک و لایسنس ها هرچقدر هم که کار سختی باشد و نیاز به یادگیری اصولی برای پاس کردن امتحان مد نظر داشته باشد نکته منفی دیگری در رزومه شما خواهد بود.همچنین درج یک یا فقط دو زبان در رزومه میتواند شما را بعنوان شخصی با تجربه ناکافی و عدم توانایی در یادگیری تکنولوژی های جدید معرفی کند.اینکه خودتان را همه کاره و آشنا با همه جور تکنولوژی نشان دهید نه تنها کمکی نمیکند بلکه بسیار منفی خواهد بود زیرا باید برای فرصت های شغلی خود را متخصص آن حوزه نشان دهید. آوردن همه مواردی که شاید هم به درستی آنها را بدانید در رزومه شما رو بعنوان غیر متخصص نشان خواهد داد.</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Tue, 30 Jul 2019 16:26:14 +0430</pubDate>
            </item>
                    <item>
                <title>چطور مقدار رندوم رو تست کنیم؟</title>
                <link>https://virgool.io/@shayanadc/%DA%86%D8%B7%D9%88%D8%B1-%D9%85%D9%82%D8%AF%D8%A7%D8%B1-%D8%B1%D9%86%D8%AF%D9%88%D9%85-%D8%B1%D9%88-%D8%AA%D8%B3%D8%AA-%DA%A9%D9%86%DB%8C%D9%85-uawwzabpnjrh</link>
                <description>فرض کنید میخواهیم برای متدی تست بنویسیم که یک توکن از رشته ای ۶۰ کاراکتری را بصورت رندوم تولید میکند. عملکرد این تابع به این صورت خواهد بود:function random_string($length) {
    $key = &#039;&#039;;
    $keys = array_merge(range(0, 9), range(&#039;a&#039;, &#039;z&#039;));

    for ($i = 0; $i &lt; $length; $i++) {
        $key .= $keys[array_rand($keys)];
    }

    return $key;
}
حالا میخواهیم تستی بنویسیم که بعد از ساختن کاربر، مقدار توکن را تست کنیم تا مطمئن شویم از این متد استفاده میکند:$this-&gt;assertEquals(&#039;c6iZq87cWhZzV0AJK0XlVqYxCIPFkBoh&#039;, $user-&gt;token);برای این کار متدی استاتیک از کلاس توکن میسازیم:&lt;?php 
class Token {     
public static function random_string($length) {         
$key = &#039; &#039;;         
$keys = array_merge(range(0, 9), range(&#039;a&#039;, &#039;z&#039;));         
for ($i = 0; $i &lt; $length; $i++) {             
$key .= $keys[array_rand($keys)];         
}         
return $key;     
} }حالا باید متدی داشته باشیم تا بتوانیم در محیط تست رشته ای رندوم را شبیه سازی و به آن اینجکت کنیم. یعنی درتست به این متد بگوییم هرگاه صدا زده شدی مقدار مشخصی را برگردان تا بتوانیم همان را انتظار داشته باشیم:Token::setTest(&#039;c6iZq87cWhZzV0AJK0XlVqYxCIPFkBoh&#039;)
$user = User::create();
$this-&gt;assertEquals(&#039;c6iZq87cWhZzV0AJK0XlVqYxCIPFkBoh&#039;, $user-&gt;token);خب حالا کافیه کلاس Token را به اینصورت تکمیل کنیم:&lt;?php

class Token
{
    static $testToken =null;
    public static function generate(){
        return static::$testToken ?:static::random_string(32);
    }

    public static function setTest($string){
        static::$testToken = $string;
    }
    public static function random_string($length) {
        $key = &#039;&#039;;
        $keys = array_merge(range(0, 9), range(&#039;a&#039;, &#039;z&#039;));

        for ($i = 0; $i &lt; $length; $i++) {
            $key .= $keys[array_rand($keys)];
        }
        return $key;
    }
}
 متد generate دو کار انجام میدهد:رشته ای رندوم تولید میکند.اگر مقداری به عنوان ورودی داشت همان را برمیگرداند.پکیج Carbon در php از این روش برای اینجکت کردن زمان مورد انتطار استفاده میکند:$knownDate = Carbon::create(2001, 5, 21, 12);          
Carbon::setTestNow($knownDate);</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Thu, 25 Jul 2019 13:18:51 +0430</pubDate>
            </item>
                    <item>
                <title>تست کردن حالتهای مختلف اعتبارسنجی ورودی</title>
                <link>https://virgool.io/@shayanadc/%D8%AA%D8%B3%D8%AA-%DA%A9%D8%B1%D8%AF%D9%86-%D8%AD%D8%A7%D9%84%D8%AA%D9%87%D8%A7%DB%8C-%D9%85%D8%AE%D8%AA%D9%84%D9%81-%D8%A7%D8%B9%D8%AA%D8%A8%D8%A7%D8%B1%D8%B3%D9%86%D8%AC%DB%8C-%D9%88%D8%B1%D9%88%D8%AF%DB%8C-ga5twwno08uk</link>
                <description>برای اینکه از درست بودن ورودی کاربر مطمئن شوید باید در تست Enpoint ها برای حالات مختلف غلط بودن ورودی ها رو شبیه سازی کنید تا بتونید پیام خطای متناسب هر کدوم رو تست کنید.در پست قبل، از اینکه FormRequest ها در لاراول چقدر میتونند برای سهولت پیاده سازی Validation به ما کمک کنند توضیح دادم. برای تست انجام صحیح یک ریکوئست (happy path) میتونید ورودی ها رو کامل کنید و تست بگیرید:$this-&gt;post(&#039;/api/users&#039;, [
    &#039;email&#039; =&gt; &#039;test@example.com&#039;,
    &#039;password&#039; =&gt; &#039;12345678&#039;
    ])-&gt;assertJson(&#039;you have successfully registered for&#039;); اما برای تست کردن حالت های مختلف ورودی باید:$this-&gt;post(&#039;/api/users&#039;, [&#039;email&#039; =&gt; gmail.com])-&gt;assertJson(&#039;your email is not valid&#039;);و سپس تست دیگری برای فیلد دوم با خطای مشخص آن:$this-&gt;post(&#039;/api/users&#039;, [&#039;password&#039; =&gt; gmail.com])-&gt;assertJson(&#039;password must be at least 8 character&#039;);و علاوه بر حالات دیگر، باید ترکیب این خطاها نیز تست شود که بسیار وقت گیر و غیرقابل کنترل خواهد بود.اما راه حل بهتر اینه که شما بجای تست Endpoint خود FormRequest رو تست کنید برای این کار یه تست مخصوص اون فرم ایجاد کنید:class StoreUserTest extends TestCase {     
private $subject;      
protected function setUp(): void {         
parent::setUp();          
$this-&gt;subject = new StoreUserRequest();     
}      
public function testRules() {         
$this-&gt;assertEquals([                 
    &#039;name&#039; =&gt; &#039;required&#039;,                 
    &#039;email&#039; =&gt; &#039;required|email&#039;            
    ],             
    $this-&gt;subject-&gt;rules()         
    ); } 
    public function testAuthorize() {         
    $this-&gt;assertTrue($this-&gt;subject-&gt;authorize());     
    } }حالا شما برای پاس کردن این تست فقط کافیه تا FormRequest ای شبیه با قوانین این تست بسازید. و هر در پیاده سازی تغییری ایجاد شد کافیه تا تست ها رو تغییر بدهید.</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Tue, 23 Jul 2019 14:24:05 +0430</pubDate>
            </item>
                    <item>
                <title>تکرار مکررات در اعتبار سنجی (Form Validation) ورودی ها در JsonApi</title>
                <link>https://virgool.io/apieco/%D8%AA%DA%A9%D8%B1%D8%A7%D8%B1-%D9%85%DA%A9%D8%B1%D8%B1%D8%A7%D8%AA-%D8%AF%D8%B1-%D8%A7%D8%B9%D8%AA%D8%A8%D8%A7%D8%B1-%D8%B3%D9%86%D8%AC%DB%8C-form-validation-%D9%88%D8%B1%D9%88%D8%AF%DB%8C-%D9%87%D8%A7-%D8%AF%D8%B1-jsonapi-d82zp1qrajse</link>
                <description>یکی از کارهای تکراری در نوشتن Api، اعتبار سنجی ورودی ها ست که به ازای هر Endpoint و به وسعت کل ورودی های مورد نظر باید انجام بشه. فریمورک لاراول برای این کنترل وروردی ها راه حل ساده و مختصری داره که این امکان این کار رو به اینصورت به شما میدهد:$validatedData = $request-&gt;validate([
        &#039;title&#039; =&gt; &#039;required|unique:posts|max:255&#039;,
        &#039;body&#039; =&gt; &#039;required&#039;,
    ]);
    داکیومنت خود لاراول کامل چگونگی استفاده رو نشون داده اما مشکل اینجاست که برای برگردوندن پیام مناسب برای هر endpoint باید در هر کنترلر exception اعتبار سنجی رو که از نوع ValidationException هست رو catch کنیم و خروجی مناسب را برگردانیم(انجام یک کار تکراری)راه حل: از اونجایی که استاندار json api به ما میگوید که باید برای خطاهای از یک نوع مشابه در همه endpoint ها باید پیام یکسانی نمایش بدهیم، میتوانیم همه نوع خطای از این دست را قبل از رسیدن به کنترلر - و قبل از اینکه مجبور باشیم در هر Endpoint بطور مجزا catch کنیم - یکجا سازماندهی کنیم و خروجی رو بسازیم.برای اینکار ابتدا در دایرکتوری app/Http/Requests/Traits یک فایل بسازید با نام UsesCustomErrorMessage.php&lt;?php

namespace App\Http\Requests\Traits;

use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;

trait UsesCustomErrorMessage
{
    protected function failedValidation(Validator $validator)
    {
        throw new HttpResponseException(response()-&gt;json([ &#039;errors&#039; =&gt; $validator-&gt;errors(), &#039;message&#039; =&gt; $message, ], 422));
    }
}این trait رو باید طوری بنویسید که مشابه signature اصلی اون باشه تا بجای متد اصلی خونده بشه حالا همینطور میتونید برای اینکه پیام ها و اینکه مربوط به کدوم فیلد میشوند رو از:$validator-&gt;getMessageBag()-&gt;getMessages(); دریافت کنید و حالا برای استفاده از این trait میتونید اون رو در هر FormRequest ای استفاده کنید:php artisan make:request StoreUserAccountو در این فایل از trait استفاده کنید تا خطاهای ValidationException قبل از رسیدن به کنترلر برگردانده شوند:&lt;?php

namespace App\Http\Requests;

use App\Http\Requests\Traits\UsesCustomErrorMessage;
use Illuminate\Foundation\Http\FormRequest;

class StoreUserAccount extends FormRequest
{
    use UsesCustomErrorMessage;

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            &#039;username&#039; =&gt; &#039;required&#039;,
            &#039;email&#039; =&gt; &#039;required&#039;,
            &#039;password&#039; =&gt; &#039;required|confirmed&#039;,
        ];
    }اما با اینکه مشکل تکرار گرفتن خطای ورودی رو حل کردیم اما هنوز باید برای هر کدام از کنترلرهامون تست اعتبارسنجی بنویسیم که این کار هم تکراری و وقت گیر خواهد بود...</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Sun, 21 Jul 2019 12:44:47 +0430</pubDate>
            </item>
                    <item>
                <title>چگونه آپلود شدن فایل ها رو تست کنیم؟</title>
                <link>https://virgool.io/@shayanadc/%DA%86%DA%AF%D9%88%D9%86%D9%87-%D8%A2%D9%BE%D9%84%D9%88%D8%AF-%D8%B4%D8%AF%D9%86-%D9%81%D8%A7%DB%8C%D9%84-%D9%87%D8%A7-%D8%B1%D9%88-%D8%AA%D8%B3%D8%AA-%DA%A9%D9%86%DB%8C%D9%85-rhr2dcjcli7f</link>
                <description>بیشتر چالش های تست نویسی وقتی اتفاق می‌افتند که میخواهیم چیزی خارج از سیستم را تست کنیم. در اینجا میخوام نحوه تست نویسی برای دریافت فایل ها رو در لاراول بررسی کنم.مثل همیشه سناریو کلی برای اپلود فایل در نظر میگیریم. ابتدا اینکه باید بدونیم از چه سیستمی برای ذخیره کردن فایل ها میخواهیم استفاده کنیم تا بتونیم توی تست اون رو شبیه سازی کنیم. برای این موضوع میتونید به کانفیگ لاراول ( config/filesystems.php) نگاهی بندازید:‘default’ =&gt; env(‘FILESYSTEM_DEFAULT’, ‘local’)حالا نوبت اون رسیده که درایور مورد نظر رو Mock کنید تا در تست بطور واقعی به سراغش نریم:Storage::fake(&#039;profile-pictures&#039;);سپس به درایور مورد نظرتون یک فایل نمونه با حجم و اندازه و اسم مورد نظرتون معرفی کنید تا در محیط تست یکی از اون بسازه:UploadedFile::fake()-&gt;image(&#039;avatar.jpg&#039;, $width, $height)-&gt;size(100)بدیهی است که میتونید در اینجا فرمت و اندازه فایل مورد نظر رو هم مورد تست قرار بدید. البته برای ساختن فایل از هر نوع دیگری همچنین میتونید:UploadedFile::fake()-&gt;create(&#039;document.pdf&#039;, $sizeInKilobytes);و در آخر باید انتظار داشته باشید تا این فایل رو در درایور مورد نظرتون دریافت کنید:Storage::disk(&#039;profile-pictures&#039;)-&gt;assertExists(&#039;avatar.jpg&#039;);بنظر میاد حالا بتونید از همه اینها برای تست یک کنترلر که گرفتن فایل از Request رو بر عهده داره استفاده کنید:class FileUploadTest extends TestCase {     
public function it_expect_file_in_storge_after_send_as_a_json_request() {         
Storage::fake(&#039;profile-pictures&#039;);          
$response = $this-&gt;json(&#039;POST&#039;,  &#039;/images&#039;, [             
    &#039;imagefile&#039; =&gt; UploadedFile::fake()-&gt;image(&#039;avatar.jpg&#039;)         
    ]); 
 Storage::disk(&#039;profile-pictures&#039;)-&gt;assertExists(&#039;avatar.jpg&#039;);
  } }همینطور میتونید نبودن یک فایل رو در موقع پاک کردن اون از storage تست کنید:Storage::disk(&#039;profile-pictures&#039;)-&gt;assertMissing(&#039;missing.jpg&#039;);برای گرفتن فایل از Request لاراول به شما این امکان رو میده تا اسم فایل فرستاده شده رو داشته باشید:$request-&gt;file&#40;&#039;imagefile&#039;&#41;-&gt;name;و همینطور محتویات اون رو داشته باشید:$request-&gt;file&#40;&#039;imagefile&#039;&#41;;اون رو در درایور مورد نظرتون (که طبعا متناسب با تستی که نوشتید خواهد بود) ذخیره کنید:Storage::disk(&#039;profile-pictures&#039;)-&gt;put($yourImageName, $profileImageContents);و موقعی که میخواهید آدرس مستقیم فایل مورد نظرتون رو در api برگردونید میتونید از این متد استفاده کنید:asset(&#039;storage/profile-pictures&#039; . $imageName)</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Sat, 20 Jul 2019 17:43:05 +0430</pubDate>
            </item>
                    <item>
                <title>تنظیمات gitignore یکبار برای همیشه</title>
                <link>https://virgool.io/@shayanadc/%D8%AA%D9%86%D8%B8%DB%8C%D9%85%D8%A7%D8%AA-gitignore-%DB%8C%DA%A9%D8%A8%D8%A7%D8%B1-%D8%A8%D8%B1%D8%A7%DB%8C-%D9%87%D9%85%DB%8C%D8%B4%D9%87-pnukgzxivzfm</link>
                <description>باید در استفاده از گیت این موضوع رو در نظر داشته باشید که بعضی فایلهای مربوط به سیستم خودتون یا IDE، که مربوط به توسعه نمیشه رو کامیت (commit) نکنید یا به اصطلاح خود گیت بگذارید untracked بمونه. برای اینکار میشه اسم فایل ها و یا دایرکتوری مورد نظرتون  رو به فایل gitignore پروژه اضافه کنید.به اینصورت:فقط برای نوشتن این فایل توجه کنید که هر خط مربوط به یک فایل یا دایرکتوری میتونه باشه و اینکه از الگوها نیز میشه استفاده کرد که پر کاربردترین اونها * (به معنی هر چیزی) هست. برای دونستن بیشتر این الگوها میتونید به اینجا  نگاهی بندازید.البته برای این که این فایل های مزاحم رو بر اساس ابزاراهایی که استفاده میکنید بطور خودکار پیدا کنید میتونید به سایت http://gitignore.io/ بروید و اسم ادیتور یا فریمورک مورد استفاده تون رو وارد کنید تا بصورت یکجا فایل gitignore رو برای شما اماده کنه.اما برای اینکه بصورت متعدد مجبور به اضافه کردن چندین باره ی اینگونه فایل ها  (به خصوص فایلهای که توسط IDE اضافه میشه) به gitignore تمام پروژه ها نباشید، گیت به شما این امکان رو میده تا بصورت سراسری و اتوماتیک در کل پروژه هایی که بر روی سیستم خودتون دارید این نوع از فایلها اضافه نشوند. برای این کار ابتدا یک فایل با ادرس و اسم دلخواه باز کنید:touch ~/.gitignore_global و فایلهایی که نمیخواهید رو توی اون اضافه کنید:.ideaحالا کافیه به گیت بگید که همیشه در تنظیماتش این فایل رو در نظر بگیره:git config --global core.excludesfile ~/.gitignore_globalاز این به بعد هر جا که از گیت استفاده میکنید این تنظیمات هم در نظر گرفته میشه.</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Wed, 17 Jul 2019 13:14:01 +0430</pubDate>
            </item>
                    <item>
                <title>تست کردن چیزی که قابل تست نیست با استفاده از Mock در Python</title>
                <link>https://virgool.io/@shayanadc/%D8%AA%D8%B3%D8%AA-%DA%A9%D8%B1%D8%AF%D9%86-%DA%86%DB%8C%D8%B2%DB%8C-%DA%A9%D9%87-%D9%82%D8%A7%D8%A8%D9%84-%D8%AA%D8%B3%D8%AA-%D9%86%DB%8C%D8%B3%D8%AA-%D8%A8%D8%A7-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-mock-%D8%AF%D8%B1-python-n70x26fbel4b</link>
                <description>در هر برنامه ممکن است قسمتهایی وجود داشته باشند که برای عملکرد خود به API بیرونی نیاز دارند. مثلا فرض کنید قسمتی از برنامه به بات تلگرام وصل شده و پیامی را میفرستد، شما نباید این API را در تست خود داشته باشید زیرا هر بار که تست خود را اجرا میکنید اولا نیاز به اینترنت دارید و همچنین باید مقدار زمانی که طول میکشد تا سرور تلگرام جواب شما را بدهد برای پاس شدن تست معطل بمانید که هر دوی اینها منطقی نیست.برای اینکار کتابخانه Mock در پایتون به شما امکان میدهد تا با استفاده  از آن رفتار شی ای دیگر را شبیه سازی کنید. برای استفاده از این کتابخانه آنرا بوسیله pip install mock نصب کنید. حال با چیزی شبیه ‍‍Python Shell یا ‍‍‍‍‍ipython دستور زیر را راجرا کنید تا کمی بیشتر با عملکرد آن آشنا شوید.from unittest import mock
m = mock.Mock()تا اینجا یک نمونه از Mock ساختیم و برای اینکه بدانیم این شی چه امکاناتی به ما میدهد:dir(m)و خروجی کل attribute های این شی است:[&#039;assert_any_call&#039;, &#039;assert_called_once_with&#039;, &#039;assert_called_with&#039;, &#039;assert_has_calls&#039;, &#039;attach_mock&#039;, &#039;call_args&#039;, &#039;call_args_list&#039;, &#039;call_count&#039;, &#039;called&#039;, &#039;configure_mock&#039;, &#039;method_calls&#039;, &#039;mock_add_spec&#039;, &#039;mock_calls&#039;, &#039;reset_mock&#039;, &#039;return_value&#039;, &#039;side_effect&#039;]ولی امکان جالب و دور از انتظار این است که شما میتوانید از attribute  هایی که برای این شی تعریف نشده هم استفاده کنید و خروجی همان قبلی خواهد بود:dir(m.some_attribute)عموما برای تست ها میخواهیم بدانیم متد مورد نظر صدا زده میشود(call) یا خیر. مثلا همینکه بدانیم کلاس Telegram متدی به نام Send دارد و آن نیز در اینجا صدا زده شده کافی است. برای اینکار از خاصیت assert_called_with  میتوانید استفاده کنید. اما برای شروع میتوانیم تستی بنویسیم که متد مورد نظر یک خروجی شبیه چیزی که تلگرام به ما میدهد را برگرداند.from unittest import TestCase
from unittest.mock import Mock
​
​
class TestTelegram(TestCase):
    def test_send_telegram_message(self):
        MockTelegram = Mock()
        MockTelegram.send.return_value = [
            {
                &#039;id&#039;: 100121,
                &#039;text&#039;: &#039;Test Title&#039;
            }
        ]
        response = MockTelegram.send()
        self.assertIsNotNone(response)
        self.assertIsInstance(response[0], dict)تا اینجا متدی از تلگرام که حتی آنرا ننوشته ایم را تست میکنیم که متد send آن دارای خروجی شبیه  return_value است. شما احتمالا میخواهید بدانید اگر سرور تلگرام در واقعیت جواب نمیداد و سیستم ما به آن دسترسی نداشت را چگونه تست کنیم. برای این کار از side_effect استفاده کنید.from unittest import TestCase
from unittest.mock import Mock
​
class TestTelegram(TestCase):
    def test_does_not_send_telegram_message(self):
        MockBlog = Mock()
        MockBlog.send.side_effect = Exception(&#039;Telegram Unreachable&#039;)
        with self.assertRaises(Exception):
            MockBlog.send()در این تست در واقع میخواهیم منتظر باشیم تا اگر تلگرام پاسخ نداد متد ‍‍‍send اکسپشن بدهد.</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Mon, 18 Feb 2019 14:31:02 +0330</pubDate>
            </item>
                    <item>
                <title>حل یک مسئله نسبتا پیچیده با php</title>
                <link>https://virgool.io/@shayanadc/%D8%AD%D9%84-%DB%8C%DA%A9-%D9%85%D8%B3%D8%A6%D9%84%D9%87-%D9%86%D8%B3%D8%A8%D8%AA%D8%A7-%D9%BE%DB%8C%DA%86%DB%8C%D8%AF%D9%87-%D8%A8%D8%A7-php-scwjxu6hbeag</link>
                <description>میخواهیم یک برای یک نیازمندی سیستم برنامه ای بهمراه تست به زبان php بنویسیم. این مسئله به این صورت است که در یک دفتر کل شبیه دفاتر حسابداری، بدهکاری یا بستانکاری افراد به همدیگر نوشته میشود. به این شکل هر تراکنش کمی بدون ساختار و بصورت ساده به شکل زیر ثبت در این سیستم میشود:صدرا به شایان مبلغ ۱۱۰۰۰ تومان بدهکار است.شایان به صدرا مبلغ  ۵۰۰۰تومان بدهکار است.رضا به مهسا مبلغ ۲۰۰۰تومان بدهکار است.مهسا از فرامرز مبلغ ۸۰۰۰تومان طلبکار است.حالا میخواهیم برای این ردیف های اطلاعات، حساب نهایی افراد که برای همه تراکنش هایشان مقدار یک مقدار بدهکار/طلبکار مشخص است را محاسبه کنیم.ابتدا برای درک بیشتر مسئله، آنرا روی کاغذ حل میکنیم. پرسش اینجاست که چطور باید کل مبالغ برای هر نفر محاسبه کرد. خب واضح است که هر جا بطور مثال نام شایان را دیدیم باید به مبلغ را محاسبه کنیم. حال اگر طلبکار بود به حساب کل او اضافه و اگر بدهکار بود از مبلغ کم میکنیم. در نهایت باید داشته باشیم:صدرا مبلغ ۶۰۰۰تومان طلبکار است.شایان مبلغ ۶۰۰۰تومان بدهکار است.مهسا مبلغ ۱۰۰۰۰تومان طلبکار است.فرامرز مبلغ ۲۰۰۰تومان بدهکار است.رضا مبلغ ۸۰۰۰تومان بدهکار است.حال این اطلاعات را به داده های قابل تفسیر تبدیل میکنیم:خب برای اینکار ابتدا با استفاده ‍‍‍data proivder یک تست مینویسیم تا چند حالت مختلف را تست کنیم و مطمئن شویم کد برای همه حالات جواب درست میدهد. ابتدا نیاز داریم ‍data proivder را برای حالتهای مختلف بسنجیم.public function calcProvider()
    {
        $case = [
            [&#039;creditor&#039; =&gt; &#039;A&#039;, &#039;owe&#039; =&gt; &#039;B&#039;, &#039;amount&#039; =&gt; 1000],
            [&#039;creditor&#039; =&gt; &#039;A&#039;, &#039;owe&#039; =&gt; &#039;B&#039;, &#039;amount&#039; =&gt; 4000],
​
            [&#039;creditor&#039; =&gt; &#039;F&#039;, &#039;owe&#039; =&gt; &#039;E&#039;, &#039;amount&#039; =&gt; 2000],
​
            [&#039;creditor&#039; =&gt; &#039;D&#039;, &#039;owe&#039; =&gt; &#039;C&#039;, &#039;amount&#039; =&gt; 2000],
            [&#039;creditor&#039; =&gt; &#039;C&#039;, &#039;owe&#039; =&gt; &#039;D&#039;, &#039;amount&#039; =&gt; 1000]
        ];
        $result= [
            [&#039;creditor&#039; =&gt; &#039;A&#039;, &#039;owe&#039; =&gt; &#039;B&#039;, &#039;amount&#039; =&gt; 5000],
​
            [&#039;creditor&#039; =&gt; &#039;F&#039;, &#039;owe&#039; =&gt; &#039;E&#039;, &#039;amount&#039; =&gt; 2000],
​
            [&#039;creditor&#039; =&gt; &#039;D&#039;, &#039;owe&#039; =&gt; &#039;C&#039;, &#039;amount&#039; =&gt; 1000]
        ];
        return [
            [$case, $result]
        ];
    }حال باید تستی بنویسیم تا از متد ‍‍‍‍‍‍‍calcProvider استفاده کند. توجه کنید استفاده از data provider به ما امکان میدهد تا بجای نوشتن چند تست برای حالات مختلف یک تست بنویسیم و برای حالت های مختلف ورودی، خروجی مورد نظر را انتظار داشته باشیم. و حالا تستی که از این ‍‍data provider استفاده کند:   /**
     * @test
     * @dataProvider calcProvider
     */
    public function it_calculates_members_status_in_ledger($arrays, $expected)
    {
        $ledgerFactory = new LedgerFactory();
        $calcArray = $ledgerFactory-&gt;calcStatus($arrays);
        $this-&gt;assertEquals($expected, $calcArray);
    }همانطور که قابل مشاهده است ما برای تست، ورودی و خروجی مشخصی معین نکردیم و حالتهای مختلف آنرا به data provider واگذار کردیم. و انتظار داریم برای همه ورودی های داده شده خروجی های متناظر مورد انتظار را تولید کند.حال برای پاس کردن تست نیاز به قابل برنامه نویسی کردن آنچه در بالا بعنوان درک مسئله گفتیم داریم. اولین چیزی که واضح است این است که نیاز داریم تا بدانیم مبلغ هر سطر برای یک کاربر باید با کل حساب او جمع شود (طلبکار) یا از آن کم (بدهکار) شود. برای این کار نیاز به یک مرتب سازی آرایه ورودی داریم. به طوری که یک بار آرایه را دور بزنیم و بدهکاری را به مبلغی منفی تغییر دهیم و سپس همه را باهم جمع کنیم. منطق این کار برای هر سطر را ابتدا به کد تبدیل میکنیم(مرحله به مرحله و ابتدا حل کردن کوچک ترین مسئله):public function sort($item)
    {
        return $item[&#039;creditor&#039;] &gt; $item[&#039;owe&#039;] ?
            [&#039;creditor&#039; =&gt; $item[&#039;owe&#039;], &#039;owe&#039; =&gt; $item[&#039;creditor&#039;], &#039;amount&#039; =&gt; $item[&#039;amount&#039;] * -1] : $item;
    }با استفاده از کد بالا برای بعضی از مقادیر که شرط درست باشد مقدار را منفی میکنیم ولی باید اینکار را برای کل آرایه ها در نظر گرفت. در واقع باید کل آرایه را یکبار دور بزنیم و مقادیر را بعد از اعمال تابعی که اسم آنرا sort گذاشتیم جایگزین کنیم تا آرایه جدید مرتب شده داشته باشیم. برای این کار بر روی آرایه ها در php متد خوب array_map را داریم. پس:array_map([$this, &#039;sort&#039;], $arrays);حال که مقادیر بدهکار یا طلبکار برای هر ردیف را مشخص کردیم باید حساب هر شخص را که به همدیگر هم بدهکار و طلبکار باشند را به یک سطر جمع زده شده تبدیل کنیم. به ردیف ۴و۵ جدول دقت کنید. باید این قسمت را حل کنیم. برای این کار array_reduce بکار می اید که آرایه مرتب شده را یکبار دور بزنیم و هر جا دوسطر شبیه ۴و۵ دیدیم به یک سطر کاهش دهیم.addition متدی است یک آرایه خالی را به همراه یک ردیف مشخص دریافت کند. آنرا علامت گذاری کند و توی یک آرایه خالی carry بگذارد.   public function addition($carry, $item)
    {
        $key = $item[&#039;creditor&#039;] . &#039;-&#039; . $item[&#039;owe&#039;];
        if (isset($carry[$key])) {
            $carry[$key][&#039;amount&#039;] += $item[&#039;amount&#039;];
        } else {
            $carry[$key] = $item;
        }
        return $carry;
    }سپس این آرایه را با استفاده از array_reduce دور بزنیم و هر جا شرط برقرار بود آنرا با مقدار جدید جابجا کنیم. تا اینجا خروجی چیزی شبیه این خواهد بود:   public function calcStatus($arrays)
    {
        $sortArray = array_map([$this, &#039;sort&#039;], $arrays);
        $additionArray = array_reduce($sortArray, [$this, &#039;addition&#039;], []);    
    }array:3 [
  &quot;A-B&quot; =&gt; array:3 [
    &quot;creditor&quot; =&gt; &quot;A&quot;
    &quot;owe&quot; =&gt; &quot;B&quot;
    &quot;amount&quot; =&gt; 50000
  ]
  &quot;E-F&quot; =&gt; array:3 [
    &quot;creditor&quot; =&gt; &quot;E&quot;
    &quot;owe&quot; =&gt; &quot;F&quot;
    &quot;amount&quot; =&gt; -20000
  ]
  &quot;C-D&quot; =&gt; array:3 [
    &quot;creditor&quot; =&gt; &quot;C&quot;
    &quot;owe&quot; =&gt; &quot;D&quot;
    &quot;amount&quot; =&gt; -10000
  ]
]تنها کاری که مانده است این است که از آنجایی که ما نمیخواهیم مقدار منفی به کاربر نشان دهیم این مورد را در آرایه اصلاح کنیم. مثل قبل ابتدا برای هر سطر:public function reverse($item)
    {
        if ($item[&#039;amount&#039;] &lt; 0) {
            return [&#039;creditor&#039; =&gt; $item[&#039;owe&#039;], &#039;owe&#039; =&gt; $item[&#039;creditor&#039;], &#039;amount&#039; =&gt; $item[&#039;amount&#039;] * -1];
        } else {
            return $item;
        }
    }و نهایتا:   public function calcStatus($arrays)
    {
        $sortArray = array_map([$this, &#039;sort&#039;], $arrays);
        $additionArray = array_reduce($sortArray, [$this, &#039;addition&#039;], []);
        $calc = array_values(array_map([$this, &#039;reverse&#039;], $additionArray));
        return $calc;
        }</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Sun, 17 Feb 2019 16:12:16 +0330</pubDate>
            </item>
                    <item>
                <title>خود ره بگویدت که چون باید رفت</title>
                <link>https://virgool.io/coderlife/%D8%AE%D9%88%D8%AF-%D8%B1%D9%87-%D8%A8%DA%AF%D9%88%DB%8C%D8%AF%D8%AA-%DA%A9%D9%87-%DA%86%D9%88%D9%86-%D8%A8%D8%A7%DB%8C%D8%AF-%D8%B1%D9%81%D8%AA-nivpx2oejgjd</link>
                <description>در دنیایی که تنها اصل ثابت تغییر است، برای اینکه نرم افزار شما همان چیزی باشد که از آن انتظار دارید تست نویسی تنها راه است. البته همیشه این نگرانی برای تیم های توسعه وجود دارد که تست نویسی موجب کند شدن روند تولید نرم افزار بشود و البته علاوه بر نیاز به مهارت های تست نویسی، پیچیدگی ها خود را نیز به سیستم اضافه میکند. اما کافیست با چگونگی تست نویسی آشنا شوید تا نه تنها برای نگرانی خود پاسخی بیابید بلکه دیگر حتی یک پروژه کوچک را هم بدون تست توسعه ندهید چرا که یافتن خطاهای سیستم نرم افزاری در مرحله توسعه و قبل از تبدیل به محصولی در دستان مشتری بسیار موثرتر و هزینه را کمتر خواهد کرد.تست نویسی پس از طراحی سیستم اتفاق می افتد، جایی که نیاز مندیهایی سیستم مشخص شده اند و تیم توسعه میخواهد به سراغ پیاده سازی برود. در این مرحله با استفاده از نیازمندیهای سیستم تست ها را طراحی میکنیم.تست نویسی ( چه UnitTest و چه تستهای مشتری ) بعد از پایان محصول و برای کدهایی که قابلیت تست را نداشته باشد کار سختی است، زمانیکه ابتدا سیستم را پیش از توسعه با تست نویسی شروع میکنیم (یعنی تست نویسی برای سیستمی که هنوز وجود ندارد)، تا انتها تمام کدهای شما (Production Code) بصورت سلسله مراتبی با قابل تست نوشته خواهند شد.قابل تست بودن هر قسمت کوچک از سیستم باعث میشود کدهای شما بسیار مینیمال شوند و در نتیجه تکه های کدی که به هم وابستگی دارند بیشتر قابل شناسایی هستند چرا که با اجرای تست یک قسمت، قسمتی دیگر از تستها fail میشود که این وابستگی را نمایان میکند و میتوان قبل از پیچیده شدن وابستگی درون سیستم چاره ای برای آن اندیشید. بعلاوه احتمالا در طراحی سیستم نقص هایی وجود دارد که در توسعه سیستم همراه با تست این نقایص بروز میکنند چرا که روابط بین اشیا بهتر و بصورت عملی قبل از شروع کدنویسی دیده میشوند.ابتدا باید بدانید چه چیزی را میخواهید تست کنید؟ (سناریوی تست) بعنوان مثال «تست عملکرد لاگین به سایت». سپس چگونگی تست را مشخص میکند. که معمولا نسبت به یک سناریو چندین مورد تست (Test Case) یا چگونگی داریم. بعنوان مثال «کاربر نام کاربری و رمز عبور خود را صحیح وارد می‌کند»، «کاربر رمز عبور خود را صحیح وارد نمی‌کند» و...برای هر مورد تست (Test Case) باید مراحلی سپری شود که از انجام آنها باهم عملکرد یک قسمت از سناریو کامل میشود. بطور مثال‌ : ۱. وارد کردن نام کاربری ۲. وارد کردن رمز عبور ۳. زدن دکمه ورودعموما تست ها برای انجام نیاز به داده های ورودی دارند که این ورودی ها در سیستم بر اساس شرایطی بوجود می آیند که پیش شرط های تست هستند. بطور مثال میتوان گفت «کاربر برای ورود به سیستم باید از قبل در سیستم ثبت شده باشد» پس باید برای تست ورود کاربر شرایط را در حالتی که کاربر ثبت نام کرده در نظر میگیریم. یعنی در نظر میگیرم اطلاعاتی که کاربر از آن بعنوان نام کاربری و رمز عبور وارد خواهد کرد باید در دیتابیس وجود داشته باشد.هر مورد تست باید با داده های مختلف تست شود تا احتمالا رفتار غیر قابل پیش بینی سیستم نیز کشف شود. به طور مثال به نام کاربری «chandler» نیاز داریم و رمز عبور «chandlerpassword123»در نهایت باید حتما از عملکرد تست چیزی را بعنوان نتیجه انتظار داشته باشیم. بطور مثال «ورود به صفحه اصلی» و یا «نمایش پیام خوش آمدگویی»بوضوح میتوانیم ببینیم که برای تست هر عملکرد سیستم به بازبینی نیازمندیهای سیستم و در نظر گرفتن روابط بین اجزای درون سیستم با همدیگر است.ولی سودای نوشتن یک جای تمام تست های سیستم را فراموش کنید. در واقع بهتر است از توسعه افزایش تست استفاده کنیم « یکم تست نویسی یکم کد نویسی ». اینگونه تمرکز ما بر روی یک تست مردود شده (Failed) خواهد بود.اما در مورد پیچیدگی های فنی، باید شرایطی که تیم تست نویسی را از تیم توسعه جدا تصور کنیم بطوریکه کد تست را از روی یک دیوار بلند به سمت توسعه دهندگان بیاندازند و منتظر پاس کردن آن ها شویم را باید فراموش کنید. در واقع توسعه دهندگان و تست نویسان با همکاری همدیگر سیستم را پیش میبرند.اما تست نوشتن برای هر عملکرد از سیستم بهره وری را کاهش خواهد داد زیرا ما در واقع داریم یک پروژه سایه برای تست که به اندازه بزرگی پروژه اصلی است را تولید میکنیم و این توسعه را بسیار کند میکند. شما باید بدانید که این تست نیست که برای شما معجزه میکند در واقع این روش شما است که معجزه میکند.ما میتوانیم با استفاده از ترکیبی از TDD و BDD همه سیستم را تست کنیم اما نباید با هر کدام از این روشها کل سیستم را تست کنیم. زیرا که هر کدام کارایی خود را دارند. بطور کلی BDD رفتار کاربر و چگونگی انجام سیستم را براساس سناریوی مشتری بررسی میکند اما TDD از اینکه چه چیزی را چه وقت تست کنید حرف میزند. تست های رفتاری BDD  میتواند در انتهای کار ضمانت انجام فرایندهای کلیدی سیستم را برعهده گیرد. اما چیزی که حجم زیادی از تست های شما را دربرمیگیرد و ممکن است موجب دردسر شود unit test ها هستند.اگر میخواهید همه چیز را تست نکنید و حجم تست های unit خود را کم کنید پس بصورت رویه ای کد نزنید تا مجبور نباشید پیوستگی های خارج از کنترل را به اجبار تست کنید. راه حل در دستان روش شی گرا است چرا که رفتار سیستم توسط کلاس ها از هم جدا میشوند. در طراحی شی گرا، سیستم بر اساس پیام هایی که بین کلاس ها فرستاده میشود کار میکند. هر شی سه نوع پیام را تبادل میکند : پیام های ورودی، پیام های درونی (جهت کار کردن اجزای درونی سیستم با همدیگر)، و پیام های خروجی(پیامد)براساس گفته ی sandi metzِ، بطور کلی میتوانیم پیام های بین کلاس ها را بر اساس عملکرد به دو نوع استاندار طراحی کنیم:Query: مقداری را برمیگردانند اما چیزی را نباید تغییر دهند.Command: مقداری را تغییر میدهند اما نباید چیزی را تغییر دهند.البته بعضی از اوقات رعایت این تقسیم بندی ممکن نیست. بطور مثال عملکرد صف را در نظر بگیرید. عمل Pop باعث برگرداندن آخرین مقدار است و همچنین عمل تغییر صف به حالت جدید و با یک مقدار کمتر است. این حالات که هم query  وهم command است را استثنا در نظر میگیریم. حال ما میتوانیم بر اساس نوع پیام ها جدول زیر را داشته باشیم.ابتدا سراغ پیام های ورودی از نوع query میرویم، در این نوع کلاس ها آنچیزی که باید برگردانده شود را با استفاده از assertion تست میکنیم. در اینجا نکته این است که باید آنچیزی که از بیرون کلاس میبینم را تست کنیم و از تست کردن نحوه پیاده سازی آن بپرهیزیم.در کلاس wheel برای محاسبه قطر متد diameter را داریم:class wheel
  attr_reader :rim,:tire
  def initialize(rim,tire)
  end
  def diameter
    rim + (tire *2)
  end
end
و تست:class WheelTest &lt; MiniTest::Unit::TestCase
  def test_calc_diameter
    wheel = wheel.new(26,1.5)
    assert_in_delta(29,wheel.diameter,0.01)
  end
end
حال سراغ پیام های ورودی از نوع command میرویم، در این نوع پیام ها که مقداری تغییر میکند باید با استفاده از assertion عوارض جانبی ای که بصورت عمومی کل سیستم از آن میتوانند مطلع باشند اما الزاما فقط همین کلاس باید نسبت به آن مسئول باشد را تست کرد.Set_cog محاسبه ای را با استفاده از پیام ورودی انجام میدهد class Gear
  attr_reader :chairing,:cog,:wheel
  def initialize(args)
  end
  def set_cog(new_cog)
    @cog = new_cog
  end
end
  
class GearTest &lt; MiniTest::Unit::TestCase
  def test_set_cog
    gear = Gear.new
    gear.set_cog(27)
    assert(27,gear.cog)
  end
end
حال به سراغ پیام های کلاس به خود میرویم. جایی که شاید بصورت عموما متدهای Private تعریف میکنیم. این متدها به خود کلاس و در متدی دیگر صدا زده میشوند و به آنها پاسخگو هستند و نه به دنیای بیرون از کلاس پس چه از نوع query و چه از نوع  command تست کردن انها را کنار بگذارید.البته اگر هم کسی این قسمت ها را تست کند اشکالی به کار او وارد نیست ولی او فقط حجم کار خود را زیاد کرده است.برای پیام ها خروجی از نوع query در نظر داشته باشید که احتمالا این نوع پیام ها احتمالا ورودی پیام دیگری هستند که باید در همان ورودی تست شوند پس برای جلوگیری از تکرار این جا هم تستی نباید انجام شود.اما در مورد پیام خروجی که از نوع command است باید فقط تا جایی که در سیستم عوارض جانبی دارد را تست کرد و بقیه کار را فقط بصورت Mock کردن قسمتی که اولین تاثیر را بر آن میگذارد انجام داد (همین که متدی در ادامه صدا زده میشود کافی است) و بقیه پیاده سازی را باید به خودش واگذار کرد. در اینجا اساس کار بر اعتماد اشیا به همدیگر است زیرا ما در جایی دیگر این پیامد را بعنوان ورودی کلاسی دیگر تست خواهیم کرد. و البته باقی ماجرا را به تست های integration نیز میتوان سپرید.</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Wed, 13 Feb 2019 16:01:24 +0330</pubDate>
            </item>
                    <item>
                <title>شهر آشوب</title>
                <link>https://virgool.io/@shayanadc/%D8%B4%D9%87%D8%B1-%D8%A2%D8%B4%D9%88%D8%A8-l3ond7sctnq5</link>
                <description>در بین پزشکان، مهندسان عمران و مهندسان کامپیوتر همیشه بحث بوده که حرفه کدامیک ریشه قدیمی تری نسبت به دیگران دارد. پزشکان معتقدند بر اساس کتاب مقدس خدا حوا را از بطن آدم ساخته است پس این کاملا مشخص میکند که جراحی قدیمی ترین حرفه ایست که به آن اشاره شده است. ولی مهندسان عمران مدعی اند قبل از آدم و حوا خداوند دنیا و بهشت را از نظم دادن به یک حرج و مرج مطلق پدید آورده است بنابراین ساخت و ساز را میتوانیم به عنوان اولین حرفه در هستی در نظر بگیریم. اما در این بین مهندسان کامپیوتر به صندلی خودشون تکیه میزنند و با لبخندی تمسخر آمیز و با اعتماد به نفس میگویند: هیچ با خود فکر کرده اید اون هرج و مرج را چه کسی بوجود آورده بود؟؟عموما پیچیدگی باعث هرج و مرج میشود. اما با نگاهی به طبیعت میتوانیم ببینیم که بسیاری از سیستم های که در طبیعت با موفقیت مشغول به کار هستند دارای پیچیدگی قابل تاملی هستند.باید بپذیریم که پیچیدگی محصول نرم افزاری ویژگی ذاتی آن است و نه یک اتفاق تصادفی چرا که عموما مشتری نمیداند چه چیزی میخواهد، چیزی که میخواهد را نمیتواند واضح بیان کند و توسعه دهنده هم برداشت خود را از خواسته های مشتری دارد.از آنجایی که تغییر اصل ثابت برای هر پروژه نرم افزاری است. طراحی ناموفق در مقابل تغییر پیش بینی نشده واکنش نشان میدهد. «بله من میتوانم این امکانات را اضافه کنم اما همه چیز از کار می افتد!!» «نه من نمیتوانم این امکانات را اضافه کنم چون این سیستم برای این کار طراحی نشده!!» «من میتوانم این امکان را به سیستم اضافه کنم اما این دقیقا اون چیزی نیست که شما میخواهید و در نهایت پشیمان خواهید شد!!»اتفاقات دنیا به صورت رویه ای است. یعنی زمان به سمت جلو حرکت میکند و اتفاقات یکی پس از دیگری رخ میدهند. احتمالا با شروع صبح از خواب بیدار میشوید. دندان های خود را مسواک میزنید و صبحانه خورده و از خانه برای کار خارج میشوید.دنیا همچنین شی گرا نیز هست. اشیایی که با آنها سر و کار داریم میتوانند رابطه یک سگ و شما باشد که هر کدام با رفتار خود تعریف میشوید. ممکن است بعضی اتفاقات قابل پیش بینی بین شما نتیجه ای دور از انتظار داشته باشد. ممکن است براساس خصوصیات ظاهری و رفتار سگی ترس را در شما برانگیزد در حالیکه سگی دیگر با شما این کار را نکند. در واقع در آنالیز شی گرا بجای چگونه بر چه تاکید داریم. هر شی چه میداند و چه کاری انجام میدهد؟و اما کدام روش برای طراحی سیستم درست است؟ در واقع هر دو دید برای تجزیه و سپس غلبه (divide and conquer) بر تکه های کوچک شده مسئله لازم است. با توجه به اینکه آنالیز و طراحی شی گرا به داشتن دید کاملی از کل سیستم در همان ابتدای طراحی نیازی ندارد و بعلاوه توسعه کاملا منطبق با طراحی انجام شده پیش خواهد، همچنین تجربه به ما میگوید که بهتر است ابتدا با دید شی گرا وارد مرحله طراحی شویم زیرا به ما کمک میکند تا پیچیدگی های سیستم را به قسمت های کوچک سازماندهی کنیم.در طراحی به روش شی گرا بخش های مختلف با برقراری ارتباط با هم رفتار سیستم را شکل میدهند. این ارتباط از طریق یک قرارداد انجام میشود طوریکه پیام وسیله انتقال بین آنها است. این موضوع مستلزم آن است که فرستنده پیام، اطلاعاتی از دریافت کننده داشته باشد. این اطلاع داشتن منجر به وابستگی بین اشیا میشود.حل مشکل پیچیدگی در طراحی شی گرا مدیریت این وابستگی ها است.شی چیست؟ و چه نیست؟در محیط اطرفمان هر چیزی که قابل مشاهده یا لمس باشد و از لحاظ فکری قابل فهم باشد را شی در نظر میگیریم ولی در دنیای شی گرایی کمی بیش از این است. هر چیزی که دارای وضعیت مشخص، رفتار قابل تعریف (چگونگی کنش و واکنش و تغییر وضعیت) و شناسه واحد یا یونیک (که آنرا از دیگر اشیا متمایز کند) باشد را شی در نظر میگیریم. و همچنین مجموعه ای از اشیا که ساختار مشترک، رفتار مشترک و معنای مشترک دارند یک کلاس را تشکیل میدهند.برای طراحی شی گرا باید با ابتدا آنالیز مفهومی از سیستم داشته باشیم. مفاهیم مرتبط با شی گرا به ما امکان طراحی دقیق تری را میدهد:Abstraction یا انتزاع:یک گیاه داری سه بخش اصلی است (ریشه، ساقه، برگ) که وظیفه و عملکرد هر کدام متفاوت از هم هستند در حالیکه همه آتها از سلول های مشابه ساخته شده است. هر بخش با رابط خود با بخش های دیگر در ارتباط است. ریشه وظیفه جذب آب و مواد معدنی از خاک را برعهده دارد. ساقه وظیفه انتقال مواد معدنی را از ریشه دارد. برگ ها با استفاده مواد معدنی دریافت کرده وظیفه تولید از طریق فتوسنتز را بعهده دارند. محدوده وظایف بصورت کاملا واضحی مشخص است در حالیکه بطور مثال ما چیزی از فرایند شیمیایی تبدیل مواد معدنی و فتوسنتز نمیبینیم.انتزاع ویژگی های اصلی یک شی را مشخص می کند طوریکه آن را از همه انواع دیگر اشیا تشخیص دهیم و بدین ترتیب مرزهای مفهومی دقیقی را با توجه به دیدگاه بیننده از یک شی پدید می آورد.برای رشد هر گیاه نیاز به تغذیه با مواد معدنی و آب و نور و دمای مناسب داریم. فرض کنید میخواهیم یک گلخانه اتوماتیک داشته باشیم که بدون دخالت انسانی و تنها با استفاده از چند سنسور دما، گرما، مواد معدنی را اندازه بگیرد و یک طرح را با استفاده داده های بدست آمده برای بهبود شرایط رشد اعمال کند. همه چیزی که شما میبینید چند سنسور است که در جاهای مختلف گلخانه نصب میشود که از طریق چند انتزاع دیگر میزان دما و نور را تغییر میدهد.انتزاع از همکاری اشیا (object) با همدیگر برای انجام یک رفتار بوجود می آید.Encapsulation یا کپسوله سازی:کپسوله سازی و انتزاع دو مفهوم بسیار به هم تنیده اند. نباید هیچ بخشی از یک سیستم پیچیده به اجزای درونی بخش های دیگر وابسته باشد. در حالیکه انتزاع بر رفتار قابل مشاهده هر شی تاکید دارد، کپسوله سازی بر نحوه پیاده سازی که منجر به رفتار میشود تمرکز میکند.در واقع انتزاع به ما کمک میکند تا کاری که انجام میدهیم برایمان قابل درک باشد ولی کپسوله سازی اجازه میدهد که برنامه با کمترین تلاش بتواند تغییر کند.در واقع هر شی به اینکه چگونه کارهای مربوط به خود را انجام میدهد آگاه است اما دیگر اشیا فقط باید بدانند شی مقابل چه کارهایی را برای آنها انجام میدهد. در واقع این شی چه کاری میتواند انجام بدهد؟ و این شی چه میداند؟ اما اینکه این شی چگونه انجامش میدهد؟ باید نسبت به سایر اشیا مخفی بماند.فرض کنید می‌خواهید تکنولوژی دقیق تری را برای اینکه بخاری ها در گلخانه اتوماتیک دمای مناسب را ایجاد کنند خریداری کنید. برای اینکار باید وسیله ارتباطی که مقدار دمای تشخیص داده شده توسط سنسور را به بخاری ها اطلاع میدهد ارتقاع یابد. برای این کار نباید مجبور باشید سنسورها را عوض کنید یا تغییری در آنها بوجود آورید.Modularity یا پیمانه ای:سیستم باید توسط اجزای جدا از هم که قابلیت ارتباط با همدیگر را دارند کار کند. در مثال گلخانه فرض کنید میخواهید کنترل شرایط را به خود کاربر بسپارید. احتمالا کاربر نیاز دارد برای شرایط رشد ویژه گیاهان یا گلها برنامه ای داشته تتظیم کند. در اینجا در واقع مجموعه ای از انتزاع های منطقی قبلی را برای اپراتور دسته بندی کرده ایم.Hierarchy یا سلسله مراتب:سلسله مراتب همان مرتب سازی انتزاع ها است.در واقع با سلسله مراتب میتوانیم بگوییم کلاس جدید همان کلاس قبلی است با چیزهایی بیشتر. سلسه مراتب به دو روش قابل شناسایی است:Is-a : ارث بری بعنوان ارتباط بین کلاس ها تعریف میشود به اینصورت که یک کلاس ساختار یا رفتار خود را با یک یا چند کلاس دیگر به اشتراک میگذارد.در مثال گلخانه ما میتوانیم پلان های متفاوتی برای رشد گیاه یا رشد گلها داشته باشیم ولی باید هر دوی آنها یک نوع از پلان رشد هستنند.Has-a : این نوع از سلسه مراتب را تجمع یا (Aggregation) می نامیم. در واقع ما یک انتزاع به نام گلخانه داریم که پلان رشد یا گیاهان، هر کدام بخشی از این گلخانه هستند.Polymorphism یا چندریختی:چندریختی به دو یا بیشتر کلاس های این امکان را میدهد تا به یک پیام مشخص جواب بدهند، البته به هر کدام به روش خود. این به آن معنی است که اشیا نیاز ندارند تا بدانند چه کسی پیام را برایشان فرستاده است.فرض کنید چند نقطه از گلخانه ابزار آبیاری کشیده شده است. نوع وسیله آبدهی بسته به نوع گیاهان آن منطقه باید متفاوت باشد. فرض کنید سنسور ها تشخیص میدهند نیاز به آبیاری است. دستور به ابزارهای آبیاری ارسال میشود ولی بعضی از آنها شروع به آبیاری قطره ای و بعضی از روش غرقابی استفاده خواهند کرد. در واقع سیستم نسبت به یک پیام جوابهای متفاوتی اعمال کرده است.Single Responsibility یا مسئولیت واحد :باید در نظر بگیریم که هر کلاس تنها و فقط یک کار را انجام دهد (Single Responsibility). در واقع نباید در توضیح عملکرد یک کلاس از دو حرف ربط «و» و «یا» استفاده کرد. اما این به معنا نیست که اصل مسئولیت واحد به طور سفت و سخت تنها اجازه انجام یک کار بسیار محدود را به کلاس بدهد. در واقع یک کلاس باید به طور بسیار منسجم کارهایی را انجام دهد که هدف آن کلاس آنرا توجیه کند.اینکه دقیقا بتوانید در همان نگاه اول و در ابتدای طراحی برای هر کلاس مسئولیت واحد را تشخصی دهید تقریبا غیرقابل ممکن است. شما همیشه بین دو سئوال باید تصمیم بگیرید بهتر است الان آن کلاس را بهبود بدهم؟ یا بعد آنرا بهبود خواهم داد؟مدیریت وابستگی ها:اگر کلاس های خود را انسان فرض کنید و به آنها در مورد وابستگی توصیه ای بدهید، باید بگویید: به چیزی وابسته باش تا کمتر از خودت تغییر کند.۱. از نیازمندیها مشخص است که بعضی از کلاس ها احتمال بیشتری نسبت به بقیه برای تغییر دارند.۲. کلاس های انتزاعی (abstract) نسبت که کلاس های ذاتی نیاز کمتری به تغییر پیدا میکنند.۳. تغییر کلاسی که وابستگی های زیادی دارد دردسرساز خواهد شد.هیچ کلاسی نباید از نام کلاسی دیگر مطلع باشد یا برای استفاده از کلاس دیگر مجبور به صدا کردن نام کلاسی که به آن وابسته است را داشته باشد.مقادیر آرگومان (Argument) کلاسی که به آن وابستگی وجود دارد نباید به عنوان ورودی پیام به کلاس دیگر فرستاده شود. در واقع کلاسی که به آن وابستگی داریم یک نمونه از خود را میسازد و همراه پیام میفرستد.ساختار پیامی بین دو کلاس فرستاده میشود نباید غیرقابل تغییر باشد. در واقع برای فرستادن پیام نباید مجبور به رعایت ترتیب آرگومان ها باشیم.فرض کنید در کلاسی به نام سفارش میخواهیم قیمت را محاسبه کنیم:قیمت تمام شده سفارش = تعداد سفارش *‌ قیمت محصولهمانطور که میبینید کلاس سفارش برای محاسبه نیاز به محصول دارد که این وابستگی را میتوانیم بصورت صدا کردن یک متد از کلاس محصول که محاسبه قیمت محصول را انجام میدهد و سپس تزریق آن نمونه (instance) از طریق ورودی پیام به سفارش انجام بدهیم تا سفارش بتواند قیمت را محاسبه کند.کلاس ذاتی و انتزاع:انتزاع را میتوان به « مستقل از هرگونه نمونه مشخص » تعریف کرد. در شی گرایی میتوانیم آنرا «بدون هیچگونه محدودیت و وابستگی فنی خاص به کلاس دیگری» تعریف کنیم.در ناحیه A بدلیل وجود وابستگی های شدید از انتزاع (abstraction) استفاده میکنیم. ناحیه C در مقابل این ناحیه A قرار دارد و ما در اینجا بدلیل وابستگی کم از کلاس های ذاتی استفاده میکنیم زیرا در صورت تغییر نیاز به تغییری دیگران ایجاد نمیکند.ناحیه B آنچنان مورد نگرانی ما نخواهند بود چرا که هم تغییر کمی خواهند داشت و هم وابستگی ندارند. اما ناحیه D منطقه خطر نام دارد به این معنی که اگر هم وابستگی های یک کلاس زیاد است و هم تغییرات در آن محتمل است، زنگ هشدار در مرحله طراحی به صدا خواهد آمد زیرا تغییرات کوچک کل سیستم شما را متاثر خواهد کرد و این چیزی است که دردسر ساز خواهد بود پس سعی کنید فرایندهای مرحله طراحی را بازبینی کنید.Interface یا رابط:دو شکل بالا را در نظر بگیرید. در شکل سمت چپ هر شی بدون هیچ الگوی مشخصی اجازه دارد با دیگر اشیا ارتباط بگیرند ولی در شکل سمت راست فقط بعضی از اشیا میتوانند با هم ارتباط مستقیم داشته باشند که امکان انتقال پیام بین همه اشیا با یک الگوی مشخص همانند پلی قرار داد شده امکان پذیر است. Interface ها جایی که اشیا با هم تعامل میکنند قرار میگیرند.یک شرکت دوچرخه سواری را در نظر بگیرید که تور دوچرخه سواری برگزار میکند. کار این شرکت این است که با توجه به موجود بودن دوچرخه ای که مشتری انتخاب میکند و انتخاب مسیر در زمانی مشخص به او پیشنهاد تور دوچرخه سواری بدهد.دو کلاس Trip و مشتری را در نظر بگیرید. مشتری به کلاس Trip درخواست میدهد و این کلاس براساس شرایط سختی، روز و دوچرخه یک تور مناسب ارائه میدهد. اولین نکته این است که کلاس Trip علاوه بر مسئولیت های خود که تشخیص میزان سختی و زمان تور است باید نسبت به موجود بودن دوچرخه نیز پاسخگو باشد که این اشتباه است.سوال پایه ای خود را از «من میدانم این کلاس چه کاری انجام میدهد؟‌» را به سوال «من میدانم نیاز دارم این پیام را در سیستم داشته باشم. چه کسی باید به این پیام پاسخ بدهد؟ » تغییر دهید. شما بخاطر اشیای موجود در سیستم پیام نمیفرستد بلکه بخاطر وجود پیام ها اشیا را میسازید. در واقع مشکل مشتری نیست که به دنبال دوچرخه موجود است. مشکل اینجاست که کلاس Trip نباید به آن پاسخ دهد.در این مرحله این مشکل را حل کردیم اما کلاس مشتری علاوه بر اینکه میداند چه میخواهد، میداند اشیا دیگر چگونه با همکاری با هم این کار را برای او انجام میدهند.فرض کنید به نیازمندیهای پروژه اضافه میشود که برای هر تور باید دوچرخه ها از نظر مکانیکی از جمله بررسی ترمزها، باد زدن چرخ ها، زنجیر و ... بررسی شوند. با توجه به اینکه کلاس Trip نباید از چکونگی مکانیک چیزی بداند پس داریم:کلاس مکانیک خود میداند که چه کارهایی را شامل میشود اما این مانند کتی بر تن Trip است زیرا هر بار تست Trip منجر به تست کلاس مکانیک خواهد شد.اما یک مرحله بالاتر:حالا کلاس Trip با استفاده از Interface میتواند کاملا از کلاس مکانیک بی خبر باشد و نه تنها از چگونگی انجام کار مطلع نشود حتی از وجود همچین کلاسی نیز مطلع نباشد.در واقع در تلاش اول، کلاس Trip به مکانیک میگفت «من میدانم چه میخواهم و میدانم تو چه کاری انجام می دهی» ولی در دومین تلاش میگوییم: «من میدانم چه میخواهم پس به قسمتی که آنرا انجام میدهد اعتماد میکنم». این اعتماد کور کورانه اساس روش شی گرا است.</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Mon, 04 Feb 2019 11:09:35 +0330</pubDate>
            </item>
                    <item>
                <title>هرچه تندتر کندتر...</title>
                <link>https://virgool.io/@shayanadc/%D9%87%D8%B1%DA%86%D9%87-%D8%AA%D9%86%D8%AF%D8%AA%D8%B1-%DA%A9%D9%86%D8%AF%D8%AA%D8%B1-gclbqqfijf58</link>
                <description>عموما پیش فرض ما برای معماری نرم افزارها با وجود مشکلاتی مثل عدم مقیاس پذیری و عدم توانایی مدیریت منابع بصورت درخواست-پاسخ (Request-Response) انجام میشود. شاید به این دلیل که وقتی همه آن چیزی که داریم فقط یک چکش باشه، هر چیزی رو میخ میبینیم.فرض کنید شما در حال غذا خوردن در رستورانی هستید. مشتری های دیگر سفارش خودشان را میدهند همانطور که شما میتوانید این کار را بکنید. شما مجبور نیستید منتظر دیگران بمانید تا آن ها غذای خود را دریافت کرده و بخورند و بعد از آنها شما بتوانید غذای خود را دریافت کرده و مشغول خوردن شوید، در واقع آنها هم مجبور نیستند منتظر شما باشند و همه غذای خود را به محض آماده شدن دریافت میکنند.دریافت سفارش غذا به این صورت است که چه غذایی چه وقت سفارش داده شده است. این درحالیست که اگر شما سفارش استیک داده باشید و من بعد از شما درخواست آب بدهم، انتظار دارم تا بدون اینکه منتظر آماده شدن سفارش شما بشم یک لیوان آب خودم را دریافت کنم.در مقابل سیستم های درخواست/پاسخ که مشتری بلافاصله پاسخ درخواست خود را میگیرد در این رستوران، مسئول پذیرش باید درخواست های مشتریان را مدیریت کند تا بتوان با اولویت به هر کدام رسیدگی کرد و شاید چند سفارش را بطور همزمان رسیدگی کرد. مثلا در یک زمان هم به سفارش آب رسیدگی شود و در همان زمان استیک آماده پخت شود.سیستم های ناهمگام یا غیر همزمان (Asynchronicity) این امکان را میدهند تا درخواست کننده و پاسخ دهنده همزمان به سیستم متصل (connect) نباشند و در خواست ها یا پیام ها بدون اینکه نیازی به پردازش یا پاسخ فوری باشند، بر روی یک صف (Message Queue) فرستاده شوند. از طرفی این طراحی ما را قادر میسازد تا بتوانیم درخواست های درون سیستم را به نحوی که اولویت دارد مسیریابی (routing) کنیم.(به مثال رستوران برگردید)البته ین معماری باعث سخت تر شدن نگهداری و اگر به درستی مدیریت نشوند کاهش کارایی (performance) و قابلیت اطمینان خواهد شد. همینطور باید بدانیم که تست کردن (test driven development) این معماری کمی پیچیده تر خواهد بود.معیارهای مهم سنجش شرایط Message Queue:در مثال رستوران فرض کنید برای دقایقی گاز در آشپزخانه قطع شود و کارمندان قادر به گرفتن و آماده کردن سفارش ها نباشند. در این حالت پذیرش قاعدتا باید بتوانند با حفظ خونسردی خود سفارش های مشتری را بگیرد تا به محض برگشتن شرایط به حالت عادی آنها را برای آماده شدن به آشپزخانه بسپارد.ماندگاری (Durability) : قابلیت اطمینان برای عدم از بین رفتن پیام ها در صورتیکه برای سرور صف ها مشکلی پیش بیاید.مدیران رستوران برای شرایط اضطرار باید فکری بکند تا از دست رفتن سفارش مشتری به دلیل ایجاد مشکل در آشپزخانه به حداقل برسد.نقطه به نقطه (point-to-point) در مقابل انتشار و اشتراک (publish/subscribe) : در مدل نقطه به نقطه پیام فرستنده از طریق صف به گیرنده یا مصرف کننده میرسد. میتوانیم بیش از چند گیرنده داشته باشیم که در انتظار پیام به صف گوش بدهند اما فقط یکی از آنها واقعا میتواند پیام را دریافت کند. اما در مدل انتشار و اشتراک همانطور که از نامش پیداست مصرف کننده ها میتوانند به همه پیام های روی صف دسترسی داشته باشند.پیام تصدیق (Message Acknowledgements) : هم فرستنده و هم گیرنده پیام نیاز دارند تا از دریافت پیام و در حال پردازش قرار گرفتن آن مطلع شوند.هر سفارش چندبار باید از پذیرش به اشپزخانه فرستاده شود؟سیاست های تحویل(Delivery Policies): اینکه هر پیام چندبار باید تحویل داده شود شود.اندازه و فرمت پیام: علاوه بر اینکه پیام ها با چه فرمتی برای ارسال پشتیبانی میشوند ، اندازه و حجم قابل ارسال انها نیز مهم است.سیاست های مسیریابی: مصرف کننده های پیام باید بتوانند اولویت های خود را برای دریافت و پردازش پیام ها درخواست کنند.قابلیت مقیاس پذیری(Scalability): توانایی پردازش در حجم بالا و مدیریت منابع با زیاد شدن تقاضا برای استفاده از آنها.قابلیت دسترسی: آیا صف ها در زمانی که برای سرور اتفاق می افتد قابل دسترسی هستند؟چند پلتفرمی (Cross platform interoperability): آیا بین چند سیستم با تکنولوژی های مختلف کارایی دارد؟ در واقع message queue باید بعنوان واسطی (broker) عمل کند که بخش های مختلف سیستم بوسیله آن با یکدیگر ارتباط بگیرند.تلاش اول - پیاده سازی Message Queue با استفاده از دیتابیس:برای این کار باید هر درخواست (سفارش غذا توسط مشتری در مثال رستوران ) را درون یک جدول از دیتابیس خود ذخیره(insert) کنید. برای هر درخواست یکی از سه وضعیت جدید،درحال پردازش، پایان یافته (New, Processing, Finished) در نظر بگیرید. سرویس شما باید بارها و بارها تلاش کند تا به سرور متصل شود و آخرین درخواست را دریافت کنند.هرچند که معمولا کو‌‌ئری زدن ها در دیتابیس به تنهایی اعمال سریعی هستند اما نه وقتی که در یک زمان چندین کوئری روی یک جدول مشخص زده شود.(تعداد سفارش های غذا توسط مشتریان خیلی زیاد میشود)اما حالا فرض کنید بیش از یک مصرف کننده به دیتابیس خود متصل کنید.( در مثال رستوران شما دو آشپز اضافه میکنید تا سفارش ها زودتر آماده و به دست مشتری برسند ) هر آشپز (worker) سعی خواهد کرد به درخواست ها در یک زمان مشخص دسترسی پیدا کند و آنرا به وضعیت در حال پردازش(Processing) تغییر حالت بدهد. اینجاست که برای جلوگیری از نوشتن همزمان و شرایط رقابتی (race condition) ایجاد شده یک مصرف کننده در ابتدا باید سطر (row) درخواست مورد نظر را قفل کند و بعد از انجام کامل عمل خود آنرا آزاد کند.از آنجایی که درخواست ها روی صف دیتابیسی ما دخیره شده اند شما باید برای تمیز کاری دیتابیس خود که پس از مدتی پر از درخواست های تلنبار شده است هم چاره ای پیدا کنید.هزینه فایدهاین روش فقط از مدل point to point پشتیانی میکند. پیام ها یا درخواست ها تا زمانی که وضعیت آنها تغییر پیدا نکند، فقط توسط یک مصرف کننده قابل مصرف هستند و هیچگونه سیاست مسریابی برای دریافت پیام ها اعمال نشده است. ( اول آب یا استیک ؟ در مثال رستوران ) بعلاوه اندازه پیام ها نیز برای ذخیره در دیتابیس محدودیت دارد.تلاش دوم - استفاده از آمازون SQS بعنوان واسط (broker) پیام ها:در Amazon Simple Queue Service ، سرویس A پیام ها را به صف SQS میفرستد. یکی از مصرف کننده های سرویس B که به انتظار نشسته است پیام یا درخواست را میگیرد. SQS اجازه نمیدهد یک درخواست به چند مصرف کننده برسد و جلوی همزمانی خوانده شدن توسط چند مصرف کننده را میگیرد.پیام دریافت شده توسط سرویس B همچنان در SQS باقی میماند ولی به مصرف کننده دیگری سپرده نمیشود و یک شمارش معکوس (به میزان دلخواه)برای آن در نظر گرفته میشود تا مصرف کننده آنرا پردازش کند و آنرا پاک کند.هزینه فایدهاین روش هم فقط از مدل Point to Point استفاده میکند. پیام ها به صورت همیشگی نیستند و پس از زمانی (به میزان دلخواه) حذف خواهند شد. این زمان باید به اندازه زمانی بیشتر از زمان طولانی ترین مدت زمان پردازش توسط مصرف کننده تنظیم شود تا پیام ها زودتر از مصرف و به دلیل تمام شدن زمان (timeout) حذف نشوند. همچین روشی برای سیاست ها مسیریابی پیام دیده نشده است.تلاش سوم - استفاده از JMS بعنوان واسط (broker) پیام ها:در ساده ترین روش که مصرف کننده و تولید کننده هردو به زبان جاوا باشند با استفاده Active MQ که از پروتکل open wire استفاده میکنند میتوانند با هم ارتباط برقرار کنند اما فرض کنید مصرف کننده به زبان جاوا و تولید کننده به زبان پایتون نوشته شده باشند.جاوا باید از کلاینت Active MQ برای ارتباط با واسط (broker) استفاده کند اما پایتون از کلاینت PyActive MQ باید استفاده کند چرا که نیازمند پروتکل STOMP (یکی از معروف ترین پروتکل های پشتیبانی کننده) برای ارتباط واسط است.هزینه فایدههر دوی این پروتکل ها ممکن است از یک نوع فرمت پیام برای فرستاد و دریافت استفاده نکنند و این روش هر چقدر هم که برای برنامه ای به زبان جاوا کارا باشد برای چند پلتفرمی (cross platform) بودن مناسب نیست.برای مشکل ایجاد شده در JMS استاندارد پروتکل باز Advanced Message Queue برای ایجاد قابلیت ارتباط در سیستم ها بین کلاینت و واسط پیام ها (broker) ساخته شده است.تلاش چهارم - استفاده از AMQP بعنوان واسط پیام ها:در این روش پیام ها به چیزی شبیه به اداره پست (exchange) فرستاده میشوند. سپس اداره پست (exchange) نسخه ای از پیام ها را به صف با قوانین (binding) مربوط به خود تحویل میدهد. نسخه های مختلفی از واسط با پروتکل AMQ پیاده سازی شده امد که در اینجا به معروفترین آنها RabbitMQ میپردازیم.فرستنده میتواند هنگام فرستادن پیام همراه آن مشخصاتی را به شکل متا دیتا همراه آن ارسال کند که این اطلاعات برای واسط قابل استفاده است.مصرف کننده به محض پردازش پیام بسته به شرایطی که توسعه دهنده برنامه (developer) ایجاد میکند علامت تصدیقی (acknowledge) را به واسط AMQ میفرستد.مصرف کننده ها برای گرفتن به نوبت پیام های روی واسط (broker) صفی را ایجاد میکنند و به پیام دریافتی گوش میدهند و تا زمانیکه پیامی برای آنها ارسال نشود صفی هم ایجاد نشده است.پیام ها میتواند به همه مصرف کننده هایی که با صف به اداره پست (exchange) متصل باشند ارسال شود. (Fanout) و یا با استفاده کلید مسیریابی (routing key) دقیقا به همان مصرف کننده ای برسند که بین پیام ها به آن کلید مشخص گوش میدهد.(Direct) همچنین این مسیر میتواند به شکل یک الگو تعریف شود(Topic)هزینه فایدهبا استفاده از روش های (direct, fanout, topic etc) هم مدل Point to Point و هم Publish-Subscribe قابل پشتیبانی است و مسیریابی با تنوع کامل فیلتر گذاری روی پیام ها برای اینکه هر مصرف کننده معطل بقیه پردازش ها نشود قابل مدیریت توسط توسعه دهنده است.تلاش پنجم - استفاده از Kafka بعنوان واسط پیام ها:در Kafka هر پیام داری کلید، ارزش و زمان است و بر خلاف RabbitMQ که واسط همه متا دیتا را دریافت میکرد و همه چیز را در مورد پیام ها میدانست. برای Kafka واسط نادان و بی اطلاع از همه چیز در نظر گرفته میشه و این مصرف کننده ها که توسط برنامه نویس توسعه داده شده اند که نسبت به پیام ها هوشمند هستند. Kafka اهمیتی نمیدهد که کدام پیام ها خوانده شده اند و پیام های مصرف نشده را نگه دارد. در عوض همه پیام ها را برای مدت زمانی نگه میدارد و مصرف کننده ها را نسبت به گروه یا محدوده خود مسئول میداند.هزینه فایدهبرای نگهداری حجم بالای اطلاعات و همینطور قابلیت توسعه پذیری کاملا مناسب است ولی نیاز به سرویس خارجی Apache برای راه اندازی دارد. همیچنین از الگوریتم ها مسیریابی پشتبیانی نمیکند و کار مسیریابی به مصرف کننده ها واگذار شده است که شاید این موضوع باعث پیچیدگی در پیاده سازی شود.RabbitMQ مسیریابی قدرتمندی را برای ساده سازی کار توسعه مصرف کننده ها پیاده سازی کرده که شما فقط با اضافه کردن مصرف کننده های بیشتر میتوانید عملکرد خود را افزایش دهید، بدون اینکه درگیر پیچیدگی های پیاده سازی شوید. اما اگر نیازمند مقیاس پذیری در حجم بالا هستید نیاز دارید تا پیچیدگی های Kafka را بپذیرید.در نهایت باید بدانیم پیاده سازی Message Queue ما را درگیر پیچیدگی های عملیاتی خواهد کرد. جدا از انتخاب اینکه کدام روش مناسب شما خواهد بود باید از ابزارهایی برای مانیتور، کانفیگ استفاده کرد.</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Mon, 04 Feb 2019 11:07:13 +0330</pubDate>
            </item>
                    <item>
                <title>فقط برای تفریح</title>
                <link>https://virgool.io/@shayanadc/%D9%81%D9%82%D8%B7-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%AA%D9%81%D8%B1%DB%8C%D8%AD-sw8waex6ckdv</link>
                <description>هیچوقت برایتان پیش آمده که یک شب گرم تابستانی به ستاره ها نگاه کنید و از خودتان سوال کنید که چرا این جایید؟ جایگاه شما در جهان چیست و قرار است با زندگیتان چه کار کنید؟خب بله، من هم برایم پیش نیامدهاما لینوس توروالدز در مقدمه کتاب فقط برای تفریح نظریه ای در مورد زندگی، جهان و همه چیز ؛ یا لااقل در مورد زیرمجموعهای از آن به نام «زندگی» ارائه داده است. این نظریه هیچ معنایی به زندگی شما نمیدهد، ولی نشانتان میدهد که پشت پرده چیزی در جریان است.من به عنوان یک تکنولوژیست، میدانم که تکنولوژی چیزی را به پیش نمیراند. این جامعه است که تکنولوژی را جلو میبرد، نه برعکس. تکنولوژی فقط تعیین کننده محدوده کارهایی است که ما میتوانیم انجام دهیم و در عین حال، هزینه هر کار را هم برای ما مشخص میکند.تکنولوژی، همانند ابزارهایی که میسازد، بسیار خرفت است. تنها جنبه جذاب تکنولوژی، کارهایی است که ما با استفاده از آن میتوانیم انجام دهیم. نیروی حرکت تکنولوژی، خواسته ها و نیازهای انسان است. ما این روزها به خاطر حضور موبایل نیست که بیشتر با هم حرف میزنیم بلکه چون این روزها به آدمی پرچانه تبدیل شدهایم و میخواهیم که بیشتر حرف بزنیم و موبایل نداشته ایم، آن را اختراع کردهایم. نوکیا را هم همین طور.پس اگر قرار است تکامل یک جامعه را بررسی کنیم، باید عاملی که انگیزه نیازهای انسان است را بشناسیم. آیا این انگیزه پول است؟ موفقیت است؟ رابطه جنسی است؟ واقعا چه چیزی مبنای چیزهایی است که انسانها میخواهند؟یکی از انگیزههایی که احتمالا هیچ کس در آن شک نخواهد کرد و اگر هم شک کند، پاسخ آن ساده است، انگیزه بقا است. در دنیایی شدیدا خصمانه که به راحتی میتواند به زندگی ما خاتمه دهد. بقا، عامل اول تعیین کننده نیازهای ما است. سوال این نیست که «آیا به خاطر پول حاضرید آدم بکشید؟» بلکه باید بپرسیم که «آیا به خاطر پول حاضرید بمیرید؟» مشخص است که جواب «نه» استاما بدون شک چیزهایی هم هستند که مردم حاضرند به خاطر آنها بمیرند. داستانها و افسانه های زیادی داریم از قهرمانان و حتی حیوانات قهرمانی که حاضر شدهاند به خاطر هدفی بزرگ، خود را به کشتن دهند. پس بقای صرف هم نمیتواند عامل پیشبرنده جامعه باشد.ولی روابط اجتماعی بدون شک میتواند یکی از آنها باشد.نمونههایی از روابط اجتماعی که میتوانند باعث کم رنگ شدن انگیزه بقا شوند، بسیارند. رومئو و ژولیت در ادبیات را در نظر بگیریدپس «روابط اجتماعی» را به عنوان انگیزه شماره دو در نظر میگیریمسومین انگیزه یا همان انگیزه نهایی، «سرگرمی» است. شاید این انگیزه به نظر مبتذل برسد، ولی شکی ندارم که نیروی فوقالعادهای دارد. مردم هر روزه به خاطر کارهایی که تنها به خاطر تفریح انجام میدهند، میمیرند؛ مثلا پریدن از یک هواپیمای کاملا سالم فقط به خاطر احساس هیجان ناشی از سقوط آزاد.به نظر من نیرویی که بتواند باعث شود یک نفر مشتاقانه در صندلی یک سفینه بنشیند و با کلی مواد منفجره خیلی قوی به فضا پرتاب شود تا بتواند زمین را از فضا نگاه کند، یک «انگیزه حسابی» است.زنده بمان. اجتماعی بشو. تفریح کن. این یعنی پیشرفتهر کاری که ما انجام میدهیم در نهایت به ابزاری برای تفریح بدل خواهد شد؛ حداقل اگر آن رفتار فرصت کند تا به اندازه کافی تکامل پیدا کند.بهترین مثال هم سکس است. سکس به عنوان راه بقا شروع و بعد به یک مساله اجتماعی تبدیل شد. به همین دلیل است که ازدواج میکنیم؛ اما حالا سکس دارد به یک جور تفریح تبدیل میشودمیتوانیم به سراغ جنگ برویم. مشخص است که اولین جنگها برای بقا بوده اند چون یک رویارویی بین شما و چاله آب ایستاده بود. بعد باید سر زن با یک مرد میجنگیدید و بعد جنگ تبدیل میشد به یک موضوع اجتماعی. این جریان سالها قبل از قرون وسطی واقع شد.یعنی جنگ به عنوان شیوهای برای برقراری نظم اجتماعی. ولی شاید بهتر باشد بگوییم روشی برای پیدا کردن جایی برای افراد در نظم اجتماعی؛ چون هیچکس برای خودِ نظم اجتماعی اهمیت چندانی قائل نیست. در این ماجرا، فرقی هم نمیکند شما یک مرغ در مرغدانی باشید یا یک انسان در جامعه. میخواهید بدانید ایا این روزها جنگ به یک سرگرمی تبدیل شده؟ بلی شاید برای کسانی که آن را روی تلویزیون میبینند این حرف درست باشد. برای آنها جنگ یک سرگرمی شده. حالا مقیاس را بزرگتر کنید. مساله فقط درباره افراد نیست، درباره کل زندگی است. مثل قانون آنتروپی. در این قانون آنتروپی زندگی، همه چیز در حال حرکت از سوی بقا به تفریح است، ولی نه به این معنا که در مقیاس کوچک، این روند هیچوقت نمیتواند در جهت معکوس حرکت کند. اتفاقا گاهی این حرکت مشخصا معکوس میشود. بعنوانیک سیستم، همه چیز در یک جهت پیش میرود ولی نه در یک زمان . پس میشود دید که سکس به مرحله تفریح رسیده است، جنگ به آن نزدیک شده و فناوری عملا به آن رسیده. چیزهای جدید، فقط به بقا توجه میکنند؛ مثلا، امیدوارم که سفر فضایی، اوایل مربوط به بقا باشد، بعد به یک امر اجتماعی تبدیل شود و در نهایت، نوعی تفریح باشد. اگر به تمدن هم به عنوان یک کیش نگاه کنید، الگوی مشابهی را خواهید دید. تمدن به خاطر بقا ایجاد شده. وقتی با هم هستید، راحتتر زنده میمانید و بعد شروع به ایجاد ساختارهای اجتماعی میکنید؛ اما در نهایت، تمدن منحصرا به خاطر تفریح حفظ میشود. قبول! منحصرا را پس میگیرم و تفریح هم تفریح بدی نیست. رومیان قدیم به خاطر نظم اجتماعی بسیار زیاد و همچنین تفریح های حسابیشان معروف اند. آنها بهترین فیلسوفان دوره خودشان را داشتند.و اما فناوری چطور به نظم اجتماعی شکل میدهد؟خب در حقیقت، بیشتر جریان صنعتی شدن مربوط به بقا و بقای بهتر است. در صنعت خودروسازی، فناوری به سراغ ساخت خودروهای سریعتر و بهتر رفته است. ولی در جاهایی هم بحث شکل دادن به نظم اجتماعی مطرح بوده؛ مثلا اختراع تلفن و تا حدی تلویزیون. بخش زیادی از برنامه های اولیه تلویزیون، در مورد آموزش عقاید بوده است. رادیو هم همینطور. به دلیل همین کارکرد نظم اجتماعی است که بسیاری از دولتها در رادیو و تلویزیون این همه سرمایه گذاری برای ایجاد و دوام نظم اجتماعی مورد نظرشان کرده اند.بعد، جریان پیشرفت کرد. این روزها مشخصا تلویزیون به منظور تفریح استفاده میشود. این روزها هر جا را که نگاه کنید پر است از تلفن همراه. این وسیله اول برای یک نظم اجتماعی تولید شده بود، ولی کم کم دارد به یک وسیله تفریحی تبدیل میشود. پس آینده فناوری چیست؟ به نظر میرسد از مرحله بقا فراتر رفته ایم و حالا در مرحله نظم اجتماعی هستیم.فناوری همیشه برای سادهتر کردن زندگی بوده است. سعی میکرده ما را سریعتر به مقصد برساند، قیمت کالاها را کمتر کند، خانهها را بهتر کند و این جور چیزها. ولی فرق فناوری اطلاعات با فناوریهای قدیمی چیست؟ این واقعیت که همه به هم متصل خواهند بود، به چه چیزی منجر میشود؟ مشخص است که ارتباط بهتر شده ولی این تفاوت پایه ای نیست. قدم بزرگ بعدی، تفریح است. ما عصر فعلی را عصر اطلاعات نامگذاری کردهایم. این یک تغییر بزرگ است. ما داریم از تکنولوژی برای ارتباطات و انتقال اطلاعات استفاده میکنیم که بر خلاف انگیزههای مبتنی بر بقای سابق، یک فعالیت اجتماعی است. اینترنت و این واقعیت که حجم زیادی از تکنولوژی این روزهای ما به سمت آن جریان پیدا کرده، میتواند بهترین نشانه از این عصر باشد. معنای این نشانه این است که لااقل بخش عمدهای از کشورهای صنعتی، خاصیت ادامه بقای تکنولوژی را غیرقابل خدشه دیدهاند و حالا به سراغ جنبه ارتباطی تکنولوژی رفتهاند: استفاده از تکنولوژی نه به منظور زندگی بهتر که به منظور بخشی جدا نشدنی از زندگی اجتماعی.هدف نهایی از همین حالا مشخص است؛ گذشتن از جامعه اطلاعاتی و رسیدن به جامعه سرگرمی. جایی که اینترنت و ارتباط بیست و چهارساعته بیسیم غیرقابل خدشه شود و دیگر اخبار مربوط به پیشرفت اینترنت، «خبر» تلقی نشود. در آن روز سیسکو یک بازار قدیمی است و شرکت دیزنی، صاحب جهان خواهد بود. این دوره، احتمالا زیاد دور نیست.شاید بخواهی در برابرش مقاومت کنی ولی هدف نهایی زندگی، به هرحال تفریح خواهد بود.این احتمالا به این معناست که اگر روزی با موجود هوشمند دیگری در کهکشان روبرو شویم، احتمالا نخواهد گفت: «مرا به پیش رهبرتان راهنمایی کنید.» اولین جمله یک موجود هوشمندتر به ما، احتمالا این خواهد بود: «بیایید جشنی راه بیاندازیم رفقا.»چطور همه اینها به معنای زندگی مرتبط میشوند؟راستش را بگویم نمیشوند. مساله این است که مشکل همین جا است.خب اگر بدانید که کل زندگی، مربوط به این پیشرفت است، بعد هدف شما این خواهد بود که خودتان هم در این مسیر حرکت کنید. این مسیر هم فقط مسیر یک چیز نیست. هر کاری که میکنید، بخشی از حرکت در مسیرهای مختلف است. میتوانید از خودتان بپرسید «چه کار کنم که جامعه بهتر شود؟» چون شما بخشی از جامعه هستید و میدانید که جامعه در این مسیر در حال حرکت است. شما هم میتوانید به این حرکت کمک کنید.شاید بتوانیم این طور نتیجه گیری کنیم که در نهایت امر، همه ما اینجا هستیم تا تفریح کنیم.تازه میتوانیم بنشینیم و استراحت کنیم و از این مسیر لذت ببریم. هر چیزی در نهایت به تفریح تغییر شکل میدهد...</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Mon, 04 Feb 2019 11:02:15 +0330</pubDate>
            </item>
                    <item>
                <title>غیر منتظره های همیشه باقی</title>
                <link>https://virgool.io/@shayanadc/%D8%BA%DB%8C%D8%B1-%D9%85%D9%86%D8%AA%D8%B8%D8%B1%D9%87-%D9%87%D8%A7%DB%8C-%D9%87%D9%85%DB%8C%D8%B4%D9%87-%D8%A8%D8%A7%D9%82%DB%8C-pnlzlbmkkjs9</link>
                <description>برای یک توسعه دهنده بعد از مراحل سخت توسعه دیگر همه چیز به رویا نزدیک میشود تا اینکه اولین باگ توسط مدیر محصول کشف میشود.همیشه پیش نرفتن هر چیزی مطابق آنچه انتظار داریم کمی افسرده کننده است.این مشکل نباید پیش می آمد؟ آیا روش من درست نبوده؟ من ایده آلیست ام؟ من چه هستم؟ آه…در مانیفست توسعه چابک نرم افزار(agile) داریم که &quot;توسعه چابک در مورد این نیست که وانمود کند جهان پیرامون شما بی عیب و تمام عیار است، بلکه در مورد سازگاری با واقعیت و بازگو کردن آن برای بهبود فرایند هایتان و انعطاف پذیری است. پس وقتی مشکلات بروز میکنند شما قادر خواهید بود با آنها مواجه شوید&quot;.پس از دانستن این تعریف میتوانیم دیگر افسرده نباشیم اما مشکلات ناشی از بروز باگ در محصول به دست مشتری رسیده همچنان وجود خواهند داشت. باید همه آنها را حل کنیم؟ چگونه؟باگ ها اغلب بر اساس تاثیر مخربی که بر محصول ما میگذارند قابل شناسایی هستند.اولین نوع آنها را میتوانیم کمترین تاثیر بدانیم، بعد از رخ دادن چنین باگی شما میتوانید به جایی که در قبل از آن بودید برگردید و مشکل حل خواهد شد.ابزارهای توزیع محصول (production deployment systems) مثل گیت به شما این امکان را میدهد.دومین نوع را میتوان به باگ های اطلاق کرد که برای کشف نیاز به عمیق شدن بیشتر در داده های بدست آمده از سیستم خود دارید زیر ا که بیشتر در ذخیره سازی اطلاعات رخ خواهد داد و اغلب با بازیابی داده ها قابل برطرف شدن است.این نوع باگ ها معمولا با در نظر گرفتن نوع آنها درمراحل توسعه و تست و همچنین عمیق تر دنبال کردن داده ها پس از ارائه سیستم قابل ردیابی است.این نوع باگ ها با توجه به اینکه در ظاهر قابل مشاهده نیستند اما بسیاری از آنها رو اغلب میتونید در خواب ببینید که بهش میگن اشراق!مثلا در خواب ببینید مقدار تخفیف که محاسبه کردید رو در فیلد تخفیف سفارش ذخیره نکردید و الان تبدیل به یک هیولا شده و دنبال شما میگرده.باگ هاي روشن و بيرون زده نوع سوم هستند که تاثیرات آنها بر سیستم بسیار حیاتی هستند و بسیار لازم است تا در اسپرینت جاری رفع شود و امکان صبر کردن برای رفع مشکل تا اسپرینت بعدی نخواهد بود.باید توجه داشت، همان قدر که برای ادامه عملکرد سیستم نیازمند رفع مشکل هستیم اما وارد کردن سناریوی جدید در میانه کار اصلا ایده خوبی نیست.برای محدود کردن این تغییرات مدیر اسکرام با مدیر محصول بدون تیم توسعه وارد مذاکره میشوند تا راه حل را برای توسعه تدوین کنند.اما گزینه آخر و کابوس وار تأثیرات هسته ای و مهلک است که راه گریز از آن فراتر از تیم توسعه است و ناچار خواهید بود که متاسفانه ادامه روند را متوقف کنید و روندهای خود را بازبینی کنید، احتمالا در نقشه نحوه عملکرد سیستم تغییر بوجود خواهد آمد.اما چه وقت میتوانیم به مسئله بوجود آمده باگ بگوییم و چه وقت نمی‌توانیم؟باگ قطعا پس از شناسایی سناریو کاربری و شبیه سازی آن رخ میدهد و در اینصورت است که میتوانید مسئله موجود را باگ بخوانید.باید ارائه محصول به تایید مدیر محصول رسیده باشد تا بتوان مشکلات پیش آمده پس از انتشار آنرا باگ نامید چرا که در بسیاری از اوقات توسعه دهندگان با وجود ایجاد محیط تست برای توسعه نرم افزار دچار اشتباه میشوند زیرا که آنها تنها پنداشت خود را از عملکرد صحیح سیستم دارند.باگ ها باید توسط مشتری یا کاربر نهایی سیستم گزارش و یا شناسایی شوند.و اما ما محصولی را باگی مینامیم که که کاربران آن تجربه کاربری خوبی ندارند.و نکته آخر در شناسایی باگ اگر هنوز مردد هستید این است که باگ ها اصولا در پایان ساعات کاری یا روزهای تعطیل وقتی در حال تفریح هستید رخ میدهند‌ :)با توجه به تعاریف گفته شده از باگ ها مطمئنا با موارد دیگری مواجه شده اید که نمیتوانیم آنها را باگ بنامیم. باقی موارد خارج از تعاریف گفته شده را با مفهوم دیگری معرفی میکنیم به نام مسئله (issue). و به مشکلاتی گفته میشود که تیم توسعه در طول یک اسپرینت با آن مواجه میشود و الزاما نباید در لیست بکلاگ باشند.شاید بتوان گفت در بسیاری مواقع یافتن و رفع باگ کافی نیست، میتوان گفت برای پوشش بیشتر و جلوگیری از ایجاد تجربه کاربری بد برای مشتری لایه جدیدی را به تیم اضافه میکنند تا مسئله یابی را انجام دهند. هدف این است که زودتر از مشتری مشکلات را بیابید و رفع نمایید و با استمرار بر این روش جنبه های پنهان محصول خود را زیر نظر بگیرید. مسئله یابی در واقع کار بر روی چیزهای درست به جای کار بر روی چیزهای نادرست است و در نهایت داشتن مشتری و البته مدیر محصول! خوشحال تر.با این روش میتوانید نیروهای بدون دانش فنی خود را آموزش دهید تا اطلاعات بدست آمده از مشکلات محصول خود را طبقه بندی کنند:ذخیره سازی: چه چیزی باید گزارش شود؟چه زمانی و چه کسی تصمیم میگیرد؟پاسخگویی: به چه کسی گفته شود؟ آنها چه پاسخی داده اند؟اولویت: چه چیز هایی اهمیت بالاتری دارند؟حل مسئله: راه حل چه بوده؟ چگونه حل شده است؟بازبینی: آیا به درستی کار میکند؟با دانستن اینکه فقط یک درصد مشتریان باگ ها را گزارش میدهند، پیداست که شما باید فرآیندی برای پیدا کردن و حل مشکلات سیستم بدون تاثیر گذاری بر روند توسعه داشته باشید.حداقل دو روش کارامد برای رفع باگ ها با رعایت اولویت اهمیت آنها بر اساس تاثیری که بر عملکرد محصول میگذارد میتوان معرفی کرد:اولین روش اینکه هات فیکس ها را در بالای لیست بک لاگ ها قرار دهیم و تیم توسعه به سرعت آنها را رفع کند.دومین روش هم اینکه هات فیکس ها را در لیست جداگانه ای قرار دهیم و تیم توسعه یا بخشی از آن قبل از توسعه امکانات جدید، ابتدا به هات فیکس ها بپردازد.در هر دو روش ریسک انجام نشدن وظایف جدید به دلیل مشغول بودن تیم توسعه به رفع باگ ها وجود دارد اما به نظر میاد روش اول شفاف تر است چرا که مشخص نیست چقدر رفع باگ ها از تیم زمان خواهد برد...</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Mon, 04 Feb 2019 11:00:02 +0330</pubDate>
            </item>
                    <item>
                <title>به مقصد نرسیده ها...</title>
                <link>https://virgool.io/@shayanadc/%D8%A8%D9%87-%D9%85%D9%82%D8%B5%D8%AF-%D9%86%D8%B1%D8%B3%DB%8C%D8%AF%D9%87-%D9%87%D8%A7-h90w7ehtk6kw</link>
                <description>آخرین باری که خودم رو برای یک ارائه آماده میکردم متوجه شدم همه دانسته ها و آموزش هایی که در گذشته بدست آورده بودم قطعی نیستند و نمی توانند عمومیت داشته باشند.اون روزها تب مدل های کسب و کار بسیار برای استارت آپ ها داغ بود اما هیچکدام از این مدل ها برای همه شرایط کارا نبودند ... یا مباحث مربوط به هوش تجاری، کدام الگو به طور قطعی برای کسب و کار مناسب است؟ این روزها آموزش از طریق رسانه های دیجیتال همه زندگی ما را فرا گرفته است، از درمان خانگی تا بدست آوردن یک مهارت شغلی جدید. اما تحقیقات دانشگاهی نشان میدهد آموزش الکترونیک غیر رسمی یا همون اموزش ناخواسته یا ناخوداگاه تاثیر بیشتری در یادگیری ما دارد، در واقع آموزش در محیط دیجیتال هم در خارج از زمانی که شما وقت خود را به آموزش اختصاص داده اید اتفاق میافتد و از این موارد عدم قطعیت بسیار میتوان یافت...در حالی که با سردرگمی به دنبال موضوعی  برای ارائه آماده بودم با بیتی از سعدی مواجه شدم:« به راه بادیه رفتن به از نشستن باطل و گر مراد نیابم به قدر وسع بکوشم». انگار سعدی داشت امیدوارم میکرد به تلاش دوباره و امیدوار بودن. موضوعی که بعد از تلاش دوباره متوجهش شدم این بود که من داشتم تلاش میکردم و این که چطور روزهام به سرعت به سمت روز ارائه سپری میشدند رو حس میکردم. موضوعی که خیلی وقتها بدلیل ایده آل گرایی درونی و بیزاری از روزمرگی، در قالب نگرانی با آن دست و پنجه نرم میکنیم. سعدی در قرن بیست ویکم! شاید با خودتان فکر کنید باید عملکرد پیشینیان ما بی نتیجه بوده باشد. اما ما به دنبال همان نسل هستیم و اختراعات و کشف های مداوم، ما را در رقابت موجودات دیگر به فرمانروای هستی تبدیل کرده. پرسش اینجاست که برتری ما نسبت به سایر موجودات در چه بوده؟بیاید از روز یکم شروع کنیم، اگر بیگ بنگ پیش نمیامد، و آن انفجار زمینه نابودی نسل دایناسورها را فراهم نمیکرد به احتمال فراوان ما الان فرمانروا نبودیم و کره زمین بین چند حکومت فرمانروایی دایناسورها تقسیم شده بود. شاید فکر کنید علاوه بر این فرق ما در ایجاد و امکان تعامل اجتماعی است و این تعامل ما باهم بوده که بعد از این اتفاق تبدیل به فرمانروای زمین شده ایم اما اگر جنگهای پیاپی و نسل کشی هایی که در نسل های مختلف در بین خود انسانها رخ داده است را هم در نظر نگیریم، چیزهای کوچکی و متهیر کننده ای مثل ساختار کندوسازی زنبورها و کار گروهی مورچه ها، نشان میدهد که در کار گروهی هم برنده مطلق ما نیستیم. فرق ما در قدرت فکر و چهارچوب ذهنی است که میتوانیم به ازای هر نفر آنرا به گونه ای متفاوت تخریب کنیم. انسان های متفاوت با باورهای متفاوت.یک میمون را در نظر بگیرید وقتی با موز مواجه میشود به حق مالکیت آن فکر نخواهد کرد و بلادرنگ آنرا برخواهد داشت. یا هیچ فیلی نیست که وقتی بعد از مسیر طولانی به آبشار میرسد با خود بگوید عجب آبشار زیبایی و چه آب زلالی و عکس یادگاری بیاندازد.بشر تنها موجودی است که قدرت انکار و نپذیرفتن واقعیت را دارد. یک سگ گرسنه ادا در نمی آورد که گوشت درون بشقاب، اشتهایش را بر نمی انگیزد. یک گربه وقتی جلو در خانه، زیر باران مانده خجالت نمی کشد یا مراعات پای خیس خود را نمی کند .تفاوت ما در باورهای متفاوت و خلق تصوراتمان است، اگر هر انسانی را به دو نیم کنید حقوقش را پیدا نمی کنید اما سازمان های بسیاری حول خلق مفهوم حقوق بشر شکل گرفته اند. اگر بخواهیم بهتر فکر کنیم باید چهارچوب ذهنی خودمان را تخریب کنیم و البته همین موضوع بسیاری از اوقات ما را به مسیر اشتباه نیز می برد. تا بحال دقت کردید در هفته سلامت چه برنامه هایی از تلویزیون پخش میشوند؟روز اول در مورد بیماری های عروقی، روز دوم در مورد بیماری های خاص ... روز هفتم مرگ و میر ناشی از آلودگی هوا!من فکر میکنم بسیاری از اوقات در برابر مشکلات اینطور فکر میکنیم.خوب ببینید! نظام درمانی حتی در توسعه یافته ترین کشورها نیز دچار چالش است زیرا مبنای خدمات درمانی بر پایه بیماری ها صورت گرفته و نه انسان ها. این ما انسان ها هستیم که قادریم میل و احساسات مان را نادیده بگیریم. ما مدام خودمان را در وضعیت های ناشناخته قرار می دهیم و با آنکه گاهی میدانیم به بیراهه خواهیم رفت سعی در انکار واقعیت داریم.انسان میخواهد به حقایق ازلی و ابدی دست پیدا کند و یک نظام هستی شناختی برای خود متصور شود، از سوی دیگر همین انسان متوجه میشود رسیدن به چنین نظامی ممکن نیست. ابزوردیسم واکنشی به این نیاز و فقدانِ پس از آن است. آثار ابزورد تلاش میکنند به مخاطب نشان دهند که تمام نظامهای معنایی و هستی شناختی شکسته شده اند، خبری از حقیقت مطلق نیست، بدون آن هم نمیشود زندگی کرد. این هفته کامل به خاطر من مانده است، همه دقایق و روزها چرا که من بدون اینکه متوجه موضوع باشم زمان را در کنترل خود گرفته بودم. واقعیت همینه که وقتی تلاش میکنیم عادتی رو به خودمون کم یا اضافه کنیم در مسیر ایجاد چالش هستیم در واقع معنی وجودی خودمان را زندگی کرده ایم. چالش رسیدن به موضوعی یا عادتی باعث میشه احساس بهتری نسبت به خودمون و دنیای پیرامون داشته باشیم.در واقع حق با سعدی بود و به راه بادیه رفتن به از نشستن باطل است.</description>
                <category>shayan hoseini</category>
                <author>shayan hoseini</author>
                <pubDate>Mon, 04 Feb 2019 10:57:54 +0330</pubDate>
            </item>
            </channel>
</rss>