<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های علی فرهادنیا</title>
        <link>https://virgool.io/feed/@ali_farhadnia</link>
        <description>برنامه نویس بک اند(ترجیحا با زبان گولنگ)-علاقه مند به اشتراک گذاری مطالبی که یاد میگیرم.</description>
        <language>fa</language>
        <pubDate>2026-06-10 13:09:19</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/1399578/avatar/pHPSWN.jpeg?height=120&amp;width=120</url>
            <title>علی فرهادنیا</title>
            <link>https://virgool.io/@ali_farhadnia</link>
        </image>

                    <item>
                <title>اصول SOLID در زبان Go (قسمت دوم-Open/Closed)</title>
                <link>https://virgool.io/@ali_farhadnia/solidingolang02-brommaqfozxk</link>
                <description>مقدمهاصل اول Single Responsibilityاصل دوم Open/Closedاصل سوم Liskov substitutionاصل چهارم Interface segregationاصل پنجم Dependency inversionمقدمه :سلامنوبتیم باشه نوبت این اصل خفنهیه جورایی میشه گفت این اصل زیربنای طراحی نرم افزارهکلا توی حوزه توسعه نرم افزار این اصل خیلی مهمه چون میتونه کلی پول و وقتو ... نجات بده.میخوایم باهم اصل باز/بسته یا به قول خارجیا open/closed یا به طور خلاصه OCP رو بررسی کنیم.این اصل به طور خلاصه میگه کد یا تابع یا کلا هر قسمتی که میخواین طراحی کنید ، یه شکلی طراحی کنید که: در برابر توسعه باز باشه و بشه راحت با اضافه کردن کد اون رو توسعه داد  در برابر تغییر بسته باشه  یعنی برای اضافه کردن یا کم کردن یک ویژگی لازم نباشه کد های نامربوط رو تغییر بدیم.مراحل کارمون به این صورته:اول این اصل رو با یک مثال زیر پا بذاریم. بعد ببینیم چه مشکلاتی برامون ایجاد میکنه.و بعد باهم مثالو باز نویسی کنیم و مشکلات رو حل کنیم و برسیم به اصل OCP.بریم اول این اصل رو زیر پا بذاریم ببینیم چی میشه :)فرض کنید میخوایم یه سیستم بنویسیم که درگاه های پرداخت مختلف رو پردازش میکنه:اینا درگاه های پرداخت ما هستن:Credit CardPayPalBitcoinبرای سادگی کار فرض میکنیم فرایند پرداخت خلاصه میشه به یه تابع که یه مبلغ رو به عنوان ورودی میگیره و بر اساس متد پرداخت  همه کارها رو انجام میده. کاش واقعا همینقدر ساده بود:/type Payment struct {
    Method string
}

func (p *Payment) ProcessPayment(amount float64) error {
    switch p.Method {
    case &amp;quotcredit_card&amp;quot:
        // Credit card payment logic
    case &amp;quotpaypal&amp;quot:
        // PayPal payment logic
    case &amp;quotbitcoin&amp;quot:
        // Bitcoin payment logic
    default:
        return errors.New(&amp;quotunsupported payment method&amp;quot)
    }
    return nil
}خب کارمون تموم شد.عا ما (بخونید آما)دو روز دیگه میان میگن یه درگاه پرداخت دیگه وصل کن.توی داستان ما میگن برامون درگاه stripe وصل کن .خب میایم اضافه میکنیم:func (p *Payment) ProcessPayment(amount float64) error {
    switch p.Method {
    case &amp;quotcredit_card&amp;quot:
        // Credit card payment logic
    case &amp;quotpaypal&amp;quot:
        // PayPal payment logic
    case &amp;quotbitcoin&amp;quot:
        // Bitcoin payment logic
    case &amp;quotstripe&amp;quot:
        // Stripe payment logic
    default:
        return errors.New(&amp;quotunsupported payment method&amp;quot)
    }
    return nil
}حالا مشکل کجاست؟مشکل زیاده:مشکل : اصل تک وظیفه ای رو زیر پا میذاره.     چون این تابع دیگه فقط مسئول پردازش پرداخت نیست بلکه باید نحوه پرداخت هرکدوم از درگاه هارو هم بدونه.مشکل:     تست کردن این کد به مرور سخت ترو سخت تر میشه .    چون هر بار که یک درگاه پرداخت اضافه میشه باید نه تنها خود درگاه رو تست کنیم بلکه تاثیرش روی بقیه درگاه    هارم تست کنیم.مشکل : اضافه کردن درگاه پرداخت رو سخت تر میکنه.     چون ممکنه روی بقیه تاثیر بذاره و این یعنی بعد یه مدت فاتحه سیستم رو باید خوند(توی بازار مجبوری در     زمان کوتاه فیچر های مختلف رو کمو زیاد کنی و بعد یه مدت یا دیگه نمیشه خیلی چیزی اضافه کرد یا با هر تغییر      اینقدر باگ میخوره سیستم که ...).مشکل: دیباگ کردنش به مرور با رشد سیستم خیلی سخت میشه.     هر سیستمی باگ داره و نیاز به نگهداری داره و نگهداری از کدی که شلوغ و کثیفه و هر روز کثیف تر میشه حقیقتا     خواب اروم شبو از ادم میگیره.مشکل:     گفتن جمله &quot; سیستم قابلیت اضافه کردن این فیچر رو نداره &quot;.      اخ اخ اخ وقتی میرسی به این نقطه که میترسی دست ببری تو کد و چیزیو تغییر بدی یا اضافه کنی  چون تا دست      ببری احتمال منفجر شدنش هست ...خب این همه ناله کردیم حالا راه حل چیه؟بیاین کد قبلیو دوباره بنویسیم ولی این بار با یک رویکرد متفاوت که اصل OCP(Open/Closed Principle) رو رعایت کنه:میایم یه اینترفیس تعریف میکنیم برای درگاه پرداخت:type PaymentMethod interface {
    ProcessPayment(amount float64) error
}میگیم هرکی میخواد درگاه پرداخت باشه باید تابع ProcessPayment رو پیاده سازی کنه.حالا بریم درگاه پرداخت هامونو ایجاد کنیم:Credit Card  :type CreditCard struct{}
func (c CreditCard) ProcessPayment(amount float64) error {
    // Credit card payment logic
}PayPal :type PayPal struct{}
func (p PayPal) ProcessPayment(amount float64) error {
    // PayPal payment logic
}Bitcoin :type Bitcoin struct{}
func (b Bitcoin) ProcessPayment(amount float64) error {
    // Bitcoin payment logic
}دوباره پروسه پرداخت رو بنویسیم:type Payment struct {
    Method PaymentMethod
}
func (p *Payment) ProcessPayment(amount float64) error {
    return p.Method.ProcessPayment(amount)
}خب حالا تست کنیم ببینیم این روش جواب میده یا نه:بریم سراغ اضافه کردن درگاه پرداخت stripe:type Stripe struct{}

func (s Stripe ) ProcessPayment(amount float64) error {
    // Stripe payment logic
}خب اضافه شد به همین راحتی و بدون خونریزی.دیگه لازم نیست برای هر بار اضافه کردن درگاه پرداخت بریم سراغ پروسه پرداخت و جراحیش کنیم.همون گوشه کنارا یه کد برای درگاه پرداخت جدید مینویسیم و استفاده میکنیم.یه جورایی انگار ماژولار شده کدمون.توی مثال ما وقتی خواستیم درگاه پرداخت اضافه کنیم قسمت پروسه پرداخت دست نخورد و در برابر تغییر بسته بود.اما راحت میشد درگاه اضافه کرد و دربرابر توسعه باز بود.و این همون اصل باز/بستسباز در برابر توسعه و بسته در برابر تغییرنکته: این پیاده سازی خیلی ساده سازی شده بود و راه های بهتری هم برای این کار هست(مثلا اینکه از چند درگاه همزمان پشتیبانی کنه و با ورود اسم درگاه خود تابع با درگاه مورد نظر پرداختش کنه)شاید بعدا درباره پیاده سازی بهتر همین کد مطلبی نوشتم:)مرسی از وقتی که گذاشتین ...لینکدینگیتهاب</description>
                <category>علی فرهادنیا</category>
                <author>علی فرهادنیا</author>
                <pubDate>Thu, 31 Aug 2023 21:27:33 +0330</pubDate>
            </item>
                    <item>
                <title>الگوهای طراحی در زبان گو (Design patterns in go)-فهرست</title>
                <link>https://virgool.io/@ali_farhadnia/design-patterns-in-go-index-unqv5wswslqs</link>
                <description>توی این قسمت فهرست سری مقاله های الگوهای طراحی در زبان گو (Design patterns in go) قرار دارهکه چون دیدم هر بار بخوام این فهرستو بالای هر قسمت بذارم ظاهر جالبی ندارهپس هر بار که قسمتی اضافه بشه اینجاهم به روزرسانی میشه و میتونید اینجا پیداش کنید.مقدمه(الگوهای طراحی سازنده (Creational Design Patterns)- سازنده(Builder)الگوهای طراحی ساختاری (Structural Design Patterns)الگوهای طراحی رفتاری (Behavioral Design Patterns)</description>
                <category>علی فرهادنیا</category>
                <author>علی فرهادنیا</author>
                <pubDate>Sat, 19 Feb 2022 23:12:20 +0330</pubDate>
            </item>
                    <item>
                <title>الگوهای طراحی در زبان گو (Design patterns in go)-Builder</title>
                <link>https://virgool.io/Solidity/design-patterns-in-go-builder-pbe9h1kpgs1p</link>
                <description>فهرستسلام علی فرهادنیا هستم :)امیدوارم حالتون خوب باشه.خب توی این قسمت میخوام درباره الگوی طراحی سازنده یا همون Builder صحبت کنم.این الگو جز دسته الگوهای طراحی سازنده (Creational Design Patterns) حساب میشه و به ما توی ساخت اشیا کمک میکنه.تعریف کلیالگوی builder اساساً در مورد ارائه نوعی API برای ساختن یک شی به صورت گام به گام است .کاربردکاربرد این الگو وقتی مطرح میشه که ما یه شی پیچیده داریم که میخوایم مقدار دهیش کنیم و اونو بسازیم.مثلا فرض کنید یه struct با 10 تا  یا بیشتر متغیر دارین، خب اینکه وقت تعریف کردنش بخوایم همه اینارو مقدار دهی کنیم گاهی اوقات کار جالبی نیست و در بعضی موارد کار رو مخی هم هست:/ .خب اینجا راه حل استفاده از builder ها و مقدار دهی گام به گام این struct هست.البته دقت کنید که این الگوی طراحی به طور کلی میتونه برای هرچیزی که بشه اونو به صورت مرحله به مرحله ایجاد کرد و اینکار مفید باشه مورد استفاده قرار بگیره.حالا جلو تر با مثال بهتر متوجه میشین.مثالیکی از کاربرد های جالبی که من اخیرا دیدم توی این پکیج هست که کارش اینه توی ساختن کوئری های sql کمک کنه.ساختارش اینجوریه که یه سری builder برای درخواست های مختلف داره که میشه باهاشون کوئری های مختلفی تولید کرد.اول خواستم از روی خود کدهای پکیج توضیح بدم مثالو ولی به نظرم اومد بهتره یه نمونه ساده سازی شدشو خودم پیداه سازی کنم.فقط دقت کنید که توی این مثال از یه کوئری خیلی ساده استفاده میکنم که خیلی مقاله طولانی نشه ولی همونطور که میدونید کوئری میتونه خیلی پیچیده ترو طولانی تر بشه که تا حد زیادی استفاد از builder هارو اینجا توجیه میکنه.فرض کنید میخوایم یه همچین کوئری بسازیم:SELECT fields FROM table_name;خب این کوئری از دو تا قسمت تشکیل شدهSELECTFROMکه روبه روی اینا باید به ترتیب اسم فیلد هایی که میخوایم و اسم اون table که میخوایم این فیلد ها از اونجا خونده بشنو بنویسیم.پس ما میتونیم با یه همچین ساختاری مدل سازیش کنیم:type selectQuery struct {
        fields                 string
        table_name      string
}خب حالا بریم تو کار ساختن یه builder برای  selectQuery که اسمشو میذاریم SelectQueryBuilder :type SelectQueryBuilder struct {
        select_query     selectQuery
}خب کار این SelectQueryBuilder اینه که اون select_query داخلشو مرحله به مرحله بسازه.پس یه سری تابع باید براش در نظر بگیریم که این کارو انجام بدن:func (b *SelectQueryBuilder) SELECT(fields string) *SelectQueryBuilder {
        b.select_query.fields = fields
        return b
}این تابع fields رو مقدار دهی میکنه.func (b *SelectQueryBuilder) FROM(table_name string) *SelectQueryBuilder {
        b.select_query.table_name = table_name
        return b
}این تابع table_name رو ست میکنه.یه نکته هم درباره اینکه چرا این توابع  SelectQueryBuilder  رو بعد اعمال اون تغییر برمیگردون بگم :این کار باعث میشه وقت استفاده ازش بتونیم به صورت یه دنباله ازش استفاده کنیم و یه فرم جالبی داره که توی تابع main میبینید منظورم چیه.خب تقریبا کار تمومه ولی خب در اخر ما خود این SelectQueryBuilder   رو که نمیخوایم!ما درواقع اون کوئری داخلشو میخوایم.برای استفاده از اون کوئری داخلش راه های متنوعی وجود داره که از حوصله بحث خارجه من در ادامه به دوتاش اشاره میکنم:راه اول اینه که میتونیم یه تابع دیگه با عنوان GetFinalQuery بنویسیم که همشو سر هم کنه و اون کوئری که خواستیمو به عنوان یه  string برگردونه.راه دوم اینه که مثلا یه تابع با نام Exec بنویسیم که یه کلاینت دیتابیسو به عنوان ورودی میگیره  و خودش این کوئری رو به اون دیتابیس میزنه و نتیجرو برمیگردونه.حالا اینجا چون نمیخوام خیلی وارد بحثای دیتابیس بشم مورد اولو مینویسم:func (b *SelectQueryBuilder) GetFinalQuery() string {
        return fmt.Sprintf(&amp;quotSELECT %s FROM %s;&amp;quot,
            b.select_query.fields, b.select_query.table_name)
}اها یادم رفت بهتره یه تابع هم برای ساخت   SelectQueryBuilder جدید هم بنویسیم:func NewSelectQueryBuilder() *SelectQueryBuilder {
         return &amp;SelectQueryBuilder{select_query: selectQuery{}}
}خب دیگه وقت نوشتن تابع main و امتحان کردن چیزاییه که نوشتیم:func main() {
        squery := NewSelectQueryBuilder() 
        final_query := squery.SELECT(&amp;quot*&amp;quot).FROM(&amp;quotbooks&amp;quot).GetFinalQuery()

        fmt.Println(final_query)
}توی تابع main میتونید اون حالت دنباله طوری که گفتمو ببینید اینکه میشه دستوراتو پشت سر هم استفاده کرد و این قابلیت به خاطر اینه که توابع  SELECT و FROM در اخر SelectQueryBuilder رو برمیگردونن.و اینم کوئری که تولید میکنه و در خروجی چاپ میکنه: SELECT * FROM books;بازم میگم که توی این مثال خیلی قضیرو ساده کردیم ولی خب خیلی کوئری های پیچیده تر و طولانی تری وجود داره که این builder ها واقعا میتونن کارو خیلی تمیزو راحت تر کنن.امیدوارم از این قسمت لذت برده باشین.کد هایی که نوشتمو میتونید توی این ریپازیتوری گیتهابم ببینید.ممنون به خاطر وقتی که گذاشتین :)فهرست</description>
                <category>علی فرهادنیا</category>
                <author>علی فرهادنیا</author>
                <pubDate>Sat, 19 Feb 2022 22:18:44 +0330</pubDate>
            </item>
                    <item>
                <title>الگوهای طراحی در زبان گو (Design patterns in go)-مقدمه</title>
                <link>https://virgool.io/golangpub/design-patterns-in-go-intro-rab9ekreapzm</link>
                <description>فهرستسلام به همه دوستانعلی فرهادنیا هستم و این بار اومدم با یه موضوع جذاب.الگوهای طراحی اونم در زبان گولنگکلا این الگوهای طراحی مبحث جالبیه و پایه ثابت خیلی از مصاحبه ها هم هست و بلد بودنشون خیلی خوبه.همونطور که در سری مقله های اصول سالید در گولنگ ( که هنوز کامل نشده)  اشاره کردم زبان گولنگ شی گرا نیست و خب این الگوهای طراحی اکثرا بر اساس منطق شی گرا ایجاد شدن.پس تکلیف چیه؟ خب مثل همون اصول سالید میشه اینجاهم کارایی کرد و یه جورایی این الگوهارو گولنگیزشون کرد.در این سری از مقاله ها سعی میکنم این اصولو با زبان گولنگ پیاده سازی کنم و توضیح بدم.ساختار کلیالگوهای طراحی بر اساس عملکردشون به سه دسته تقسیم میشن:الگوهای طراحی سازنده (Creational Design Patterns) این الگوها روشهای مختلف ایجاد یک شی رو ارائه میدن و باعث افزایش انعطاف پذیری و توانایی استفاده مجدد از کد میشن.الگوهای طراحی ساختاری (Structural Design Patterns)مجموعه ای از راه حل هایی هستن که برای حل یه سری مشکلات توی زمینه توسعه پذیری نرم افزار راه حل هایی ارائه میدن.الگوهای طراحی رفتاری (Behavioral Design Patterns)این الگو ها مجموعه ای از راه حل ها برای ارتباط بین اشیا مختلف هستند.من سعی میکنم این الگوهارو طبق همین دسته بندی ارائه بدم.منابعمنابع اصلیم شامل یه دوره ویدئویی میشه که این لینکشه  و منبع دیگم این وبسایته.کدهایی که توی این سری از مقالات مینویسمو میتونید توی این ریپازیتوری گیتهام پیدا کنید.فهرست</description>
                <category>علی فرهادنیا</category>
                <author>علی فرهادنیا</author>
                <pubDate>Fri, 18 Feb 2022 01:00:37 +0330</pubDate>
            </item>
                    <item>
                <title>Copy on write(COW)</title>
                <link>https://virgool.io/@ali_farhadnia/copy-on-writecow-mnwcun3kdai0</link>
                <description>www.geeksforgeeks.org منبع عکس  سلام من علی فرهادنیا هستم و میخوام درباره یه تکنیک بهینه سازی منابع به نام copy on write صحبت کنم.نکته:من متخصص این موضوع نیستم و صرفا چیزایی که میگم حاصل خوندن یه سری منابع و و برداشت شخصی من از اونه پس لطفا اگر میخواین دقیق این مبحثو یادبگیرین برین از منابع معتبر بخونید.داشتم مباحث ساختمان دادرو مرور میکردم و توی مبحث هزینه زمانی توابع بازگشتی به یه چیزی به نام copy on write برخوردم.طبق معمول وقتی به یه چیز جدید بر میخورم اول یه سرچ توی محتوای فارسی میکنم که یه دید کلی نسبت بهش پیدا کنم بعد میرم انگلیسیشو میخونم که کامل یادش بگیرم.ولی خب وقتی سرچ کردم مطلب فارسی براش پیدا نکردم و تصمیم گرفتم چیزی که ازش یادگرفتمو بنویسم و منتشر کنم که اگر فارسی زبان دیگه ای خواست یادش بگیره کمی راحت تر بشه کارش(امیدوارم:)).البته که من متخصص نیستم و صرفا چیزی که از روی یه ویدئو یوتوب دیدمو و فهمیدمو توضیح میدم و اگر شما تخصصی دارین خوشحال میشم توی کامتا اگر جاییو اشتباه میکنم یا کامل نیستو پوشش بدین .اگرم یه مطلب کامل دربارش بنویسین که چه بهتر خود منم استفاده میکنم :)اول از همه منبعی که اینارو از روش میگم این ویدئو یوتوبه که پیشنهاد میکنم ببینیدش.ویدئو منبعخب خلاصه چیزی که یاد گرفتم:ترجمه ای که خودم و مترجم گوگل برای copy on write روش توافق داریم میشه کپی در نوشتن(البته شاید کپی در هنگام نوشتن مفهومو بهتر برسونه)خلاصه ماجرا اینه که این تکنیک بهینه سازی میگه که فقط در صورتی که لازم بود یه چیزیو کپی کن و اگر لازم نبود از همون استفاده کن.خب شاید یکم قضیه  گنگ باشه پس بیشتر توضیح میدم:فرض کنید یه فرایند دارین که از یه سری منابع استفاده میکنه.مثلا یه تابع دارین که داره از یه سری داده توی حافظه استفاده میکنه.حالا میخواین یه تابع دیگه بنویسین که اونم از همون منابع استفاده میکنه(مطمئن نیستم ولی فکر کنم منظور اینه این دوتا تابع همزمان دارن کار میکنن)خب برای اینکار میشه همه منابعو یه کپی ازشون گرفت و به تابع دوم اختصاص داد که هر کاری میخواد باهاشون انجام بده.ولی خب این یعنی تقریبا دوبرابر هزینه حافظه.درصورتی که یه راه ساده تر هست:اینکه بیایم بگیم به جای اینکه یه کپی از منابع بگیری کاری کن هردوتا تابع از همون منابع استفاده کنن.چقدر جالب تر شد همه چی:)ولی خب یه مشکلی هست:فرض کنید یکی از برنامه ها میخواد یه تغییری توی منابعش بده.مثلا میخواد یه چیزی اضافه یا کم کنه خب این دوتا تابع قراره توی این سناریو مستقل از هم کار کنن و این یعنی تداخل.پس تکلیف چیه؟خب برای درست کردن این موضوع اومدن گفتن وقتی که دارین از این اصل استفاده میکنید باید حالت قابل نوشتن بودن فایلو غیر فعال کنید و فقط اجازه خوند منبع و استفاده از اطلاعاتش وجود داشته باشه و امکان تغییرش وجود نداشته باشه.خب حالا ما شاید خواستیم فایلو تغییر بدیم الان تکلیف چیه؟خب این اصل میگه وقتی خواستی تغییری ایجاد کنی یه کپی از اون منبعی که میخوای میگری و از این به بعد به اون اشاره میکنی و از اون استفاده میکنی و فایلی هم که بهش اشاره میکردی  و مشترک بود اگر فقط یه نفر دیگه بهش اشاره میکردو ازش استفاده میکرد باید دوباره قابل نوشتن بشه چون تداخلی ایجاد نمیکنه.برای همین این اصل میگه وقتی مجبور به نوشتن شدی فایلو کپی کن یا همون copy on writeمزیت این روش اینه که خیلی از اوقات ما فقط یه فایلو میخونیم و چیزی روش نمینویسیم و در این صورت اگر چنتا منبع داشته باشیم که از یه فایل استفاده کنن دیگه لازم نیست برای هرکدوم یه کپی از فایل بگیریم و فقط در صورتی که یکی از اون برنامه ها بخواد روی فایل بنویسه یه کپی بهش میدیم و میگیم بیا این مال تو کاری به بقیه نداشته باش.خب من فعلا همینارو فهمیدم اگر چیز جدیدی فهمیدم یا فهمیدم جاییشو اشتباه گفتم نوشترو اصلاح میکنم.اگر شما چیز بیشتری میدونید ممنون میشم توی کامنتا توضیح بدین که من و بقیه هم استفاده کنیم.ممنون که وقت گذاشتین.</description>
                <category>علی فرهادنیا</category>
                <author>علی فرهادنیا</author>
                <pubDate>Sun, 19 Dec 2021 22:48:47 +0330</pubDate>
            </item>
                    <item>
                <title>اصول SOLID در زبان Go (قسمت اول-Single Responsibility)</title>
                <link>https://virgool.io/golangpub/solidingolang01-anlstxlhaqnp</link>
                <description>مقدمهاصل اول Single Responsibilityاصل دوم Open/Closedاصل سوم Liskov substitutionاصل چهارم Interface segregationاصل پنجم                            Single Responsibility principleیا اصل تک وظیفه ایسلام من علی فرهادنیا هستم،برنامه نویس و علاقه مند به دنیای تکنولوژی در این قسمت از این سری میخوام اولین اصل از اصول سالید رو در زبان گولنگ توضیح بدم.این اصل توی دنیای شی گرایی برای کلاس ها بیان شده و به طور خلاصه میگه که هر کلاس باید یک مسئولیت داشته باشه ، برای یک چیز ایجاد شده باشه و به یک دلیل تغییر کنه.ولی خب ما توی دنیای گولنگ کلاس ملاس نداریم :/پس تکلیف چیه؟خب اصلا کلاس چیه و چرا وجود داره؟تعریف من از کلاس اینه که کلاس یه قالب کدنویسیه که یه سری چیزای مرتبطو کنار هم نگه میداره و بهشون یه ماهیت خاص و گاهی یه سری رفتار میده.خب توی گولنگ یه چیزی وجود داره به نام type که با یه سینتکس به خصوص میشه انواع جدیدی از دادرو ایجاد کرد.مثلا میشه به کمک ساختار داده ای به نام structure یه سری انواع داده مختلفو کنار هم قرار داد و بهشون یه ماهیت جدید داد.و از جذابیتای زبون گولنگ اینه که میشه به کمک تابع ها برای این استراکچر ها یه سری رفتار تعریف کرد و یه سری تابعو بهشون نسبت داد.پس تا حدی میشه این اصل تک وظیفه ایو گولنگیزش کرد:)خب یه بازنویسی از این اصل برای دنیای گولنگ داشته باشیم:اصل تک وظیفه ای در زبان گولنگ یعنی هر type باید یک مسئولیت داشته باشه ، برای یک چیز خاص ایجاد شده باشه و به یک دلیل تغییر کنه.مقدمه بسه بریم ببینیم چه خبره:با یه مثال شروع میکنم:فرض کنید میخوایم یه دفترچه یادداشت (یا به قول خارجیا notepad) خیلی ساده برای خودمون بسازیم که هر وقت لازم شد بتونیم توش یه متن وارد کنیم و امکان حذف کردن متن هم داشته باشه.به نظرم امکان ذخیره کردن متن توی فایل هم داشته باشه خوبه.شاید بعدا خواستیم وصلش کنیم به یه پرینتر و هر وقت خواستیم فایلارو پرینت بگیریم.خب پس شد:ساختاری برای نگه داری متن هاقابلیت اضافه کردن متنقابلین حذف متنقابلیت ذخیره کردن توی فایلبریم تو کار پیاده سازی:برای ساختار دفترچه یادداشت از یه استراکچر ساده شامل یه آرایه از رشته ها استفاده میکنم://Notepad structure
type Notepad struct {
    notes []string //slice of strings to to keep notes
}تابعی برای اضافه کردن نوشته به دفترچه یادداشت://AddNote get string and add it to notes
func (n *Notepad) AddNote(text string) {
    n.notes = append(n.notes, text)
}تابعی برای حذف کردن یک یادداشت://RemoveNote get index and remove it from notes
func (n *Notepad) RemoveNote(index int) {
    n.notes =append(n.notes[:index], n.notes[index+1:]...)
}یه تابعم برای چسبوندن همه یادداشت ها ب هم با فرمتی که مد نظرمونه به هم مینویسیم که برای پرینت کردنو و جاهای دیگه به درد میخوره(یه چیزی مثل تابع ToString جاوا)://String join all notes and return them as one string
func (n *Notepad) String() string {
    return strings.Join(n.notes, &amp;quot\n&amp;quot)
}و در آخر تابعی برای ذخیره کردن یادداشت ها توی فایل:توجه:بعد از منتشر کردن لینک مقاله توی لینکدینم یکی از دوستان گفتن که پکیج io/ioutil هم از ورژن 1.16 به بعد کنار گذاشته شده پس من هم کامنتش میکنم و به جاش از پکیج os استفاده میکنم(همه تابع هایی که در ادامه از این پکیج استفاده کردنو تغییر میدم و کد قبلیو کامنت میکنم که مشخص باشه)//function to save notes to file
func (n *Notepad) SaveToFile&#40;path string&#41; {
      _ = os.WriteFile&#40;path, []byte(n.String(&#41;), 0644)
/*The io/ioutil package has turned out in go 1.16
     _ = ioutil.WriteFile&#40;path,
    []byte(n.ToString(&#41;), 0644)
*/
}خب تقریبا دفترچه یادداشتمونو درست کردیم حالا وقت امتحان کردنشه پس بیاین یه چنتا یادداشت بهش اضافه کنیم:func main() {
    mynotes := Notepad{} //create notepad
    //adding note to notepad
    mynotes.AddNote(&amp;quotcongratulations&amp;quot)
    mynotes.AddNote(&amp;quotBreaking the first principle was done successfully!&amp;quot)
    //save notes to file
    mynotes.SaveToFile&#40;&amp;quottest1&amp;quot&#41;
    //print notes

   fmt.Println(mynotes.String())
}خب خروجی کارو ببینیم:congratulations
Breaking the first principle was done successfully!خب ما همین الان اصل تک وظیفه ایو زیر پا گذاشتیم!ما گفتیم این اصل میگه هر type  که ایجاد میشه باید مسئول یک چیز باشه و خب دفترچه یادداشت مسئول نگه داری متنه نه نوشتن اون توی یه فایل دیگه .پس تابع  SaveToFile این اصلو زیر پا گذاشت چون به دفترچه یادداشت چسبوندیمش و گفتیم جزیی از اونهخب راه حل چیه؟سادستراه حل اینه که تابع رو به صورت مستقل تعریف کنیم(حتی کلا میشه بردش توی یه پکیج دیگه)اینجوری:func SaveToFile&#40;input string, path string&#41; {
   _ = os.WriteFile&#40;path, []byte(input&#41;, 0644)
/*The io/ioutil package has turned out in go 1.16
    _ = ioutil.WriteFile&#40;path, []byte(input&#41;, 0644)
*/
}برنامه که حالت قبلیم درست کار میکرد پس این کارا برای چیه؟خب باید به عرضتون برسونم که درسته در این برنامه کوچیک همه چی به نظر درست میاد ولی فرض کنید برنامتون خیلی بزرگ تر میشه و مثلا همین تابع ذخیره در فایل به جز این دفترچه یادداشت خیلی جاهای دیگه هم کاربرد داره و باید برای هرجا که کاربرد داره بازم بنویسیمش و... که این موضوع علاوه بر زحمت زیاد در مرحله اولیه نوشتن میتونه یه فاجعه در مرحله گسترش دادن برنامه به همراه داشته باشه(اشک ها پای همین مسئله ریخته شده:))این فقط یکی از دلایلشه و کلی دلیل دیگه هم داره که اگر خواستین بدونین به نظرم برین دنبال یادگیری مسائل مربوط به برنامه نویسی تمیز و اصولی(که البته فکر کنم کسی  که داره این مقالرو میخونه داره دنبال همین میگرده:| ولی خب توضیح بیشتر در حوصله این بحث نمیگنجه).در این مسئله حتی میشه کلا یه ماهیت جدا برای تابع ذخیره در فایل قائل شد و مثلا در اینده گسترش داد که کارهای دیگه ای مثل فرمت کردن یا ذخیره توی فضاهای ذخیره سازی ابری و ... رو پوشش بده://save structure
type Save struct {
    default_path    string
    //...
}
//function to save notes to file
func (s *Save) SaveToFile&#40;input string, path string&#41; {
    if path == &amp;quot&amp;quot {
        path = s.default_path
}
    _ = os.WriteFile&#40;path, []byte(input&#41;, 0644)
/*The io/ioutil package has turned out in go 1.16
    _ = ioutil.WriteFile&#40;path, []byte(input&#41;, 0644)
*/
}از طریق گیتهابم میتونید به فایل کلی برنامه دسترسی داشته باشین.از این لینک.توی قسمت بعدی درباره اصل دوم صحبت میکنم.بعد از انتشار قسمت دوم لینکشو اینجا قرار میدم.ممنون به خاطر وقتی که گذاشتین.</description>
                <category>علی فرهادنیا</category>
                <author>علی فرهادنیا</author>
                <pubDate>Sat, 18 Dec 2021 15:58:50 +0330</pubDate>
            </item>
                    <item>
                <title>اصول SOLID در زبان Go (قسمت صفرم-مقدمه  )</title>
                <link>https://virgool.io/golangpub/solidingolang00-kwljbshvwywg</link>
                <description>مقدمهاصل اول Single Responsibilityاصل دوم Open/Closedاصل سوم Liskov substitutionاصل چهارم Interface segregationاصل پنجمسلام دوستان من علی فرهادنیا هستم .برنامه نویس بک اند و علاقه مند به زبان گولنگ.در این سری از پست ها میخوام اصول سالیدو در حد توانم توی زبون جذاب گولنگ اجرا کنم و توضیح بدم.فکر کنم بعد خوندن این مقدمه تا حدی بفهمین که میخواین این سری پست هارو دنبال کنید یا نه:)اگر کمی با زبان گولنگ آشنایی داشته باشین(که من ب نظرم کسی که دنبال این موضوعه  این آشناییو داره) احتمالا با دیدن عنوان تعجب کردین!چون اصول سالید برای زبون های شی گرا طراحی شده و خب گولنگ زبان شی گرا نیست!ولی خب اونقدراهم غیر شی گرا نیست:/خب این یعنی چی؟!یعنیطراحان این زبون یه سری مفاهیم رو توی این زبون تعریف کردن که میشه تا حدی مشابهشو توی زبون های شی گرا پیدا کرد ولی نه کاملا!مثلا این زبون اینترفییس داره(البته تا حدی با اینترفیس زبون های شی گرا متفاوته)از اون ور ارث بری اینجا وجود ندارهو یا ایده کپسوله کردن اینجا قابل اجراس ولی نه به قدرت زبون های شی گرا.و موارد دیگه ای که در حد سوادم توی ادامه قسمت ها در جای مرتبط بهش اشاره میکنم.به همین خاطر پیاده سازی کامل اصول سالید توی این زبان تا حدی دور از انتظاره(جذابه) ولی خب توی این سری من قصد دارم تا حد امکان سعی کنم این اصولو پیاده کنم.خب اصلا چرا باید این اصولو توی زبونی مثل گولنگ یادبگیریم؟!به نظر من برای کسانی که برنامه نویسی شی گرا و اصول سالید رو بلدن این سری مطالب میتونه در درک بهتر زبون گولنگ بهشون کمک کنه(به من که کمک کرد:))و اگر صرفا مثل من کنجکاوین که این زبون جذاب تا چه حد جذابه توصیه میکنم این سریو از دست ندین:)از اونجا که این قسمت فقط مقدمس مطلب زیادی برای گفتن ندارم ودرواقع اینو نوشتم که خودمو متعهد کنم به نوشتن بقیه قسمتا و همچنین شمارو بشارت بدم به اینکه چی داخل این سری هست و چی نیست(البته تقریبا)خواستم در ادامه یه تاریخچه از سالید و عمو بابو ... بگم که به نظرم یه لینک مرتبط بذارم خیلی مفید تره تا اینکه من خودم توضیحش بدم .به نظرم اینجوری احترام بیشتری به شما و وقتتون گذاشته میشه.راستی بحث عمو باب شد اگر برنامه نویسین و تا الان کتاب clean code عمو بابو نخوندین حتما یه سری بهش بزنین پشیمون نمیشین:)و در اخر جاهای جذاب بحث از قسمت بعدی شروع میشه:)اها یه نکترو فراموش کردماگر انگلیسیتون خوبه و میخواین این مباحثو با کیفیت بیشتری پیگیری کنید منبع اصلیم برای توضیح این مباحث، این دورس.اگرم با قیمتش یا تهیه دوره به مشکل برخوردینیه سرچ توی سایتای داخلی با اسم این دوره میتونه کمک کننده باشه:)قسمت بعدی ممنون به خاطر وقتی که گذاشتین.</description>
                <category>علی فرهادنیا</category>
                <author>علی فرهادنیا</author>
                <pubDate>Fri, 17 Dec 2021 00:03:15 +0330</pubDate>
            </item>
            </channel>
</rss>