
نوشتن نرم افزار یکی از خلاقانه ترین فعالیت های انسان است. برخلاف بسیاری از فعالیت های مهندسی، برنامه نویس برای خلق یک سیستم نرم افزاری با محدودیت های فیزیکی دنیای واقعی روبه رو نیست. می توان دنیای مجازی ساخت، رفتارهایی را پیاده سازی کرد که در جهان واقعی امکان پذیر نیستند و سیستم هایی طراحی کرد که تنها محدودیت آن ها توانایی ما در تصور و سازماندهی ایده هاست.
اما همین آزادی، یک چالش بزرگ هم ایجاد می کند: هرچه نرم افزار بزرگ تر و کامل تر می شود، درک تمام اجزای آن دشوارتر می شود.
در ابتدای یک پروژه، معمولا همه چیز ساده به نظر می رسد. چند کلاس، چند تابع و تعدادی ارتباط مشخص میان اجزای سیستم وجود دارد. اما با اضافه شدن قابلیت های جدید، اصلاح خطاها، تغییر نیازمندی ها و ورود برنامه نویسان بیشتر به پروژه، ارتباط میان بخش های مختلف افزایش پیدا می کند. وابستگی های پنهان شکل می گیرند و تغییر یک قسمت ممکن است رفتار قسمت دیگری را تحت تاثیر قرار دهد.
در نتیجه، پیچیدگی به مرور زمان انباشته می شود و برنامه نویس برای انجام یک تغییر ساده مجبور می شود بخش های زیادی از سیستم را در ذهن خود نگه دارد. این پیچیدگی نه تنها سرعت توسعه را کاهش می دهد، بلکه احتمال ایجاد خطا را نیز افزایش می دهد.
کتاب حاضر به یکی از مهم ترین موضوعات در مهندسی نرم افزار می پردازد: چگونه می توان پیچیدگی را کنترل کرد و نرم افزارهایی ساخت که در طول زمان همچنان قابل درک، قابل تغییر و قابل توسعه باقی بمانند؟
پیچیدگی یکی از اجتناب ناپذیرترین ویژگی های پروژه های نرم افزاری است. تقریبا هر برنامه ای که برای مدت طولانی توسعه داده شود، قابلیت های بیشتری دریافت می کند و بخش های بیشتری به آن اضافه می شود. حتی اگر تیم توسعه از ابزارهای مدرن استفاده کند و فرآیندهای مناسبی داشته باشد، پیچیدگی به طور کامل از بین نمی رود.
مشکل اصلی زمانی ایجاد می شود که پیچیدگی از ظرفیت ذهنی توسعه دهندگان بیشتر شود.
یک برنامه نویس برای ایجاد تغییر در یک سیستم باید بتواند رفتار بخش های مرتبط با تغییر را درک کند. اگر وابستگی ها زیاد باشند یا ساختار سیستم به شکل مناسبی طراحی نشده باشد، انجام یک تغییر کوچک می تواند نیازمند بررسی تعداد زیادی فایل، کلاس، تابع و ارتباط باشد.
در چنین شرایطی، سرعت توسعه کاهش پیدا می کند و احتمال ایجاد خطا بیشتر می شود. خطاهای جدید نیز معمولا نیازمند تغییرات بیشتری هستند و همین تغییرات می توانند پیچیدگی بیشتری ایجاد کنند. به این ترتیب، یک چرخه شکل می گیرد که در آن پیچیدگی بیشتر باعث توسعه دشوارتر و توسعه دشوارتر باعث پیچیدگی بیشتر می شود.
ابزارهای توسعه می توانند بخشی از این مشکل را حل کنند. محیط های توسعه، سیستم های کنترل نسخه، ابزارهای تحلیل کد، تست خودکار و بسیاری از فناوری های دیگر به برنامه نویسان کمک می کنند. اما ابزار به تنهایی کافی نیست.
برای ساخت نرم افزارهای بزرگ تر و قدرتمندتر، باید خود طراحی نرم افزار را ساده تر کنیم.
یکی از ایده های مهم کتاب این است که برای کنترل پیچیدگی، دو رویکرد کلی وجود دارد.
کلمات کلیدی:رویکرد اول، حذف پیچیدگی است. در این روش تلاش می کنیم کد را تا حد امکان ساده و واضح طراحی کنیم. حذف حالت های خاص غیرضروری، استفاده منظم از نام گذاری ها و جلوگیری از رفتارهای استثنایی می تواند باعث شود کد برای برنامه نویس قابل درک تر باشد.
هدف این نیست که صرفا تعداد خطوط کد کاهش پیدا کند. یک برنامه ممکن است خطوط کمتری داشته باشد اما درک آن دشوار باشد. سادگی واقعی یعنی برنامه نویس بتواند رفتار سیستم را راحت تر بفهمد و بدون بررسی جزئیات غیرضروری، تغییر موردنظر خود را ایجاد کند.
رویکرد دوم، کپسوله کردن پیچیدگی است.
در این روش فرض می کنیم بعضی از پیچیدگی ها را نمی توان حذف کرد، بنابراین آن ها را پشت مرزهای مشخص قرار می دهیم. برنامه نویس هنگام کار با یک بخش از سیستم نباید مجبور باشد تمام جزئیات بخش های دیگر را بداند.
این ایده اساس طراحی ماژولار است.
در طراحی ماژولار، یک سیستم نرم افزاری به بخش های مختلفی تقسیم می شود که هرکدام مسئولیت مشخصی دارند. این بخش ها می توانند کلاس ها، زیرسیستم ها، سرویس ها یا دیگر اجزای نرم افزاری باشند.
هدف این است که ماژول ها تا حد امکان مستقل از یکدیگر طراحی شوند.
برای مثال، زمانی که یک برنامه نویس روی یک کلاس کار می کند، نباید مجبور باشد جزئیات پیاده سازی تمام کلاس هایی را که با آن ارتباط دارند بررسی کند. اگر مرزهای میان بخش ها به درستی طراحی شده باشند، هر قسمت می تواند پیچیدگی داخلی خود را پنهان کند.
طراحی ماژولار باعث می شود برنامه نویس بتواند با بخشی از سیستم کار کند، بدون اینکه مجبور باشد تمام سیستم را همزمان درک کند.
این موضوع برای پروژه های بزرگ اهمیت بسیار زیادی دارد؛ زیرا با افزایش تعداد اجزای سیستم و تعداد اعضای تیم، مدیریت تمام ارتباطات میان بخش های مختلف دشوارتر می شود.
یکی از تفاوت های مهم نرم افزار با سیستم های فیزیکی در این است که نرم افزار انعطاف پذیری بسیار بالایی دارد.
برای مثال، در ساخت یک ساختمان یا پل، طراحی معمولا قبل از شروع عملیات اصلی انجام می شود و تغییرات بزرگ پس از آغاز ساخت می توانند بسیار پرهزینه باشند. اما نرم افزار را می توان در طول توسعه تغییر داد، بازطراحی کرد و حتی ساختار بخش های اصلی آن را اصلاح کرد.
به همین دلیل، طراحی نرم افزار نباید فقط به ابتدای پروژه محدود شود.
طراحی از زمان شروع پروژه آغاز می شود، اما در تمام طول عمر سیستم ادامه دارد. هر قابلیت جدید، هر تغییر نیازمندی و هر تجربه ای که تیم توسعه به دست می آورد می تواند نشان دهد که طراحی فعلی به اصلاح نیاز دارد.
بنابراین یک توسعه دهنده حرفه ای باید همیشه به طراحی سیستم و فرصت های بهبود آن توجه داشته باشد.
در رویکردهای قدیمی توسعه نرم افزار، طراحی معمولا در ابتدای پروژه انجام می شد. یکی از نمونه های شناخته شده این تفکر، مدل آبشاری است.
در این مدل، پروژه به مراحل جداگانه ای مانند تحلیل نیازمندی ها، طراحی، پیاده سازی، آزمایش و نگهداری تقسیم می شود. هر مرحله باید قبل از شروع مرحله بعدی به پایان برسد.
در چنین رویکردی، فرض اصلی این است که می توان طراحی کل سیستم را در ابتدای پروژه انجام داد و سپس همان طراحی را در مراحل بعدی پیاده سازی کرد.
اما مشکل اینجاست که سیستم های نرم افزاری بزرگ آن قدر پیچیده هستند که نمی توان تمام پیامدهای طراحی را قبل از پیاده سازی پیش بینی کرد.
بسیاری از مشکلات طراحی زمانی مشخص می شوند که بخشی از سیستم واقعا ساخته شده باشد. در این مرحله ممکن است تغییر طراحی دشوار باشد و تیم توسعه مجبور شود برای حل مشکلات، راه حل های موقتی روی ساختار قبلی ایجاد کند.
این راه حل های موقتی معمولا پیچیدگی بیشتری ایجاد می کنند.
در مقابل رویکرد آبشاری، بسیاری از پروژه های نرم افزاری مدرن از توسعه تدریجی استفاده می کنند.
در این روش، به جای اینکه تمام سیستم از ابتدا طراحی شود، ابتدا بخش کوچکی از قابلیت های سیستم طراحی و پیاده سازی می شود. سپس نتیجه بررسی می شود و مشکلات طراحی شناسایی می شوند.
پس از اصلاح مشکلات، قابلیت های بیشتری اضافه می شوند.
این چرخه بارها تکرار می شود.
مزیت این روش این است که اشکالات طراحی زمانی شناسایی می شوند که سیستم هنوز کوچک است و اصلاح آن ها ساده تر است.
همچنین تجربه حاصل از پیاده سازی قابلیت های اولیه می تواند برای طراحی قابلیت های بعدی مورد استفاده قرار بگیرد. بنابراین طراحی سیستم به تدریج بر اساس تجربه واقعی توسعه پیدا می کند.
این موضوع یکی از دلایل مهمی است که توسعه تدریجی برای نرم افزار مناسب است. نرم افزار انعطاف پذیر است و می توان ساختار آن را در طول توسعه تغییر داد.
توسعه تدریجی به این معنی است که طراحی نرم افزار هیچ وقت کاملا تمام نمی شود.
اولین طراحی یک سیستم یا یک جزء نرم افزاری، معمولا بهترین طراحی ممکن نیست. با گذشت زمان، برنامه نویس اطلاعات بیشتری درباره رفتار سیستم، نیازهای کاربران و مشکلات ساختار فعلی به دست می آورد.
این تجربه می تواند نشان دهد که راه بهتری برای طراحی یک بخش وجود دارد.
به همین دلیل، بازطراحی نباید به عنوان یک کار اضافی و غیرضروری در نظر گرفته شود.
توسعه دهنده باید بخشی از زمان خود را به بهبود طراحی اختصاص دهد. اگر این کار انجام نشود، پیچیدگی به مرور افزایش پیدا می کند و در نهایت تغییر دادن سیستم بسیار دشوار می شود.
هدف این کتاب ارائه یک دستورالعمل ساده برای طراحی تمام نرم افزارها نیست. در طراحی نرم افزار نمی توان یک مجموعه قانون ثابت ارائه کرد که در تمام پروژه ها بهترین نتیجه را تضمین کند.
در عوض، کتاب مجموعه ای از مفاهیم سطح بالا و اصول طراحی را معرفی می کند که به برنامه نویس کمک می کنند میان گزینه های مختلف طراحی تصمیم بگیرد.
مفاهیمی مانند «کلاس ها باید عمیق باشند» یا «خطاها را از وجود خارج کنید» در نگاه اول ممکن است کاملا انتزاعی به نظر برسند، اما هدف آن ها ایجاد یک چارچوب ذهنی برای بررسی طراحی است.
هنگامی که با دو طراحی متفاوت روبه رو می شوید، چنین اصولی می توانند به شما کمک کنند مزایا و مشکلات هرکدام را بهتر ببینید.
در واقع، کتاب تلاش می کند نحوه فکر کردن درباره طراحی نرم افزار را تقویت کند، نه اینکه صرفا چند الگوی آماده برای کپی کردن ارائه دهد.
یکی از روش های مهم برای بهبود مهارت طراحی، یادگیری تشخیص نشانه هایی است که نشان می دهند یک بخش از کد احتمالا بیش از حد پیچیده شده است.
این نشانه ها را می توان مانند هشدارهایی در نظر گرفت که به برنامه نویس می گویند بهتر است یک بار دیگر درباره طراحی فعلی فکر کند.
ممکن است یک بخش از کد بیش از حد وابسته به بخش های دیگر باشد، مسئولیت های زیادی را بر عهده داشته باشد یا برای انجام یک کار ساده نیازمند درک جزئیات زیادی باشد.
در چنین شرایطی، برنامه نویس می تواند طراحی های جایگزین را بررسی کند.
هدف حذف هر نشانه هشدار به هر قیمتی نیست؛ هدف این است که وجود چنین نشانه هایی باعث شود درباره طراحی آگاهانه تر فکر کنیم.
با تمرین، برنامه نویس به تدریج الگوهای پیچیدگی را سریع تر تشخیص می دهد. این مهارت یکی از مهم ترین بخش های رشد در طراحی نرم افزار است.
مطالعه اصول طراحی به تنهایی ممکن است کافی نباشد. بسیاری از مفاهیم طراحی زمانی بهتر درک می شوند که روی کد واقعی بررسی شوند.
به همین دلیل، بازبینی کد یکی از روش های پیشنهادی برای استفاده از مفاهیم این کتاب است.
وقتی کد دیگران را بررسی می کنید، می توانید ببینید که ساختارهای مختلف چگونه روی پیچیدگی تاثیر می گذارند. همچنین معمولا تشخیص مشکلات طراحی در کد دیگران آسان تر از کدی است که خودتان نوشته اید.
در جریان بازبینی می توانید نشانه های هشدار را پیدا کنید و درباره راه های ساده تر کردن طراحی فکر کنید.
کدخوانی و بازبینی کد فقط برای پیدا کردن خطا نیست؛ یکی از روش های موثر برای یادگیری طراحی نرم افزار است.
با بررسی پروژه های مختلف، با شیوه های متفاوت حل مسئله مواجه می شوید و به تدریج مجموعه ای از الگوهای ذهنی برای تشخیص مشکلات طراحی در اختیار خواهید داشت.
یکی از نکات مهم کتاب، توجه به تعادل در طراحی است.
هیچ اصل طراحی را نباید بدون توجه به شرایط پروژه و تا نهایت ممکن اجرا کرد. هر قاعده ای استثناهایی دارد و هر اصل طراحی محدودیت هایی دارد.
اگر یک ایده خوب را بیش از حد دنبال کنیم، ممکن است نتیجه نهایی حتی بدتر شود.
طراحی خوب معمولا نتیجه تعادل میان چند اصل و چند نیاز متفاوت است. هدف این نیست که یک ویژگی خاص را تا جای ممکن افزایش دهیم، بلکه باید ساختاری ایجاد کنیم که در مجموع ساده، قابل فهم و قابل نگهداری باشد.
به همین دلیل، در بخش هایی از کتاب درباره زمانی صحبت می شود که اجرای بیش از حد یک ایده طراحی می تواند نتیجه معکوس داشته باشد.
بخش قابل توجهی از مثال های کتاب با زبان های جاوا و ++C ارائه شده اند و بسیاری از مفاهیم در قالب طراحی کلاس ها در زبان های شیءگرا توضیح داده می شوند.
با این حال، اصول مطرح شده محدود به کلاس ها نیستند.
بسیاری از مفاهیمی که درباره متدها مطرح می شوند، در زبان هایی که قابلیت های شیءگرایی محدودی دارند نیز برای طراحی تابع ها قابل استفاده هستند.
همچنین همین ایده ها را می توان برای اجزای بزرگ تر نرم افزار مانند زیرسیستم ها و سرویس های شبکه نیز به کار گرفت.
بنابراین ارزش کتاب تنها به یادگیری بهتر طراحی کلاس ها محدود نمی شود. موضوع اصلی، یادگیری روش هایی برای کنترل پیچیدگی در سطوح مختلف سیستم نرم افزاری است.
این کتاب برای برنامه نویسانی مناسب است که می خواهند از مرحله صرفا «نوشتن کد» عبور کنند و به درک عمیق تری از طراحی نرم افزار برسند.
اگر برنامه نویس هستید و گاهی با خودتان فکر می کنید چرا تغییر دادن یک قابلیت ساده در پروژه به کاری پیچیده تبدیل شده است، موضوعات این کتاب می توانند برایتان کاربردی باشند.
همچنین برای توسعه دهندگانی که روی پروژه های متوسط و بزرگ کار می کنند، کنترل پیچیدگی اهمیت بسیار بیشتری پیدا می کند. در پروژه های کوچک ممکن است یک طراحی ضعیف برای مدتی قابل تحمل باشد، اما با افزایش اندازه سیستم، تعداد قابلیت ها و تعداد اعضای تیم، مشکلات طراحی خود را بیشتر نشان می دهند.
دانشجویان مهندسی نرم افزار و علوم کامپیوتر نیز می توانند از این کتاب برای درک بهتر مفاهیمی مانند طراحی شیءگرا، ماژولار بودن، وابستگی میان اجزای سیستم و نگهداری نرم افزار استفاده کنند.
برنامه نویسان جاوا و ++C نیز به دلیل استفاده گسترده کتاب از مثال های این دو زبان، ارتباط مستقیمی با نمونه های آن برقرار خواهند کرد.
ساده بودن نرم افزار به معنی کم بودن تعداد قابلیت ها نیست. یک سیستم می تواند قابلیت های بسیار زیادی داشته باشد و در عین حال ساختاری قابل فهم داشته باشد.
سادگی در طراحی یعنی هر بخش از سیستم بتواند بدون ایجاد بار ذهنی غیرضروری برای برنامه نویس، مسئولیت مشخصی را انجام دهد.
وقتی طراحی ساده باشد، اضافه کردن قابلیت های جدید راحت تر می شود. پیدا کردن خطاها سریع تر انجام می شود. اعضای جدید تیم آسان تر می توانند ساختار سیستم را درک کنند و تغییرات آینده با ریسک کمتری همراه خواهند بود.
در مقابل، طراحی پیچیده باعث می شود حتی توسعه دهندگان باتجربه نیز برای ایجاد تغییرات کوچک مجبور به بررسی بخش های زیادی از سیستم شوند.
بنابراین سرمایه گذاری روی طراحی مناسب تنها یک موضوع زیبایی شناختی نیست؛ مستقیما روی سرعت توسعه، هزینه نگهداری و قابلیت توسعه نرم افزار تاثیر می گذارد.
یکی از ارزشمندترین بخش های این کتاب این است که خواننده را به یک روش عملی برای فکر کردن درباره طراحی هدایت می کند.
قرار نیست بعد از خواندن یک اصل، بلافاصله آن را در تمام پروژه ها اجرا کنید. بهتر است هنگام نوشتن یا بازبینی کد، به نشانه های پیچیدگی توجه کنید و سپس راه حل های مختلف را مقایسه کنید.
گاهی اولین راه حل، بهترین راه حل نیست.
ممکن است لازم باشد چند طراحی مختلف را امتحان کنید تا ساختاری پیدا شود که پیچیدگی کمتری داشته باشد. همین فرآیند آزمایش و مقایسه باعث افزایش تجربه طراحی می شود.
به مرور زمان، برنامه نویس در تشخیص مشکلات طراحی سریع تر می شود و قبل از اینکه پیچیدگی به یک مشکل جدی تبدیل شود، می تواند نشانه های آن را شناسایی کند.
تمرکز اصلی کتاب بر پیچیدگی نرم افزار و راه های کنترل آن در طول چرخه عمر سیستم است. در این مسیر، خواننده با مفاهیمی مانند طراحی ماژولار، ساده سازی کد، کپسوله سازی پیچیدگی، طراحی کلاس ها، وابستگی میان اجزا، بازطراحی مستمر و تشخیص نشانه های طراحی نامناسب آشنا می شود.
کتاب تلاش می کند این مفاهیم را از حالت تئوری خارج کند و آن ها را به ابزارهایی برای تصمیم گیری در طراحی تبدیل کند.
در نهایت، هدف این است که هنگام مواجه شدن با چند راه حل مختلف، فقط به این فکر نکنید که «کدام کد کار می کند؟»، بلکه سؤال مهم تری مطرح کنید:
کدام طراحی باعث می شود سیستم در آینده ساده تر باقی بماند؟
نرم افزار با گذشت زمان تغییر می کند. قابلیت های جدید اضافه می شوند، نیازمندی ها تغییر می کنند، اعضای تیم جابه جا می شوند و بخش های مختلف سیستم به یکدیگر وابسته می شوند. در چنین شرایطی، پیچیدگی به تدریج افزایش پیدا می کند.
نمی توان جلوی تمام پیچیدگی ها را گرفت، اما می توان پیچیدگی غیرضروری را حذف و پیچیدگی اجتناب ناپذیر را در بخش های مشخصی از سیستم محصور کرد.
طراحی ماژولار، کپسوله سازی، ساده سازی، بازطراحی مستمر و توجه به نشانه های هشدار، مجموعه ای از ابزارهای ذهنی هستند که به برنامه نویس کمک می کنند سیستم را در طول زمان قابل فهم تر نگه دارد.
این کتاب به جای ارائه یک نسخه ثابت برای تمام پروژه ها، تلاش می کند نگاه شما را نسبت به طراحی نرم افزار تغییر دهد. موضوع اصلی کتاب این است که طراحی نرم افزار یک مرحله کوتاه در ابتدای پروژه نیست؛ بلکه فعالیتی مداوم است که باید در تمام طول عمر سیستم ادامه داشته باشد.
اگر می خواهید علاوه بر نوشتن کد، درک عمیق تری از این موضوع داشته باشید که چرا بعضی سیستم ها با گذشت زمان همچنان قابل توسعه باقی می مانند و چرا بعضی پروژه ها به تدریج به مجموعه ای از وابستگی ها و پیچیدگی های دشوار تبدیل می شوند، مفاهیم این کتاب می توانند چارچوب مناسبی برای مطالعه و تمرین در اختیار شما قرار دهند.
نمونه چاپ کتاب موجود نیست.
نظرات کاربران (0)