<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های Baron</title>
        <link>https://virgool.io/feed/@m_24251209</link>
        <description>In the trees</description>
        <language>fa</language>
        <pubDate>2026-06-18 06:45:04</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/1201465/avatar/dc4uAh.jpeg?height=120&amp;width=120</url>
            <title>Baron</title>
            <link>https://virgool.io/@m_24251209</link>
        </image>

                    <item>
                <title>کتب سازندگان زبان های برنامه‌نویسی</title>
                <link>https://virgool.io/@m_24251209/%DA%A9%D8%AA%D8%A8-%D8%B3%D8%A7%D8%B2%D9%86%D8%AF%DA%AF%D8%A7%D9%86-%D8%B2%D8%A8%D8%A7%D9%86-%D9%87%D8%A7%DB%8C-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%86%D9%88%DB%8C%D8%B3%DB%8C-a2igcxggcobx</link>
                <description>سلام :)امیدوارم خوب و خوشحال باشیدتو این نوشته در مورد این صحبت میکنیم که سازندگان زبان های برنامه نویسی چه کتاب هایی رو تألیف کردنداینجوری شاید راحت تر بتونید خط فکری این افراد رو دنبال کنید(هرچند که این تنها راهش نیست). البته اینو بگم غیر از اینها افراد دیگه ای هم هستند که زبانی نساختند ولی دنبال کردن خط فکریشون با ارزشه و یا زبانی ساختند ولی کتابی رو تالیف نکردن پس واسه بعضی از این دست افراد هم دوتا کتاب معرفی میکنم.این هم بگم که بیشترشون صرفا کتاب در مورد زبان خودشون نوشته‌اند و کتاب دیگه ای ازشون در دسترس نیست.کتاب Dennis Ritchie سازنده زبان C:کتاب های Bjarne Stroustrup سازنده زبان cpp:کتاب Martin Odersky سازنده زبان Scala:کتاب های Stephen Wolfram سازنده Mathematica و زبان Wolfram:کتاب Rob Pike سازنده Golang:کتاب های Bertrand Meyer سازنده زبان Eiffel:کتاب Matthias Felleisen سازنده زبان Racket:حقیقتا اینو خیلی مطمئن نیستم. آقای Matthias Felleisen فاندر PLT inc هستش(سازمانی که اطلاعات خاصی ازش پیدا نکردم) و در ویکیپدیا نوشته سازنده این زبان PLT inc هستش. پس احتمالا اشتباه نباشه اینکه عامل اصلی ساخت زبان Racket رو به این آقا نسبت بدیم. اصلا به این چیزا اهمیت ندین، این کلا کتاب خیلی خوبیه و چیزای زیادی ازش یاد میگیرید.کتاب Don Syme سازنده زبان F sharp:کتاب James Gosling سازنده زبان Java:یه پرانتز ریز هم باز کنیم برای آقایون Joshua Bloch و Philip Wadler که به ترتیب بر روی  Java Collection Framework و Java Generics کار کردن:البته آقای Wadler  در ساخت زبان Haskell هم مشارکت داشته:کتاب Larry Wall سازنده زبان Perl:کتاب Joe Armstrong سازنده زبان Erlang:اینها کتاب هایی بودن از سازنده های زبان های برنامه نویسی. احتمالا این لیست کامل نیست و عذر می‌خوام. اگر شما اضافه بر اینها کتابی سراغ دارید ممنون میشم بگید.خب میرسیم به معرفی اون دو کتاب آخر که قول‌شو دادم:مراقب خودتون باشیدخدانگهدار</description>
                <category>Baron</category>
                <author>Baron</author>
                <pubDate>Sat, 17 Aug 2024 21:16:50 +0330</pubDate>
            </item>
                    <item>
                <title>الگو طراحی factory</title>
                <link>https://virgool.io/@m_24251209/%D8%A7%D9%84%DA%AF%D9%88-%D8%B7%D8%B1%D8%A7%D8%AD%DB%8C-factory-mxissgqupcj6</link>
                <description>چند وقت پیش یه api واسه پردازش اسلایس های go ساختم. این بخشش که میخوام توضیح بدم یکمی object oriented نوشته شده که خیلی با مذاق go سازگار نیست. خلاصه اگه یکم زشت شده شما ببخشید.فعلا به این عکس نگاه نکنید چون کد نهایی هستش و میخوایم کم کم بهش برسیمکد نهاییماجرا اینکه ما یه اینترفیس Stream داریم و دوتا struct که این اینترفیس رو پیاده سازی کردن(در oop میگیم اینترفیس Stream دوتا زیر کلاس داره)اسم این struct ها:sequentialStreamconcurrentStream تفاوتشون هم از اسمها معلومه و اینم بگم که هرکدوم یه فیلد از اسلایس دارن که پردازشو رو اون اسلایس انجام میدنحالا اگر کلاینت(کسی که قراره از کد ما استفاده کنه) بخواد یه استریم ترتیبی بسازه باید اینکارو کنه: s := []int{1, 5, 16, 13, 71, 22}seqStream := sequentialStream{slice: s}و یا همروند:conStream := concurrentStream{slice: s}اینکه کلاینت ما میدونه دقیقا چه struct هایی با چه اسم هایی وجود داره مشکل حساب میشهکلاینت صرفا نیاز داره بدونه که دو &quot;نوع&quot; استریم داریم که یکی با قابلیت ترتیبی و یکی همروند. حالا اینکه اسم هرکدوم struct چیه نیاز نیستپس از factory method استفاده میکنیممرحله اول ساخت تابع فکتوری هستاسمشو New میذاریمخروجی از نوع اینترفیس Stream هست و ورودی هم فیلد های struct هامون هست که اینجا فقط اسلایس هستشو یه ورودی دیگه هم که مشخص کنه کدوم &quot;نوع&quot; میخوایم ساخته بشه(ترتیبی یا همروند) که من اینجا از int استفاده میکنم: اگر 0 بود یعنی ترتیبی میخوایم اگر 1 بود یعنی همروند میخوایم ساخته شه.پس تابع New یه همچین چیزی میشه:همینجا بگم که بخاطر اینکه کد الکی پیچبده نشه از اسلایس int  استفاده کردم و مثال ها generic نیستنبلاک تابع New ساده هستش:خب حالا کلاینت برای اینکه استریم بسازه باید اینکارو کنه:s := []int{1, 5, 16, 13, 71, 22}seqStream := New(s, 0)conStream := New(s, 1)خب این سه تا مشکل داره(شاید شما بیشتر از سه تا پیدا کنید)یکی اینکه 0 و 1 خیلی تجربه جالبی ایجاد نمیکنهبهتره تو هر package ای که این تابع New رو گذاشتیم یه همچین چیزی هم اضافه کنیم: const (    SequentialType = 0    ConcurrentType = 1)حالا شرط ایف تو New میشه این: if t == SequentialTypeو ساخت استریم ترتیبی:s := []int{1, 5, 16, 13, 71, 22}seqStream := New(s,  SequentialType)مشکل دوم اینکه New به تنهایی منظور خاصی رو نمیرسونه. اصلا چی رو new میکنه؟ بهتر نبود اسمش NewStream می بود؟جواب سوال آخر اینکه نه نیاز نیست. چرا؟چون در حقیقت ما داریم تمام این استراکت ها اینتفرس و متد New رو در یک پکیج جدا مینویسیم مثلا فرض کنید اسم پکیج رو میذاریم gostream در این صورت کلاینت ما باید برای ساخت استریم ترتیبی همچین چیزی بنویسه:s := []int{1, 5, 16, 13, 71, 22}seqStream := gostream.New(s, gostream.SequentialType)اینجوری کلاینت دیگه میدونه که تابع New ای که در پکیج gostream هست احتمالا کارش ساخت استریم هستشاگر هم حس میکنید gostream برای چند بار نوشتن زیادی طولانیه، میشه در بخش ایمپورت ها gostream رو تبدیل کنه به یه کلمه کوچیکتر(مثلا gs) و حالا اینجوری بنویسه:s := []int{1, 5, 16, 13, 71, 22}seqStream := gs.New(s, gs.SequentialType)مشکل سوم چیه؟ اینکه برای ورودی دوم New که تایپ استریم رو مشخص میکنه میشه اعداد غیر از 0 و 1 هم داد که این فعلا برامون مشکل ایجاد نمیکنه چون که گفتیم اگر 0 نبود (حالا یا میخواد 1 باشه یا 13 یا 100) استریم همروند بساز. خلاصه اگه 0 بود ترتیبی بساز و هرچی جز 0 بود همروند. البته بعدا مشکل ایجاد میشه ولی فعلا راحتیم. خداروشکر :)خب ازینجا به بعد دیگه کاری به کد کلاینت نداریم یعنی کد کلاینت برای ساخت استریم ازینجا به بعد کلا همینه:gostream.New(s, gostream.SequentialType)ازینجا به بعد میخوایم کد پکیج خودمون رو بهتر کنیمیه نکته خارجی هم بگم: ما میخوام کد های داخلی package رو عوض کنیم اما کد کلاینت عوض نشه. این دقیقا یکی از تعریف های abstraction هستشخب برگردیم به تابع New. یک بار دیگه ببینیدش:فرض کنید بعد ها خواستید یه نوع جدید از Stream داشته باشید( استراکت سوم)اینجا باید در if else برای ساختنش  لحاظش کنید که این با قانون open closed در تضادهخب چیکار کنیم؟ از abstract factory استفاده میکنیم :) سعی میکنم به ساده ترین روش توضیح بدم اول از همه یه اینترفیس می‌سازیم (بهش میگیم streamFactory)type streamFactory interface {}این اینترفیس یه متد داره که اسمشو میذاریم Create.  اگرم با حرف کوچیک شروع میشد فرقی نمیکرد چون متد Create قرار نیست خارج از پکیج فراخوانی بشه.ورودی این متد هم فیلد های struct هامون هستن که اینجا فقط اسلایس هستش و خروجی هم Stream. پس:type streamFactory intrrface {   Create(s []int) Stream}حالا میایم برای هرکدوم از struct هامون(sequentialStream  و concurrentStream) یه struct میسازیم که هیچ فیلدی ندارن و اینترفیس streamFactory رو پیاده سازی میکنن(اسمشون رو میذاریم sequentialStreamFactory و concurrentStreamFactory) هرکدوم ازین استراکت های Factory یه متد Create دارن طبیعتا.متد Create ای که sequentialStreamFactory داره کارش اینکه یه شی از جنس sequentialStream  ریترن کنه و متد Create ای که concurrentStreamFactory داره کارش اینکه به شی از جنس concurrentStream ریترن کنه:دید کلی ای که نسبت به abstract factory وجود داره هم این شکلیه: نایده اینکه ما یه سلسه مراتب داریم با اینترفیسی به اسم Result و زیرکلاس هاش. حالا میایم یه سلسه مراتب دیگه می‌سازیم به اسم Factory که یه متد به اسم Create داره و واسه هر کدوم از زیر کلاس های Result یه کلاس(استراکت) میسازیم که اینترفیس Factory رو پیاده سازی میکنه و متد Create ای که داره یه شی از جنس کلاس متناظر با خودش رو ریترن میکنهاینجا Result همون Stream هستشحالا بیاین ببینیم چطور با همچین چیزی میتونیم یه استریم همروند بسازیم:s := []int{1, 5, 16, 13, 71, 22}خب این از اسلایس.حالا باید یه شی از concurrentStreamFactory بسازیم:f := concurrentStreamFactory{}که طبیعتا هیچ فیلدی نداره اما یه متد Create داره که اون استریم همروند ریترن میکنه: conStream := f.Create(s)پس برای ساخت استریم همروند:اول فکتوری استریم همروند رو میسازیمبعد از متد Create اون فکتوری استفاده میکنیمیه سوال میپرسم  قبل از اینکه ادامه بدید روش فکر کنید: ما برای ساخت شی از یه سلسله مراتب(Stream و زیر کلاس هاش)  اومدیم به سلسله مراتب دیگه(Factory و زیر کلاس هاش) ساختیم. خب این سلسله مراتب دومی خودش برای ساخت شی ازش نیاز به یه سلسله مراتب دیگه نیاز نداره؟خب طبیعتا و منطقا نباید نیازی باشه چون این کار رو میشه زنجیر وار تا بینهایت ادامه داد ولی بذارید بریم تابع New رو عوض کنیم و در کنارش به این سوال هم پاسخ بدیم:ورودی دوم تابع New مشخص میکرد که استریمی که میسازیم ترتیبیه یا همروند. خب با یه ایف الز، اول فکتوری رو میسازیم بعد متد Create اون فکتوری رو فراخوانی میکنیم:خب ازتون میخوام این نسخه New رو با نسخه قبلی مقایسه کنید:در نسخه قبلی با توجه به ورودی یه ایف الز میذاشتیم و دقیقا  به صورت مستقیم یه شی از استراکت های Stream می‌ساختیمدر این نسخه با توجه به ورودی و با ایف الز، اول factory رو میسازیم بعد از متد Create ای که داره استفاده میکنیم که برای ساخت یه شی از استراکت Stream مد نظرش هستش.تفاوتی که وجود داره اینکه ما نیاز نداریم برای هر بار فراخوانی New یه factory جدید بسازیمهمونطوری که گفتم استراکت های factory هیچ فیلدی ندارن (خلاصه که منو یاد singleton objects میندازه که از هر کلاس یا استراکت به یه شی ازش بیشتر نیاز نداریم)اصلا واسه همینه که سلسله مراتب دومی(factory) خودش نیاز به یه سلسه مراتب دیگه نداره چون اصلا دغدغه ای واسه ساخت شی ازشون نداریم و یه بار ساخت شی ازشون بسه. پس از فرایندی استفاده میکنیم به اسم object caching:const (    sequentialType = 0    concurrentType = 1)این کانست ها دقیقا بالای تابع New بودنکاری که میکنیم اینکه یه ساختمان داده map میسازیم(اسمشو میذاریم factories) با کلید های int (همون sequentialType و concurrentType) و value هایی از جنس Factory:یه [ بعد Factory اضافس خب حالا نسخه جدید تابع New رو ببینید:منطقیه دیگه؟ اگه ورودی گفت استریم ترتیبی میخوام از کلید SequentialType برای مپ استفاده کن در غیر این صورت از کلید ConcurrentType.حالا لطفا یبار دیگه به این New نگاه کنید :)اگه t همون SequentialType بود پس از SequentialType به عنوان کلید استفاده کن(که اینجا چون if گذاشتیم پس t همون SequentialType هست پس میشه گفت از همون t به عنوان کلید استفاده کن)برای ConcurrentType هم همینطور. خلاصه t چه 0 باشه چه 1 باشه به هر حال از همون t به عنوان کلید استفاده میشهپس بجای اینکه من از if else استفاده کنم مستقیم از t به عنوان کلید مپ استفاده میکنیم:و یا: میبینید چه قشنگ؟ نه تنها از ایف الز دیگه استفاده نمیکنیم بلکه کل بلاک تابع New یه خط بیشتر نشد.خب کد کلاینت طبیعتاً عوض نمیشه و برای ساخت استریم همچنان یه همچین کاری میکنه:gostream.New(slc, gostream.SequentialType)حالا اون مشکلی بود که گفتم فعلا از دستش راحتیم، اینجا گریبانگیر میشه :)نکته اینجاس که کلاینت میتونه همچین چیزی بنویسه:gostream.New(s, 10)که از این 10 به عنوان کلید map استفاده میشه و ما میدونیم در map فقط کلید های 0 و 1 وجود دارن.خب چیکار کنیم؟ راه حل های متفاوتی هستاولین و ساده ترین راهش اینکه بگیم اگه همچین کلیدی در map وجود نداشت یه nil ریترن کن:راه حل دوم یکم پیچیده تر هستش ولی از nil استفاده نمیکنه و این خودش خوبه. توضیح میدم:اول از همه یه استراکت جدید میسازیم به اسم inputType که یه فیلد از جنس int داره (اسم فیلدو میذاریم t):type inputType struct {    t int}همین الان بگم این struct با i کوچیک شروع میشه.حالا ورودی دوم تابع New که مشخص میکرد از چه نوع استریم میخوایم ساخته بشه بجای  t int یه inputType میگیره و داخل بلاک هم از فیلد t ای که inputType داره استفاده میکنیم:خب حالا وقتشه برگردیم به const ها:const(    SequentialType = 2    ConcurrentType = 1     ...)نکته ای که هست اینکه به عنوان وروردی دوم تابع New نمیتونیم دیگه از SequentialType و یا ConcurrentType استفاده کنیم چون اینا از جنس int هستن ولی ورودی دوم دیگه از جنس inputType میگیرهغصه نداره. اینا رو بجای int به inputType تبدیل میکنیم:خب کد کلاینت همچنان این شکلیه:gostream.New(slc, gostream.SequentialType)ولی حتی نمیدونه که جنس SequentialType از int به inputType عوض شده :))خلاصه این روش این شد:ما اومدیم یه استراکت به اسم inputType ساختیم و در ورودی دوم New به جای int یه inputType میگیریم. دوتا const از inputType ساختیم که کلاینت موقع فراخوانی New از اونا استفاده کنه. این نکته هم اضافه کنم که کلاینت نمیتونه هر شی دلخواه از inputType بسازه(بخاطر اینکه inputType با حرف کوچیک شروع شده نه بزرگ)و فقط مجبوره از اون دوتا SequentialType و ConcurrentType استفاده کنه. و اینجوری دیگه هیچوقت در map ای که داریم از کلیدی جز 0 و یا 1 استفاده نمیشهو در اخر بگم که اینترفیس Stream چند تا متد داره که میتونید ازشون استفاده کنید(تمام این کارا رو کردیم که بتونیم از متد های استریم استفاده کنیم)مثلا قطعه کد زیر خونه هایی از اسلایس که زوج هستن رو چاپ میکنه:و یا قطعه کد زیر مجموع مربع خونه های فرد رو حساب میکنه و در sum قرار میده:اول اعداد فرد رو با متد Filter جدا می‌کنیم بعد با متد Map اونا  رو به توان دو میرسونیم بعد با Reduce جمعشون رو حساب میکنیمخب تموم شد:) اون کدی که گفتم فعلا بهش نگاه نکنید و الان میگم که کلا نیازی نیست نگاهی بهش بندازید :)ولی اگه میخواید یه تصویر کلی ازش داشته باشید میتونید یه نگاهی کنید فقط چند تا نکته:۰. در کد اصلی به جای const از var استفاده کردم(که اشتباهه)۱. در کد اصلی بجای اسم Create از New استفاده کردم. یعنی تو قطعه کد اصلی دوتا New داریم که در توضیحات بخاطر اینکه ابهامی پیش نیاد من اسم یکی رو Create گذاشتم(طبیعتا بهتر بود که در کد اصلی هم همینکارو باید میکردم)۲. اینترفیس Stream و استراکت هاش و  متد New و سلسله مراتب Factory همگی generic هستن. همون طور که گفتم برای راحتی از int استفاده کردم. در ادامه باید بگم طبیعتا const ها و var هایی که بیرون از توابع تعریف میکنیم نمیتونن generic باشن. پس در کد اصلی، مپ factories رو داخل تابع New تعریف کردم که البته این دیگه object caching حساب نمیشه.۳. من این مشکل که map کلیدی با مقدار مثلا 10 نداره رو در کد اصلی لحاظ نکردم(باید اینکارو بکنم ولی چند وقتیه بخاطر افسردگی اصلا حوصله انجام دادن عملی به اسم برنامه نویسی ندارم)یه خسته نباشید به خودم و شما میگم و ممنونم که تا اینجا همراهم اومدید مراقب خودتون باشید </description>
                <category>Baron</category>
                <author>Baron</author>
                <pubDate>Sat, 03 Aug 2024 12:39:17 +0330</pubDate>
            </item>
                    <item>
                <title>Function currying</title>
                <link>https://virgool.io/@m_24251209/function-currying-fhapzvzlhpks</link>
                <description>قبل از همه بگم من بعد از یک سال برگشتم و اقا تواین یه سال چقد عجیب غریب بود زندیگم. بگذریم.توی functional programming یه بحثی هست به اسم function currying. ایده‌اش هم اینه که ما یه تابع داریم با n تا ورودی و تبدیلش میکنیم به n تا تابع که هرکدوم یه ورودی دارند. از ویکی پدیا: Curryification is useful in both practical and theoretical settings. In functional programming languages, and many others, it provides a way of automatically managing how arguments are passed to functions and exceptions. In theoretical computer science, it provides a way to study functions with multiple arguments in simpler theoretical models which provide only one argument.  خب بیاید با یه مثال بررسی کنیم:(مثال ها از go هستن) تو این مثال اول از همه یه تایپ مشخص کردم که یه ورودی داره و خروجیش boolean هست و صرفا هم Predicate هستش(مشخص میکنه ورودی تابع فلان ویژگی رو داره یا نه)بعد از اون تابع فیلتر رو ساختم ایدش اینکه یه لیست داریم میخوام تبدیل کنیم به لیستی از اعضاش که ویژگی خاصی رو دارن(مثلا فرض لیستی از student داریم و میخوایم لیستی از اونها رو داشته باشیم که معدل بالای ۱۶ دارند)حالا توی main اول از همه یه لیست از چند تا عدد صحیح ساختم و بعدش با استفاده از تابع Filter اعداد زوج و فرد رو در اورد و چاپشون کردمتا اینجا از function currying استفاده نشده و ما یه تابع Filter دوتا ورودی داره حالا به کد ریفکتور شده دقت کنید :تابع Filter دیگه یه ورودی داره اما خروجیش یه تابع دیگه هستش که اون تابع یه ورودی Predicate داره به فراخوانی هم توی main دقت کنید اول خروجی تابه Filter رو ریختیم توی fn. حالا fn خودش یه تابع هستش که که predicate میگیره.یبار fn رو برای اعداد زوج یبار هم برای اعداد فرد فراخوانی کردم.خلاصه همین، مراقب خودتون باشید </description>
                <category>Baron</category>
                <author>Baron</author>
                <pubDate>Sat, 29 Apr 2023 01:17:39 +0330</pubDate>
            </item>
                    <item>
                <title>نگهداری نرم‌افزار</title>
                <link>https://virgool.io/@m_24251209/%D9%86%DA%AF%D9%87%D8%AF%D8%A7%D8%B1%DB%8C-%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-mruazg54ac4r</link>
                <description>مفاهیم مهندسی نرم‌افزار - قسمت اولنگهداری نرم‌افزار یا software maintenanceبه نظر شما چرا برنامه ها و سیستم های نرم‌افزاری ساخته می‌شوند؟ شاید یکی از اصلی ترین دلایل این اتفاق، رفع نیاز های دنیای واقعی باشد(از این بگذریم که برخی از نرم افزار ها برای ایجاد نیاز هم ساخته می‌شوند!).بطور مثال به سیستم گلستان فکر کنید. برای رفع چه نیازی ساخته شده؟ به زبان ساده می‌توان گفت برای مدیریت هرچه که به دانشگاه مربوط میشود. مثل مشخصات دانشجویان، اساتید، رشته ها و واحد های تحت پوشش دانشگاه.شاید یک برنامه نویس مبتدی تنها  از برنامه نویسی یک هدف داشته باشد: برنامه ساخته شده به درستی کار کند.اما درستی کارکرد برنامه شاید بخشی از ویژگی هایی باشد که یک برنامه را بهتر میکند.یکی از ویژگی های دیگر که به همان اندازه‌ی کارکرد اهمیت دارد، این است که برنامه قابل نگهداری باشد.چرا برنامه و کد های برنامه نویسی باید قابل نگهداری باشند؟ برای اینکه بعدها راحت تر برنامه را تغییر دهیم و نسخه های بعدی را بسازیم.اصلا چرا باید برنامه را تغییر دهیم؟ یکی از مهم ترین دلایل آن این است نیاز های کاربران در طول زمان تغییر میکند. بطور مثال به این برنامه ساده فکر کنید: چاپ مقسوم علیه های یک عدد. حتی سه سال دیگر هم از این برنامه انتظار می‌رود که مجموع مقسوم علیه های یک عدد را چاپ کند. برای همین برنامه نویس های مبتدی معمولا به این فکر نمی‌کنند که کد هایشان را جوری بنویسند که بعد ها راحت تر تغییرش دهند(که با توجه مسائلی که درگیرشان هستند طبیعتا حق هم دارند).اما در دنیای واقعی هم همینطور است؟ نگاهی کوتاه به اپلیکیشن های مطرح دنیا مشخص می‌کند که این اپ ها در بدترین حالت ماهانه بروزرسانی می‌شوند. حتی پیش‌روی در این امر باعث پدید آمدن مفاهیمی مثل beta version  و  early access  شده.به مثال های زیر در دنیای واقعی دقت کنید:- دیجی کالا  برای بهبود ظاهر سایتش، تکنولوژی  front-end سایت خود را از jQuery به reactJs تغییر می‌دهد. - فیلیمو با توجه به اینکه تلویزیون های خانگی امروزی به سیستم عامل اندروید مجهز هستند، نسخه android tv اپلیکیشن‌اش را می‌سازد و سرور های سرویس‌دهی فیلم اش را روی آن پیاده‌سازی می‌کند. به این فکر کنید که نیاز ها نسبت به  android box کمتر شده. به این که برای ساخت این اپلیکیشن از سورس کد قبلی اپ اندرویدش اسفاده کرده یا این که از از همه را از صفر ساخته؟ - شرکت sony بعد از اینکه متوجه می‌شود سرویس های استریم برای بازی محبوبیت زیادی پیدا کرده، دست به کار می‌شود و امکانات مربوط به استریم بازی را به پلی استیشن اضافه میکند.- اینستاگرام برای رقابت با  TikTok قابلیت reels را به اپلیکیشن خود اضافه میکند.اینها فقط بخشی از میلیون ها تغییراتی بودند که در مهندسی نرم‌افزار رخ داده است.  با وجود اینکه روش های علمی برای محاسبه قابلیت نگهداری نرم‌افزار وجود دارد شاید بتوان تعریف کیفی زیر را پذیرفت:هرچه برنامه‌ راحت تر تغییر کند و برای تغییر پیچیدگی کمتری داشته باشد، قابلیت نگهداری آن بیشتر است.برای همین میتوانیم بجای قابلیت نگهداری از  تغییر پذیری هم در گفتار استفاده کنیم. دو عامل اصلی کد های تغییر پذیر، الگوهای طراحی و مستند سازی دقیق هستند. در آخر برای مطالعه مفاهیم نگهداری نرم‌افزار مطالعه کتاب های زیر را پیشنهاد میکنم:همه این کتاب ها به خصوص کتاب اول و آخر به شدت کاربردی و حرفه ای هستند.-- Edward Sciore, Java program design, Apress, 2019.-- Gamma E, Vlissides J, Johnson R, Helm R, Design patterns: elements of reusable object-oriented software, Addison-Wesley 1994.--Jared Bhatti, Docs for developers: An Engineer’s Field Guide to Technical Writing, Apress 2020-- Joost Visser, Building maintainable software, 2nd edition, O&#x27;Reilly, 2016.-- Ervin varga, Unraveling software maintenance and evolution: thinking outside the box,  Springer, 2018.</description>
                <category>Baron</category>
                <author>Baron</author>
                <pubDate>Sat, 12 Mar 2022 20:06:38 +0330</pubDate>
            </item>
            </channel>
</rss>