Practical Object Oriented Design an Agile Primer Using Ruby
See a Problem?
Thanks for telling us about the problem.
Friend Reviews
Reader Q&A
Be the first to ask a question about Practical Object Oriented Design in Ruby
Community Reviews
Sandi does a really great job, but not for the reason you'd expect: POODR is more pragmatic than one would expect. Especially in the Rails world, where OO design is looked down upon as 'academic' and 'not actually worthwhile,' one would expect all the usual explanations and reasonings.
But not this book. Sandi does a great job of explaining the tensions between all of these different maxims, and acknowledges th
Full disclosure: I helped contribute early reviews of much of the content of this book.Sandi does a really great job, but not for the reason you'd expect: POODR is more pragmatic than one would expect. Especially in the Rails world, where OO design is looked down upon as 'academic' and 'not actually worthwhile,' one would expect all the usual explanations and reasonings.
But not this book. Sandi does a great job of explaining the tensions between all of these different maxims, and acknowledges that software is always in flux; in many ways, it's more of a process than a product. Some techniques are useful at different points in that process, and sometimes, business constraints don't allow for constructing perfect software, if such a thing were even possible.
I'm still slightly concerned with the primary metaphor for much of the design: a bicycle. Too many people think of objects as only being concrete 'things' that you can touch or feel, and while the bicycle metaphor works well, I'm hoping that it doesn't further encourage this style of thinking. This is, again, a Rails concern, and POODR doesn't really concern itself with Rails. But in Rails apps, there's a real problem with monolithic models, and while POODR _should_ help, I'm not sure it goes far enough in that regard.
But seriously, that's the only complaint that I have about it, it is a truly excellent book.
...more
That, dear reader, is exactly what static typing is for, and in 2014, we do have type inference even in C++.
While this book starts out being excellent, it just turns out as yet another of those "static typing is wrong because type casts are dangerous and you need to write type annotations everywhere". Then in the last chapter it basically re-implements a type system via tests, by checking if a class has certain methods.That, dear reader, is exactly what static typing is for, and in 2014, we do have type inference even in C++.
...more
"Warning: The portions about statically vs dynamically types languages show a very marked lack of balance, objectivity and depth of knowledge. Safest to simply not believe anything said about statically typed languages in this book. Most of it is not exactly wrong, but still very misleading."
Sandi: Should you happen to read this I would
This book is an excellent book on good OO design. I would recommend it to anyone. But I would not recommend it to anyone without a large warning sign stuck to it:"Warning: The portions about statically vs dynamically types languages show a very marked lack of balance, objectivity and depth of knowledge. Safest to simply not believe anything said about statically typed languages in this book. Most of it is not exactly wrong, but still very misleading."
Sandi: Should you happen to read this I would strongly recommend removing the bash-static-typing section in the next edition, or working very hard to make it balanced. Your book is truly not enhanced by a semi-informed attack on static typing. And it is otherwise such a good book! Had the book not even mentioned static typing it would have gotten 5 stars.
Examples:
"the huge gains in efficiency provided by removing the compile/make cycle. This trade is a bargain. Take it"
Competent programmers do not sit around waiting for the compiler and running tests manually. They use tools that do this automatically in the background for them. Within a second or two of two of changing code the tools will have detected the change, compiled the code, executed the tests, and notified you if you broke something..
See for instance NCrunch;
There is no huge gain to be found here. Maybe there was when all statically typed languages took long to compile and these tools did not exist. That was last century!
"Any language that allows casting a variable to a new type is vulnerable"
Casting is highly unusual in code written by competent programmers. Casting is a code stink. This is an argument along the lines of "Red lights are useless, you can just drive right past!"
"Programmers find the code easier to understand when it does not contain type declarations; they can infer an object's type from its context."
Then why do you spend 90% of the testing trying to add types back through tests? Why do you explicitly say that you do this to make the types visible? Why do you talk time and time and time again about how to make the implicit types visible so that it is possible to understand the code?
"the belief that static typing is fundamentally preferable often persists because it is self-reinforcing. Programmers who fear dynamic typing tend to check the classes of objects in their code"
Manual type checks are not common in code written by competent programmers. It is another code stink. Just like in a dynamic language.
"The notion that static typing provides safety, comforting though it may be, is an illusion"
Then tell me again why the book spends 90% of the testing effort manually building a fragile type system without once mentioning how this is not needed with static typing. It's almost all "responds_to_size", "responds_to_width" This is just type checking. Something that a static language compiler does for you.
"Metaprogramming, used wisely, has great value; ease of metaprogramming is a strong argument in favor of dynamic typing".
Meta-programming might be somewhat harder in static languages. But our whole code base would be impossible without it. See tools such as NHibernate, Entity Framework, NServiceBus. There are a plethora of libraries and frameworks, written in static languages, out there that are based on meta programming.
"Duck typing is built on dynamic typing; to use duck typing you must embrace this dynamism."
..
"Duck typing detaches these public interfaces from specific classes, creating virtual types that are defined by what they do instead of by who they are."
Exactly what you get in a static language by simply extracting an interface and implementing it. This add up to a grand total of one more word in the method that uses the interface, one word per type that implements it, and one line per method/message in the interface declaration.
"Duck typing reveals underlying abstractions that might otherwise be invisible. Depending on these abstractions reduces risk and increases flexibility, making your application cheaper to maintain and easier to change."
And when these abstractions get names in the code they actually become visible, without having to hunt for their meaning in tests somewhere else. You can see it right there in the code. And you do not need to spend 90% of your testing type checking these types.
"Creating code that fails with reasonable error messages takes minor effort in the present but provides value forever. Each error message is a small thing, but small things accumulate to produce big effects and it is this attention to detail that marks you as a serious programmer. Always document template method requirements by implementing matching methods that raise useful error"
But using language that guarantees this out of the box is useless, because such errors dont occur in reality. was that not what you said?
"There is a level of design abstraction where it is almost impossible to safely make any change unless the code has tests
...
Tests are your record of the interface of every abstraction and as such they are the wall at your back. They let you put off design decisions and create abstractions to any useful depth"
With static languages the actual abstractions have concrete representations in the code. You do not need to go searching in tests to see the abstractions and the design.
Given a well designed code base I would say that a highly abstracted code base is far easier to refactor safely without tests than a code base with few abstractions. This of course goes for static languages with the excellent tool support that they afford.
* Tools support
Not once does the book mention what might be the greatest advantage of all to static languages. The excellent tools support that the ability to do static analysis affords.
Tools that do
Refactoring
Code navigation
Metrics
UML Diagrams
Architecture diagrams
Type checking
It is impossible(even theoretically) to make such tools, that are truly reliable/accurate, for dynamically typed languages.
In my opinion the greatest of these tools are the refactoring tools.
I can very quickly completely transform the structure of large portions of code in a large code base in C# with 99% assurance that it will all work exactly the same afterwards. In seconds I rename a class/method/interface. Another few seconds and I move half the files in one folder/namespace to another one where they fit better. Another few seconds and I extract a new interface for use as a "duck".
All of that took about 1 minute of actually changing code. Obviously the thinking part is apt to take more, but doing is almost instant. And SAFE. I do this all the time in C# and it just works!
I've done these types of refactorings in dynamic languages. Even in well written code it is likely that such refactorings are so hard to perform that I will just not do it. We would probably be talking, at least, an hour for each step. More likely hours or days. If we did not have very near 100% test coverage I would never dare to attempt it. How often do you see 100% code coverage?
The list does go on and on but I'm tired now and I hardly think I need more examples to make the point that the position this book takes on this issue is partisan and/or uninformed. I'll stop here.
...more
If there's one thing I would definitely take away from this book, it's from the last part on testing. Sandi describes a technique there on how to make a test code base that extensively relies mocks & stubs much more trustworthy, by adding interface related tests on both sides to ensure contract adherence. It's a technique I've heard only a few times about (the last time in 2009 by JB Rainsberger http://www.infoq.com/presentations/in...), but never seen actually anyone describing in detail in code. Although I've applied parts of the idea, like ensuring interface adherence for ducks and hierarchies, I often missed proper tests for the stubs used in the consumer related specs. I will definitely try to use this technique more in the future.
Some minor points of critique: For one thing, one of the usual things to criticize for this kind of book (I guess): It doesn't really show end to end code with persistence and presentation added to the mix, which definitely is a place where novices and even often intermediary designers hit a wall applying those principles. The other thing that I missed (and maybe this goes hand in hand with the first one), is the notion that one single model might not be the best choice for all aspects of an applications and sometimes you have to weigh if and when to insert model borders (E. Evans famous Bounded Contexts come in mind here).
That being said I really enjoyed the book and I will definitely recommend it to colleagues.
...more
Very well written, it explains how to manage dependencies, how to implement duck types and how to use inheritance and composition. It finishes with a great chapter about testing.
I do recommend!
(ps.: if you're a beginner with Ruby - like me - and you want to learn more about the language features FIRST, you should pick another book. This one is focused in OOD!)
Great book about object-oriented design, tackling the main principles of OO.Very well written, it explains how to manage dependencies, how to implement duck types and how to use inheritance and composition. It finishes with a great chapter about testing.
I do recommend!
(ps.: if you're a beginner with Ruby - like me - and you want to learn more about the language features FIRST, you should pick another book. This one is focused in OOD!)
...more
An object has a dependancy when it knows:
- 1) The name of another class.
- 2) The name of a message that it intends to send to someone other than self.
- 3) The argument that a message requires.
- 4) The order of those arguments.
Writing Loosely Coupled Code techniques
- Inject dependencies
- Isolate dependencies: isolate instance creation, isolate external vulnerable messages, explicitely define defaults, isolate multiparameter initialization
- Choosing the dependency d
An object has a dependancy when it knows:
- 1) The name of another class.
- 2) The name of a message that it intends to send to someone other than self.
- 3) The argument that a message requires.
- 4) The order of those arguments.
Writing Loosely Coupled Code techniques
- Inject dependencies
- Isolate dependencies: isolate instance creation, isolate external vulnerable messages, explicitely define defaults, isolate multiparameter initialization
- Choosing the dependency direction
The only thing I didn't like are code examples with real-world objects like Bike, Gear and Mechanic. You can write two or three good examples that way, but trying to adhere to it throughout the whole book make these examples worse and worse. The further into the book, the worse the code is.
The book is full of valuable insights and good, elaborate explanations. Well worth the read.The only thing I didn't like are code examples with real-world objects like Bike, Gear and Mechanic. You can write two or three good examples that way, but trying to adhere to it throughout the whole book make these examples worse and worse. The further into the book, the worse the code is.
...more
These are some of the parts that were most valuable to me:
"Sometimes the value of having the feature right now is so great that
Having been a Ruby programmer full-time for a year now, this book finally made "click" many of the Best Practices I've seen and used in code but haven't really been able to articulate. It got a little long-winded and redundant at some points, probably because it's geared more towards people who haven't been exposed much to OO, but overall it was definitely worth reading.These are some of the parts that were most valuable to me:
"Sometimes the value of having the feature right now is so great that it outweighs any future increase in costs."
"Design is more the art of preserving changeability that it is the act of achieving perfection."
On designing a class: "If the simplest description you can devise uses the word 'and,' the class likely has more than one responsibility. If it uses the word 'or,' then the class has more than one responsibility and they aren't even very related."
"When faced with an imperfect and muddled class ... ask yourself: 'What is the future cost of doing nothing today?'"
"If you can control the input, pass in a useful object, but if you are compelled to take a messy structure, hide the mess even from yourself."
On classes with too many dependencies: "Because they increase the chance that [the class] will be forced to change, these dependencies turn minor code tweaks into major undertakings where small changes cascade through the application, forcing many changes."
"depend on things that change less often than you do."
"Classes control what's in your source code repository; messages reflect the living, animated application."
"public methods should read like a description of responsibilities."
"Interfaces evolve and to do so they must first be born. It is important that a well-defined interface exist than it be perfect."
"Even if the original author did not define a [good] public interface it is not too late to create one for yourself."
"The general rule for refactoring into a new inheritance hierarchy is to arrange code so that you can promote abstractions rather than demote concretions."
"Identifying the correct abstraction is easiest if you have access to at least three existing concrete classes."
"Because `extend` adds the module's behavior directly to an object, extending a class with a module creates class methods in that class and extending an instance of a class with a module creates instance methods in that instance."
"Aggregation is exactly like composition except that the contained object has an independent life [outside of the has-a relationship]."
"If you cannot explicitly defend inheritance as a better solution, use composition.
"Inheritance is best suited to adding functionality to existing classes when you will use most of the old code and add relatively small amounts of new code."
"Tests provide the only reliable documentation of design. The story they tell remains true long after paper documents become obsolete and human memory fails. Write your tests as if you expect your future self to have amnesia."
"Costly tests do not necessarily mean that the application is poorly designed. It is quite technically possible to write bad tests for well-designed code... The best way to [design good tests] is to write loosely coupled tests about only the things that matter."
"It is an unfortunate truth that the most complex code is usually written by the least qualified person... Novice programmers don't yet have the skills to write simple code."
"Do not test an incoming message that has no dependents; delete it; Your application is improved by ruthlessly eliminating code that is not actively being used. Such code is negative cash flow, it adds testing and maintenance burdens but provides no value. Deleting unused code saves money right now, if you do not do so you must test it."
If using an object is cheap, injecting an actual one instead of a double into a test is fine.
"An object with many private methods exudes the design smell of having too many responsibilities. If your object has so many private methods that you dare not leave them untested, consider extracting the methods into a new object."
"When you treat test doubles as you would any other role player and test them to prove their correctness, you avoid test brittleness and can stub without fear of consequence."
"On testing abstract base classes: "If you leverage Liskov and create new subclasses that are used exclusively for testing, consider requiring these subclasses to pass your subclass responsibility test to ensure they don't accidentally become obsolete."
...more
If you want information beyond the basic topics, then this book about that. Ideas presented in the book are good, but the examples are not so much. Examples are very well chosen to fit the narrative of the book and are far from reality.
If you wan't to learn basic of object oriented design and don't have much experience in the field - then the book is right for you. It present's good basic ideas to follow to improve your OO design and provides simple examples that are understandable to everyone.If you want information beyond the basic topics, then this book about that. Ideas presented in the book are good, but the examples are not so much. Examples are very well chosen to fit the narrative of the book and are far from reality. I.e. example in chapter 8 works very well to present composition why composition is better alternative in that situation, but in reality, if sub-types were not mere data-bags, the whole example wouldn't have worked.
Discussion about application layer how to structure it, which is IMO the most interesting part about OO design, is not provided.
...more
The author does a great job of following the development and improvement of a sample app throughout the book (an app for a bike shop). The continuous narrative helps you see how the pieces fit together, though
This book helped tie together my understanding of OOP best practices in Ruby and has produced immediate benefits in the quality of code I'm writing. It contains great examples of refactoring code, along with checklists, red flags and questions to ask yourself throughout the design process.The author does a great job of following the development and improvement of a sample app throughout the book (an app for a bike shop). The continuous narrative helps you see how the pieces fit together, though a few examples from other domains would have been helpful in some places. At the same time, that's really an exercise for the reader.
I found Chapter 4's discussion of creating a public interface particularly helpful in determining the proper responsibilities of objects by "Asking for 'What' Instead of Telling 'How'." The continued discussion of messages when identifying duck types in Chapter 5 helped reinforce the concepts. The chapters on modules and testing also helped tighten up my thinking on a few topics.
As I've shifted from hobbyist to freelancer to full time developer over the past few years, there have been a few books or tutorials that have really helped me improve (along with bugging friends and countless hours of troubleshooting), and this is definitely one of them. Highly recommended.
...more
Chapter 4: Creating Flexible Interfa
In my humble opinion, this book's greatest strength lies in its advice to think first not of objects themselves and their responsibilities, but as actors and messages passed between them. Perhaps you already knew this; I didn't, and doing so has been a tremendous new tool in my arsenal to tackle problems. Seeing and defining public interfaces and abstractions has become a lot easier. It's become so much clearer now, it's like the idea just popped into my head.Chapter 4: Creating Flexible Interfaces has been a joy. While reading it, I couldn't drop the book for the life of me. It just clicked at the time: this is what I'm reading this book for.
Why the 3-star? I'm gonna share another humble reader's opinion here: While I know this is a Ruby book, I guess it could have done without the obvious dynamic/weak typing bias, only to spend half the book later providing tips to prevent problems inherent in the typing system.
...more
I don't have anything bad to say about this book, which I think is a first for me. It's just that good.
...more
2) A lot of books of this type tend spread the content pretty thin and have a lot of hype and used car salesman tricks and negging. This book has a brief introductory section, and then she is 100% content right until
1) I love this book. There are parts I could nitpick (like a lot of reviewers, I strongly disagree with author on static typing; dynamic typing is definitely my least favourite part about Ruby) but I've gained so much from this book that I can overlook the small bits I didn't like.2) A lot of books of this type tend spread the content pretty thin and have a lot of hype and used car salesman tricks and negging. This book has a brief introductory section, and then she is 100% content right until the end.
3) This book improves my code at lot every time I read it. I spent the last month or so paging through it and doing hours of joyful refactoring. Nothing in the book is exactly revolutionary, but she puts together a lot of little good observations and gives her reasoning in a convincing manner. I wish all books could have such a positive effect on my actions and my attitude.
...more
I was a bit skeptical at first, 'cause I thought the book was going to tell me things that I already knew. Boy was I wrong! I already feel that I've learn a lot and can't wait to apply all this new knowledge on my next and existing projects.
I think it's definitely a must have in your library as a reference. Very well written, simple yet very understandable examples, and lots of insights.
Excellent read, no matter how much experience you have or if you use Ruby or not.I was a bit skeptical at first, 'cause I thought the book was going to tell me things that I already knew. Boy was I wrong! I already feel that I've learn a lot and can't wait to apply all this new knowledge on my next and existing projects.
I think it's definitely a must have in your library as a reference. Very well written, simple yet very understandable examples, and lots of insights.
...more
This book approaches OOP with grace and simplicity, showing the strength of Ruby and OOP in small but concrete examples. As much experience I have on the field, this book taught me a lot and I think everyone who takes programming seriously and loves Ruby must read it. I'll definitely read it again a couple of times.
I read this book in a time where functional programming is gaining a lot of traction and it was both refreshing and reassuring to read it.This book approaches OOP with grace and simplicity, showing the strength of Ruby and OOP in small but concrete examples. As much experience I have on the field, this book taught me a lot and I think everyone who takes programming seriously and loves Ruby must read it. I'll definitely read it again a couple of times.
...more
Would've rated 5 stars if it wasn't for the unnecessary dissing of statically typed languages.
Well-crafted analogies that really drive the point home. The last section on testing is gold. There's a 30 min talk based on it (by the author) that is available for free: https://www.youtube.com/watch?v=URSWY...Would've rated 5 stars if it wasn't for the unnecessary dissing of statically typed languages.
...more
The book examples are written in Ruby and some of the topics apply more narrowly to that particular language, but as someone who doesn't know any Ruby and is more at home in Python I found that the vast majority of concepts apply just as well. The important point here is th
I greatly enjoyed the author's treatment of the concepts of object oriented design. Free of dogmatism and full of good best practices, focusing on the values behind the principles rather than exact prescriptions of what to do.The book examples are written in Ruby and some of the topics apply more narrowly to that particular language, but as someone who doesn't know any Ruby and is more at home in Python I found that the vast majority of concepts apply just as well. The important point here is that they both are dynamically typed languages but where Ruby has "modules", Python has multiple inheritance / mixins.
I'd recommend this book to anyone who has experience programming but has occasionally experienced the problem of code that just became too unwieldy and entangled to maintain.
Important concepts about reducing the coupling between objects are introduced, and the authors encourages us to make that important, fundamental to OOD, shift away from objects and toward the messages they exchange.
The code examples do a good job explaining the concepts without obscuring them behind any inherent complexity. That means that, taken at face value, some of the examples might appear over-engineered for the problem at hand. It just takes a bit of imagination to say "Okay, but if the inner workings of that class were actually as complicated as they'd bound to be in a real-world production application, then this particular technique of encapsulating that complexity would make total sense."
...more
For an experienced developer, there may be no new concepts in the book, but it is still a good opportunity to refresh your knowledge. And Sandi's cycling coding examples are just brilliant.
The book will teach you how to create stable abstractions and design maintainable hierarchies, when to chose composi
I would definitely recommend this book for absolute beginners and for those with some experience in software development. Read it through, go write some code, and reread it again in 6-12 months.For an experienced developer, there may be no new concepts in the book, but it is still a good opportunity to refresh your knowledge. And Sandi's cycling coding examples are just brilliant.
The book will teach you how to create stable abstractions and design maintainable hierarchies, when to chose composition over inheritance and vice versa, how to write helpful tests and many more while keeping things pragmatic.
The only thing I don't agree with Sandi in this book is her stance on static type checking: "A serious restriction that has high cost and provides little value, for the huge gains in efficiency provided by removing the compile/make cycle". To replicate some of the type checking value she rejects, Sandi dedicates a whole Testing Duck Types and part of Testing Inherited Code sections writing tests filled with numerous calls of assert_respond_to just to check that objects indeed implement certain members - something that you'd never do in a statically typed language. That might confuse people with C/Java background.
...more
Goodreads is hiring!
Learn more »
Other books in the series
News & Interviews
Welcome back. Just a moment while we sign you in to your Goodreads account.
Practical Object Oriented Design an Agile Primer Using Ruby
Source: https://www.goodreads.com/en/book/show/13507787
Enregistrer un commentaire for "Practical Object Oriented Design an Agile Primer Using Ruby"