<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>نوشته های مرتضی گودرزی</title><link>https://virgool.ir/feed/@goodarzi.morteza73</link><description>Software Engineer</description><language>fa</language><pubDate>2026-11-11 10:32:35</pubDate><image><url>https://files.virgool.ir/upload/users/1682022/avatar/avatar.png</url><title>مرتضی گودرزی</title><link>https://virgool.ir/@goodarzi.morteza73</link></image><item><title>دل‌نوشته‌ای برای تقدیر و تمجید از افراد تاثیرگذار در زندگی</title><link>https://virgool.ir/@goodarzi.morteza73/دلنوشته-ای-برای-تقدیر-و-تمجید-از-افراد-تاثیرگذار-در-زندگی-dgj2fdsquth0</link><description>امروز دنیا «روز جهانی تعریف و تمجید» را جشن می‌گیرد. در زندگی ما افرادی وجود دارند که می‌توانند الهام بخش زندگی ما باشند و در مسیر پیشرفت ما را یاری کنند. ادب حکم می‌کند که بابت لطف و محبتی که آنها نسبت به ما دارند از آنها تشکر کنیم.در روزهایی که امید به زندگی کمی کم‌رنگ شده و دیدن نیمه‌ی پر لیوان کار آسانی نیست، مایل هستم در این روز از این افراد قدردانی کنم. این کار باعث ایجاد امید و انگیزه در آنها می‌شود و با شکل‌گیری این فرهنگ باعث می‌شویم جامعه‌ای امیدوار‌تر داشته باشیم.« ممکن است افرادی بتوانند همه‌ی گل‌های شما را بچینند، اما هیچ‌کس نمی‌تواند از آمدن بهار جلوگیری کند... »اولین نفری که به ذهنم می‌رسد معلم سال اول هنرستانم است. آقای هوشنگ کولیوند که در حال حاضر شاغل در دانشگاه John Moores در لیورپول انگلستان است. افتخار این را داشتم که در آن مقطع دانش‌آموز درس الگوریتم، فلوچارت با ایشان باشم. نوع نگاه به چالش‌ها و تفکر حل مسئله را از او آموختم و این باعث شد علاقه‌مند به دنیای برنامه‌نویسی شوم. از این بابت از او سپاسگزارم.دومین نفری که قصد قدردانی از او را دارم یکی از دوستانم است. امیر کسی بود که هدیه ای بینظیر به من داد. او به من هنر شک به دانسته‌ها را آموخت. وقتی شما بتوانید به دانسته‌ها، اعتقادات و باورهای خود شک کنید، زندگی از آن روز شکل متفاوتی به خود می‌گیرد؛ اهداف شما و اولویت‌های شما در زندگی دگرگون می‌شوند و باورهایی که شاید زمانی در اولویت بودند را با اکراه از ذهن بیرون می‌کنید. از این بابت از امیر سپاسگزارم.سومین نفری که به ذهنم می‌رسد یک دوست قدیمی است. کمال کریمی همکار سابق؛ کسی که متانت در گفتار را به من آموخت. او بارها به من نشان داد که حتی اگر روزی بهترین برنامه‌نویس دنیا شوم، بدون غرور و تکبر به افرادی که نیاز به راهنمایی برنامه‌نویسی دارند کمک کنم و هیچ وقت خودم را بالاتر از کسی نبینم. همیشه در ادبیات خود از کلماتی استفاده کنم که نه تنها باعث برداشت بد نشود، بلکه باعث شود مخاطب من احساس ارزشمند بودن پیدا کند. از کمال سپاسگزارم.چهارمین نفری که مایلم از او یاد کنم محسن طاووسی است. کسی که اکثرا به واسطه‌ی تخصص و حرفه کاری‌اش (سئو) او را می شناسند. اما من از او به عنوان شخصی یاد می‌کنم که همیشه در شبکه‌های اجتماعی در حال تلاش برای بهبود عملکرد خود و اطرافیانش است. در دنیای پر از خبر مخصوصا در شبکه‌های اجتماعی، یکی از موضوعاتی که اهمیت بسیاری دارد مدیریت توجه است. موضوعی که اهمیت آن را از رشته استوری‌های محسن طاووسی متوجه شدم و بابت آن از محسن ممنونم.آخرین نفری که قصد دارم در این لحظه از او یاد کنم، پیام بهرام‌پور است. مدیر کسب‌و‌کار بیشتر از یک و مجموعه‌ی آرامیا. در روزهایی که همه‌ی ما تحت فشار روانی بودیم، او محصولات آموزشی مجموعه‌ی آرامیا را به صورت رایگان در اختیار عموم قرار داد تا سهم خود را در بهبود روان سالم جامعه انجام داده باشد. این آموزش‌ها  به من کمک کرد تا بتوانم از این شرایط سخت عبور کنم و من آن را کار بسیار بزرگی می دانم. از پیام ممنونم.امیدوارم با این کار کوچک ولی مهم توانسته باشم اندکی حس خوب به دوستانم منتقل کرده باشم.از همه‌ی دوستانی که این مطلب را می‌خوانند دعوت می‌کنم تا از افرادی که در زندگی‌شان تاثیر‌گذار بوده‌اند قدردانی کنند. به امید روزهای بهتر</description><category>مرتضی گودرزی</category><author>مرتضی گودرزی</author><pubDate>Tue, 28 Feb 2023 20:39:23 +0330</pubDate></item><item><title>آموزش دیزاین پترن ریپازیتوری در لاراول</title><link>https://virgool.ir/laravelweb/آموزش-دیزاین-پترن-ریپازیتوری-در-لاراول-tzdbyogcm4ym</link><description>مقدمهآموزش‌های زیادی به زبان فارسی و انگلیسی در این مورد وجود داره، ولی هیچ‌کدوم کامل نیستن و یا به نکاتی که در پروژه‌های واقعی ما رو با چالش روبرو می کنند هیچ اشاره ای نشده.ساختاری رو که قصد دارم شرح بدم توسط چندین برنامه نویس بازنگری شده. اگر دغدغه شما هم اینه که سورس کد تمیز و قابل توسعه‌ای بنویسید، این ساختار خیلی میتونه به شما کمک کنه.هیچ لزومی نداره که داخل پروژه‌های کوچیک از این الگو استفاده کنیم، اما به عنوان توسعه‌دهنده لازمه که یکی از کاربردی‌ترین الگو‌های برنامه‌نویسی رو بشناسیم.هدف دیزاین‌پترن ریپازیتوری ریپازیتوری یک استراتژی برای دسترسی به داده فراهم می‌کنه تا بتونیم عملیات مربوط به دیتابیس رو انجام بدیم. به زبان ساده‌تر؛  این الگو یک wrapper روی Model ایجاد می‌کنه و باعث میشه اصل Solid تا حد زیادی رعایت بشه.در قسمت‌های مختلف یک پروژه عملیات‌هایی پر‌تکرار برای کار با دیتابیس وجود داره. این دیزاین‌پترن که در دستهٔ الگوهای ساختاری قرار میگیره، به ما کمک می‌کنه تا این کدها رو از لایهٔ سرویس جدا کنیم و به لایهٔ Data Access Layer انتقال بدیم. خیلی مزیت در این فرآیند هست که در ادامه بهش اشاره می‌کنیم.دلایل استفاده از دیزاین‌پترن ریپازیتوریرعایت اصل Single Responsibility (اصل اول Solid):  این اصل میگه &#34;هر کلاس باید یک وظیفه واحد داشته باشه&#34;. فرض کنید سرویسی داریم که اطلاعات کاربران رو دریافت می‌کنه و عملیاتی رو روی اون‌ها انجام میده و نتیجه رو به کنترلر برمیگردونه. خب اینجا این اصل نقض شد. سرویس وظیفه دریافت اطلاعات رو باید به کلاس دیگه‌ای واگذار کنه. با کمک ریپازیتوری این کار انجام میشه. رعایت اصل Open Closed (اصل دوم Solid): این اصل میگه &#34;موجودیت‌های یک نرم‌افزار (مثل کلاس‌ها، ماژول‌ها، توابع و ...) باید برای &#39;توسعه‌دادن&#39; باز و برای &#39;تغییر&#39; بسته باشند&#34;. ریپازیتوری دقیقا از این اصل پیروی میکنه و کدهای ما قابلیت باز بودن رو دارن و در عین حال نمیشه اون‌ها رو تغییر داد.رعایت اصل  DRY  (مخفف Don&#39;t Repeat Yourself): این اصل میگه &#34;کدهای تکراری ننویس&#34;. البته که همیشه به این سادگی هم نیست ولی به‌هر‌حال ریپازیتوری به ما کمک می‌کنه که از تکرار کدها جلوگیری کنیم.رعایت اصل Dependency Inversion (اصل پنجم Solid): توضیح این اصل یک پست جداگانه رو میطلبه. اما می تونیم به این جمله بسنده کنیم که &#34; کلاس‌های سطح بالا نباید به کلاس‌های سطح پایین وابسته باشن؛ هر دو باید وابسته به انتزاع (Abstractions) باشن &#34;. فرض کنید توی یه کنترلر به طور مستقیم با Model کار کنیم. اینجا وابستگی شدید بین کنترلر و مدل بوجود میاد. ریپازیتوری اینجا به کمک ما میاد تا به اون کنترلر کمک کنیم که وابسته به Model نباشه.کد ما تست‌پذیر میشه: وقتی قسمت‌های مختلف یک پروژه مستقل از هم باشند، به راحتی می تونیم برای هر قسمت Test‌های مجزا بنویسیم.قابلیت استفاده مجدد: جدا شدن کدهای مربوط به دیتابیس از لایه سرویس باعث میشه کدهای ما قابلیت استفاده مجدد در سرویس های مختلف رو داشته باشن. پیاده‌سازی دیزاین‌پترن ریپازیتوری در لاراولمرحله اول ایجاد یک ساختار مشخص برای کدهای عمومی استفاده از دیتابیسه.| -- app&#xA;    | -- Console&#xA;    | -- Exceptions&#xA;    | -- Http&#xA;    | -- Models&#xA;    | -- Providers&#xA;    | -- Repositories&#xA;        | -- Base&#xA;            | -- BaseRepository.php&#xA;            | -- BaseRepositoryInterface.phpدر مسیر App لاراول یک دایرکتوری به نام Repositories می کنیم. همهٔ فایل‌های مربوط به ریپازیتوری در این قسمت قرار می‌گیره. یک دایرکتوری دیگر به‌نام Base داخل آن میسازیم. در نهایت دو فایل به نام BaseRepository.php و BaseRepositoryInterface.php ایجاد می‌کنیم.در مرحله دوم کدهای زیر رو در این دو فایل می‌نویسیم.BaseRepositoryInterface.php&lt;?php&#xA;&#xA;namespace App\Repositories\Base;&#xA;&#xA;interface BaseRepositoryInterface{&#xA;&#xA;    public function all();&#xA;    public function get(array $condition);&#xA;    public function delete(int $id);&#xA;    public function save(array $data,int $id = null);&#xA;    public function saveMany(array $data);&#xA;    public function truncate();&#xA;&#xA;}متد‌هایی که نوشتیم میتونه بیشتر از این باشه که توضیح هر کدوم باعث میشه از بحث اصلی دور بشیم. این نکته قابل ذکر هست که متدهای این کلاس بر اساس نیازهای ما ایجاد میشه و ممکنه در پروژه‌های مختلف کم یا زیاد بشن. یا پیاده‌سازی این متد‌ها کمی تغییر کنه. به‌هر‌حال این اینترفیس رو باید در فایل BaseRepository استفاده کنیم و اون‌ها رو به شکل زیر پیاده کنیم.BaseRepository.php&lt;?php&#xA;&#xA;namespace App\Repositories\Base;&#xA;use Illuminate\Database\Eloquent\Model;&#xA;&#xA;class BaseRepository implements BaseRepositoryInterface{&#xA;&#xA;    public function __construct(Model $model)&#xA;    {&#xA;        $this-&gt;model = $model;&#xA;    }&#xA;&#xA;    public function all()&#xA;    {&#xA;         return $this-&gt;model-&gt;all();&#xA;    }&#xA;&#xA;    public function get(array $condition)&#xA;    {&#xA;         return $this-&gt;model-&gt;where($condition[0],$condition[1],$condition[2])-&gt;get();&#xA;    }&#xA;&#xA;    public function delete(int $id)&#xA;    {&#xA;        return $this-&gt;model-&gt;findOrFail($id)-&gt;delete();&#xA;    }&#xA;&#xA;    public function save(array $data, int $id = null)&#xA;    {&#xA;        if($id){&#xA;            return $this-&gt;model-&gt;find($id)-&gt;update($data);&#xA;        }&#xA;        return $this-&gt;model-&gt;create($data);&#xA;    }&#xA;&#xA;    public function saveMany(array $data)&#xA;    {&#xA;        return $this-&gt;model-&gt;insert($data);&#xA;    }&#xA;&#xA;    public function truncate()&#xA;    {&#xA;        return $this-&gt;model-&gt;truncate();&#xA;    }&#xA;&#xA;}با در نظر‌گرفتن اینکه متدهای نوشته‌شده کدهای پرتکرار ما هستن، کار ما با این دو تا فایل تمومه. مرحله سوم اینه که به ازای هر Entity در پروژه، ما یک دایرکتوری در مسیر app/Repositories ایجاد کنیم و یک فایل به نام Entity مورد نظرمون بسازیم. برای مثال ما قصد داریم Entity محصولات رو با ریپازیتوری پیاده کنیم. کافیه یک دایرکتوری در مسیر app/Repositories به نام Product ایجاد کنیم و فایل‌های ProductRepository.php و ProductRepositoryInterface.php  رو بسازیم و کدهای زیر رو داخلش بنویسیم. این کار رو برای تمام موجودیت هامون باید انجام بدیم.ProductRepositoryInterface.php&lt;?php&#xA;&#xA;namespace App\Repositories\Product;&#xA;&#xA;use App\Repositories\Base\BaseRepositoryInterface;&#xA;&#xA;interface ProductRepositoryInterface extends BaseRepositoryInterface {&#xA;&#xA;}ProductRepository.php&lt;?php&#xA;&#xA;namespace App\Repositories\Product;&#xA;&#xA;use App\Models\ProductModel;&#xA;use App\Repositories\Base\BaseRepository;&#xA;use Illuminate\Database\Eloquent\Model;&#xA;&#xA;class ProductRepository extends BaseRepository implements ProductRepositoryInterface{&#xA;&#xA;    public Model $model;&#xA;    public function __construct(ProductModel $model)&#xA;    {&#xA;        $this-&gt;model = $model;&#xA;    }&#xA;&#xA;}اینجا یکم دقت بیشتری میطلبه. در فایل ProductRepositoryInterface ما فقط از اینترفیس Base ارث بری کردیم تا این ریپازیتوری رو مجبور کنیم که متدهای عمومی رو پیاده‌سازی کنه. سپس در فایل ProductRepository از اینترفیس جدیدی که ساختیم implement کردیم تا به متدهای عمومی که قبلا ایجاد کرده‌بودیم دسترسی داشته باشیم. اما ما کدهای عمومی رو قبلا ایجاد کردیم. پس نباید دوباره اون ها تعریف بشن  (مگر در صورت نیاز). فقط کافیه از BaseRepository ارث بری کنیم تا به همهٔ متدهای نوشته شده دسترسی داشته باشیم. حالا در دو صورت می تونیم متدهای دیگه ای به این ریپازیتوری اضافه کنیم. حالت اول اینه که ما یک کوئری دیگه‌ای داریم که مختص این موجودیته. پس اون رو توی اینترفیس مینویسیم و در ریپازیتوری پیاده‌سازیش می‌کنیم. حالت دوم اینه که بخواهیم متدی رو تغییر بدیم. مثلا متد all که همهٔ رکوردها رو برمیگردوند، اینجا قراره به صورت صعودی براساس id برگردونه. می تونیم این متد رو اصطلاحا override کنیم (اصل open - closed).مرحله چهارم و مرحله آخر اینه که از این ریپازیتوری ها در لایهٔ سرویس استفاده کنیم. فقط کافیه که در متد construct سرویس، یه آبجکت از ریپازیتوری مورد نظرمون بسازیم. مانند کد زیر:ProductService.phppublic ProductRepositoryInterface $productRepository;&#xA;&#xA;public function __construct()&#xA;{&#xA;     $this-&gt;productRepository = App::make(ProductRepositoryInterface::class);&#xA;}کلیت کاری که انجام دادیم مشخصه. اما شاید براتون این سوال در مورد نحوه آبجکت‌ساختن پیش بیاد. خب ما می‌تونستیم از این کد استفاده کنیم:$this-&gt;productRepository = new ProductRepositoryInterface();دلیل این کار Dependency Injection بود. ما هیچ پارامتری پاس ندادیم. البته تو این مثال فرقی نمیکنه، چون ریپازیتوری هیچ‌وقت قرار نیست از ما ورودی بگیره. اینترفیس‌های ما داخل construct خودشون فقط از یک Model یک شئ خالی میسازن. اما خواستم به این نکته اشاره کنم که سعی کنید آبجکت‌هاتون همیشه به این شکل ساخته بشن. این روش آبجکت‌سازی، هر پارامتری که لازم باشه رو به صورت بازگشتی میسازه و تزریق وابستگی رو خودش مدیریت میکنه.حالا ما می تونیم توی متد مورد نظرمون از این ریپازیتوری استفاده کنیم....&#xA;public function get(array $condition)&#xA;{&#xA;    return $this-&gt;productRepository-&gt;get($condition);&#xA;}&#xA;...مقدار آرایه condition بهتره که از کنترلر بیاد. اما همینجا هم می تونیم یه condition مشخصی ایجاد کنیم و به ریپازیتوری پاس بدیم.ProductController&lt;?php&#xA;&#xA;namespace App\Http\Controllers;&#xA;use App\Services\Product\ProductService;&#xA;&#xA;class ProductController extends Controller&#xA;{&#xA;&#xA;    public function __construct()&#xA;    {&#xA;        $this-&gt;productService = App::make(ProductService::class);&#xA;    }&#xA;    public function get(Request $request)&#xA;    {&#xA;        $categoryId = $request-&gt;input(&#34;category-id&#34;);&#xA;        return $this-&gt;productService-&gt;get([&#34;category_id&#34;,&#34;=&#34;,$categoryId]);&#xA;    }&#xA;&#xA;...&#xA;}دلیل استفاده از سرویس این بود که قسمت business پروژه نباید داخل کنترلر پیاده‌سازی بشه و کنترلر صرفا از طریق لایهٔ سرویس داده‌های مورد نظرش رو میسازه و به فرانت پروژه ارسال می‌کنه.خب کارهای لازم رو انجام دادیم، ولی اگه این متد رو از طریق یه route اجرا کنیم ارور زیر رو میگیریم:متن ارور که مشخصه و برای رفع این ارور باید فایل های ریپازیتوری که ایجاد می کنیم رو اصطلاحا bind کنیم. برای این کار با دستور زیر یک Provider جدید می نویسیم که کارهای مربوط به bind کردن رو انجام بده.php artisan make:provider RepositoryServiceProviderبعد از این کار برای اینکه از این provider جدید استفاده کنیم باید فایل app.php که در دایرکتوری config قرار داره رو ویرایش کنیم و این provider رو معرفی کنیم:&#39;providers&#39; =&gt; [&#xA;...&#xA;/*&#xA; * Custom Service Providers...&#xA; */&#xA;App\Providers\RepositoryServiceProvider::class,&#xA;...در مرحله بعد فقط کافیه در متد register این provider که ساختیم کد زیر رو مینویسیم$this-&gt;app-&gt;bind(&#xA;    ProductRepositoryInterface::class,&#xA;    ProductRepository::class,&#xA;);کارمون تموم شد. حالا ریپازیتوری های ما instantiable هستن و دیگه بدون مشکل کد ما کار خواهد کرد.اشتباهات رایج در استفاده از الگوی ریپازیتوریتوی کنترلر مستقیما از ریپازیتوری آبجکت میسازن و Business پروژه رو میارن توی کنترلر.این الگو فقط یک لایه بین دیتابیس و سرویس شماست و وظیفه سفارشی‌کردن داده‌ها و پردازش اون‌ها رو نداره. پس متدهایی مثل GetPostForCategoryPage رو نباید توی ریپازیتوری پیاده‌سازی کنین.متدهای عمومی ریپازیتوری باید داخل فایلی به نام Base قرار بگیره و نباید در ریپازیتوری های مختلف تکرار بشه. این کار از تکرار کد جلوگیری میکنه.نتیجه گیری سعی کردم با زبان ساده این دیزاین‌پترن رو توضیح بدم. در کنارش کمی هم از اصول Solid و clean code صحبت کردم که هر کدوم نیاز به توضیح مفصل دارن. اگه این مطلب بهتون کمک کرد حتما کامنت بزارید و یا سوال خودتون رو بپرسید.این قسمت از پست رو باز میزارم تا بعدا در مورد اتصال ریپازیتوری به سیستم caching و توضیحات بیشتر در مورد clean code و آموزش های مرتبط دیگه لینک بزارم.</description><category>مرتضی گودرزی</category><author>مرتضی گودرزی</author><pubDate>Wed, 24 Aug 2022 06:18:32 +0430</pubDate></item></channel></rss>