I'm happy to announce that my Testing Without Mocks training course has returned! This is an in-person course that's ideal for people in Europe. It's taking place in Budapest, just prior to the Craft Conference, on May 28th and 29th.
I'm not sure when I'll have a chance to deliver the course again, so if you're interested, this is a rare opportunity.
@davenicolette@jasongorman It's a lot of material, but I invite you to read the full article, and maybe check out the examples, before making up your mind:
@RonJeffries@davenicolette@jasongorman I’ll take a look at your code when I get the chance. There are some common mistakes people make. But it’s also possible it’s just not a good match for you. That’s okay too.
@RonJeffries@davenicolette@jasongorman I looked at your sample code (the v4 version) and I saw one misunderstanding of Nullables and several overcomplications that are typical of people used to a mock-based approach. I'm not familiar with the kata, so maybe I missed something.
The summary: for your current code, you only need four classes: Driver, Weather, Football, and FileSystem.
First, the overcomplications: You don't need interfaces. Your code doesn't have multiple implementations of the interface, so they're redundant. WeatherData and WeatherDataImpl can be combined into WeatherData. Ditto for FootballData.
Also, Weather/Football doesn't have any meaningful code. They're both answering a question about the underlying Weather file. Why not answer that question directly in WeatherData, rather than a different question?
You might think, "well, I might have more complicated business logic in the future." Great. Solve that problem in the future. For now... YAGNI.
And as long as you're combining Weather and WeatherData, why not call it what it is? It's an abstraction over the "weather.dat" file. I would call it "WeatherFile."
Finally, the misunderstanding. You have a separate "StubbedReader" class, which is used by WeatherDataImpl and FootballDataImpl. In the Nullables patterns, stubs are an implementation detail. They aren't exposed. It should be a private class within WeatherDataImpl and FootballDataImpl...
...except that would mean duplication. Right now, WeatherDataImpl and FootballDataImpl duplicate their file-handling logic.
In the Nullables patterns, WeatherDataImpl and FootballDataImpl are "high level infrastructure wrappers." They should delegate to a "low level infrastructure wrapper" that talks to the external system. In this case, I would have them delegate to something that abstracted the file system. Because I like stupid-obvious names, I would call it "FileSystem." It can expose the only thing you care about, which is String readFileContents(filename).
FileSystem is the only thing that should have a stub, and that stub should be a private implementation detail. You can use a flag and an if statement if you prefer... embedded stubs are optional, but often make the code cleaner.
WeatherFile (aka WeatherDataImpl) and FootballFile (aka FootballFileImpl) would have a simple createNull() that would just delegate to FileSystem.createNull().
Or you can stick with the existing design. But there's absolutely no reason to have more classes in the Nullables version than in the mocked-base version, as you claimed in your readme. Nullables support a low ceremony approach: no interfaces, no layers, no nothin'... until you actually need them.
@RonJeffries@jasongorman@davenicolette It may be be an overreaction, but I don’t agree the WeatherFile name is a minor detail. It gets to the heart of my design philosophy. (It’s not really part of the Nullables patterns, but may shed light on some of them.) The philosophy is this: call things what they are. WeatherFile could be another data source, some day, but today, it’s not. It’s a file. If it ever changes, it’s trivial to rename it.
"What I’m really doing is changing the engineering culture at OpenSesame. Culture doesn’t change easily. It tends to snap back. True change involves changing hundreds of little day-to-day decisions. That’s hard, even when people want to make those changes, and full buy-in is hard to come by... This is where the new career ladder comes in."
@RonJeffries Thanks, appreciate the feedback. Agreed that this loses some of the juice of the thing. Like being told how an orange tastes rather than eating one. ### Regarding Humility and Psych Safety, they’re implied by a lot of skills (like “Try it their way” and “Yes and”), so those are more about being a leader. Did you look at the skill descriptions document? Your comments valued either way.
@jitterted@mlevison It’s in the AI Chronicles source code, which is under an MIT license, and I just pushed the incremental testing changes to the repo. I don’t have a formal npm release, but I’m thinking about doing it if there’s enough interest.
This week on my #livecoding stream with @jitterted, we discuss estimation, responding to dealine pressure, academic studies, and more. Oh, and our tests find a bug that only #nullables could expose!
This is the final episode of the season, but we'll be back in two weeks with an interesting new problem: a natural-language role-playing game. We'll be using #TypeScript + #React with a #Java + #SpringBoot back end to integrate with #ChatGPT. Should be super interesting.
That starts in two weeks—the livestream is May 8th from 1-4pm Pacific, and the recording will go up on May 12th. Calendar reminder here: