<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های امیرمحمد ابوالحسنی</title>
        <link>https://virgool.io/feed/@am-abolhasani</link>
        <description>برنامه نویس فرانت‌اند</description>
        <language>fa</language>
        <pubDate>2026-06-16 21:28:41</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/3947635/avatar/oFaXSZ.jpg?height=120&amp;width=120</url>
            <title>امیرمحمد ابوالحسنی</title>
            <link>https://virgool.io/@am-abolhasani</link>
        </image>

                    <item>
                <title>کدنویسی تمیز: نکات کلیدی از دوره‌ی Maximilian Schwarzmüller - بخش دوم</title>
                <link>https://virgool.io/@am-abolhasani/%DA%A9%D8%AF%D9%86%D9%88%DB%8C%D8%B3%DB%8C-%D8%AA%D9%85%DB%8C%D8%B2-%D9%86%DA%A9%D8%A7%D8%AA-%DA%A9%D9%84%DB%8C%D8%AF%DB%8C-%D8%A7%D8%B2-%D8%AF%D9%88%D8%B1%D9%87-%DB%8C-maximilian-schwarzm%C3%BCller-%D8%A8%D8%AE%D8%B4-%D8%AF%D9%88%D9%85-oq8c2tx77dy4</link>
                <description>در این مقاله قصد دارم نکاتی را که از مشاهدهی دورهی «کد تمیز» به تدریس Maximilian Schwarzmüller  آموختهام، با نگارشی شخصی و ساده با شما به اشتراک بگذارم. اگر هنوز بخش اول این مقاله را مطالعه نکردهاید، توصیه میشود پیش از ادامه، آن را مرور کنید. اکنون به سراغ این موضوع میرویم که چه عواملی یک تابع یا متد تمیز را تعریف میکنند.توابع و متدهانوشتن یک تابع تمیز مستلزم توجه به چند نکتهی کلیدی است. هم نگارش و هم فراخوانی تابع باید ساده، شفاف و قابلدرک باشد. کار با توابع نباید پیچیده یا گیجکننده باشد.یکی از اصول بنیادین در این زمینه، توجه به تعداد و ترتیب ورودیهاست. هرچه یک تابع پارامترهای کمتری داشته باشد، خواندن و نگهداری کد آسانتر خواهد بود. در حالت ایدهآل، یک تابع نباید هیچ ورودیای داشته باشد. در چنین حالتی، نیازی به در نظر گرفتن ترتیب پارامترها نخواهد بود و درک رفتار تابع بسیار سادهتر میشود. هرچند دستیابی به این وضعیت همواره ممکن نیست، اما در صورت امکان، این بهترین حالت محسوب میشود.یک تابع با تنها یک ورودی همچنان خوانا و قابلاستفاده باقی میماند، زیرا در این حالت ترتیب ورودیها اهمیتی ندارد. وجود دو ورودی نیز قابلقبول است، اما باید با دقت بیشتری از آنها استفاده شود. زمانی که تعداد ورودیها به سه یا بیشتر میرسد، درک و استفاده از تابع دشوارتر میشود؛ بنابراین بهتر است از چنین شرایطی پرهیز شود.اگر کاهش تعداد ورودیها ممکن نباشد، میتوان آنها را در قالب یک شیء (برای مثال، یک شیء در JavaScript) گروهبندی کرد. این روش باعث میشود نام پارامترها واضحتر باشد و ترتیب آنها نیز دیگر اهمیت نداشته باشد. برای نمونه:// Dirty Code
const user = new User(&#039;Max&#039;, 31, &#039;max@test.com&#039;);

// Clean Code
const user = new User({ name: &#039;Max&#039;, email: &#039;max@test.com&#039;, age: 31 });گاهی بهجای نوشتن یک تابع مستقل، بهتر است یک کلاس ایجاد کرده و متدهای مرتبط را بهصورت ساختاریافته و شفاف درون آن قرار داد. این کار موجب میشود کد خواناتر و از نظر مفهومی شفافتر باشد. علاوه بر این، محیطهای توسعه (IDEها) هنگام استفاده از کلاسها با ارائهی پیشنهادها و راهنماییهایی دربارهی پارامترها و نحوهی استفاده از متدها، به درک بهتر کد کمک میکنند. برای مثال:class User {
 constructor(name, age, email) {
 this.name = name;
 this.age
        age;
 this.email = email;
    }
}
const user = new User(&#039;Max&#039;, 31, &#039;max@test.com&#039;);نکتهای مهم آن است که گاهی ممکن است وجود دو ورودی در نگاه اول قابلقبول به نظر برسد، اما در واقع یکی از آنها زائد باشد. برای مثال، زمانی که یک نوع خاص را بهعنوان ورودی دریافت میکنیم و سپس براساس آن نوع عملیات متفاوتی انجام میدهیم، بهتر است برای هر نوع، یک تابع جداگانه نوشته شود. این کار باعث سادهتر شدن ساختار کد و افزایش خوانایی آن میشود. برای نمونه:// Dirty Code
function log(message, isError) {
 if (isError) {
 console.error(message);
    } else {
 console.log(message);
    }
}
log(&#039;Hi there!&#039;, false);

// Clean Code
function log(message) {
 console.log(message);
}
function logError(errorMessage) {
 console.error(errorMessage);
}
log(&#039;Hi there!&#039;);
LogError(&#039;An error!&#039;);ورودیهای پویا نیز نیازمند توجه ویژهای هستند. در بسیاری از زبانهای برنامهنویسی، روشهایی برای مدیریت این نوع ورودیها وجود دارد. برای مثال، در زبان JavaScript میتوان از عملگر پخش (spread operator) استفاده کرد تا تعداد نامشخصی از ورودیها را دریافت نمود. این روش به ما اجازه میدهد که تعداد ورودیها را بهصورت انعطافپذیر مدیریت کنیم، در حالی که همچنان خوانایی کد حفظ میشود.function
 sumUp(...numbers) {
 let sum = 0;
 for (const number of numbers) {
        sum += number;
 return sum;
    }
}
const total = sumUp(10, 19, -3, 22, 5, 100);نکته مهم دیگر این است که باید از خروجیهای غیرمنتظره پرهیز کنیم. توابع باید خودبسنده باشند و از اصول توابع خودبسنده (Pure Functions) پیروی کنند. یک تابع خودبسنده، خروجی را تنها بر اساس ورودیها تولید میکند و هیچ اثر جانبی (Side Effect) ندارد. اگر یک تابع تغییراتی ایجاد کند که بر ورودیها تأثیر بگذارد یا وضعیت سیستم را دگرگون سازد، دیگر یک تابع خودبسنده محسوب نمیشود و دارای اثر جانبی خواهد بود.از این رو، باید تا حد امکان از اثرهای جانبی ناخواسته اجتناب کرد. اگر ایجاد چنین اثری اجتنابناپذیر باشد، لازم است یا در نام تابع به آن اشاره شود یا این تغییرات را به توابع جداگانه منتقل کنیم.برای مثال، قطعه کد زیر مناسب نیست زیرا باعث میشود شیء کاربر بهطور غیرمنتظرهای تغییر کند:function createId(user) {
    user.id = &#039;ul&#039;;
}
const user = { name: &#039;Max&#039; };
createId(user);
console.log(user);کد زیر تا حدی قابلقبول است، زیرا هرچند تغییری در شیء کاربر ایجاد میشود، اما تابع بهصراحت این تغییر را نشان میدهد:function addId(user) {
    user.id = &#039;ul&#039;;
}
const user = { name: &#039;Max&#039; };
addId(user);
console.log(user);کد زیر بهترین حالت است، زیرا کاملاً واضح و صریح است که تغییرات انجامشده در شیء کاربر عمدی است:class User {
 constructor(name) {
 this.name = name;
    }
 addId() {
 this.id = &#039;ul&#039;;
    }
}
const customer = new User(&#039;Max&#039;);
customer.addId();
console.log(customer);بدنهی یک تابع باید کوتاه و ساده باشد. نوشتن توابع کوتاه و ساده یکی از اصول بنیادی برنامهنویسی است. توابع کوچکتر این امکان را فراهم میکنند که نام آنها بهطور واضح هدفشان را بیان کند، که باعث خوانایی و درک بهتر کد میشود. بهطور کلی، بهجای نوشتن یک تابع پیچیده، بهتر است آن را به توابع کوچکتر تقسیم کنیم که هرکدام وظیفهی خاصی را انجام دهند.ما باید بخشهای کدی را که وظیفه خاصی را انجام میدهند شناسایی کرده و آنها را در توابع جداگانه قرار دهیم. علاوه بر این، بخشهایی از کد که نیاز به تفسیر بیشتری نسبت به کدهای اطراف خود دارند باید جدا شوند تا خواندن و درک آنها آسانتر باشد.توابع باید تنها یک کار انجام دهند. این به این معنا نیست که هر تابع باید تنها یک خط کد داشته باشد؛ زیرا در این صورت تعداد توابع بهطور قابلملاحظهای زیاد میشود که خود میتواند مشکلساز باشد.اگر به یک تابع نگاه کنیم و متوجه شویم که بیشتر از یک کار انجام میدهد، آن تابع باید به توابع کوچکتر تقسیم شود. برای مثال، ممکن است یک تابع همزمان اقدام به اعتبارسنجی (Validation)، ساخت محتوا و نمایش دادهها کند. چنین توابعی باید به اجزای کوچکتر تقسیم شوند.برای تعیین زمان تقسیم یک تابع به توابع کوچکتر، از مفهومی به نام سطوح انتزاع (Levels of Abstraction) استفاده میکنیم. در یک تابع، اگر بخشهایی از کد در سطوح مختلف انتزاع قرار داشته باشند، این نشاندهندهی این است که باید تابع به توابع کوچکتر تقسیم شود.در طراحی توابع، یکی از اصول کلیدی این است که هر تابع باید فقط یک وظیفه خاص را انجام دهد. به این معنی که تمامی خطوط کد در داخل یک تابع باید برای دستیابی به یک هدف واحد خدمت کنند. اگر یک تابع چندین کار مختلف انجام میدهد، باید آن را به توابع کوچکتر تقسیم کرد.در برنامهنویسی، کد میتواند در سطوح مختلف انتزاع قرار داشته باشد:کد سطح پایین (Low-level code): مانند email.includes() که یک متد داخلی زبان برنامهنویسی است و ما دقیقاً میدانیم که چه کاری انجام میدهد.کد سطح بالا (High-level code): مانند saveUser() که توسط برنامهنویس نوشته شده و نام آن به وضوح توضیح میدهد که چه کاری انجام میدهد، حتی اگر ندانیم که درون آن چه اتفاقی میافتد.نوشتن کد در سطوح بالا یا پایین بهطور خود به خود نه خوب است و نه بد؛ نکته مهم این است که این سطوح را در زمینه مناسب بهکار ببریم. اگر در یک تابع از کد سطح پایین استفاده میکنید، نام تابع باید به اندازه کافی توصیفی باشد تا درک آن برای دیگران آسانتر شود.از ترکیب سطوح مختلف انتزاع در یک تابع پرهیز کنید. اگر یک تابع کارهایی مانند ساخت دادهها، اعتبارسنجی و نمایش خروجی را همزمان انجام میدهد، این تابع شامل سطوح مختلف انتزاع است و باید به بخشهای کوچکتر تقسیم شود.چه زمانی باید بخشی از کد را در یک تابع جداگانه قرار دهیم؟زمانی که چندین خط کد دارید که همه به یک هدف خاص مرتبط هستند، میتوانید آنها را در یک تابع جداگانه قرار دهید.اگر بخشی از کد پیچیدهتر از کدهای اطراف خود باشد و نیاز به توضیح بیشتری داشته باشد، بهتر است آن را در یک تابع جداگانه با نام توصیفی قرار دهید.یکی از مزایای بزرگ تقسیم کد به توابع کوچکتر، قابلیت استفاده مجدد است. باید از نوشتن کد تکراری پرهیز کنیم. در واقع، هرگز نباید کد خود را تکرار کنیم. بنابراین، هر منطقی که در چندین قسمت از کد تکرار میشود، باید در یک تابع اختصاصی قرار گیرد تا از اضافهگویی جلوگیری شود.با این حال، باید توجه داشت که خوانایی کد همیشه باید اولویت اول باشد. تقسیم توابع به بخشهای کوچکتر باید با دقت انجام شود زیرا گاهی تقسیم غیرضروری ممکن است خوانایی کد را کاهش دهد. برای مثال، اگر برای هر عملیات یک تابع جداگانه ایجاد کنیم و نتوانیم نام مناسبی برای آن پیدا کنیم یا دائماً نیاز به جستجو برای توابع مختلف داشته باشیم، ممکن است این کار پیچیدگی ایجاد کند و به جای بهبود خوانایی، کد را دشوارتر کند. در چنین مواقعی، بهتر است تابع را یکپارچه نگه داریم.در نهایت، باید سعی کنیم توابع خود را خود بسنده نگه داریم. توابع خودبسنده، توابعی هستند که پیشبینیپذیرند و هیچ اثر جانبی غیرمنتظرهای ندارند. این نوع توابع راحتتر قابل تست و نگهداری هستند.تستهای واحد یکی از ابزارهای اساسی در نوشتن کد تمیز هستند. زمانی که قصد داریم برای کد تست بنویسیم، باید از خود بپرسیم: آیا این تابع به راحتی قابل تست است؟ اگر پاسخ مثبت باشد، احتمالاً کد تمیزی نوشتهایم. در غیر این صورت، باید کد را بازنویسی کرده و توابع را به بخشهای کوچکتر تقسیم کنیم تا قابل تستتر و تمیزتر شوند.ساختارهای کنترلیهنگام کار با ساختارهای کنترلی مانند حلقهها و عبارات شرطی، یکی از مشکلاتی که ممکن است پیش بیاید پیچیدگی کد است. چنین کدی ممکن است برای ما یا دیگران بهراحتی قابلفهم نباشد. یکی از راهحلها برای رفع این مشکل، کاهش استفاده از ساختارهای شرطی تو در تو (nested) است.برای این منظور، میتوانیم از تکنیکهایی مانند Guard و Fail-Fast استفاده کنیم.گارد به روشهایی اطلاق میشود که در آن شرایط یا خطاهای خاص به محض بروز، فوراً مدیریت میشوند و جریان اصلی کد بلافاصله متوقف میشود. استفاده از Guard به ما این امکان را میدهد که شرایط خاص یا خطاها را بهسادگی مدیریت کرده و آنها را از منطق اصلی جدا کنیم.فیلفست یک الگوی طراحی است که در آن برنامه یا سیستم بلافاصله پس از شناسایی خطا یا مشکل متوقف میشود و از ادامهی اجرا جلوگیری میکند. این الگو در محیطهایی مفید است که خطاهای زودهنگام میتوانند مشکلات بزرگی ایجاد کنند و نیاز به شناسایی و رفع سریع دارند.در مثال زیر، از این تکنیکها برای بهینهسازی کد استفاده شده است:// Dirty Code
function handleCheckout(user, cart) {
 if (user) {
 if (cart.items.length &gt; 0) {
 if (cart.isStockAvailable) {
 proceedToCheckout();
            } else {
 alert&#40;&amp;quotSome items are out of stock.&amp;quot&#41;;
            }
        } else {
 alert&#40;&amp;quotYour cart is empty.&amp;quot&#41;;
        }
    } else {
 alert&#40;&amp;quotPlease log in to continue.&amp;quot&#41;;
    }
}

// Clean Code
function handleCheckout(user, cart) {
 if (!user) return alert&#40;&amp;quotPlease log in to continue.&amp;quot&#41;;
 if (cart.items.length === 0) return alert&#40;&amp;quotYour cart is empty.&amp;quot&#41;;
 if (!cart.isStockAvailable) return alert&#40;&amp;quotSome items are out of stock.&amp;quot&#41;;

 proceedToCheckout();
}با منفی کردن شرایط و استفاده از خطاها، میتوانیم کد را از پیچیدگیهای غیرضروری رها کنیم. این روش به ما اجازه میدهد تا کد را سادهتر نگه داریم و از گم شدن در لایههای متعدد شرایط جلوگیری کنیم. به جای پیچیده کردن کد با شرایط تو در تو، میتوانیم آن را بهطور واضح و مستقیم با منفی کردن شرایط یا معرفی خطاها مدیریت کنیم.در مثال زیر، از این تکنیک برای سادهسازی کد استفاده شده است:// Dirty Code
if (user &amp;&amp; !user.isLoggedIn &amp;&amp; product.isActive &amp;&amp; !product.isDeleted) {
 addToFavorites(product);
}

// Clean Code
function canFavorite(user, product) {
 return user &amp;&amp; !user.isLoggedIn &amp;&amp; product.isActive &amp;&amp; !product.isDeleted;
}

if (canFavorite(user, product)) {
 addToFavorites(product);
}با نوشتن گاردها در توابع جداگانه و دادن نامهای توصیفی به آنها، میتوانیم به گونهای عمل کنیم که تنها با خواندن نام تابع، بهراحتی شرایطی که باید کد در آنها اجرا شود را درک کنیم.یکی از روشهای موثر برای جلوگیری از پیچیدگی زیاد در کد، استفاده از پلیمورفیسم (اشکال متعدد) و توابع کارخانهای است. با استفاده از این تکنیکها، میتوانیم کدی بنویسیم که هم قابل گسترش و هم انعطافپذیر باشد.فرض کنید چندین نوع شیء داریم که ساختار مشابهی دارند، اما رفتارهای متفاوتی نشان میدهند. به جای شلوغ کردن کد با دستورات  if یا switch، میتوانیم از پلیمورفیسم استفاده کنیم تا برای هر نوع شیء پیادهسازی جداگانهای ارائه دهیم. در این صورت، هر شیء میداند که باید چگونه رفتار کند و دیگر نیازی به گنجاندن شرایط در کد اصلی مانند &quot;اگر این باشد، آن را انجام بده؛ اگر آن باشد، این را انجام بده&quot; نداریم. مزایای استفاده از این الگوها قابل توجه است: ما شرایط پیچیده و اضافی را از بین میبریم که به حفظ کد تمیزتر و سادهتر کمک میکند. علاوه بر این، افزودن یک نوع جدید ساده میشود—میتوانیم به راحتی یک شیء جدید معرفی کنیم بدون نیاز به تغییر کد موجود.در ادامه به یک مثال ساده در جاوااسکریپت میپردازیم که نشان میدهد چگونه میتوانیم با استفاده از پلیمورفیسم و تابع کارخانهای شرایط را حذف کرده و کدی مقیاسپذیرتر بنویسیم. در این مثال که نمایش پیام خوشآمدگویی برای کاربران با نقشهای مختلف را نشان میدهد، کد را با استفاده از پلیمورفیسم و توابع کارخانهای تمیز خواهیم کرد.// Dirty Code
function welcomeMessage(user) {
 if (user.role === &amp;quotadmin&amp;quot) {
 return &amp;quotWelcome admin!&amp;quot
    } else if (user.role === &amp;quotguest&amp;quot) {
 return &amp;quotWelcome guest!&amp;quot
    }
 return &amp;quotWelcome user!&amp;quot
}

// Clean Code
function createUser(role) {
 const roles = {
 admin: () =&gt; ({
 welcome: () =&gt; &amp;quotWelcome admin!&amp;quot
        }),
 guest: () =&gt; ({
 welcome: () =&gt; &amp;quotWelcome guest!&amp;quot
        }),
    };

 return roles[role]?.() || {
 welcome: () =&gt; &amp;quotWelcome user!&amp;quot
    };
}خطاهایکی از اشتباهات رایجی که بسیاری از توسعهدهندگان مرتکب میشوند، استفاده از عبارات مانند if برای بررسی شرایط به جای مدیریت مستقیم خطاها است. زمانی که با شرایط خطا مواجه میشویم، باید از خطاها برای مدیریت آنها استفاده کنیم. اگر چیزی قرار است یک خطا باشد، باید خطا را مستقیماً مدیریت کنیم و از دور زدن این مرحله با استفاده از عبارت if خودداری کنیم.این رویکرد کد ما را سادهتر کرده و رفتارهای خطا را واضح میکند. به جای تلاش برای جلوگیری از وقوع خطا با شرایط پیچیده در داخل کد، باید خطاها را مدیریت کرده و بهطور مناسب به آنها واکنش نشان دهیم.در زیر، مثالهایی از رویکردهای مختلف آمده است که نشان میدهند چگونه میتوان خطاها را بهطور مؤثر مدیریت کرد.// Try Catch With Throwing Errors
// Dirty Code
function processTransactions(transactions) {
 if (!transactions || transactions.length === 0) {
 showErrorMessage(&amp;quotNo transactions provided!&amp;quot);
 return;
    }

 // process logic here...
}

// Clean Code
function processTransactions(transactions) {
 if (!transactions || transactions.length === 0) {
 const error = new Error(&amp;quotNo transactions provided!&amp;quot);
 throw error;
    }

 // ... continue processing
}

try {
 processTransactions(transactions);
} catch (error) {
 showErrorMessage(error.message);
}// Error Guards
// Dirty Code
function showUserInfo(user) {
 if (!user) {
 return;
    }

 console.log(`User: ${user.name}`);
}

// Clean Code
function showUserInfo(user) {
 if (!user || !user.name) {
 throw new Error(&amp;quotInvalid user object: &#039;name&#039; is required&amp;quot);
    }

 console.log(`User: ${user.name}`);
}
try {
 showUserInfo(user);
} catch (err) {
 showToast(err.message);
}// Extracting Validation
// Dirty Code
function checkout(user, cart) {
 if (!user || !user.isLoggedIn) {
 return alert&#40;&amp;quotPlease log in first&amp;quot&#41;;
    }

 if (!cart || cart.items.length === 0) {
 return alert&#40;&amp;quotYour cart is empty&amp;quot&#41;;
    }

 // continue with checkout...
 submitOrder(cart);
}

// Clean Code
function validateCheckout(user, cart) {
 if (!user || !user.isLoggedIn) {
 throw new Error(&amp;quotPlease log in first&amp;quot);
    }

 if (!cart || cart.items.length === 0) {
 throw new Error(&amp;quotYour cart is empty&amp;quot);
    }
}

function checkout(user, cart) {
 try {
 validateCheckout(user, cart);
 submitOrder(cart);
    } catch (error) {
 showToast(error.message);
    }
}اشیاء، کلاسها و ساختارهای دادهدر برنامهنویسی، اشیاء و ساختارهای داده دو مفهوم اساسی هستند که تفاوتهای زیادی با یکدیگر دارند. نحوه استفاده صحیح از هرکدام از آنها میتواند تأثیر زیادی بر تمیزی و قابلفهم بودن کد داشته باشد.اشیاء در برنامهنویسی شیءگرا بهگونهای طراحی شدهاند که جزئیات داخلی خود را پنهان کنند. به عبارت دیگر، این اشیاء دادههای خود را خصوصی نگه میدارند و تنها از طریق متدها یا API عمومی با دنیای خارج تعامل میکنند. اشیاء معمولاً مسئول انجام کارهای پیچیدهتری مانند منطق تجاری هستند.ساختارهای داده (مانند آرایهها، دیکشنریها یا اشیاء ساده بدون متد) عمدتاً برای ذخیره و انتقال داده استفاده میشوند. معمولاً آنها متدی ندارند و هیچ رفتار خاصی انجام نمیدهند — فقط کانتینرهایی برای داده هستند.زمانی که این دو مفهوم را ترکیب میکنیم و دادهها و رفتارها را بهطور همزمان ذخیره میکنیم، کد ما پیچیدهتر و شکنندهتر میشود. ساختار کد غیرشفاف میشود و نگهداری آن در آینده دشوار خواهد بود.بنابراین، از اشیاء برای تعریف رفتارها و مسئولیتها استفاده کنید. از ساختارهای داده برای ذخیره اطلاعات ساده استفاده کنید.ساختارهاپلیمورفیسم یکی از مفاهیم کلیدی در برنامهنویسی شیءگرا است که به ما اجازه میدهد تا رفتارهای مختلفی را برای اشیاء مختلف با استفاده از یک نام مشترک تعریف کنیم.برای مثال، فرض کنید تابعی به نام draw() داریم. در حالی که این تابع رفتار خاصی برای یک دایره دارد، ممکن است برای یک مربع بهطور کاملاً متفاوت عمل کند—اما از همان نام draw() استفاده میشود.زمانی که پلیمورفیسم بهدرستی استفاده میشود:کد ما را تمیزتر و قابلفهمتر میکند.نیاز به شرایط تکراری مانند if یا switch برای هر نوع شیء را از بین میبرد.اضافه کردن موارد جدید را بدون تغییر در کد موجود آسانتر میکند.بنابراین، پلیمورفیسم به این معنی است که &quot;یک نام، چندین رفتار&quot; — این ویژگی برنامهنویسی ما را سازماندهیشدهتر، مقیاسپذیرتر و نگهداری آن را آسانتر میکند.در برنامهنویسی تمیز، یکی از اصول مهم این است که کلاسها و توابع باید همبستگی بالا داشته باشند. این به این معنی است که تمام متدهای یک کلاس باید مرتبط باشند و از ویژگیهای خود کلاس استفاده کنند.زمانی که همبستگی بالا باشد، کلاسها هدف مشخصی دارند که باعث میشود کد قابلفهمتر، قابلاطمینانتر و قابلنگهداریتر باشد.قانون دِمتر بیان میکند:&quot;با دوستان خود صحبت کنید، نه با دوستان دوستان خود.&quot;در عمل، این بدین معناست که نباید بهطور مستقیم به ویژگیها یا متدهای داخلی اشیاء دیگر دسترسی پیدا کنیم. به جای استفاده مستقیم از چیزی مانند user.profile.avatar.url، بهتر است از متدی مانند user.getAvatarUrl()  استفاده کنیم.اگر ساختار داخلی profile یا avatar تغییر کند، در حالت اول باید بسیاری از قسمتهای کد را بهروزرسانی کنیم. در حالت دوم، تنها نیاز به بهروزرسانی متد getAvatarUrl() داریم.این امر وابستگیها را کاهش داده و نگهداری کد را آسانتر میکند.بنابراین، همبستگی بالا به این معنی است که کلاسها باید تنها یک وظیفه خاص انجام دهند. قانون دِمتر به کاهش وابستگیها میان بخشهای مختلف کد کمک میکند.اصل تک مسئولیتی بیان میکند که هر کلاس باید تنها یک مسئولیت داشته باشد. به عبارت دیگر، اگر یک کلاس بیشتر از یک کار انجام میدهد، باید تقسیم شود. این اصل باعث میشود کد قابلفهمتر و قابلنگهداریتر باشد.علاوه بر این، اصل &quot;برای توسعه باز، برای تغییر بسته&quot; بیان میکند که کلاسها باید برای توسعه باز و برای تغییر بسته باشند. این اصول به ما کمک میکنند تا کدی بنویسیم که هم انعطافپذیر و هم تمیز باشد.سخن پایانیدر این مقاله، یاد گرفتیم که چگونه توابع و متدهای تمیز بنویسیم. اما نوشتن کد تمیز فقط بخشی از داستان است. گام بعدی یادگیری درباره معماری تمیز است — فهمیدن اینکه هر بخش از کد کجا باید در یک پروژه قرار گیرد. این زمانی است که کد واقعاً شروع به معنی پیدا کردن میکند.</description>
                <category>امیرمحمد ابوالحسنی</category>
                <author>امیرمحمد ابوالحسنی</author>
                <pubDate>Fri, 09 May 2025 13:20:24 +0330</pubDate>
            </item>
                    <item>
                <title>روش‌های آپگرید پروژه‌های React Native</title>
                <link>https://virgool.io/@am-abolhasani/%D8%B1%D9%88%D8%B4-%D9%87%D8%A7%DB%8C-%D8%A2%D9%BE%DA%AF%D8%B1%DB%8C%D8%AF-%D9%BE%D8%B1%D9%88%DA%98%D9%87-%D9%87%D8%A7%DB%8C-react-native-u1al6xtwvehc</link>
                <description>آپدیت به‌موقع پروژه‌های React Native برای جلوگیری از مشکلات جدی بسیار حیاتی است. بدون به‌روزرسانی، اپلیکیشن شما ممکن است با نسخه‌های جدید سیستم‌عامل‌ها سازگار نباشد و از انتشار در مارکت‌هایی مانند Google Play یا App Store باز بماند. علاوه بر این، عدم آپگرید می‌تواند مشکلات امنیتی و عملکردی ایجاد کند. پروژه‌های قدیمی‌تر، به‌ویژه به‌دلیل وابستگی‌ها و کدهای منسوخ‌شده، نگهداری و توسعه پیچیده‌تر و زمان‌بر خواهند شد. به همین دلیل، آپگرید به نسخه‌های جدید، نه‌تنها الزامی است، بلکه برای حفظ امنیت و عملکرد اپلیکیشن ضروری است.با این حال، ارتقاء پروژه‌های React Native به نسخه‌های جدید می‌تواند چالش‌برانگیز باشد. برخلاف کتابخانه‌های جاوااسکریپتی ساده، React Native تنها یک وابستگی Node نیست که با تغییر شماره نسخه در package.json به‌راحتی ارتقاء یابد. این پروژه‌ها شامل بخش‌های نیتیو iOS و Android هستند که باید با نسخه جدید هماهنگ شوند. علاوه بر این، ارتقاء همزمان react و سایر وابستگی‌ها ممکن است شما را با مشکلات peer dependency مواجه کند.در این مقاله، روش‌های رایج برای آپگرید پروژه‌های React Native را بررسی می‌کنیم. این روش‌ها شامل راهکارهای رسمی و خودکار، روش‌های دستی و حتی راه‌حل‌های غیررسمی هستند. توجه داشته باشید که انتخاب روش مناسب به شرایط خاص هر پروژه بستگی دارد و بهترین راهکار برای یک پروژه ممکن است برای پروژه دیگر مناسب نباشد. همچنین، این مقاله فقط به آپگرید React Native اختصاص دارد و به‌روزرسانی وابستگی‌ها یا پکیج‌های جانبی را پوشش نمی‌دهد، هرچند که در عمل ممکن است نیاز به ارتقاء آن‌ها نیز باشد.۱. استفاده از ابزار Upgrade Helper برای ارتقاء دستیابزار Upgrade Helper ابزاری تعاملی است که در داکیومنت رسمی React Native معرفی شده و به شما کمک می‌کند تا نسخه‌های فعلی و هدف پروژه را انتخاب کرده و تفاوت‌های فایل‌های الگوی پیش‌فرض را مشاهده کنید. این ابزار یک Diff جامع از پروژه React Native خام ارائه می‌دهد که شما باید تغییرات آن را به‌صورت دستی در پروژه خود اعمال کنید.این روش مزایای زیادی دارد؛ شما می‌توانید خط‌به‌خط تغییرات بین دو نسخه را مشاهده کرده و کنترل کاملی بر اعمال تغییرات داشته باشید. علاوه بر این، امکان انجام تغییرات به‌صورت مرحله‌ای وجود دارد. اما این روش به‌دلیل ماهیت دستی‌اش زمان‌بر است و احتمال خطاهای انسانی را افزایش می‌دهد. همچنین، از نسخه‌های قدیمی‌تر React Native پشتیبانی نمی‌کند و برای نسخه‌های پایین‌تر از ۰٫۶۵ مناسب نیست.۲. استفاده از کامندلاین react-native upgrade برای ارتقاء خودکاردستور react-native upgrade در React Native CLI، یکی از روش‌های خودکار برای ارتقاء پروژه است. این دستور تغییرات لازم را در فایل‌های پروژه اعمال می‌کند و از مخزن Diff ویژه‌ای به نام rn-diff-purge برای شناسایی فایل‌های مورد نیاز استفاده می‌کند. این فرایند مبتنی بر Git است و به‌طور خودکار اکثر تغییرات را اعمال می‌کند.این روش سرعت بالایی دارد و بسیاری از تغییرات را به‌صورت اسکریپت‌شده انجام می‌دهد، بنابراین از این نظر کارآمد است. با این حال، در برخی جهش‌های بزرگ، به‌ویژه از نسخه ۰٫۵۶ به ۰٫۵۷، ابزار CLI به‌تنهایی قادر به پوشش تمامی تغییرات نیست و نیاز به اعمال تغییرات دستی خواهد بود. این روش مناسب پروژه‌های متوسط و بزرگ است که تغییرات زیادی در آن‌ها اعمال نمی‌شود، ولی در برخی شرایط خاص ممکن است به تحقیق و مطالعه Release Notes نیاز داشته باشید.۳. ساخت یک پروژه جدید و انتقال کدها به آنگاهی اوقات، برای پروژه‌های قدیمی بهتر است به‌جای ارتقاء مستقیم، یک پروژه جدید React Native با نسخه هدف ایجاد کرده و کد منطق برنامه و منابع دیگر را به آن منتقل کنید. این روش به شما این امکان را می‌دهد که از یک پایه تمیز شروع کنید و از مشکلات مربوط به آپگرید فایل‌های پیکربندی منسوخ‌شده جلوگیری کنید.البته این روش به‌ویژه برای پروژه‌های بزرگ زمان‌بر خواهد بود. شما باید کدها و منابع را از پروژه قدیمی منتقل کرده و تنظیمات خاص را در پروژه جدید وارد کنید. اگر پروژه شما وابستگی‌های نیتیو پیچیده‌ای دارد، این انتقال ممکن است به‌طور قابل توجهی زمان‌بر و چالش‌برانگیز شود، اما در نهایت باعث ایجاد یک پروژه با ساختاری تمیز و قابل نگهداری‌تر خواهد شد.۴. جایگزینی پوشه‌های نیتیو از یک پروژه به‌روز و اصلاح آن با کمک Gitدر این روش، یک پروژه جدید با نسخه به‌روز React Native ایجاد کرده و فقط پوشه‌های نیتیو (Android و iOS) را از پروژه جدید به پروژه قدیمی منتقل می‌کنید. این روش به شما این امکان را می‌دهد که تغییرات نیتیو را به‌روز کنید، در حالی که تغییرات خود را در دیگر بخش‌های پروژه حفظ می‌کنید.این روش معمولاً سریع‌تر از بازسازی کامل پروژه است و نیازی به انتقال تمام کدها ندارد. البته برای این که تغییرات به‌درستی اعمال شوند، باید دقت زیادی در مقایسه و اعمال تغییرات داشته باشید، به‌ویژه اگر تغییرات زیادی در فایل‌های نیتیو صورت گرفته باشد.چالش نهایی: اجرای پروژه در دو پلتفرمپس از اعمال تغییرات و ارتقاء به نسخه جدید React Native، چالش اصلی اجرای پروژه در دو پلتفرم Android و iOS است. در این مرحله، باید خطاهای بیلد را رفع کرده و خطاهای احتمالی باندل را هم برطرف کنید. ابزارهایی مانند react-native doctor و react-native-clean-project می‌توانند در این فرآیند مفید باشند. هدف نهایی این است که پروژه به نسخه‌ای پایدار و استیبل برسد که در هر دو پلتفرم به درستی اجرا شود.</description>
                <category>امیرمحمد ابوالحسنی</category>
                <author>امیرمحمد ابوالحسنی</author>
                <pubDate>Sun, 20 Apr 2025 17:41:05 +0330</pubDate>
            </item>
                    <item>
                <title>کدنویسی تمیز: نکات کلیدی از دوره‌ی Maximilian Schwarzmüller - بخش اول</title>
                <link>https://virgool.io/@am-abolhasani/%DA%A9%D8%AF%D9%86%D9%88%DB%8C%D8%B3%DB%8C-%D8%AA%D9%85%DB%8C%D8%B2-%D9%86%DA%A9%D8%A7%D8%AA-%DA%A9%D9%84%DB%8C%D8%AF%DB%8C-%D8%A7%D8%B2-%D8%AF%D9%88%D8%B1%D9%87-%DB%8C-maximilian-schwarzm%C3%BCller-%D8%A8%D8%AE%D8%B4-%D8%A7%D9%88%D9%84-my0dtjm3gfhw</link>
                <description>در این مقاله قصد دارم نکاتی را که از مشاهده‌ی دوره‌ی «کد تمیز» به تدریس Maximilian Schwarzmüller آموخته‌ام، با نگارشی شخصی و ساده با شما به اشتراک بگذارم. بی‌مقدمه سراغ اصل ماجرا برویم: کد تمیز چیست و چرا اهمیت دارد؟کد تمیز چیست؟کد تمیز، قابل فهم و خواناست؛ در حالی که کد شلوغ و نامرتب (یا به‌اصطلاح کثیف) چنین نیست. شاید بتوان گفت این تعریف، مهم‌ترین پیام این مقاله است. تمام نکات و توصیه‌هایی که در ادامه می‌آیند، در راستای دستیابی به همین هدف ارائه شده‌اند: افزایش خوانایی و درک‌پذیری کد.هدف از نوشتن کد تمیزهدف از نوشتن کد تمیز، صرفاً عملکرد فنی نیست؛ بلکه ایجاد کدی مختصر، معنادار و قابل درک است. کدی که نه‌تنها زمان کمتری برای فهمیدن می‌طلبد، بلکه برای توسعه‌دهندگان خواندن و کار کردن با آن لذت‌بخش است.همان‌طور که نویسندگان حرفه‌ای سعی می‌کنند متونی روان و ساده بنویسند، برنامه‌نویسان نیز باید کدی بنویسند که به راحتی قابل خواندن، درک و نگهداری باشد.رابطه‌ی دوطرفه‌ی کد تمیز و اصول کدنویسیکدنویسی تمیز و رعایت اصول طراحی نرم‌افزار، رابطه‌ای متقابل و وابسته دارند. بدون پیروی از اصول، دستیابی به کدی تمیز ممکن نیست. در مقابل، وقتی کدی تمیز نوشته شود، خودبه‌خود به بهبود ساختار، معماری و پیروی از الگوهای استاندارد کمک می‌کند.کد تمیز ⇔ پایبندی به اصول، الگوهای کدنویسی و بهترین روش‌هااهمیت موضوعهیچ کدی کامل و نهایی نیست؛ همیشه می‌توان آن را بهبود بخشید. ریفکتورینگ یا بازنویسی کد، بخش طبیعی چرخه‌ی توسعه‌ی نرم‌افزار است و در بلندمدت باعث افزایش بهره‌وری و کاهش هزینه‌های نگهداری می‌شود.اگر بین &quot;کد سریع&quot; و &quot;کد تمیز&quot; مردد هستید، به یاد داشته باشید که هرچند نوشتن کد تمیز در ابتدا زمان‌برتر است، اما در بلندمدت، پروژه را پایدارتر، قابل‌نگهداری‌تر و توسعه‌پذیرتر می‌کند.اهمیت نام‌گذارینام‌گذاری مناسب یکی از مهم‌ترین عوامل در افزایش خوانایی و درک سریع‌تر کد است. نام مناسب کمک می‌کند تا نیازی به مرور خط به خط کد برای درک عملکرد یا نوع داده‌ها نباشد.متغیرها، ثابت‌ها و پراپرتی‌ها باید طوری نام‌گذاری شوند که هم نوع داده‌ی ذخیره‌شده و هم نقش آن‌ها را مشخص کنند. مثلاً برای متغیر بولی، از فرم سوالی مثل isValid استفاده کنید.برای متغیرهای عددی یا متنی، از نام‌هایی استفاده کنید که مقدار مورد نظر را توصیف کنند، مثل userAge یا emailAddress.توابع و متدها باید نشان دهند چه عملی انجام می‌دهند. بهتر است نام‌ آن‌ها با یک فعل یا عبارت توصیفی همراه باشد؛ مثل sendData() یا getUserInfo(). توابع بولی بهتر است به صورت سوالی باشند، مانند hasPermission().کلاس‌ها باید به‌روشنی موضوع و وظیفه‌ی خود را بازتاب دهند؛ مثلاً کلاس User یا Admin.هم‌راستایی در نام‌گذاری میان اعضای تیم بسیار مهم است. از اصطلاحات محلی یا اختصارات نامفهوم پرهیز کنید. وضوح، مهم‌تر از خلاقیت‌های پیچیده است. اگر لازم بود جزییات بیشتری به نام‌ها اضافه شود، تعادل را با سادگی حفظ کنید.چند مثال از نام‌گذاری صحیحاگر متغیری شامل اطلاعات کاربر (نام، ایمیل، سن) باشد، استفاده از نام‌هایی مثل u یا data بسیار گنگ است. به‌جای آن، نام‌هایی مانند user یا customer انتخاب‌های بهتری هستند.برای تابعی که اطلاعات کاربر را ذخیره می‌کند، نام‌هایی مثل process() یا handle() گنگ هستند. نام‌هایی مثل saveUser() یا user.store() دقیقاً هدف عملکرد را مشخص می‌کنند.کلاس‌هایی با نام‌هایی مثل Uentity یا ObjA باعث گیجی می‌شوند. اما نام‌هایی مثل User یا Admin به‌خوبی نقش کلاس را نشان می‌دهند.کامنت‌گذاری در کدکامنت‌ها باید فقط در موارد ضروری استفاده شوند. بسیاری از کامنت‌ها نه‌تنها مفید نیستند، بلکه ممکن است خوانایی کد را کاهش دهند. باید طوری نوشته شود که تا حد امکان نیازی به توضیح نداشته باشد. به عنوان مثال:از کامنت‌هایی که فقط به عنوان جداکننده هستند پرهیز کنید.اگر کدی نیاز نیست، آن را حذف کنید، نه اینکه کامنت کنید.کامنت‌هایی که اطلاعات نادرست یا قدیمی دارند می‌توانند گمراه‌کننده باشند.با این حال، مواردی وجود دارد که کامنت‌های خوب و مفید هستند، از جمله:کامنت‌های قانونی یا مربوط به مجوز در ابتدای فایل‌هاکامنت‌های توضیحی برای منطق‌های پیچیده (مثل RegExهای خاص)هشدارهای سازگاری برای مرورگر یا پلتفرم خاصکامنت‌های TODO برای یادآوری کارهای آینده (البته نباید جایگزین کامل کردن کدها شود.)مستندسازی برای معرفی نحوه‌ی استفاده از کتابخانه یا سرویسفرمت و قالب‌بندیقالب‌بندی شاید از نظر فنی تأثیری بر اجرای کد نداشته باشد، اما نقش کلیدی در افزایش خوانایی و درک سریع‌تر کد ایفا می‌کند. کدی که به‌درستی فرمت شده باشد، مانند یک مقاله‌ی منظم و قابل دنبال‌کردن است.فرمت عمودیاستفاده از فاصله‌گذاری مناسب میان بخش‌های مختلف کد باعث می‌شود بتوان مفاهیم مجزا را سریع‌تر تشخیص داد. اما در استفاده‌ی بیش‌ازحد از خطوط خالی بین بخش‌های مشابه نباید زیاده‌روی کرد.فرمت افقیاز خطوط طولانی و نیاز به اسکرول افقی پرهیز کنید.از تورفتگی (Indentation) یکنواخت استفاده کنید— اگر زبان برنامه‌نویسی آن را اجباری نکند.خطوط پیچیده را به چند خط بشکنید.استفاده از متغیرهای کمکی برای کاهش پیچیدگی هر خط توصیه می‌شود.در زبان‌های مختلف، سبک‌های قالب‌بندی متفاوتی وجود دارد. راهنماهایی مانند JavaScript Style Guide می‌توانند کمک‌کننده باشند. بسیاری از ویرایشگرهای مدرن (IDE) نیز قابلیت فرمت خودکار (auto-formatting) را دارند.سخن پایانیآنچه در این مقاله خواندید، بخش اول از نکاتی بود که از دوره‌ی Clean Code یاد گرفته‌ام. اگر این موضوع برایتان جذاب بوده، حتماً بخش دوم را برای دریافت دیدگاه‌ها و مثال‌های عملی بیشتر بررسی کنید!</description>
                <category>امیرمحمد ابوالحسنی</category>
                <author>امیرمحمد ابوالحسنی</author>
                <pubDate>Fri, 11 Apr 2025 18:56:41 +0330</pubDate>
            </item>
            </channel>
</rss>