حالت تاریک
فصل ۱ — مهندسی نرمافزار چیست؟
مهندسی — کاربرد عملی علم
توسعهٔ نرمافزار فرایندی از کشف و کاوش است؛ بنابراین برای موفقیت در آن، مهندسان نرمافزار باید در یادگیری متخصص شوند.
بهترین رویکرد بشریت برای یادگیری، علم است؛ پس باید فنون و راهبردهای علم را بپذیریم و آنها را روی مسائل خود به کار ببریم. اغلب این را اشتباه برداشت میکنند و فکر میکنند منظور این است که باید فیزیکدان شویم و چیزها را با دقتی غیرمنطقی — در بستر نرمافزار — اندازه بگیریم. مهندسی عملیتر از آن است.
وقتی میگویم باید فنون و راهبردهای علم را به کار ببریم، منظورم بهکارگیری چند ایدهٔ بسیار پایهای، اما در عین حال بسیار مهم، است.
روش علمی که بیشتر ما در مدرسه دربارهٔ آن آموختیم، در ویکیپدیا اینگونه توصیف شده است:
- مشخصسازی (Characterize): مشاهدهٔ وضعیت فعلی.
- فرضیهسازی (Hypothesize): ساختن توصیفی، یک نظریه که شاید مشاهدهٔ شما را توضیح دهد.
- پیشبینی (Predict): پیشبینی بر اساس فرضیه.
- آزمایش (Experiment): آزمودن پیشبینی.
وقتی تفکر خود را اینگونه سامان میدهیم و بر پایهٔ آزمایشهای کوچک و غیررسمی زیاد پیش میرویم، ریسک پرش به نتیجهگیریهای نامناسب را محدود میکنیم و کار بهتری انجام میدهیم.
اگر شروع کنیم به فکر کردن دربارهٔ کنترل متغیرها در آزمایشها تا به نتایج سازگارتر و قابلاتکاتری برسیم، به سمت سیستمها و کدی قطعیتر هدایت میشویم. اگر شروع کنیم به تردید نسبت به ایدههایمان و کاوش در چگونگی رد کردن آنها، میتوانیم ایدههای بد را زودتر شناسایی و حذف کنیم و خیلی سریعتر پیشرفت کنیم.
این کتاب عمیقاً بر پایهٔ رویکردی عملی و pragmatیک برای حل مسائل نرمافزاری استوار است؛ رویکردی مبتنی بر پذیرش غیررسمی اصول علمی پایهای — به عبارت دیگر، مهندسی!
مهندسی نرمافزار چیست؟
تعریف کاری من از مهندسی نرمافزار که ایدههای این کتاب بر آن استوار است، این است:
مهندسی نرمافزار، بهکارگیری رویکردی تجربی و علمی برای یافتن راهحلهای کارآمد و اقتصادی برای مسائل عملی در نرمافزار است.
پذیرش رویکرد مهندسی در توسعهٔ نرمافزار به دو دلیل اصلی مهم است. نخست، توسعهٔ نرمافزار همیشه تمرینی در کشف و یادگیری است؛ دوم، اگر هدف ما «کارآمد» و «اقتصادی» بودن باشد، توانایی یادگیری ما باید پایدار باشد.
این یعنی باید پیچیدگی سیستمهایی که میسازیم را طوری مدیریت کنیم که توانایی یادگیری چیزهای تازه و سازگاری با آنها حفظ شود.
پس باید در یادگیری و در مدیریت پیچیدگی متخصص شویم.
پنج فن که ریشههای این تمرکز بر یادگیری را شکل میدهند، عبارتاند از:
- تکرار (Iteration)
- بازخورد (Feedback)
- افزایش تدریجی (Incrementalism)
- آزمایشگری (Experimentation)
- تجربهگرایی (Empiricism)
این رویکردی تکاملی برای ساخت سیستمهای پیچیده است. سیستمهای پیچیده کامل و یکجا از تخیل ما بیرون نمیآیند. حاصل گامهای کوچک زیادند؛ جایی که ایدههایمان را امتحان میکنیم و در مسیر به موفقیت و شکست واکنش نشان میدهیم. اینها ابزارهاییاند که کاوش و کشف را ممکن میکنند.
کار به این شکل محدودیتهایی بر نحوهٔ پیشروی ایمن ما تحمیل میکند. باید طوری کار کنیم که سفر کاوشی که در قلب هر پروژهٔ نرمافزاری است را تسهیل کند.
پس علاوه بر تمرکز تیز بر یادگیری، باید طوری کار کنیم که وقتی پاسخها — و گاه حتی جهت — نامشخص است، بتوانیم پیشرفت کنیم.
برای آن باید در مدیریت پیچیدگی متخصص شویم. هرچه ماهیت مسائلی که حل میکنیم یا فناوریهایی که برای حل آنها به کار میبریم چه باشد، رویارویی با پیچیدگی مسائل و راهحلهایی که به آنها میدهیم، تفکیککنندهٔ اصلی میان سیستمهای بد و خوب است.
برای متخصص شدن در مدیریت پیچیدگی به موارد زیر نیاز داریم:
- مدولاریته (Modularity)
- چسبندگی (Cohesion)
- جداسازی دغدغهها (Separation of Concerns)
- انتزاع (Abstraction)
- جفتشدگی سست (Loose Coupling)
آسان است به این ایدهها نگاه کرد و آنها را آشنا و کماهمیت دانست. بله، تقریباً حتماً با همهٔ آنها آشنا هستید. هدف این کتاب ساماندهی آنها و قرار دادنشان در رویکردی منسجم برای توسعهٔ سیستمهای نرمافزاری است که به شما کمک کند بیشترین بهره را از پتانسیلشان ببرید.
این کتاب توضیح میدهد چگونه از این ده ایده بهعنوان ابزار برای هدایت توسعهٔ نرمافزار استفاده کنیم. سپس مجموعهای از ایدهها را معرفی میکند که ابزارهای عملی برای راهبرد مؤثر در هر توسعهٔ نرمافزاریاند، از جمله:
- قابلیت آزمون (Testability)
- قابلیت استقرار (Deployability)
- سرعت (Speed)
- کنترل متغیرها (Controlling the variables)
- تحویل مستمر (Continuous delivery)
وقتی این تفکر را به کار میبریم، نتایج عمیق است. نرمافزاری با کیفیت بالاتر میسازیم، سریعتر کار میکنیم، و افرادی که در تیمهایی که این اصول را میپذیرند کار میکنند گزارش میدهند از کارشان بیشتر لذت میبرند، استرس کمتری دارند و تعادل بهتری میان کار و زندگی دارند.[^1]
این ادعاهای بزرگیاند، اما باز هم با داده پشتیبانی میشوند.
بازپسگیری «مهندسی نرمافزار»
روی عنوان این کتاب سخت فکر کردم — نه به این دلیل که نمیدانستم چه بناممش، بلکه چون صنعت ما معنای engineering را در بستر نرمافزار آنقدر بازتعریف کرده که اصطلاح ارزشش را از دست داده است.
در نرمافزار اغلب یا صرفاً مترادف «کد» دیده میشود، یا چیزی که مردم را از خود میراند چون بیش از حد بوروکراتیک و رویهمحور به نظر میرسد. برای مهندسی واقعی، هیچچیز دورتر از حقیقت نیست.
در رشتههای دیگر، engineering به سادگی یعنی «چیزهایی که کار میکنند». فرایند و عملی است که برای افزایش شانس انجام کار خوب به کار میبرید.
اگر شیوههای «مهندسی نرمافزار» ما اجازه ندهد نرمافزار بهتری سریعتر بسازیم، واقعاً مهندسی نیستند و باید آنها را تغییر دهیم!
این ایدهٔ بنیادین در قلب این کتاب است و هدفش توصیف مدلی فکری منسجم است که چند اصل بنیادین را — که در ریشهٔ همهٔ توسعهٔ نرمافزاری عالی قرار دارند — گرد هم میآورد.
هیچ تضمینی برای موفقیت نیست، اما با پذیرش این ابزارهای ذهنی و اصول سازماندهنده و بهکارگیری آنها در کار خود، قطعاً شانس موفقیتتان را افزایش میدهید.
چگونه پیشرفت کنیم
توسعهٔ نرمافزار فعالیتی پیچیده و پیشرفته است. از بعضی جهات یکی از پیچیدهترین کارهایی است که بهعنوان گونه انجام میدهیم. مضحک است فرض کنیم هر فرد یا حتی هر تیم میتواند — و باید — هر بار که کار تازهای شروع میکنیم، از صفر روش برخورد را اختراع کند.
چیزهایی را آموختهایم — و همچنان میآموزیم — که کار میکنند و چیزهایی که نمیکنند. پس چگونه بهعنوان صنعت و بهعنوان تیمها میتوانیم پیشرفت کنیم و — همانطور که اسحاق نیوتن گفت — بر شانهٔ غولها بایستیم، اگر همه روی همهچیز حق وتو داشته باشند؟ به اصول توافقشده و انضباطی نیاز داریم که فعالیتهایمان را هدایت کند.
خطر این خط فکر آن است که اگر نادرست به کار رود، به تفکر draconian و بیشازحد دستوری از نوع «تصمیم از بالا» منجر شود.
به ایدههای بد گذشته برمیگردیم؛ جایی که فرض میشود وظیفهٔ مدیران و رهبران گفتن به بقیه است که چه کنند و چگونه.
مشکل بزرگ «prescriptive» یا بیشازحد «directive» بودن این است: اگر بعضی ایدههای ما اشتباه یا ناقص باشند چه میکنیم؟ حتماً چنین خواهند بود؛ پس چگونه میتوانیم ایدههای بد قدیمی اما ریشهدار را به چالش بکشیم و رد کنیم، و ایدههای تازه و بالقوهٔ عالیِ آزموننشده را ارزیابی کنیم؟
نمونهٔ بسیار قوی از حل این مسائل داریم: رویکردی که آزادی فکری برای به چالش کشیدن و رد کردن سگما و تمایز میان مد، ایدههای بد قدیمی و ایدههای عالی — هر منبعی که باشند — به ما میدهد. اجازه میدهد ایدههای بد را با ایدههای بهتر جایگزین کنیم و ایدههای خوب را بهبود دهیم. اساساً به ساختاری نیاز داریم که بتوانیم رشد کنیم و رویکردها، راهبردها، فرایندها، فناوریها و راهحلهای بهبودیافته را تکامل دهیم. به این نمونهٔ خوب علم میگوییم!
وقتی این نوع تفکر را برای حل مسائل عملی به کار میبریم، مهندسی مینامیمش!
این کتاب دربارهٔ معنای بهکارگیری استدلال به سبک علمی در رشتهٔ ما و دستیابی به چیزی است که واقعاً و دقیقاً بتوانیم مهندسی نرمافزار بنامیم.
تولد مهندسی نرمافزار
مفهوم مهندسی نرمافزار در اواخر دههٔ ۱۹۶۰ پدید آمد. اصطلاح را نخست Margaret Hamilton به کار برد؛ او بعدها مدیر بخش مهندسی نرمافزار آزمایشگاه ابزار دقیق MIT شد. Margaret رهبری تلاش برای توسعهٔ نرمافزار کنترل پرواز برنامهٔ فضایی Apollo را بر عهده داشت.
در همان دوره، سازمان پیمان آتلانتیک شمالی (NATO) کنفرانسی در Garmisch-Partenkirchen آلمان برگزار کرد تا اصطلاح را تعریف کند. این نخستین کنفرانس مهندسی نرمافزار بود.
نخستین رایانهها با تغییر سوئیچها — یا حتی بهصورت سختافزاری در طراحیشان — برنامهریزی میشدند. بهزودی برای پیشگامان روشن شد که این کند و انعطافناپذیر است و ایدهٔ «برنامهٔ ذخیرهشده» متولد شد. این نخستین باری بود که تمایز روشنی میان نرمافزار و سختافزار ایجاد شد.
تا اواخر دههٔ ۱۹۶۰، برنامههای رایانهای آنقدر پیچیده شده بودند که ساخت و نگهداریشان به خودی خود دشوار بود. در حل مسائل پیچیدهتر نقش داشتند و بهسرعت گام توانمندسازی شدند که کلاسهایی از مسائل را اصلاً قابل حل کردند.
شکاف قابلتوجهی میان سرعت پیشرفت در سختافزار و نرمافزار دیده میشد. آن زمان به بحران نرمافزار (software crisis) اشاره میکردند.
کنفرانس NATO تا حدی در پاسخ به این بحران برگزار شد.
با خواندن یادداشتهای کنفرانس امروز، ایدههای زیادی هست که clearly پایدارند. آزمون زمان را پس دادهاند و امروز به همان اندازهٔ ۱۹۶۸ درستاند. اگر میخواهیم ویژگیهای بنیادینی را که رشتهٔ ما را تعریف میکنند شناسایی کنیم، باید برایمان جالب باشد.
چند سال بعد، Fred Brooks برندهٔ جایزهٔ Turing، پیشرفت نرمافزار را با سختافزار مقایسه کرد:
هیچ توسعهٔ واحدی — نه در فناوری و نه در تکنیک مدیریت — بهتنهایی حتی یک مرتبه بهبود در بهرهوری، قابلیت اطمینان یا سادگی در یک دهه وعده میدهد.[^2]
Brooks این را در مقایسه با قانون Moore[^3] معروف میگفت؛ قانونی که توسعهٔ سختافزار سالها با آن همراستا بود.
این مشاهدهٔ جالبی است و فکر میکنم بسیاری را شگفتزده کند، اما در اصل همیشه درست بوده است.
Brooks ادامه میدهد که این چندان مشکل توسعهٔ نرمافزار نیست؛ بیشتر مشاهدهای است روی بهبود خیرهکننده و منحصربهفرد عملکرد سختافزار:
باید ببینیم ناهنجاری این نیست که پیشرفت نرمافزار اینقدر کند است، بلکه این است که پیشرفت سختافزار رایانه اینقدر سریع است. هیچ فناوری دیگری از آغاز تمدن شش مرتبه بهبود قیمت-عملکرد در ۳۰ سال ندیده است.
این را در ۱۹۸۶ نوشت؛ دورانی که امروز طلوع عصر رایانه مینامیمش. پیشرفت سختافزار از آن زمان با همین سرعت ادامه یافته و رایانههایی که برای Brooks قدرتمند به نظر میرسیدند در برابر ظرفیت و عملکرد سیستمهای امروز اسباببازی به نظر میرسند. و با این حال... مشاهدهٔ او دربارهٔ نرخ بهبود در توسعهٔ نرمافزار همچنان درست است.
تغییر پارادایم
ایدهٔ تغییر پارادایم (paradigm shift) را فیزیکدان Thomas Kuhn مطرح کرد.
بیشتر یادگیری نوعی انباشت است. لایههای درک را میسازیم و هر لایه بر لایهٔ قبلی استوار است.
اما همهٔ یادگیری اینگونه نیست. گاه دیدگاهمان نسبت به چیزی اساساً عوض میشود؛ این اجازه میدهد چیزهای تازه بیاموزیم، اما یعنی باید آنچه قبل بود را کنار بگذاریم.
در قرن هجدهم، زیستشناسان معتبر (آن زمان اینطور نمینامیدندشان) باور داشتند بعضی جانوران خودبهخود پدید میآیند. Darwin در میانهٔ قرن نوزدهم فرایند انتخاب طبیعی را توصیف کرد و ایدهٔ تولید خودبهخود را کاملاً برانداخت.
این تغییر تفکر در نهایت به درک مدرن ما از ژنتیک و توانایی فهم زندگی در سطح بنیادینتر، ساخت فناوریهای دستکاری ژن، واکسنهای COVID-19 و درمانهای ژنتیکی منجر شد.
بههمین شکل Kepler، Copernicus و Galileo حکمت رایج آن زمان — که زمین مرکز جهان است — را به چالش کشیدند و مدل خورشیدمرکزی برای منظومهٔ شمسی پیشنهاد دادند. این در نهایت به قوانین گرانش Newton و نسبیت عام Einstein و سفر فضایی و فناوریهایی مثل GPS انجامید.
ایدهٔ تغییر پارادایم ضمناً شامل این است که در این فرایند بعضی ایدههایی را که دیگر درست نیستند دور میریزیم.
پیامدهای تلقی توسعهٔ نرمافزار بهعنوان رشتهٔ مهندسی واقعی — ریشهدار در فلسفهٔ روش علمی و عقلانیت علمی — عمیق است.
نه فقط در اثر و کاراییاش — که در کتاب Accelerate[^4] چنان زیبا توصیف شده — بلکه در نیاز اساسی به کنار گذاشتن ایدههایی که این رویکرد جایگزینشان میکند.
این رویکردی برای یادگیری مؤثرتر و دور انداختن کارآمدتر ایدههای بد به ما میدهد.
باور دارم رویکرد توسعهٔ نرمافزاری که در این کتاب توصیف میکنم چنین تغییر پارادایمی است. دیدگاه تازهای از آنچه انجام میدهیم و چگونه انجام میدهیم ارائه میدهد.
خلاصه
بهکارگیری این نوع تفکر مهندسی در نرمافزار لازم نیست سنگین یا بیشازحد پیچیده باشد. تغییر پارادایم در تفکر متفاوت دربارهٔ آنچه انجام میدهیم و چگونه نرمافزار میسازیم باید کمک کند جنگل را از درختان ببینیم و کار را سادهتر، قابلاتکاتر و کارآمدتر کنیم.
این دربارهٔ بوروکراسی بیشتر نیست؛ دربارهٔ تقویت توانایی ساخت نرمافزار باکیفیت بهشکل پایدارتر و قابلاتکاتر است.
[^1]: بر اساس یافتههای گزارشهای «State of DevOps» و همچنین گزارشهای Microsoft و Google.
[^2]: منبع: مقالهٔ ۱۹۸۶ Fred Brooks با عنوان «No Silver Bullet». نگاه کنید به https://bit.ly/2UalM4T.
[^3]: در ۱۹۶۵ Gordon Moore پیشبینی کرد تراکم ترانزیستورها (نه عملکرد) هر سال — بعداً به هر دو سال — برای دههٔ بعد (تا ۱۹۷۵) دو برابر میشود. این پیشبینی هدفی برای تولیدکنندگان نیمهرسانا شد و بهمراتب فراتر از انتظارات Moore برآورده شد و چند دهه دیگر هم ادامه یافت. بعضی ناظران باور دارند به پایان این رشد انفجاری ظرفیت نزدیک میشویم — بهخاطر محدودیت رویکردهای فعلی و اثرات کوانتومی — اما در زمان نگارش، توسعهٔ نیمهرسانهای با تراکم بالا همچنان قانون Moore را دنبال میکند.
[^4]: افراد پشت گزارشهای «State of DevOps»، DORA، مدل پیشبینیکنندهای را که از پژوهششان ساختهاند توصیف کردند. منبع: Accelerate: The Science of Lean Software and DevOps اثر Nicole Fosgren، Jez Humble و Gene Kim (۲۰۱۸).