<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های امیر واحدی</title>
        <link>https://virgool.io/feed/@AmirVahedix</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-06-07 15:09:17</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/1003292/avatar/yH09jS.jpeg?height=120&amp;width=120</url>
            <title>امیر واحدی</title>
            <link>https://virgool.io/@AmirVahedix</link>
        </image>

                    <item>
                <title>اسکلت بندی پروژه لاراول با TALL!</title>
                <link>https://virgool.io/@AmirVahedix/laravel-tall-stack-bzldboonel3x</link>
                <description>سلام دوستان! احتمالا اگر لاراول کار هستین اسم TALL Stack به گوشتون خورده. توسعه دهنده های لاراول همیشه سعی داشتن که شما رو توی یه اکوسیستم باحال و خفن قرار بدن که هم شما از کدنویسی لذت ببرین هم بتونین کدهای بقیه توسعه دهنده ها رو خیلی راحت بفهمین و حتی کدهاتون رو با اونها به اشتراک بزارین. یجورایی دوست دارن یه نظمی رو بین برنامه نویسایی که توی این حوزه هستن ایجاد کنن.در واقع شما از یه سری ابزار برای Backend و Frontend سایت خودتون استفاده میکنین که خیلی از توسعه دهنده های دیگه هم دقیقا از همون ابزار ها استفاده میکنن و خیلی راحت تر میتونین با هم ارتباط برقرار کنین. (خودشون بهش میگن Stack!)یکی از این استک ها که جدیدا خیلی بین برنامه نویس ها محبوب شده TALL Stack هستش؛ مخفف Tailwind Alpine Livewire Laravel. چهارتا غول که میتونن برنامه نویسی وب رو برای شما خیلی لذت بخش تر کنن!خب بریم دونه دونه این ابزار ها رو با هم بررسی کنیم و درنهایت یاد بگیریم که چطوری میتونیم وارد این استک بشیم و خودمون رو جزو بچه های TALL Stack بدونیم ?شماره یک : Laravelطبیعتا لاراول معرف حضور همگی هست! یه فریمورک بر پایه PHP که خودش رو به توسعه دهنده ها ثابت کرده و از حدود 10 سال پیش تا الان به محبوبیت خیلی زیادی بین توسعه دهنده ها رسیده. پس هسته اصلی TALL شد خود فریمورک لاراول عزیز.شماره دو : Livewireوقتی که وبسایت رسمی Livewire رو باز میکنیم یه سری دیالوگ جالب نوشته:building dynamic interfaces simple, without leaving the comfort of Laravel.خیلی ساده بخوام بگم ساختن وبسایت های داینامیک، بدون ترک راحتی لاراول! Livewire در اصل یه فریمورک Full-Stack هست که بر روی لاراول سوار میشه و یجورایی یه پل میزنه بین Frontend و Backend سایت شما. خیلی از کارها مثل صفحه بندی داده ها، لایک کردن مطالب، ارسال نظر و... که اگر بخوایم با فریمورک هایی مثل vue و react و... پیاده کنیم کارمون یخورده سخت میشه رو لایووایر خیلی راحت با همون کدهایی که توی بک اند مینویسیم برامون هندل میکنه. نه نیازی به نوشتن API داریم نه هندل کردن اون توی فرانت و نه هیچ کار دیگه. فقط نوشتن یه تابع توی لایووایر و کال کردن اون توی فرانت ?شماره سه : Tailwindتکنولوژی ای که توی چند وقت اخیر خیلی سر و صدا کرده و عملا ما رو از نوشتن CSS خام بی نیاز میکنه و سرعت توسعه ما رو چند برابر میکنه. هرکاری که توی CSS مجبور بودین کلی کد براش بنویسین تبدیل شده به یه سری کلاس های از پیش تعریف شده توی Tailwind، استفاده کنین و لذت ببرین ❤️شماره چهار : Alpine JSوقتی از توسعه وب صحبت میکنیم غیر ممکنه سر و کارمون به JavaScript عزیز نیوفته. یه فریمورک خیلی سبک و جذاب که کارهای خسته کننده‌ای که به صورت دستی توی جاوا اسکرپت (یا حتی jQuery) انجام میدادیم رو خیلی برای ما راحت تر و لذت بخش تر میکنه. ترکیب این دوستمون با Tailwind و کامپوننت های Blade خیلی چیز جالبی در میاد.خب حالا که همه این تکنولوژی های TALL رو معرفی کردیم بریم سراغ اینکه چجوری همه این ها رو روی یه پروژه لاراول سوار کنیم و از قابلیت هاشون لذت ببریم.قدم اول: Laravelخب اول از همه بیاین یه پروژه جدید لاراول نصب کنیم، من اسم پروژه رو tall-stack میزارم:composer create-project laravel/laravel tall-stackخیلی راحت با این دستور کامپوزر میتونیم آخرین نسخه لاراول رو روی سیستم خودمون نصب کنیم. با دستور زیر میتونیم اپلیکیشن لاراولی خودمون رو روی لوکال ببینیمphp artisan serveخب خیلی راحت لاراول رو نصب کردیم، حالا بریم سراغ بقیه بچه ها. اول از لایووایر شروع می‌کنیمقدم دوم: Livewireبرای نصب لایووایر باید پکیج اون رو به پروژه خودمون اضافه کنیمcomposer require livewire/livewireبرای اینکه لایووایر بتونه توی فرانت به درستی کار کنه باید استایل ها و اسکریپت هاش رو به صفحه خودمون اضافه کنیم. قبل از بسته شدن تگ head دایرکتیو (directive) زیر رو اضافه میکنیم تا استایل ها لود بشن:@livewireStylesو برای لود شدن کدهای جاوا اسکریپت لایووایر دایکتیو زیر رو به قبل از بسته شدن تگ body اضافه میکنیم@livewireScriptsبیاین با هم یه کامپوننت ساده شمارنده با لایووایر بسازیم تا مطمعن شیم داره به درستی کار میکنه. لایووایر دستورات آرتیسان خوبی رو بهمون میده برای استفاده از قابلیت هاش. با دستور زیر یه کامپوننت به اسم Counter ایجاد میکنیمphp artisan make:livewire Counterبا این کار یه فایل ویو برای این کامپوننت توی پوشه Resources/views/livewire و یه فایل php برای تعامل با این کامپوننت توی پوشه app/Http/Livewire ایجاد میشه. دوتا فایل که قراره کلی کار ما رو راحت کنن کنار همدیگه.اول از همه بریم توی فایل ویو و کدهای زیر رو که یه متن برای نمایش مقدار شمارنده، یک دکمه برای افزایش، یک دکمه برای کاهش و یک دکمه برای ریست هست رو داخلش قرار میدیم. (استایل دهی رو هم جلوتر انجام میدیم با هم)&lt;div&gt;
    &lt;button&gt;+&lt;/button&gt;
    &lt;span&gt;0&lt;/span&gt;
    &lt;button&gt;-&lt;/button&gt;
    &lt;button&gt;Reset&lt;/button&gt;
&lt;/div&gt;خب برای اینکه این کامپوننت توی صفحه نمایش داده بشه کافیه اون رو به صورت زیر توی blade خودمون استفاده کنیم.&lt;livewire:counter/&gt;کل کدهای welcome.blade.php که صفحه اصلی من هستش به این صورته: &lt;!doctype html&gt;
&lt;html lang=&amp;quoten&amp;quot&gt;
&lt;head&gt;
    &lt;title&gt;TALL Stack&lt;/title&gt;
    @livewireStyles
&lt;/head&gt;
&lt;body&gt;
&lt;div&gt;
    &lt;livewire:counter/&gt;
&lt;/div&gt;

@livewireScripts
&lt;/body&gt;
&lt;/html&gt;خب حالا بریم سراغ کنترلر این کامپوننت لایووایر توی پوشه app/Http/Livewire. طبیعتا یه متغیر برای ذخیره مقدار شمارنده نیاز داریم با سه تا تابع برای افزایش، کاهش و ریست.اول از همه یه property روی کلاس Counter ایجاد میکنیم و مقدار اولیه اون رو برابر با صفر قرار میدیم.public int $counter = 0;حواستون باشه که این property حتما باید public باشه تا بتونیم به صورت اتوماتیک از اون توی ویو خودمون استفاده کنیم.بعد دوتا تابع تعریف میکنیم برای کاهش و افزایش مقدار این متغیر:public function increment()
{
    $this-&gt;counter++;
}

public function decrement()
{
    $this-&gt;counter--;
}توی لایووایر به همین راحتی میتونیم دوتا action ایجاد کنیم که متغیرهای ما رو به دلخواهمون تغییر میدن و این مقدار به صورت خودکار توی ویو آپدیت میشه! بدون هیچ کار اضافه ای.در مرحله سوم هم تابع ریست کردن شمارنده رو مینویسیمpublic function resetCounter()
{
    $this-&gt;reset(&#039;counter&#039;);
    // OR $this-&gt;counter = 0;
}این کار رو به دو روش میتونیم انجام بدیم؛ راه اول اینه که مثل متد increment مقدار متغیر رو به صورت دستی برابر با صفر قرار بدیم (که به صورت کامنت نوشتم). راه دوم و بهتر اینه که از تابع reset خود لایووایر استفاده کنیم تا به صورت اتوماتیک اون رو به مقدار اولیه برگردونه. شاید اینجا زیاد تفاوتی نداشته باشه، ولی توی کامپوننت های پیچیده تر خیلی به کارمون میاد این تابع reset.خب حالا که کارمون با کنترلر این کامپوننت تموم شد بریم و این توابع رو توی ویو خودمون استفاده کنیم.&lt;div&gt;
    &lt;button wire:click=&amp;quotdecrement&amp;quot&gt;-&lt;/button&gt;
    &lt;span&gt;{{ $counter }}&lt;/span&gt;
    &lt;button wire:click=&amp;quotincrement&amp;quot&gt;+&lt;/button&gt;
    &lt;button wire:click=&amp;quotresetCounter&amp;quot&gt;Reset&lt;/button&gt;
&lt;/div&gt;برای اینکه یه تابعی که توی کنترلر لایووایر نوشتیم رو بتونیم از توی ویو کال کنیم، کافیه از wire:click استفاده کنیم و اسم اون تابع رو بهش پاس بدیم! بقیه کارها رو خود لایووایر هندل میکنه. برای سه تا دکمه ای که داشتیم من همینکار کردم.حالا که دکمه های خودمون رو به توابع (یا به اصطلاح همون action) های لایووایر وصل کردیم، باید مقدار شمارنده رو هم توی سایت نمایش بدیم. برای اینکار خیلی راحت میتونیم مثل یه متغیر ساده که قبلا توی کنترلر ها پاس میدادیم و توی ویو ازش استفاده میکردیم؛ کافیه که از {{ $counter }}  استفاده کنیم تا این مقدار هم به درستی نمایش داده بشه.نکته جالب کار هم همینجاست، متغیرهایی که توی لایووایر داریم مثل متغیرهایی که از توی کنترلر ها پاس میدادیم نیست که مرده باشن! این متغیرها وقتی مقدارشون تغییر کنه به صورت خودکار توسط لایووایر آپدیت میشن و ویو ما هم به صورت خودکار آپدیت میشه!خب حالا نتیجه کار رو میتونیم توی مرورگر با اجرای دستور محبوب php artisan serveروی پورت 8000 ببینیم. (سورس کامل رو هم در انتها براتون قرار میدم)یه نکته ای رو هم همینجا بهتون بگم راجع به لایووایر. احتمال زیاد وقتی که با این شمارنده کار کردین متوجه شدین که Real-Time نیست داستان، یجورایی لگ داره. این داستان برمیگرده به ماهیت لایووایر که اصلا برای همچین کارهایی مثل یک شمارنده ساخته نشده! وقتی که شما یک اکشن لایووایر رو کال میکنین یک درخواست به  سرور ارسال میشه، توی سرور مقدار این متغیر تغییر میکنه، مقدار جدید برمیگرده به لایووایر و خودش ویو ما رو آپدیت میکنه. یعنی عملا این داستان سمت فرانت هندل نمیشه که بخوایم یه شمارنده Real-Time داشته باشیم.با این اوصاف یعنی لایووایر به درد نمیخوره؟ ? به هیچ وجه اینطور نیست. هر تکنولوژی ای وقتی در جای خودش استفاده بشه خیلی هم میتونه کمک کننده باشه. به عنوان مثال صفحه بندی و سرچ اطلاعات؛ بدون لایووایر شما برای اینکه به عنوان مثال 2000 داده رو صفحه بندی کنی و بخوای قابلیت سرچ هم به کاربر بدی بدون اینکه کاربر مجبور باشه صفحه رو ریفرش کنه؛ باید برید سراغ فریمورک های جاوااسکریپی و نوشتن API و... که نیازی به توضیح نداره حجم کار. اما توی لایووایر این کار 1 دقیقه‌ست! چجوریش دیگه از حوصله این مقاله خارجه، یه لینک میزارم اگه دوست داشتین بررسی کنین: لینک  قدم سوم: Tailwindبرای داشتن یه چارچوب کاری مدرن طبیعتا نیاز به یه راه جدید برای نوشتن CSS قدیمی و وقت گیر داشته باشیم. اینجاست که Tailwind به کارمون میاد و سرعت کارمون رو خیلی بالا میبره.برای نصب Tailwind طبق مستندات خود کتابخونه اول از همه باید خود tailwind و postcss و autoprefixer رو از طریق npm نصب کنیمnpm install -D tailwindcss postcss autoprefixerبعد از اون با دستور زیر کانفیگ پیشفرض tailwind رو ایجاد میکنیمnpx tailwindcss init -pحالا توی فایل کانفیگ مشخص میکنیم که فایل های ورودی ما کجان. یعنی توی چه فایلهایی قراره از کلاس های تیلویند استفاده کنیم تا بانلدر ما بتونه اونها رو به کدهای css خام تبدیل کنه و در اختیار ما قرار بده.توی فایل tailwind.config.js قسمت کانتنت میتونیم نوع  فایلهامون رو مشخص کنیمcontent: [  
  &amp;quot./resources/**/*.blade.php&amp;quot
],بهش گفتم که برو توی پوشه resources، بعد ** به معنای &quot;هر پوشه ای&quot; هست؛ یعنی برو توی تک تک پوشه های اونجا (هم خود پوشه ها هم پوشه های داخل پوشه ها تا اخر) و هرچی فایل که با پسوند .blade.php هست رو پیدا کن و برای من بیلد بگیر.طبیعتا اگه از فایل های vue یا js یا jsx استفاده میکنین هم میتونین به همین صورت اونها رو مشخص کنین. حتی اگه فایل های blade تون توی پوشه متفاوتی هست میتونین اینجا براش مشخص کنین (مثلن توی پوشه مخصوص module ها)خب حالا باید یه فایل CSS خام داشته باشیم برای چی؟ اول اینکه که بتونیم اون رو به فایل blade خودمون لینک کنیم. دوم اینکه tailwind استایل هایی که بیلد میگیره رو اونجا اعمال کنه. سوم اینکه استایل های پایه tailwind رو هم اونجا اعمال کنیم تا تیلویند بتونه درست کار کنه. برای اینکار توی resources/css/app.css من ایمپورت های زیر رو اضافه میکنم@tailwind base; 
@tailwind components; 
@tailwind utilities;حالا  باید این فایل css رو به صفحه خودمون اضافه کنیم. من از Vite استفاده میکنم که کار رو خیلی برامون راحت کرده. قبل از بسته شدن تگ Head:@vite(&#039;resources/css/app.css&#039;)دیگه خودش تشخیص میده که فایل ورودی ما توی resources هستش و توی پروداکشن قراره از فایلی که توی پوشه پابلیک بیلد گرفته میشه استفاده کنه! این هم از زیبایی های Vite.خب بریم یه سری استایل به اون Counter خودمون بدیم تا مطمعن شیم درست کار میکنه. (لیست کامل استایل ها رو میتونین توی مستندات Tailwind چک کنین طبیعتا)کل کار tailwind با استفاده از کلاس ها انجام میشه. به کلاس هایی که دادم دقت کنین، مطمعنم که میتونین معنی هر کلاسی که اعمال شده رو بفهمید. فایل counter.blade.php:&lt;div class=&amp;quotflex flex-col items-center justify-center p-4 gap-4&amp;quot&gt;
    &lt;div class=&amp;quotflex items-center gap-12&amp;quot&gt;
        &lt;button
            wire:click=&amp;quotdecrement&amp;quot
            class=&amp;quotbg-amber-400 text-4xl px-2 text-white rounded-md hover:bg-amber-500 transition-all hover:shadow-md&amp;quot
        &gt;-&lt;/button&gt;
        &lt;span class=&amp;quotbg-gray-300 p-5 rounded&amp;quot&gt;{{ $counter }}&lt;/span&gt;
        &lt;button
            wire:click=&amp;quotincrement&amp;quot
            class=&amp;quotbg-amber-400 text-4xl px-2 text-white rounded-md hover:bg-amber-500 transition-all hover:shadow-md&amp;quot
        &gt;+&lt;/button&gt;
    &lt;/div&gt;
    &lt;button
        wire:click=&amp;quotresetCounter&amp;quot
        class=&amp;quotbg-red-500 text-2xl px-2 text-white rounded-md hover:bg-red-600 transition-all hover:shadow-md&amp;quot
    &gt;Reset&lt;/button&gt;
&lt;/div&gt;برای اینکه این کلاس ها اعمال بشن کافیه دستور npm run dev روی توی ترمینال اجرا کنین تا توی حالت watch قرار بگیره. البته اگه از vite استفاده میکنین خودش به صورت اتوماتیک وقتی تغییری اعمال میکنین ریلود میکنه صفحه رو بعد از اجرای این دستور :)خب حالا صفحه رو چک کنین و استایل ها رو ببینید که بدون حتی نوشتن یک خط css پیاده شده.قدم چهارم: Alpineخب حالا که نمیخوایم از فریمورک های بزرگ (و صد البته سنگین) جاوا اسکریپی استفاده کنیم، لاراول به ما پیشنهاد میده که از یه فریمورک خیلی مینیمال و سبک به اسم AlpineJS استفاده کنیم. بنظرم ایده کار رو از تیلویند گرفته این دوستمون. کارش اینه که مث تیلونید که استایل میدادی بدون css، خب، اسکریپت مینویسی بدون اینکه مستقیما جاوا اسکریپت بنویسی ?بریم همین counter ساده ای که با لایووایر نوشتیم رو با آلپاین بازنویسی کنیم و اون رو بزاریم برای کارهای بزرگتر و سنگین تر. (این رو هم بگم که Alpine با لایووایر خیلی خوب مچ میشه و میتونن یه سری کارهای باحال رو با هم انجام بدن که توی این لینک میتونین بخونین راجع بهش)خب اول از همه بریم آلپاین رو با استفاده از npm نصب کنیم:npm install alpinejs بعد آلپاین رو به فایل JS خودمون اضافه میکنیم و اون رو به فایل blade خودمون لینک میکنیم:توی فایل app.js:import Alpine from &#039;alpinejs&#039;

window.Alpine = Alpine

Alpine.start()با اینکار موتور Alpine شروع به کار میکنه. یادتون باشه که این فایل app.js رو به فایل blade خودتون هم اضافه کنین. قبل از بسته شدن تگ body:@vite(&#039;resources/js/app.js&#039;)خب حالا میتونیم از قابلیت های alpine عزیز استفاده کنیم.آلپاین کلا بر اساس دایرکتیو ها کار میکنه. مهمترین دایرکتیوی که توی آلپاین داریم x-data هستش. آلپاین فقط توی تگ هایی کار میکنه که داخل یه x-data قرار گرفته باشن و کاری به بقیه نداره.توی فایل counter.blade.php که قبلا ساخته بودیم توی بالاترین تگ div من x-data رو اضافه میکنم و متغیر count رو تعریف میکنم و مقدار اون رو برابر با 0 قرار میدم:&lt;div 
    x-data=&amp;quot{ count: 0 }&amp;quot
    ...
&gt;
  ...
&lt;/div&gt;به همین راحتی یه متغیر تعریف کردیم. حالا چجوری مقدارش رو نمایش بدیم؟ با دایرکتیو x-text! این دایرکتیو رو به span خودمون اضافه میکنیم و داخلش چیزی نمینویسیم:&lt;span x-text=&amp;quotcount&amp;quot &gt;&lt;/span&gt;حالا باید به جای تمام wire:click هایی که داشتیم از دایرکتیو x-on:click استفاده کنیم.// for decrement
x-on:click=&amp;quotcount--&amp;quot

// for increment
x-on:click=&amp;quotcount++&amp;quot

// for reset
x-on:click=&amp;quotcount = 0&amp;quotاین دایرکتیو ها رو به جای ایونت های کلیک لایووایر قرار بدین و خیلی راحت از alpine لذت ببرین. امیدوارم alpine نظرتون رو جلب کرده باشه تا یه سر به داکیومنتش بزنین تا ببینین دیگه چه کارهایی از دستش بر میاد.خب این هم از مقاله TALL Stack که خودم به شخصه خیلی این ستاپ اولیه رو دوست دارم. سورس این کدهایی که نوشتیم رو میتونین توی این لینک گیتهاب ببینین. امیدوارم این مقاله به کارتون اومده باشه. خوشحال میشم نظرتون رو برام بنویسین ❤️</description>
                <category>امیر واحدی</category>
                <author>امیر واحدی</author>
                <pubDate>Tue, 21 Feb 2023 18:40:16 +0330</pubDate>
            </item>
                    <item>
                <title>بررسی معماری Clean در فلاتر Flutter</title>
                <link>https://virgool.io/@AmirVahedix/%D8%A8%D8%B1%D8%B1%D8%B3%DB%8C-%D9%85%D8%B9%D9%85%D8%A7%D8%B1%DB%8C-clean-%D8%AF%D8%B1-%D9%81%D9%84%D8%A7%D8%AA%D8%B1-flutter-wt0sd8mbym4m</link>
                <description>معماری Clean در Flutterپیدا کردن یه معماری خوب برای پیاده‌سازی اپلیکیشن کار راحتی نیست و نیاز به تجربه زیادی داره. اگه از همون اول توسعه اپلیکیشن راه منطقی و منظمی رو پیش نگیریم؛ در گذر زمان هم توسعه اپلیکیشن برای ما سخت میشه و هم ممکنه در حین توسعه باگ‌های زیادی رو به صورت ناخواسته به وجود بیاریم که فیکس کردن اونها شاید کار ساده‌ای نباشه. حتی ممکنه شما از یک معماری برای پیاده‌سازی یه اپلیکیشن استفاده کنید و باهاش راحت باشید و جواب هم بگیرید، ولی همون معماری توی یه اپلیکیشن دیگه زیاد جوابگو نباشه. پس معماری نرم‌افزار چیزی نیست که بتونیم یک نسخه بپیچیم برای تمامی نرم‌افزارها.ولی طبیعتا سطح همه برنامه‌نویس ها در اون سطحی نیست که بتونن یک معماری رو از صفر ایده‌پردازی و  پیاده کنن و اپلیکیشن خودشون رو بر اون اساس توسعه بدن.یه راه حل اینه که از معماری‌های معروف دنیای برنامه‌نویسی که امتحان خودشون رو پس دادن استفاده کنیم! مثل معماری MVC یا MVVM یا MVP یا چیزهای دیگه.معماری‌ای که امروز من میخوام راجع به اون صحبت کنم معماری Clean هست که این روزها توی دنیای فلاتر خیلی داره مورد استفاده قرار میگیره.یکی از مهمترین چیزهایی که باید توی پیاده سازی یک معماری رعایت بشه اصل SoC یا Seperation of Concern یا جداسازی توجه هستش. (امیدوارم ترجمه خیلی بدی نکرده باشم?) به این معنی که ما به عنوان مثال وسط کدهای UI خودمون نیایم و یهو دیتایی رو از اینترنت دریافت کنیم، اون رو مدیریت کنیم و حتی همونجا State Management رو هم انجام بدیم. کم کم بریم راجع به منطق معماری Clean صحبت کنیم؛ این معماری به طور کلی از 3 لایه تشکیل شده:معماری Clean در Flutterلایه Data &amp; Platform:این لایه بیرونی‌ترین لایه اپلیکیشن ما هست، منظورم از بیرونی‌ترین لایه اینه که بیشترین ارتباط رو با دنیای بیرون اپلیکیشن داره. این لایه دو قسمت کلی دارهقسمت اول Data هست که وظیفه تامین داده رو از منابع بیرونی (سرور، دیتابیس لوکال و...) داره، یعنی کدهایی که برای ارتباط با سرور (API) و کدهایی که برای خوندن داده از Local Database و... استفاده میشن توی این قسمت قرار دارن.قسمت دوم Platform هست که در واقع همون ویجت‌ها و صفحاتی هست که UI ما رو تشکیل میدن و کاربر با اونها تعامل داره.پس دوتا منبع بیرونی داریم که توی این لایه باهاشون کار میکنیم: منابع داده (سرور و دیتابیس) و خود کاربر (یه سری چیزا بهش نشون میدیم و یه سری ورودی‌ها  ازش میگیریم) لایه Presentation:این لایه شامل کدهایی هستش که وظیفه تامین داده رو برای Platform Layer یا همون UI اپلیکیشن ما بر عهده دارن. این لایه هم از 2 بخش تشکیل شده: Repository و Presenterکار قسمت Repository به این صورت هست که داده رو از Data Layer درخواست میکنه و اون داده‌های خامی که از لایه داده گرفته رو تبدیل میکنه به داده‌های قابل استفاده توی اپلیکیشنو اما قسمت Presenter: توی این لایه ما به داده دسترسی داریم و کار اصلی این لایه State Management (مدیریت وضعیت) هست. کتابخونه‌هایی مثل BLoC، Provider، Riverpod و... کارشون رو توی این لایه انجام میدن.لایه Domain:این لایه درونی‌ترین لایه توی معماری Clean هست. کدهایی که مربوط به Business Logic ما میشن، Modelها، Usecaseها، Repositoryها و... توی این لایه قرار میگیرن.شاید یه سوال براتون پیش اومده باشه اون هم اینکه Repositoryها مگه توی Presentation Layer نبودن؟ پس اینجا چیکار میکنن؟! ماجرا به این صورته که ما کلاس Repository خودمون رو به صورت Abstract توی Domain پیاده میکنیم، بعد این کلاس توسط Repositoryهایی که توی لایه Presentation هستن ارث بری میشن. چون ممکنه برای تامین داده قرار باشه از چند منبع داده گرفته بشه (سرور، دیتابیس یا حتی کش) بهتره که Repository رو به صورت Abstract توی Domain Layer پیاده کنیم معماری Clean در Flutterنکته قابل توجه این هستش که تمام لایه های اپلیکیشن ما به هم دیگه وابسته ان و با همدیگه ارتباط تنگاتنگی دارن.تنها لایه‌ای که به بقیه لایه‌ها وابسته نیست Domain Layer هستش که شامل Business Logic ما میشه. به همین خاطر اگه به عنوان مثال ما بخوایم State Management خودمون رو از BLoC به Riverpod تغییر بدیم به عنوان مثال، نیازی به تغییر در کدهای لاجیک اصلیمون نداریم. (مدل‌ها و...) ساختار زیر یک Folder Structure خوب برای پیاده‌سازی این معماری رو نشون میده:lib
├── data
│   ├── constants.dart
│   ├── datasources
│   │   └── remote_data_source.dart
│   ├── exception.dart
│   ├── failure.dart
│   ├── models
│   │   └── weather_model.dart
│   └── repositories
│       └── weather_repository_impl.dart
├── domain
│   ├── entities
│   │   └── weather.dart
│   ├── repositories
│   │   └── weather_repository.dart
│   └── usecases
│       └── get_current_weather.dart
├── injection.dart
├── main.dart
└── presentation
    ├── bloc
    │   ├── weather_bloc.dart
    │   ├── weather_event.dart
    │   └── weather_state.dart
    └── pages
        └── weather_page.dartفولدر Presentation هم شامل Presentor میشه هم UI. لایه Presentor داره به وسیله BLoC کار State Management رو انجام میده. فولدر Data هم شامل خود Data Provider ها میشه هم شامل Repository ها که داده‌ها رو به صورت مدل برای قسمت Presentor فراهم میکنه.امیدوارم تونسته باشم توی این مقاله دید خوبی از این معماری بهتون بدم.Sources:https://dev.to/george_andronchik/clean-architecture-of-flutter-application-part-1-theory-3b6phttps://betterprogramming.pub/flutter-clean-architecture-test-driven-development-practical-guide-445f388e8604    </description>
                <category>امیر واحدی</category>
                <author>امیر واحدی</author>
                <pubDate>Sat, 28 May 2022 23:37:44 +0430</pubDate>
            </item>
                    <item>
                <title>10 پلاگین کاربردی VS Code برای فلاتر Flutter (بخش اول)</title>
                <link>https://virgool.io/Rocket/5-%D9%BE%D9%84%D8%A7%DA%AF%DB%8C%D9%86-%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%D8%AF%DB%8C-vs-code-%D8%A8%D8%B1%D8%A7%DB%8C-%D9%81%D9%84%D8%A7%D8%AA%D8%B1-flutter-%D8%A8%D8%AE%D8%B4-%D8%A7%D9%88%D9%84-ze0nr3s0samb</link>
                <description>پلاگین‌های کاربردی VS Code برای فلاتر Flutterیکی از بهترین قابلیت هایی که VS Code در اختیار ما برنامه‌نویس ها قرار میده، استفاده از Extension یا افزونه‌ها توی اون هستش. هر برنامه‌نویسی میتونه افزونه‌های خودش رو توسعه بده و اون ها رو برای استفاده عموم منتشر کنه. در واقع اگه افزونه ها نبودن، نمیتونستیم به راحتی الان اپلیکیشن های فلاتری خودمون رو توی VS Code توسعه بدیم و الان همگی داشتیم از Android Studio استفاده میکردیم و RAM و CPU سیستم خودمون رو در راه استفاده از اندروید استودیو فدا میکردیم :)توی این ویرگول میخوام 5 تا از کاربردی‌ترین افزونه‌های VS Code رو خدمتتون معرفی کنم تا نهایت لذت رو از برنامه نویسی ببرین.افزونه های رسمی فلاتر (Flutter &amp; Dart Extension)اولین مورد افزونه رسمی خود فلاتر و دارت هستش که پشتیبانی از زبان دارت و فریمورک فلاتر رو به VS Code شما اضافه میکنه. قابلیت‌هایی مثل Format کردن خودکار کدها، اجرا کردن برنامه از طریق VS Code، دیباگ کردن کدها از طریق VS Code و تمام قابلیت های حیاتی رو به VS Code شما اضافه میکنه.لینک افزونه Flutter  -  لینک افزونه Dartافزونه Flutter2.  افزونه Dart Data Class Generatorاگه با فلاتر به طور حرفه ای کار کرده باشین، مخصوصا با معماری هایی مثل BLoC، این افزونه خیلی به کارتون میاد. به عنوان مثال خیلی وقت ها شده که میخوایم مدلی رو برای دیتاهامون درست کنیم ولی ساختن متدهای toMap و fromMap برای کار کردن با دیتایی که از سرور میاد خیلی از وقتمون رو گرفته باشه. این افزونه خیلی راحت این متدها رو به طور اتوماتیک برامون میسازه. یا مواقعی که برای State Management به متد copyWith برای ساده تر کردن کارمون نیاز داریم این متد رو هم خودکار برامون ایجاد میکنه. علاوه بر اینها میتونین با این افزونه constructor رو به صورت خودکار برای کلاسهاتون ایجاد کنین، متد toString اونها رو ایجاد کنید و همچنین متد equality اونها رو override کنین (نیاز شما رو به پکیج Equatable در بحث State ها رو هم رفع میکنه). لینک این افزونهافزونه Dart Data Class Generator3. افزونه dart-importافزونه مورد علاقه من بین تمام این افزونه ها :) خیلی راحت و با یک کلیک کل ایمپورت های شما رو بهینه سازی میکنه! این شکلی از ایمپورت های من هستش قبل بهینه سازی:و این هم ایمپورت ها بعد از بهینه سازی:خیلی مرتب تر و تمیز تر. البته که میتونیم این کار رو به صورت دستی هم انجام بدیم، ولی این افزونه خیلی راحت و با یک کلیک همه این کارها رو برامون انجام میده. برای استفاده از اون هم فقط کافیه از قسمت Action های VS Code (میانبر من F1 هستش برای شما رو نمیدونم)، گزینه Fix imports رو کلیک کنید.لینک این افزونه4. افزونه bloc:اگه استفاده از معماری bloc رو بلد باشین، این افزونه خیلی میتونه بهتون کمک کنه. ساختار اولیه bloc و cubit رو به صورت خودکار براتون ایجاد میکنه. ویجت ها رو به صورت اتوماتیک با BlocListener و BlocBuilder و BlocProvider و ... رپ میکنه. و خیلی چیزهای دیگه که توی استفاده از bloc کار شما رو آسون میکنه.لینک این افزونه5. افزونه Error Lens:بعضی ها ممکنه این افزونه رو دوست داشته باشن و بعضی ها هم مثل من از اون متنفر باشن! کاری که این افزونه میکنه اینه که متن کامل ارورها رو روبروی اون خطی که ارور داره به طور کامل مینویسه. از یه طرف خوبه که ارورها رو خیلی راحت پیدا میکنین. از یه طرف هم محیط کدنویسی شما رو خیلی شلوغ میکنه که به همین خاطر من ازش خوشم نمیاد و استفاده نمیکنم.لینک این افزونه هر زمان افزونه به درد بخور دیگه ای برای VS Code پیدا کنم توی بخشهای بعدی با شما به اشتراک میزارم. روز خوبی داشته باشین!</description>
                <category>امیر واحدی</category>
                <author>امیر واحدی</author>
                <pubDate>Mon, 02 May 2022 00:18:52 +0430</pubDate>
            </item>
                    <item>
                <title>چرا از Cross Platform بودن فلاتر استفاده نکنیم؟</title>
                <link>https://virgool.io/@AmirVahedix/%DA%86%D8%B1%D8%A7-%D8%A7%D8%B2-cross-platform-%D8%A8%D9%88%D8%AF%D9%86-%D9%81%D9%84%D8%A7%D8%AA%D8%B1-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D9%86%DA%A9%D9%86%DB%8C%D9%85-fydbpvu0cvhk</link>
                <description>طبیعتا همه کسایی که میخوان برنامه نویسی فلاتر رو شروع کنن، یکی از مهمترین فاکتور هایی که بخاطر اون فلاتر رو انتخاب میکنن خروجی گرفتن در چند پلتفرم هستش. یک Codebase واحد که برای ما خروجی اندروید، iOS، ویندوز، وب و … رو میده؛ خیلی قابلیت خوبیه!ولی چیزی که امروز میخوام راجع بهش صحبت کنم، اینه که چرا از این قابلیت خفن استفاده نکنیم!احتمالا با Design System ها آشنایی دارین، اصول طراحی ای که هر پلتفرم توی طراحی رابط کاربریش رعات میکنه. مثلا اندروید از Material Design استفاده میکنه، iOS از Apple Human Interface، ویندوز از  Fluent Design System و …طبیعتا شما وقتی که داری یه اپلیکیشن اندروید توسعه میدی بهتره که از material design استفاده کنی تا تجربه کاربری بهتری واسه کاربرها فراهم کنی. همچنین توی iOS و ویندوز هم بهتره که از دیزاین سیستم خود اون پلتفرم های استفاده کنیم.نکته مثبت داستان اینه که فلاتر از این دیزاین سیستم ها پشتیبانی میکنه، اگه بخوای از استایل های متریال استفاده کنی فقط لازمه که material.dart رو ایمپورت کنی، اگه بخوای از استایل های iOS استفاده کنی فقط لازمه cupertino.dart رو ایمپورت کنی.کلی ویجت با استایل های استاندارد سیستم عامل در اختیارت میزاره، به همین سادگی! (البته fluent design هنوز پشتیبانی رسمی نداره)خب حالا مشکل چیه؟شما وقتی اپلیکیشن خودت رو داری توسعه میدی، یا از ویجت های متریال استفاده میکنی یا از ویجت های کوپرتینو. (فعلا همین دوتا روبحث میکنم)اگه بخوای توی اندروید از دکمه استایل اندروید استفاده کنی باید ElevatedButton استفاده کنی، و برای دکمه با استایل iOS بجای اون باید از CupertinoButton استفاده کنی.حالا چجوری توی هرکدوم از این سیستم عامل ها دکمه (یا هر ویجتی) با استایل خود اون سیستم عامل رو نشون بدیم؟ با شرط چک کردن سیستم عامل!Platform.isAndroid ? ElevatedButton() : CupertinoButton()این به مثال ساده بود، حالا فرض کنین برای نصف ویجت های اپلیکیشن مجبور شیم شرط چک کردن سیستم عامل بنویسیم. یا حتی بدتراز اون، کارفرما بخواد پشتیبانی از ویندوز رو هم اضافه کنه! باید if else یا switch case بنویسیم واسه ویجت هایی که استایل متفاوتی توی دیزاین سیستم این پلتفرم ها دارن.(البته راه های ساده تری هم واسه این کار وجود داره ولی اون چیزی که ما میخوایم شاید در نیاد)مشکل از اینها بزرگتر هم میشه، اون هم جاهایی که دیزاین سیستم اندروید و iOS از اساس متقاوت میشه. فرض کنین طراح UI اپلیکیشن شما، تصمیم میگیره UI اپلیکیشن شما توی iOS رو بر اساس  BottomNavigation طراحی کنه ولی دیزاین Android رو بر اساس TabBar! که دوتا ساختار کاملا متفاوت هستن.چیزی که شما در نهایت باهاش مواجه میشین به احتمال زیاد یه کد به هم ریخته، پر از شرط های تکراری، با خوانش پایین هستش.چیزی که میخوام مطرح کنم اینه که بیخیال نوشتن یه codebase واحد و انتشار اون روی همه پلتفرم ها بشیم.جای اون تمرکز خودمون رو روی جداکردن Business Logic از Presentation Layer بزاریم. به عنوان مثال برای یه اپ موبایل دو پروژه داشته باشیم که از logic مشترکی استفاده میکنن، ولی UI اپلیکیشن و تجربه کاربری اون بر اساس همون پلتفرم طراحی شده.بنظرم ایده خوبی میتونه باشه مخصوصا برای پروژه های بزرگ. مشکلی از بابت Scale پذیری پروژه نخواهیم داشت توی بحث Flutter UI. اگه کارفرما تصمیم به اضافه کردن ساپورت وب یا ویندوز بگیره، ما میتونیم یه پروژه مخصوص وب ایجاد کنیم که لاجیکش هیچ تفاوتی با اپلیکیشن های ما نداره (State Management، ارتباط با سرور، ارتباط با دیتابیس یا هرچیز مشابه این رو نیاز نیست از اول پیاده سازی کنیم) فقط تنها کاری که باید بکنیم پیاده کردن UI مناسب یک وبسایت هستش. طبیعتا کار جالبی نیست که ما دقیقن همون استایل اپلیکیشن اندروید رو بیاریم و به عنوان یک وبسایت ارائه بدیم :)  به عنوان مثال توی یه اپلیکیشن فروشگاهی، لاجیک سبد خرید رو میتونیم تبدیل کنیم به یه پکیج لوکال. این پکیج لوکال ما قراره که همه عملیات ارتباط با سرور جهت ذخیره سازی سبد خرید و پرداخت رو توی خودش داشته باشه و هندل کنه. بعد از اون میتونیم هر چند تا پروژه که بخوایم برای سیستم عامل های متفاوت ایجاد کنیم و از این لاجیک استفاده کنیم.از اینجا به بعد هر پروژه مخصوص یه سیستم عامل هستش و مشکل شرط های تکراری برای UI، پکیج های بی استفاده توی بعضی سیستم عامل ها، مقیاس پذیری پایین بعد توسعه توی چند سیستم عامل و خوانایی پایین کد بعد بزرگ شدن پروژه رو تا حدودی میتونیم برطرف کنیم.اگه تجربه ای توی این زمینه دارین خوشحال میشم توی کامنت ها مطرح کنین.</description>
                <category>امیر واحدی</category>
                <author>امیر واحدی</author>
                <pubDate>Sat, 16 Apr 2022 14:08:27 +0430</pubDate>
            </item>
            </channel>
</rss>