— Robin, in Once Bitten (Thanks, Helzibah!)
andrelopesmrx asked: hi mate,I found a patch of yours, posted 2 years back. I have the very same problem, I want 12bits lenght vhids to keep them aligned with vlan ids. Did you face some side effect using it? I wonder why it was not merged to the branch. Any information you could give us is very welcome. Thanks in advance!
I’m pretty sure we backed it out, but I don’t remember whether that was because it crashed FreeBSD, or because it crashed adjacent switches. Sorry, I know that’s not very helpful. In the end, it was cheaper to give up and throw more firewall pairs at the problem.
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 provides clear context for this notion of "Place" earlier in the talk.
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.
The wall of doubt
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.
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.”
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.