نرمافزار شیءگرا در حال رشد، با راهنمایی تستها (مجموعهٔ امضای بک)
Growing Object-Oriented Software, Guided by Tests (Beck Signature Series)
معرفی کتاب «نرمافزار شیءگرا در حال رشد، با راهنمایی تستها (مجموعهٔ امضای بک)» (با عنوان لاتین Growing Object-Oriented Software, Guided by Tests (Beck Signature Series)) نوشتهٔ Steve Freeman و Nat Pryce، منتشرشده توسط نشر Addison Wesley; Addison-Wesley Professional در سال 2009. این کتاب در 150 صفحه، فرمت pdf، زبان انگلیسی ارائه شده است. «نرمافزار شیءگرا در حال رشد، با راهنمایی تستها (مجموعهٔ امضای بک)» در دستهٔ برنامهنویسی قرار دارد.
کتاب «نرمافزار شیءگرا در حال رشد، با راهنمایی تستها» (Growing Object-Oriented Software, Guided by Tests) نوشتهٔ استیو فریمن (Steve Freeman) و نت پرایس (Nat Pryce) که در مجموعهٔ امضای کنت بک (Kent Beck) توسط انتشارات Addison-Wesley Professional منتشر شده، راهنمایی عملی و پیشرفته برای پیادهسازی مؤثر آزمونمحوری (Test-Driven Development) است. این کتاب با تکیه بر بیش از یک دهه تجربهٔ نویسندگان در ساخت سیستمهای واقعی، فراتر از مفاهیم پایه رفته و نشان میدهد که چگونه آزمونها میتوانند توسعهٔ نرمافزاری منسجم، قابلاعتماد و پایدار را هدایت کنند.
دربارهٔ کتاب نرمافزار شیءگرا در حال رشد، با راهنمایی تستها (مجموعهٔ امضای بک)
ایدهٔ محوری این کتاب که در عنوان آن نیز منعکس شده، «رشد» نرمافزار تحت هدایت آزمونها است. نویسندگان با معرفی مفهوم «اسکلت راهرونده» (Walking Skeleton) - یعنی پیادهسازیِ حداقلی و سرتاسری از سیستم که زیرساختهای اصلی را در بر میگیرد - فرایندی گامبهگام برای شروع و پیشبرد پروژههای نرمافزاری ارائه میدهند. آنها با استفاده از یک مثال گسترده و عملی، توسعهٔ برنامهای برای حراج آنلاین (AuctionSniper) را به تصویر میکشند و نشان میدهند که چگونه آزمونها نه تنها صحت کد را تضمین میکنند، بلکه به عنوان ابزاری برای کشف و اصلاح طراحیِ شیءگرا عمل میکنند. سبک نگارش کتاب روان و غیررسمی اما دقیق است و با ارائهٔ جزئیات کامل از فرایندهای فکری نویسندگان، تجربهای شبیه به نشستن در کنار یک برنامهنویس خبره را برای خواننده فراهم میآورد. این کتاب به خصوص بر نقش اشیاء ساختگی (Mock Objects) در کشف روابط بین کلاسها و هدایت طراحیِ مبتنی بر تعاملات تأکید دارد و رویکردی متمایز از نمونههای ساده و آموزشیِ مرسوم ارائه میدهد. با وجود اینکه مثالها به زبان جاوا نوشته شدهاند، اصول مطرحشده برای توسعهدهندگان سایر زبانهای شیءگرا مانند سیشارپ و پیاچپی نیز قابلاستفاده است.
دربارهٔ نویسنده
استیو فریمن و نت پرایس هر دو از متخصصان شناختهشده و پیشگامان حوزهٔ توسعهٔ نرمافزار چابک و آزمونمحوری هستند. فریمن مشاوری مستقل در زمینهٔ توسعهٔ چابک و یکی از اعضای بنیانگذار باشگاه «سهشنبههای افراطی» (Extreme Tuesday Club) در لندن است. پرایس نیز به عنوان برنامهنویس، معمار و مشاور در صنایع مختلف فعالیت داشته است. این دو نویسنده، خالقان کتابخانهٔ متنباز جیماک (jMock) هستند که در کتاب به طور گسترده از آن استفاده شده است. فریمن و پرایس به طور مشترک در سال ۲۰۰۶ موفق به دریافت جایزهٔ گوردون پاسک (Gordon Pask Award) از اتحادیهٔ چابک (Agile Alliance) شدند که به پاس قدردانی از مشارکتهای برجستهشان در جامعهٔ توسعهٔ چابک به آنها اعطا گردید.
چرا باید نرمافزار شیءگرا در حال رشد، با راهنمایی تستها (مجموعهٔ امضای بک) را بخوانید؟
مطالعهٔ این کتاب، بینشها و مهارتهای کلیدی زیر را برای توسعهدهندگان نرمافزار به ارمغان میآورد:
طراحی محور و تکاملی: برخلاف بسیاری از کتابهای مقدماتی، این اثر طراحی را به عنوان یکی از ارکان اصلی آزمونمحوری معرفی میکند و نشان میدهد چگونه آزمونها میتوانند به تکامل طراحی کمک کنند.
یادگیری از یک مثال واقعی و کامل: بخش عظیمی از کتاب (حدود ۱۵۰ صفحه) به توسعهٔ گامبهگام یک برنامهٔ کاربردی واقعی (سیستم حراج) اختصاص دارد که به درک چالشهای دنیای واقعی مانند همزمانی، رابط کاربری و وابستگیهای خارجی کمک میکند.
تسلط بر اشیاء ساختگی: کتاب به طور عمیق به استفاده از اشیاء ساختگی برای هدایت طراحی و آزمایشِ تعاملات بین اشیاء میپردازد و راهبردهای مؤثری برای پیادهسازی آن ارائه میدهد.
پایداری و نگهداشتپذیری آزمونها: یکی از بخشهای ارزشمند کتاب به چگونگی نگهداشت و خواناییِ آزمونها اختصاص دارد. موضوعاتی مانند بوی بدِ آزمونها (Test Smells)، استفاده از سازندهها (Builders) برای ساخت دادههای آزمون و افزایش خوانایی پیامهای خطا در این بخش پوشش داده شدهاند.
مباحث پیشرفته و چالشبرانگیز: کتاب به موضوعات دشواری مانند آزمونِ پایداری دادهها (Persistence)، کدهای همروند (Multithreading) و کدهای ناهمگام (Asynchronous) میپردازد و راهکارهای عملی برای مواجهه با این چالشها ارائه میکند.
این کتاب برای چه کسانی مناسب است؟
این کتاب برای توسعهدهندگانی که با مفاهیم اولیهٔ آزمونمحوری آشنایی دارند و به دنبال درک عمیقتر از کاربرد آن در پروژههای واقعی هستند، بسیار مناسب است. همچنین، برای برنامهنویسانی که دانش طراحی شیءگرا دارند اما در پیادهسازی عملیِ آزمونها در پروژههای بزرگ با چالش مواجه میشوند، منبعی ارزشمند محسوب میشود. به دلیل تأکید بر اصول طراحی و معماری، این کتاب برای معماران نرمافزار و تیمهای توسعهای که به دنبال بهبود کیفیت کد و فرایندهای خود هستند نیز بسیار سودمند است. با اینکه مثالها به زبان جاوا هستند، مباحث آن برای توسعهدهندگان سایر زبانهای شیءگرا نیز قابلتعمیم است و به عنوان یکی از منابع کلاسیک و تأثیرگذار در این حوزه شناخته میشود.
سوالات متداول
آیا برای درک این کتاب به دانش قبلیِ کاملی در مورد آزمونمحوری نیاز است؟
خیر، کتاب با مرور سریع مفاهیم پایهٔ آزمونمحوری و ابزارهایی مانند جییونیت (JUnit) و جیماک آغاز میشود، اما هدف اصلی آن ارائهٔ بینشهای عمیقتر و پیشرفتهتر است. بنابراین، داشتن آشنایی اولیه با اصول آزموننویسی میتواند به درک بهتر مطالب کمک کند.
آیا این کتاب صرفاً بر روی زبان برنامهنویسی جاوا متمرکز است؟
اگرچه تمام مثالهای کد به زبان جاوا نوشته شده و کتابخانهٔ جیماک از ابزارهای اصلی آن است، اما اصول طراحی و مفاهیم ارائهشده در کتاب، مستقل از زبان خاصی هستند و برای توسعهدهندگان زبانهای مدرن شیءگرا مانند سیشارپ و پیاچپی نیز قابلاستفاده و بسیار ارزشمند هستند.
با وجود گذشت سالها از انتشار کتاب، آیا محتوای آن هنوز معتبر است؟
بله، این کتاب به عنوان یکی از متون کلاسیک و بنیادین در زمینهٔ آزمونمحوری شناخته میشود و اصول و الگوهای مطرحشده در آن، همچنان در توسعهٔ نرمافزارهای مدرن کاربرد دارند. با اینکه ممکن است برخی از ابزارهای خاص بهروزرسانی شده باشند، رویکردهای طراحی و تفکرات بنیادین کتاب همچنان معتبر و تأثیرگذارند.
This book has been in my Amazon pre-ordered list for quite a while and I was looking forward to this. I found the title alone already excellent. Steven and Nat (authors of jMock) are well known expert TDD practitioners, so I was looking forward to what they had to say. The book was better than I had expected. The book consists of 5 parts. The first part of a very quick introduction to TDD and jMock. The second part discusses the tdd cycle in more detail. The third part (150 pages) is a very large example of growing a piece of software. The fourth part discusses topics on how to sustain TDD and the last part covers some advanced topics. In this review, I'll skip part 1 as it was short and nothing special. Part two covers the TDD cycle and the link to evolutionary design. Steve and Nat have a design style that focuses almost purely on the interactions between classes which are most frequently tested using expectations on mock objects (which, as authors of jMock, they have lots of experience with). Most notable from part 2, for me, were the classifications of objects that they used, the strong focus on interaction and mocking (more than I usually have when test-driving) and their lack of focus on classes but focus on roles and responsibilities. Nat and Steve clarify their thinking exceptionally well which makes it all easy to understand. Part 3 takes the largest part of the book, which is where they test-drive an AuctionSniper application. It is a small application, but large for a book example. The authors show how they gradually build up the application by adding one test at the time and how they gained insights during this process which made them adjust their design. I had mixed feelings about this part as a book didn't seem like the best medium for doing this, but still I appreciate the insights they had and also their attempt to make it as close to "real world" as possible. Writing tests is one thing, maintaining them in another. Part 4 discusses how to make the tests maintainable and the tdd cycle sustainable. Personally, I found this part very insightful and the authors discipline exemplar. The authors start of with different test smells and what to do about it. They then discuss readability of the tests and of the error messages and spend some time of test object creation. Most notable from that part (for me) was their focus on using builders for creating test data, rather than object mothers. The final part covers three (or actually two!) advanced topics. First is testing persistence where most interesting was how the authors seemed to prefer to "go all the way" whereas the common advise (for test speed) is to rollback and mock more. (this was actually a common theme in their book). The last two chapters deal with multi-threading and async code. I was unclear why these were separated in two chapters and they they were in this particular order. The content was excellent though, except that I missed some typical design guidelines related to multi-threading design. It almost felt they were in a hurry to write the last two chapters... Anyways, in conclusion, this will definitively be one of my favorite (if not the favorite) TDD books and general design books. Steven and Nat did a wonderful job on this one. Though the book is not perfect, I enjoyed it thoroughly. A definite recommendation for anyone interested in modern design and TDD. Growing Object-Oriented Software, Guided by Tests......Page 1 Contents......Page 9 Foreword......Page 15 Preface......Page 17 Acknowledgments......Page 21 Part I: Introduction......Page 25 Software Development as a Learning Process......Page 27 Feedback Is the Fundamental Tool......Page 28 Practices That Support Change......Page 29 Test-Driven Development in a Nutshell......Page 30 The Bigger Picture......Page 31 Testing End-to-End......Page 32 Levels of Testing......Page 33 External and Internal Quality......Page 34 Values and Objects......Page 37 Follow the Messages......Page 38 But Sometimes Ask......Page 41 Unit-Testing the Collaborating Objects......Page 42 Support for TDD with Mock Objects......Page 43 A Minimal Introduction to JUnit 4......Page 45 Hamcrest Matchers and assertThat()......Page 48 jMock2: Mock Objects......Page 49 Part II: The Process of Test-Driven Development......Page 53 Introduction......Page 55 First, Test a Walking Skeleton......Page 56 Deciding the Shape of the Walking Skeleton......Page 57 Build Sources of Feedback......Page 59 Expose Uncertainty Early......Page 60 Start Each Feature with an Acceptance Test......Page 63 Separate Tests That Measure Progress from Those That Catch Regressions......Page 64 Start Testing with the Simplest Success Case......Page 65 Watch the Test Fail......Page 66 Unit-Test Behavior, Not Methods......Page 67 Listen to the Tests......Page 68 Tuning the Cycle......Page 69 Designing for Maintainability......Page 71 Internals vs. Peers......Page 74 No And's, Or's, or But's......Page 75 Object Peer Stereotypes......Page 76 Composite Simpler Than the Sum of Its Parts......Page 77 Context Independence......Page 78 Hiding the Right Information......Page 79 An Opinionated View......Page 80 How Writing a Test First Helps the Design......Page 81 Communication over Classification......Page 82 Value Types......Page 83 Where Do Objects Come From?......Page 84 Refactor Interfaces Too......Page 87 Compose Objects to Describe System Behavior......Page 88 Building Up to Higher-Level Programming......Page 89 And What about Classes?......Page 91 Only Mock Types That You Own......Page 93 Mock Application Objects in Integration Tests......Page 95 Part III: A Worked Example......Page 97 To Begin at the Beginning......Page 99 Communicating with an Auction......Page 102 Getting There Safely......Page 103 This Isn't Real......Page 105 Get the Skeleton out of the Closet......Page 107 Our Very First Test......Page 108 Some Initial Choices......Page 110 Building the Test Rig......Page 113 Failing and Passing the Test......Page 119 The Necessary Minimum......Page 126 An Introduction to the Market......Page 129 A Test for Bidding......Page 130 The AuctionMessageTranslator......Page 136 Unpacking a Price Message......Page 142 Finish the Job......Page 145 Introducing AuctionSniper......Page 147 Sending a Bid......Page 150 Tidying Up the Implementation......Page 155 Defer Decisions......Page 160 Emergent Design......Page 161 First, a Failing Test......Page 163 Who Knows about Bidders?......Page 164 The Sniper Has More to Say......Page 167 The Sniper Acquires Some State......Page 168 The Sniper Wins......Page 170 Making Steady Progress......Page 172 A More Realistic Implementation......Page 173 Displaying Price Details......Page 176 Simplifying Sniper Events......Page 183 Follow Through......Page 188 Final Polish......Page 192 Observations......Page 195 Testing for Multiple Items......Page 199 Adding Items through the User Interface......Page 207 Observations......Page 213 Finding a Role......Page 215 Extracting the Chat......Page 216 Extracting the Connection......Page 219 Extracting the SnipersTableModel......Page 221 Observations......Page 225 Stop When We've Had Enough......Page 229 Observations......Page 236 What If It Doesn't Work?......Page 239 Detecting the Failure......Page 241 Displaying the Failure......Page 242 Disconnecting the Sniper......Page 243 Recording the Failure......Page 245 Observations......Page 249 Part IV: Sustainable Test-Driven Development......Page 251 Introduction......Page 253 I Need to Mock an Object I Can't Replace (without Magic)......Page 254 Logging Is a Feature......Page 257 Mocking Concrete Classes......Page 259 Don't Mock Values......Page 261 Bloated Constructor......Page 262 Confused Object......Page 264 Too Many Dependencies......Page 265 Too Many Expectations......Page 266 What the Tests Will Tell Us (If We're Listening)......Page 268 Introduction......Page 271 Test Names Describe Features......Page 272 Canonical Test Structure......Page 275 Streamline the Test Code......Page 276 Assertions and Expectations......Page 278 Literals and Variables......Page 279 Introduction......Page 281 Test Data Builders......Page 282 Creating Similar Objects......Page 283 Emphasizing the Domain Model with Factory Methods......Page 285 Removing Duplication at the Point of Use......Page 286 Communication First......Page 288 Design to Fail......Page 291 Highlight Detail with Matchers......Page 292 Self-Describing Value......Page 293 Tracer Object......Page 294 Diagnostics Are a First-Class Feature......Page 295 Introduction......Page 297 Test for Information, Not Representation......Page 298 Precise Assertions......Page 299 Precise Expectations......Page 301 "Guinea Pig" Objects......Page 308 Part V: Advanced Topics......Page 311 Introduction......Page 313 Isolate Tests That Affect Persistent State......Page 314 Make Tests Transaction Boundaries Explicit......Page 316 Testing an Object That Performs Persistence Operations......Page 318 Testing That Objects Can Be Persisted......Page 321 But Database Tests Are S-l-o-w!......Page 324 Introduction......Page 325 Separating Functionality and Concurrency Policy......Page 326 Unit-Testing Synchronization......Page 330 Stress-Testing Passive Objects......Page 335 Synchronizing the Test Thread with Background Threads......Page 336 The Limitations of Unit Stress Tests......Page 337 Introduction......Page 339 Sampling or Listening......Page 340 Two Implementations......Page 342 Runaway Tests......Page 346 Lost Updates......Page 347 Testing That an Action Has No Effect......Page 349 Externalize Event Sources......Page 350 A......Page 373 C......Page 374 E......Page 375 I......Page 376 L......Page 377 N......Page 378 R......Page 379 S......Page 380 T......Page 381 X......Page 382 Afterword: A Brief History of Mock Objects......Page 353 Appendix A: jMock2 Cheat Sheet......Page 359 Appendix B: Writing a Hamcrest Matcher......Page 367 Bibliography......Page 371 About the Authors......Page 23 Foreword by Kent Beck "The authors of this book have led a revolution in the craft of programming by controlling the environment in which software grows. --Ward Cunningham At last, a book suffused with code that exposes the deep symbiosis between TDD and OOD. This one's a keeper. --Robert C. Martin If you want to be an expert in the state of the art in TDD, you need to understand the ideas in this book.-- Michael Feathers Test-Driven Development (TDD) is now an established technique for delivering better software faster. TDD is based on a simple Write tests for your code before you write the code itself. However, this "simple" idea takes skill and judgment to do well. Now there's a practical guide to TDD that takes you beyond the basic concepts. Drawing on a decade of experience building real-world systems, two TDD pioneers show how to let tests guide your development and grow software that is coherent, reliable, and maintainable. Steve Freeman and Nat Pryce describe the processes they use, the design principles they strive to achieve, and some of the tools that help them get the job done. Through an extended worked example, youll learn how TDD works at multiple levels, using tests to drive the features and the object-oriented structure of the code, and using Mock Objects to discover and then describe relationships between objects. Along the way, the book systematically addresses challenges that development teams encounter with TDD--from integrating TDD into your processes to testing your most difficult features. Coverage includes Implementing TDD getting started, and maintaining your momentum throughout the project Creating cleaner, more expressive, more sustainable code Using tests to stay relentlessly focused on sustaining quality Understanding how TDD, Mock Objects, and Object-Oriented Design come together in the context of a real software development project Using Mock Objects to guide object-oriented designs Succeeding where TDD is managing complex test data, and testing persistence and concurrency. Test-Driven Development (TDD) is now an established technique for delivering better software faster. TDD is based on a simple idea: Write tests for your code before you write the code itself. However, this'simple'idea takes skill and judgment to do well. Now there's a practical guide to TDD that takes you beyond the basic concepts. Drawing on a decade of experience building real-world systems, two TDD pioneers show how to let tests guide your development and “grow” software that is coherent, reliable, and maintainable. Steve Freeman and Nat Pryce describe the processes they use, the design principles they strive to achieve, and some of the tools that help them get the job done. Through an extended worked example, you'll learn how TDD works at multiple levels, using tests to drive the features and the object-oriented structure of the code, and using Mock Objects to discover and then describe relationships between objects. Along the way, the book systematically addresses challenges that development teams encounter with TDD—from integrating TDD into your processes to testing your most difficult features. Coverage includes Implementing TDD effectively: getting started, and maintaining your momentum throughout the project Creating cleaner, more expressive, more sustainable code Using tests to stay relentlessly focused on sustaining quality Understanding how TDD, Mock Objects, and Object-Oriented Design come together in the context of a real software development project Using Mock Objects to guide object-oriented designs Succeeding where TDD is difficult: managing complex test data, and testing persistence and concurrency