Another advantage of values is that they’re easy to fabricate.
So for testing it’s really fantastic that you can fabricate inputs, to test programs using any technology. You don’t have to get the class library that has the right classes and interfaces and relate it to the stuff that you used in your program. Your program takes data, you can now write another program that produces data to test it.
And also for simulation purposes. So when you start raising your testing up to the next level, and you’re trying to drive your program to different kinds of situations, all you need to do is algorithmic generation of data to get a variety of simulation points for your program.
If your program can only get into a particular state by a series of interactions through objects, how are you going to algorithmically drive that program to different kinds of test cases? It’s a huge problem. It’s just a mess.
Whereas, if you can just algorithmically generate data, you’re done.
And again, it goes to this point about places. With places, you have to emulate an operational interface. It’s a ton more work. And also when you want to drive it, you have to drive it through the operational interface instead of with data. — Rich Hickey in The Value of Values
Rich provides clear context for this notion of “Place” earlier in the talk.
— Sheldon Hearn (@sheldonh) August 15, 2012
@qcoding I’ve heard a rigid bottom leads to pain. Good luck! :-)
Robert C. Martin (Uncle Bob) wrote something in The Clean Coder that has rocked my little world:
Much has been written about the principles and patterns of software design that support structures that are flexible and maintainable. Professional software developers commit these things to memory and strive to conform their software to them. But there’s a trick to this that far too few software developers follow: If you want your software to be flexible, you have to flex it!
The only way to prove that your software is easy to change is to make easy changes to it. And when you find that the changes aren’t as easy as you thought, you refine the design so that the next change is easier.
I’m seeing the benefits of this kind of thinking with interface_enforcement, a library I’m developing for elective test enforcement in Ruby.
I started out by implementing interface enforcement as a proxy. This produced code that seemed fine. However, I had a few doubts about distribution of responsibility and clarity of abstraction, and I couldn’t think my way through them.
Experimental refactoring helped a lot. I extracted ad absurdum from one bloated family of classes, and gained insight into the true nature of the family. Then I inlined most of what I’d abstracted, but now into fewer, more clearly defined collaborators.
Still, there remained an opaque core in there, that I couldn’t break into.
So I took Uncle Bob’s advice one step further and started working on an alternative enforcement strategy prematurely. I say prematurely because I was pretty sure I would never ship it, and the primary strategy of proxying wasn’t finished by a long shot.
The additional strategy is enforcement by injection. How it works doesn’t contribute to my point. What matters is that it’s a different way to apply an interface to an object. It’s a different delivery mechanism for the core value of the library.
This additional use case applied pressure to my code from a different angle. All of a sudden, inappropriate responsibilities and missing abstractions leaped out at me. Being forced to distinguish an interface from the method of applying it exposed opportunities for valuable refactorings toward cleaner code in surprising places.
I’m pretty sure that the injection strategy is a dead end. Sure, it will make automatic interface enforcement possible. But I’m not sure how desirable automatic enforcement is, and injection is brittle with dynamic test subjects. Proxying is verbose, but I have a strong intuition that it’ll be bullet proof.
No, the primary value of an additional delivery mechanism is not in its usefulness as product. The value is in its usefulness as design constraint. Having pressure applied from a different angle highlights inappropriate coupling and complicated decoupling.
If you want your software to be flexible, you have to flex it!
I know Uncle Bob’s advice was intended to support continual refactoring. But sometimes great advice extends to multiple levels. And on this young project, I’m already benefiting from developing two delivery strategies, even though I plan to ship only one. And who knows? Maybe the second strategy will turn out better than I can imagine right now. Only more use cases and refactorings will tell.
P.S. Okay, I lie. I don’t plan to ship interface_enforcement at all. It’s an exploration, and clearly disclaims itself as such on the front page. Shipping isn’t the point. :-P
When I see creators constrained by their tools and their ideas compromised I don’t say “Oh good, an opportunity to make a product, an opportunity to start a business or an opportunity to do research or contribute to a field.” I’m not excited about finding a problem to solve. I’m not in this for the joy of making things.
Ideas are very precious to me. And when I see ideas dying it hurts. I see a tragedy. To me it feels like a moral wrong. It feels like an injustice. And if I think there’s anything I can do about it I feel it’s my responsibility to do so.
Not opportunity, but responsibility. Now this is just my thing. I’m not asking you to believe in this the way that I do. My point here is that these words that I’m using, injustice, responsibility, moral wrong; these aren’t the words we normally hear in a technical field.
We do hear these words in association with social causes. So things like censorship, gender discrimination, environmental destruction; we recognize these things as moral wrongs. Most of us wouldn’t witness a civil rights violation and think “Oh good, an opportunity.” I hope not. Instead we’ve been very fortunate to have people throughout history who recongized these social wrongs and saw it as their responsibility to address them.
And so there’s this activist lifestyle, where a person dedicates themselves to fighting for a cause they believe in. And the purpose of this talk is to tell you that this activist lifestyle is not just for social activism.
As a technologist, you can recognize a wrong in the world. You could have a vision for what a better world could be and you can dedicate yourself to fighting for a principle. Social activists typically fight by organizing, but you can fight by inventing. — Bret Victor in Inventing on Principle
Objects were made to encapsulate IO devices. So there’s a screen, but I can’t touch the screen, so there’s this object. And there’s a mouse, but I can’t touch the mouse, so there’s this object.
That’s all they’re good for. They were never supposed to be applied to information, and when you apply them to information, it’s just wrong.
But I can now say it’s wrong for a reason. It’s wrong because it’s complex. In particular, it ruins your ability to build generic data manipulators. If you leave data alone, you can build things once that manipulate data and you can reuse them all over the place. You know they’re right once, and you’re done.
The other thing about it, which also applies to Object Relational Mapping, is that it will tie your logic to representational things. Again: tying; complecting; intertwining.
So represent data as data. Please, start using maps and sets directly. Don’t feel like “I have to write a class now, because I have a new piece of information.” — Rich Hickey in Simple Made Easy
When you write your tests first, you have to design the production code to be accessible from the tests. Since you haven’t written the production code yet, the tests have a tremendous influence on the design of the production code. And that influence is to make the production code testable. Writing tests first makes production code testable. And another word for testable is decoupled.
The only way to test lines of code is to access them from the tests. But the only way to access them from the tests is to decouple the functions that contain them. So the act of writing your tests first causes you to have a system that is far less coupled than otherwise. In short, you get a better design simply by writing your tests first. — Robert C. Martin in Clean Code, Episode 6 - TDD - Part 1
I’ve seen a lot of newcomers to rspec trip up over the documentation; where to find it, and how to become familiar with it. The two common mistakes are:
With a little guidance, it’s easy to become familiar with the rspec documentation. Start by knowing that it’s documented at a site called relishapp.com, which hosts documentation in the form of cucumber test output, for several projects, including rspec. So rspec is at relishapp.com/rspec/.
With that clear, I recommend that you perform an initial review of the structure and key elements of the documentation up front. The following review, which should take you less than half an hour, will set you up for easily finding the documentation you need when you’re knee deep in testing.
With this review under your belt, you’ll have seen enough of the structure of rspec to know what kind of thing you need to read about (e.g. a built in matcher) and where to find documentation for it. Happy testing!
The following started as a comment response to Uncle Bob’s “Active Record vs Objects”, but the comment trail is so littered with spam that I feared it would be lost.
In the article, Uncle Bob illuminates the flexibility cost of Active Record, providing background for its negative impact on The Clean Architecture pattern he presented in: Architecture: The Lost years.
If you’re a long-time Rails developer, you will probably experience two things as you read Uncle Bob’s concerns and watch the video:
Both responses are well-placed; don’t let the conflict stop you thinking! After all, what you’re struggling for is valuable: to have all the dependencies in your application pointing inward toward the domain model.
I don’t have the answers. I’m just embarking on the journey myself. And here’s how I plan to tackle it.
Start by designing your domain model with plain old Ruby objects, with no regard for persistence, making heavy use of Tell-Don’t-Ask. Once your domain model starts to look interesting enough to be worth persisting, then take a look at how you might go about persisting the data from your business objects without attaching additional behaviour to them. At all.
Take a look at the Repository and Row Data Gateway patterns and consider hand-coding them for a few iterations to get a feel for what you’d want from a library.
There seem to be three concerns that need to be addressed:
Repository implementations exist. My gut feeling is that the active_record library probably works really well as a Row Data Gateway, as would data_mapper or just about any Ruby ORM. Mapping the data into business objects is a responsibility that must lie outside the business objects themselves if we are to maintain the correct direction of dependencies. But the business objects need to provide an interface to their data, violating Tell-Don’t-Ask.
And so I think our sense of dread stems from the fear of not being able to handle the data mapping concern correctly. Where does this responsibility lie? Observing the Single Responsibility Principle, it definitely doesn’t belong in the business objects or the Row Data Gateways. My guess is that mapping belongs in adaptors that are private to the repository, leaning on a mild Tell-Don’t-Ask violation in the business objects.
Dan Bernier provides another valuable perspective on this sense of dread. In Out of Love with Active Record, he demonstrates that the Repository pattern forces us to think about our applications’ data access patterns in ways that we have not had to think about them with fat active_record models. This thinking is hard, and I think it’ll pay off.
Here are some working examples that have captured my interest and gotten me thinking about how I’d like to solve the problem:
I know of two books that deal with this issue (inter alia). I’ve only read Objects on Rails, but plan to purchase Clean Ruby soon too. The way these authors implement Data Context Interaction to separate persistence out of business objects looks promising.
And remember, the fact that it’s hard doesn’t always mean you’re doing it wrong.
Creationists believe God put dinosaur bones in the ground to test our faith. I believe God put Creationists here to test our sense of humor.— Scott Weinberg (@scottEweinberg) June 6, 2012