Embedded - 103: Tentacles Of the Kraken
Episode Date: June 3, 2015Mark VanderVoord (@mvandervoord) spoke with us about leading open source projects and test driven development. His site is ThrowTheSwitch.org, a good place to get started with test driven development.... Get more info (and a coupon) for his course. Mark's book is Embedded Testing with Unity and CMock. Lengthy list of unit testing frameworks for C Why's Guide to Learning Ruby (free! with entertaining comics!) D Lang
Transcript
Discussion (0)
Welcome to Embedded FM, the show for people who love building gadgets.
I'm Alicia White, along with Christopher White.
Our guest today will be Mike Vandervoord.
We're going to talk about test-driven development and open source, among other things.
Before we get started, I'd like to remind you that we have a contest going for another week or two.
Email us to enter the contest and tell me what you'd put in a satellite.
Be as fanciful as you want. The contest winners will be chosen randomly.
It's only for my amusement.
We have two copies of my book and one copy of Kerbal's space program to give away.
So why satellites and Kerbal?
Because this contest is sponsored
by Planet Labs, a new kind of space company based out of San Francisco. They're building
satellites to photograph the Earth every day, the whole world. And they're ditching the old
slow-to-get-things-done mindset in favor of developing a new approach to space development
with cheaper hardware and faster cycles. They've already put over 80 imaging satellites across seven major hardware generations in orbit. Right now, Planet is on
the hunt for embedded and electrical engineers, especially intermediate to senior level people.
If you want to work on space gadgets, and who doesn't, reach out to them at embeddedfm at planet.com. And there are 40 positions open, planet.com slash careers,
and send me your contest ideas. Now to our guest.
Hi, Mark. Thanks for joining us today.
Thanks. Thanks for having me.
Could you tell us a bit about yourself?
I am officially a consultant for embedded software. And that always sounds kind of pretentious or something.
So I go with, I'm a maker of things and ones and zeros.
I don't know about the whole consultant pretentious things.
That's what Chris and I do.
Yeah, we're going to have to do some soul searching after this.
But you also teach a class.
And you wrote a book.
Yes, just recently I started a class with a friend of mine.
It's to teach people how to do test-driven development for embedded software,
and that's what the book was about too.
We talked about test-driven development, or TDD, with James Grenning about a year and a half ago.
But for people totally new to the idea, what is test-driven development?
It's a method of creating your software by writing tests for it or specs for it. It's saying what you want to happen before you actually write the software and then letting
that lead your design. It's less about testing and more about driving good design, I guess.
This sounds dangerously close to planning out what you're doing.
It does. And it's just planning out what you're doing in little tiny steps and then having a nice little validation when you've actually done it that, yes, I followed my plan.
I've always really focused on the unit tests and having it be more about the testing part and less about the planning part. So I kind of like this idea that it is as much about the planning as it is
about actual testing.
Yeah.
Yeah.
It works pretty well.
But when you,
when you come up with code that is already extant,
somebody already wrote it.
Do you have an opinion about that?
Should you go back and do unit tests?
Should you go back and make a spec and make a plan?
There's definitely purists who go back and they make a test for every single feature of everything they're going to be working with.
I don't tend to do that myself.
I tend to write tests for the things that I'm going to be interacting with to verify that it works the way I think it does.
And then I can go from there.
And I don't worry about exhaustively testing all of their features.
I hope that they got their job right and then I can move on and do mine.
Do you get pushback for TDD?
Oh, yeah, of course. You know, anybody that's preaching a philosophy or a method of doing something, you're going to have people that agree with you and disagree with you.
And I'm not the zealot type, but I guess I try to just be the type that's, hey, this has worked really well for me.
And I can hopefully teach you how to do it the way I did,
and maybe it'll work for you, and that's awesome.
And if it doesn't, don't kill me.
So it's not a religious war for you?
No, no, not really.
I certainly work with people who are much more into it than I am.
And does test-driven development,
is it a reaction to agile programming, where it feels very seat of the pants and we're just going to plan this week by week, story by story?
So I use Agile, but I would not call myself an Agile expert.
So I don't know how it started originally.
I believe that test-driven development was actually part of the original Agile philosophy process and everything. I could be wrong about that.
No, definitely. It was.
Okay, yeah. So I think it's baked in right from the beginning because they don't have this huge pre-planning step. And so this is the lightweight replacement to that. Right.
James, in his book, uses CPPU test, which I have found a little difficult to get set up in an environment.
But you have some other testing frameworks you work with.
Yeah. Yeah, so primarily the main framework is Unity, which if I could rename things, I would name it something different at this point because everybody assumes that it's Unity 3D, the open source graphic framework.
But this is Unity, the open source testing framework.
Anyways, so James actually uses Unity at the beginning of his book for, I don't know,
a couple chapters, and then he switches to CppuTest afterwards.
The nice thing about Unity is that it stays in pure C land
the whole time, which a lot of embedded people seem to enjoy.
And it's focused almost completely on embedded
development.
Embedded is special. We're kind of
ignoring that fact that test-driven development in Embedded is different than test-driven
development on web applications or normal
high-level applications
because you're dealing with hardware and things
and device drivers.
Right.
Nobody else worries about registers or tick timers
or things like this, right?
Right.
So two questions, I guess.
Do the different frameworks have different capabilities
with respect to testing embedded versus other things?
And what are some of those challenges and how do you get around them?
Boy, where to start on that one?
Sorry.
No, that's okay.
So I guess I'll start with what some of the challenges are.
So everybody comes into unit testing and assumes that if you're writing embedded software,
that the best way to do that is to test your code on your target.
And that's, from my experience anyways, that hasn't been true at all.
It's much better to test your code in either a native app or native on the host machine that you're working on whether it's linux
or a mac or windows or whatever or in a simulator and the reason is because you have full control
over everything when you're when you're working on a actual target and you want to write something
to the usart you now are dealing with an actual peripheral USART and it behaves a certain
way. And you can't, it's very hard to fake out.
What happens when I get this weird error?
What happens when this bit flag says that my queue is full or whatever.
Right. And if you're on a simulator, you can fake anything you want to fake.
So I, And if you're on a simulator, you can fake anything you want to fake. So most of the frameworks that I'm familiar with for testing C and testing embedded code,
they actually are made to run natively instead of on your target system.
And since I usually develop in Windows, that means it would run all in Windows.
I would write a, I don't know, I would write a class or an object.
Since we're in C, I would write some functions.
Yeah.
And then I would call them from my native app.
I would run it all in Windows.
And if I needed to work with a UART or some other hardware,
I would go ahead and simulate the basics I could inside that app. Right? acts exactly like the USERTs or the register sets or whatever,
you can treat almost all of it as if it's just RAM.
And that way you can set it to be whatever you want ahead of time and then double check that your code is changing what it's supposed to.
That does mean, though, that you have sort of two things to worry about,
whether you're modeling the hardware correctly
and whether you're writing your own code correctly that runs against the tests.
So it's kind of a cascade. Well, these tests work and pass, but it turns out
I modeled the USART incorrectly, so they really shouldn't pass.
Yes, and that definitely happens.
One of the things that I used to talk quite a bit at conferences
and stuff about system testing, and I'm still a big believer in system testing, even though I spend most of my time telling people about unit testing these days.
Unit testing or test-driven development, it's definitely not a replacement for actually having some sort of overall, my whole system works the way I expect it to.
No, of course not.
So let's say you're writing a file to, I don't know,
I've been thinking a lot about inertial sensors lately,
to interface to an accelerometer.
You have a couple of things going on there.
There is the lower level, say I squared C,
and then there's the dealing with the registers on
the accelerometer, and then there's presenting a nice interface.
So somebody can come and say, what is my acceleration right now?
And what's my sample rate?
Or something like that.
Where do you start?
Yeah.
I mean, I guess you start by installing unity
or do you start with a pen and paper and design out what everything's going to be block diagram
like um well i guess for me uh i happen to always when i work on a project i have unity and
cmoc and a couple other tools all set up already. So
my going in position is that I'm going to be using those things.
So, but once you have all those things configured, then you do a little bit of paper planning.
It's usually pretty minimal, but it's, you know, I usually scribble out a rough block diagram or
something, but I always start in the middle of the feature, which in your example would be the nice user interface,
which is the, you know, I want to just find out what the acceleration is or
whatever. And I would start there, writing that code first.
For the outer API.
Yes. And then since I'm a big user of CMock,
which is the part we haven't really talked about yet,
CMock is a framework for automatically generating
fake interfaces to things.
And so if I make a header file that has functions
for what I think a I squared C driver might look like,
then I can have it automatically generate functions to test against all those interfaces.
And so I can just assume that my I squared C interface is working as far as my test goes.
And I can write that nice layer that you're talking about just against that.
I don't understand CMUK. Let's do that one again.
Okay.
So I write a header file, I squared C, read, write,
and then some sort of setting, set the timer,
set the frequency, some sort of iOctal-like thing.
You can tell I like linux drivers but mostly
also open and close um so i have these five functions
and i write it you have those in a header file called i squared c dot h or something okay
so then we have this tool called cmock that you tell CMock, hey, I have this I squared C dot H. I want you to make a mock version of that. And so it creates a set of extra functions for saying things like
i'm expecting open to be called with these arguments and i'm expecting right to be called
with these other arguments and then you can use all those functions to specify what you're
expecting to happen when you call your actual function under test.
This is way easier to explain when I can write on a whiteboard.
You can, we just can't see it.
It gives you a template to fill out the mocks.
It does.
It sounded more than that.
Do you remember expect and tickle where you could say,
whatever happens next, what should happen is you should receive an error from the I squared C saying it hasn't been opened.
And so in CMock, it sounds like you can say, I'm going to write this unit test.
And the first thing I'm going to do is I'm going to try to write I squared C, but I'm not going to try to open it first to test that functionality. And then I can say, I expect to send back an error from the I squared C,
right?
Yeah,
absolutely.
So you could say,
I'm expecting that they're going to call right with whatever arguments you want to call right with,
and it's going to return an error because they shouldn't be calling it yet.
And then you can see how your code handles that error.
That's sort of weird.
It writes a simulator for you because all functions really sort of do the same thing?
Right.
Or at least once you know what their interface looks like, all functions kind of do the same thing.
They have some inputs, they have some outputs.
And everything that happens in between is an assumption.
So you can just say,
I'm expecting this interface to behave this way.
I mean, you have to fill out some of the functionality yourself.
It's not magically saying,
this is an I2C driver, so this is how I work.
Right. You're filling out what the interface looks like,
and then as the test goes, you're telling it what inputs you're expecting that function to be calling those with and what you would expect it to return in that case. in this situation, but all the backgrounds queuing up of arguments
and checking them against the things you expected
and handling all the returns and stuff, that's all automatic.
And so do you ever go into this CMock file and edit I2C right to do stuff,
or do you only use these other expect and ignore and um we just at for the mocked
functions you should be able to leave those alone because every time you change the header file
you're going to want to automatically regenerate it um and so you just burn it or you just pull
the whole thing into your make setup whatever your your make setup looks like, so that these mocks automatically get generated on demand.
There are certainly places where you will want to have
some custom control over it,
and CMock lets you do that by,
instead of running the typical mock,
you can say, hey, I want to stub it instead
and use this function that I wrote that does this custom thing.
And that could mean, trying to think of a good example here,
let's say you have a function that you pass a pointer
and you're expecting that function to fill the buffer that that points to.
CMock's not particularly great at things like that,
where it's this weird corner case of you're passing as an input, but you're expecting it to actually fill it, and then the results have changed.
So in those cases, you can just stub it out and do whatever you want.
Okay.
I mean, stubbing it out is sort of what I would have done naturally. I mean, I would have made a function that looked a lot like my I2C function, except instead of using registers, it sort of did what I thought it should do as I was doing my testing.
Right. But it's a little weird because that means every time you call I2C write, you have to have all of these expect things because I2C is something that doesn't give you the same answer each time.
It depends on what your inputs are and the state of the world.
So you have to have a whole bunch of these expect functions for every time you have a call.
Yes.
Yeah. for every time you have a call. Yes, yeah. Which, you know, if you're writing a lot to it,
it can get a little bit tedious,
but it is still all pure C.
So if you want to pass in an array
and then iterate over that array
and call and expect for each one,
you know, you can do that.
It's a shortcut from making you write a stub
for every single function you talk to.
I guess the other thing about it is you're only going to mock the things that your current module is directly talking to.
So if you get six layers away from this I squared C driver, you're never going to be talking to the I squared C directly
anymore. You've got all those nice layers in between. And so at that point, you would just
be mocking those layers if you're testing something. Well, one of the things I like about
this mocking system or just being able to do this sort of thing with mocks and whatnot is
that it kind of makes you layer things because if you don't, then you have to thing with mocks and whatnot is that it kind of makes you layer things because
if you don't then you have to deal with mocks all over the place yes but if you nicely layer things
like a good design then you have only a few things that call you and a few things you call and you
don't have this giant tentacle cracking going all over your code. Yeah, you've definitely nailed it.
It's a big motivator to not pull in 50 mocks.
And it's a pretty big motivator that you don't have to be so stressed about working with hardware anymore.
Now your hardware is just going to do what it's supposed to do at this time.
And you aren't really building a simulator.
You're building a header file, which you probably got from somewhere else, like the driver you
actually wrote.
And then it's doing stuff and you aren't building a whole processor simulator, which I think
is something people fear when you talk about test-driven development.
Yeah, right.
They're afraid they're going to have to build an emulation of their entire system from scratch.
And nobody wants to do that.
No, no.
I mean, that's a real barrier to entry, I think.
Yeah, for sure.
Okay, so let's see.
Where were we in this example?
We installed some stuff, which you glossed over because you haven't installed it lately.
But that's a barrier, too.
But I think we should continue to gloss over that.
Yes.
And it's actually the big barrier right now.
I guess as we've developed these tools, which I should start by admitting, I'm not the one who started these tools.
Some awesome people at Atomic Objects started, and I just happened to be the first
embedded project that they used it a lot. And so I became a big part of improving the tools to make
them more usable. And as open source projects grow, I think each big phase
is how can we make it easier to use
for the next group of people?
And then when all those people are familiar,
then it's how do we make it easier to use
for the next group of people?
And so we're on like our third or fourth iteration of that.
So other people worked on these,
but now actually you're the primary
on these open source projects, Unity and CMock.
And Seedling, was that the other one?
Yes. So I'm the primary on Unity and CMock.
I've never actually used Seedling on my own.
It's on your website i know well it's i've been involved in developing it and i've um i've been a big part
of continuing to maintain it but i'm i'm not the primary person on seedling itself and um
i don't use it myself because it's it's like this giant framework that's made to help people that
don't know understand how all the tools work together. And I do understand how they work together. And so I'd rather just do it the slim, tedious way.
Okay, but you are lead on Unity and CMock.
I am.
What does that mean?
It means that I spend more time than I should answering forum questions and chatting with people and looking at code submissions and trying to figure out exactly,
does this fit in with where we want this tool to go overall?
Or is this just noise that people are going to get confused about? And it's a lot of being as friendly as I can
and encouraging when people submit something
because it's a rare gem when people actually submit something
to a small open source project.
But it is an application that isn't embedded.
No.
So isn't it strange to be developing for non-embedded at this point?
It is, because the rest of my job is all embedded work.
And yet this thing I'm known for is it's for embedded stuff,
but it's not embedded itself at all.
I want to get back to embedded software versus non-embedded
software, but first I want to go on with open source.
It's a lot like herding cats.
People are volunteering their time. They're only going to
work on what they want to work on.
Your goal is to get things done
and yet you don't get paid either.
How does anything get done sometimes I wonder that
there's um well first of all you know everybody including myself it's just when you have time
so I guess when you start working on a project you you have to get in the mindset that, yes, I might be having an emergency right now
that I can't get this thing working, but the people that are maintaining this,
they might have their own lives and not actually be able to answer right now. And I always feel
awful when that happens, but after doing this for many years now, I guess you just solely accept it
and then you just apologize when I'm available again.
I'm like, I'm very sorry it took me two weeks to get back to you, but what was your question again?
Ouch.
On the other hand, the code is open.
If they had that big of a problem, they can try to fix it.
Some of them, yeah.
So that's part of the extra challenge with this project.
So it's a project for embedded developers.
Most of us embedded developers are C developers, and maybe some of us branch out to C++ or
maybe a little further than that.
But CMock itself is written completely in Ruby, which is not in the primary skill set of most embedded people I know.
I know.
Yeah, so we get a lot of, yeah, I would love to help you with this, but I don't know what you're talking about.
Why was that chosen? Do you know? Just because it's great at stream manipulation and parsing? Yeah, it's really, really good at things like this where you can tear apart a header file in no time flat
and then just go, I'm going to generate a bunch of code with that.
It's a great language when you know it,
but yeah, it's not the primary skill set
for a lot of embedded people.
And we've talked about a number of times now,
we've talked about, well, maybe we make a C or C++ version of CMock just so that people can be more involved in it or, you know, understand what's going on.
Is it hard having a tool that is supposed to make your code better. And then everybody looks at your code and says,
well,
I thought you were trying to make my code better.
That's not good code.
I mean,
it's one of those being a reference.
Are you held up to a higher standard?
Maybe.
I don't know if I actually am or not,
but I always feel like I am.
I feel really,
really guilty every time somebody finds a bug in Unity.
I feel really guilty anytime somebody finds a bug in my book, even if it's one that's already reported.
It's like physical pain.
It is, I tell you.
I think it makes it all the worse that Unity's been out there now for almost, well, I don't know when we actually made it open source, but we've been
working on it now for 10 years. And most of that it's been on the web somewhere. And it shocks me
just how many bugs people can still find today. I'm like, man, how junky was this thing when we
posted it? Does it have unit tests? It does, which is a little tricky.
Unity tests itself, so it has some unit tests that are also written in Unity.
Ah, but what tests? The unit tests that test Unity.
I know, right? So there's a little bit of a catch-22 there.
Go on and on.
Yeah.
So going back to my accelerometer, and we've written the API because somebody else needs to know that,
and that's good design.
Yes.
And we've written a header file,
and CMock has magically made that into something we can call and control.
Yeah, automagically even, yeah.
And so now we write some code?
Yes.
Real code.
Yes, so now you've written a test
using the mocked version of I2C,
and now you can actually write real code
that proves that your interface can do what you're hoping it can, what your specifications that it can.
Okay, let's set the sample rate on the accelerometer.
Okay.
Because that's a pretty easy function from an API perspective.
Yeah.
And it's a pretty easy function from I2C.
We're just going to write a register
out there on the accelerometer. It's test-driven development, so we're going to start by writing
a unit test that
presumably this is what we want to have happen, which is when we call this function set sample rate to value X,
when we read sample rate, it will be value X.
Yes.
And then it fails to compile.
When I went through James' class, he was like,
and then you compile, and it fails to compile
because those functions don't exist.
And I was like, oh, come on, I can skip that stuff.
And I guess this is where CMock is fun. You do skip that step because CMock is going to go
through and it's going to actually, well, you're talking about making the actual function that you want to test, right?
Yes.
Oh.
No, my I2C driver sort of exists out there now.
Yes.
My mock.
Yep.
Yeah, so that exists out there.
You want to write your real test i i guess the the pure tdd developer is going to follow james's method and and they're
going to actually let it break and but i've i've always started by i always throw a the function
that i'm testing i always throw that in there and i just return something that i know is wrong all
the time so if it's So if it's a function,
like you're talking about this function
that's going to set our rate, right?
Yeah.
Does it have a return code?
I don't know.
Aren't we designing it now?
Yeah, I think it should
because we should have return codes for just about everything.
Yeah, it doesn't always succeed, so we need to know when it fails.
Or zero isn't a valid.
Right, yeah.
So yeah, your number could be wrong or whatever.
So we'll say it returns a status code.
The nice thing about status codes is
you can always set up a status code that means
I haven't actually implemented this function yet.
And you can just start by making a function that returns that.
That's usually my starting point.
And then I compile it and make sure that everything works.
I like that a lot better, actually.
It feels better.
It does.
Yeah, I trust myself to take that one tiny little step, I guess.
I cut other corners too.
We can get into that in a minute if you want.
I do actually believe overall that TDD is a good method,
but I kind of practice a very close to test-driven development.
As long as I'm not changing the tests and the code at the same time,
I think you're doing pretty well.
Yeah.
I mean, I have heard people say that writing tests like this
means you're writing your code twice.
And when the person who said that to me said that derisively,
and I was like, yeah, exactly. That's the great thing. and when the person who said that to me said that derisively,
and I was like, yeah, exactly.
That's the great thing.
You are deciding what the plan is.
You're implementing it two different ways,
and if both of those ways agree,
then you probably implemented the plan.
And if one of them doesn't,
then you did not implement your plan, and your brain and your hands are not in agreement with what was going to happen here.
Right. It's the double accounting thing, right?
Exactly.
Yeah.
Yeah, we've used that technique in hardware all the time on safety critical systems where you have two sensors that have to agree or else you screenplay murder.
So there's no reason not to extend that to software.
Yeah.
So, okay.
Do we write our test and then it returns,
I have not implemented yet.
And then we go on and we write another test or we go back and we just make
that test a little, do more stuff.
Well, I guess at this point we've written a test.
We've made a stubbed out version of our function, right?
That's returning an error.
Yeah.
And so at that point I would actually run the test
and it would fail
because it's not actually doing the things
that told CMock that we were expecting to happen.
And so it runs the test and it says, oh, by the way, you never
called set rate on the I squared C function.
And it tells you what line you gave the expectation
and it never happened. So clearly something was wrong.
And so then I would go in and fix that particular thing before I moved on to adding more
tests.
And that is more of the pure TDD thing, right?
You always want to have everything green before you go back and make more broken things.
Well, that's one of the things that I've been thinking about.
There are a couple open source projects that I want.
Well, really, I want to move them from floating point to fixed point so I can use them on
more processors.
Oh, nice.
But I don't want to start that refactoring until I can have some tests so that I know
I don't hideously break things.
Oh, hey, this is earlier on, you brought um what happens when you talk to third-party
libraries or things like that and this is exactly that type of a thing like personally i wouldn't
go through and write a test for everything that your old code could possibly do but you want to
write tests for the things that you're that are going to be touching the things that you're changing now, I guess.
You want to say, this is a snapshot of how I expect this thing to work.
And then you can go through and refactor your code to be fixed point
and have some confidence that everything is still happy, right?
Well, I'll probably be changing every file, every function in every file.
Ooh.
Well, just, I mean, things are passed around floating
point even when they're not touched.
They're just passed through.
But I have to change that type.
And my tentative
plan is to copy the code and have a floating
point version and a fixed point version instead of having
a pound
def typed, but i haven't figured
this out yet um how do i okay you you control an open source thing how do i suggest to these
two open source projects i'm thinking about i want to add tests to your system without making
it sound like they were doing it wrong all along.
I mean, I'm really impressed that this code exists and I'm really happy and I'm so happy. I want to make it more flexible for things I want to do, but I also don't want to be that jerk that says,
I'm an engineer and you're hackers and I'm going to do this right. Yeah. Well, I think
just, just going into it already,
it sounds like you're worried about what other people are feeling.
And that's a good going in position on any open source project.
It's really about being nice and respecting everybody that has worked on the project.
As for how to actually get this done, in this particular case,
it sounds like your best approach might be,
hey, I'm really excited and want to add this fixed point version of your stuff because your stuff is so awesome.
But I want to make sure I didn't break anything along the way.
So I'm thinking of writing these tests for it.
I'm thinking of using this framework.
How does that sound to you guys?
Yeah, that was the other thing is, do I make the tests and then present it to them?
I did this. If you'd like to include it, that's great.
If you didn't, then I wrote this fixed point code and you can have that.
Or do I instead start with, I want to do this.
And what testing framework do you want?
And then when they say testing framework, what's that?
What do I say after that?
Yeah, I don't think I would start with a,
what testing framework do you want?
If they don't have one already, I think I'd propose one.
And just because, I don't know,
as a person that's already running a couple open source projects,
people have a lot of really cool ideas that they bring to you.
And it's way easier to get on board with these people's ideas when they give you the information.
I don't have to go Google it myself.
That's a good point.
Well, how do I choose Unity and CMock or CPPU test? Or there are other ones out there.
We mentioned Seedling earlier, which I guess is an easier form of doing it.
So Seedling is just a build framework that kind of wraps up CMock and Unity and some other tools
and tries to make your life easier so you don't have to figure out how to wrap all this into a make
file or a rake file or whatever. How do I decide which unit framework, unit testing framework
to propose? Oh yeah, because there are a lot of them actually. If you go to,
there's a website or a page on Wikipedia that has all the unit testing frameworks for just about any language you can
imagine. And I believe last time I looked, there's something like 20 for C, which is a lot of
choices. Well, I don't want to spend all my time doing this. I just want something that will work.
I would rather spend my time on the code that I want to do, not on dorking around with unit tests.
I know. And I'm not really, I'm most familiar with my framework, obviously, and then a couple
of the others out there. And I'm fine with you selling me your framework. This was not meant to
be a please give me the pros and cons of each. No, I know that.
I guess where I'm going with that is,
so I'm very used to answering the question of,
do I need to use Unity or do I need CMock and Unity
or should I be using Seedling to wrap this all together?
Or I'm used to answering the question of,
what of the tools that I'm working on
does a particular person need for
their project? And I get that question so much, actually,
that we made a Decidotron on our website
that helps people make that decision.
I've seen the Decidotron. It was cool.
Although, I think I answered the first three questions,
and then it had already made a decision.
Oh, yeah.
But I, of course, answered them like,
well, of course I know what I'm doing.
Which probably wasn't true.
I know what I'm doing code-wise.
But I will link to the Decidetron
in case anybody wants to try it for themselves.
We're hoping that someday we can strong arm somebody who has some web development skills
into making the Decidotron like an actual fill out your form and have it, you know,
animated stuff and look cool.
Right now it's a big table that you look up the answer on, but you know.
Yeah. So the first question is, if we walk you through how all this works and give you some
handy examples would you be comfortable setting up your own build system you get 16 points for
sure why not and zero points for yikes i'd really rather not and you have to you know you have to
add these things as you go along yourself there's no push the button and make it a game.
But it seemed really appropriate for working on embedded systems.
See, exactly. I should have put them in hex, really.
That would have made more sense.
Yeah.
Okay, so yeah.
Then forget my question about which one should I use.
Let's assume I'm going to use Unity and CMock.
That was the right choice anyway.
I'm sorry. Go ahead.
I'm biased.
I just have to decide whether or not I'm using seedling
because I'm uncomfortable with builds.
Is that right?
Yes. Yeah, that's the big differentiator there is.
If you don't want to have to figure out how to automatically mock files or things like that, or how to set up multiple builds.
Because I guess the one thing we kind of glossed over in the past is every single one of your test files becomes its own executable.
And so every single module that you're testing is its own executable and you so every single module that
you're testing is its own little tiny exe and you you can run them all separately or you can run
them all together or whatever you know one after another and then collate the results so you're
either coding that on your own in make or whatever or you let seedling do it because you don't want
to mess with all that well and then does seedling pull down Unity and CMock as well?
Oh, yeah. Yeah, it's all baked right into it. When you pull down Seedling, you get everything.
And you don't have to be a Ruby expert to run Seedling. You do have to install Ruby,
and then it's like a one-line gem install Seedling or something like that, and it just pulls down all the extra stuff that it needs for you.
And then does CMock install Unity?
Or does Unity install CMock, or are they separate?
So CMock will automatically install Unity every time
because it needs it to work.
If you just wanted to use Unity and didn't want to do any mocking,
you could just download Unity by itself.
The mocks seem really cool.
I know. That's my favorite part of it, honestly.
Okay.
Okay, so
I'm working with my little
open-source
project that I want to participate
in, but I'm a little too shy to get
too involved.
I've written the email that says, I think I want to update your code, and I'm going
to put some tests in Unity and CMock so that when I make changes, I won't break things.
And they've emailed and said, that seems hard.
We don't want to install those things.
What are my choices then?
I mean, I can do it on my own, but I don't want to make it throw away.
Yeah. You could ask them if they're willing to have a folder with all your tests on the project,
even if they don't install all this stuff.
I mean, there's a number of open
source projects that you know you've got your main source folder and you've got some doc folder
things like that and you just have a test folder sitting there and if you're somebody who doesn't
care what the tests look like you just never open that folder um the problem course, is going to be if you're the only person on that project that's gung-ho about testing,
that means that every time anybody else makes a change, they're probably going to be breaking your tests,
and you're going to have a lot of work to do.
Well, ideally, once I make it work and it works better, other people will join the test bandwagon because they'll see that it really is better.
And then maybe we'll get one engineer who doesn't.
But at some point, peer pressure will make him do it too.
Yeah.
I think as soon as it actually pays itself off by catching something major, then people will get on board with it.
Well, in the worst case, if it doesn't,
you've at least been able to implement the feature that you wanted
and verify that you haven't changed the behavior.
True.
And if they abandon it after that, then, well, that's not great,
but it was still a useful task.
Right.
And the main point of TDD was to help design good code.
It wasn't to do the testing for you.
That's just the nice side effect.
So if you're throwing away the testing in the end, it's a bummer,
but you still got your main goal accomplished, right?
Right.
And that's a good thing to keep in mind.
It is a matter of good design and good code. The regression test is just kind of a happy positive, not the end goal.
Right. have some online classes and people can go see them and we'll talk about them more in a minute but in part of the class i watched you had some advice on separating test code from runtime source
and you just mentioned it now to have a test directory and keep it relatively separate from
the normal runtime source code do you have other very tactical advice unrelated to specific frameworks about making
your tests work or about making TDD easier on a system or group that not everybody is participating?
I'm not actually sure where to go with that one. I liked that very, here's how you can set up directories.
In the video, you described a few other ways of setting.
I mean, you had source, build, test, and then there were some other ways of doing it.
And I liked being able to see some reasons for why you would want to have a common directory.
Yeah.
Yeah, we do talk a bit, quite a bit about, yeah, so I guess when we were talking earlier,
I talked about having a test directory.
Another common layout is to actually have modules that you're planning on reusing be like its own named folder
and then under that it has its own source and test directory and so then you can just take that whole
parent folder and you can take it from this project and you can copy it to another project
and you now have a fully tested working module that you're pulling in to another project. And if you're doing a lot of projects that all are using Unity and CMock,
your reuse gets really fast in certain cases
because you're being forced to be very layered and modular in the first place.
And if your directory structure supports that,
then it's very easy just to pick
it all up and just move it over and drop it in. And it makes it harder to entangle in the other
code because it is separate. Right, exactly. And I like what you just said about a module
or a small sub area gets its own directory. You don't just make one giant common directory
because it's a lot harder to keep things separate.
And a lot of times you don't want to copy the whole common directory to the new project.
You only want the accelerometer driver or you only want the X-Squared C driver.
You don't want also all the timing stuff that no longer applies on your new processor.
Right, exactly.
And the word module gets a little squishy.
I haven't figured out a better name for it.
But especially when you get into mocking,
you end up, you very quickly get to a point
where you're starting to make your files much smaller than you used to.
Because once again, you don't want to pull in 500 mocks.
And so you're making these very focused
C files and so instead of it could be before you you might have written a your accelerometer
driver you may have written it all in one file hopefully you're not the person that writes it
all in one file but certainly some people would and that includes your I squared C driver and
everything now you're you've broken it up into four or five files,
and that whole thing can be in a nice package in a folder.
And as you said, that's the way you should be doing things.
To have C++ enforces a certain kind of structure on your code.
Using these test frameworks imposes a certain kind of structure on your code, which is
good structure. So I'm always
in favor of things that force me to be
good instead of having to...
Me too, because otherwise you forget and get sloppy.
Right, it's hard to be virtuous all the time.
Exactly.
And that's why we aren't allowed to have cookies in the house.
Me either.
I'm not going to comment on that
So you have an online course
tell me about your online course
it's Throw the Switch
So our
online
community is Throw the Switch
and that
is where
I guess that's kind of the central hub
for where our projects are and where the blog is.
And we've just recently launched a class, Mike Karleski and I, one of the other main developers.
We just recently launched a class that's on Udemy, but you can get to it through our Throw the Switch website. website and the the class is mostly trying to teach people how to do test driven development
and such and particularly for embedded and it's uh it answers a lot of the questions that we get
over and over again the how do i get started and you know why do we do it this way? And all the weird corner cases.
And sometimes just setting it up and figuring out how to use things.
Yeah.
Let's see, it was 95 bucks for about 16 hours of coursework.
Is that right?
Yeah.
Yep.
Which includes, it's mostly project driven, which was a big thing for us.
We wanted to make sure that too many times you sign up for an online course or any course,
and it ends up being like these little toy examples that aren't close enough to the real
world that you walk away and you go, okay, that's nice, but how do you actually do it?
We didn't want to be that class.
So we start out in these smaller projects and it
eventually builds up to be a very large project that you can take and use when you're done.
I hear about a lot of companies who have courses they go to and it can be quite expensive. Do you do the in-person courses as well?
I hate traveling.
Me too.
Me too.
Yeah, so I have not so far.
I've taught a couple companies locally just here in Grand Rapids,
and I enjoy it when I do that sort of thing,
but I think that's never going to be my career.
I'll leave that to the James Grennings of the world.
Well, I mean, his class was good, and we did some lecture, but quite a bit of the week was working with the client's code.
I didn't get to stay for that because i wasn't the client um so there's i can totally
see the value but for people who are talking about lunchtime brown bags and getting together
to have a club to start learning this it wouldn't be hard to go through this in you know three or
four or heck take three months and do an hour a week sort of class.
And it becomes cheap that way.
Yeah.
And it's something you can do on your own time.
You don't have to plan your life around it.
That's what we're hoping anyways.
Or you can probably get your company to pay for it and to give you time and space to do it.
Yeah.
That's the way we're hoping it goes.
We hope we can bring a lot of people to use the tools and understand them.
And as a side effect, we're charging for it because then it lets me work on these tools more.
You know, this is not my primary job, as we talked about earlier.
I'm an embedded software developer, but I really, really enjoy working on embedded software.
And anything I can do to spend more
time working on that is kind of a cool thing.
So this is one of my attempts to do that.
We had an email exchange and in which I talked about the podcast as a way to
advertise for my book and our consulting company,
although we don't really talk about them much other than say, yeah,
still there.
Yeah.
And at the end you said you totally understand about using the podcast to
drive interest and that you find yourself doing the same sorts of mental
gymnastics to make enough money to support your family,
but working on things that interest you,
which means at least part giving away what you're doing for free.
Yeah, so I really think that the biggest useful part of Unity and CMock is that it's completely free
and that people can just pick it up and they can try it and they can decide if it works for them
and not shell out a bunch of money to find that out. And it's important to me that it stays that way. And
it's important to a lot of other people. And, but at the same time, you know, I'm working on it in
evenings and, you know, when the kids go to bed and things like that and trying to get in as much time as I can to answer questions and fix bugs and whatnot.
And it'd be nice if I could spend more of my day doing that.
And so, you know, I tried writing the book and I've tried this class and none of these things pay a lot.
But they all help give me just a few more hours where I can do stuff like this,
which is cool. You mentioned your book, Embedded Testing with Unity and CMock.
Yeah, that's the short version of the title. There's a longer version.
It is. You know, I named it as a joke, and then one of my friends was like,
oh, you totally got to call it that.
So if you actually look at the cover,
it's Embedded Testing with Unity and CMock,
a book for those who code C and want awesome, well-tested products using free tools, and for those who enjoy books with really long titles.
And that is actually self-published through Lulu.
It is, yeah yeah what made you decide
to go that route um well i guess i should back up a step and go have you ever heard of why the
lucky stiff no so in the ruby world he was kind of a big deal he's this developer guy that had the pseudonym Y. And he's kind of the strange artsy guy, I guess,
that he wrote tons and tons of code. And he also published a couple books that were,
well, his first book was completely free. And it taught a lot of people, including myself,
how to do Ruby. And it was just full of comic strips and jokes and just, it was the most entertaining way of learning something I've ever experienced,
which reminded me of Joel Swalsky talked a lot about how
technical material should be entertaining.
Like we're spending so much of our time reading things that we should at least
enjoy it.
Anyways.
I'm actually a big believer on that.
Me too.
I've gotten comments that my writing is too casual and not formal enough.
And I'm like, yeah, and I work hard for that.
Thank you.
Yes, I would agree.
I think casual is the way to go.
I would much rather read your stuff if it's casual.
If there isn't a joke on every page, I'm doing something wrong. Or you're just not getting it. Right, exactly. Yeah. So, Wai's second book was this little tiny pamphlet of a book. It was maybe 30 pages, I'm guessing right right now but it was a little tiny thing
and it was you know it's all
graphics and
just jokes and things like that
but it was a seriously awesome book
and he published it through Lulu
and I'm like this is exactly the type of
thing I want to do I don't want to write
an 800 page volume
on how to
unit test.
There's people that are going to do a much better job of that than I am.
I'm going to write something small and entertaining.
And hopefully it answers the questions of people that are looking at my project anyway.
So I did that.
And Lulu was a great place to do that. And I've, yeah, I'm still selling copies of that book, even though it's
five years old now. So. Well, things, I mean, has Unity and CMock changed all that much?
Um, Unity itself hasn't, we've been working hard to make it easier to use, but that hasn't changed
the, that's changed the experience of getting it all installed, but it hasn't changed the experience of using it really.
So the book is mostly relevant on that.
CMock has gotten a lot of features since then,
which has motivated me just recently.
I've been starting to work on volume two of my,
or not volume two, version two of my book.
And I'm finally almost done with it.
So hopefully that'll get pushed out to Lulu in
the next month. Well, now you have to do it because you've Osborne-ed it because I was
thinking about pushing the buy button, but now I have to wait till you're ready.
There you go. Now I have to.
Exactly.
That's good. I need deadlines.
Well, it doesn't sound like you have anything else to do.
Right, exactly.
So, the videos.
You know, 19, 16, I don't know, how many hours of videos?
I like books a lot better.
Videos require too much of my attention, and they tend to go too slow.
I'm one of those people who listens to podcasts at 1.2x or 1.5x.
Nice.
Do you hear this sort of whining about videos being too attention-intensive from other people,
or is it just me with my attention deficit disorder?
No, I'm actually on the exact same page as you. We put off making this class in the first place
because I'm like, I don't want to watch videos about this and I don't think anybody else does.
But really that just helped shape the way we put together the class.
So I guess I should say the 16 hours is the estimated time that people are going to take
to get through our class the amount of videos is really three and change I think okay and and most
of that is actually code examples on the screen like highlighting different parts of the code as
we build it up and so at that point the, the visual part of it is important because you're
actually looking at source code and you're kind of being guided through the source code. So it's
most of the class is working on the projects. So that was a big thing for us.
Well, I think that's one reason to do it with other people at your company.
Because then you can do the projects together instead of getting stuck and frustrated and saying, shove it.
This isn't worth it.
Other people around is good.
I didn't realize it isn't as long as I thought, which is kind of nice. Because that means that I could have this setup done in probably three or four hours.
I could at least have Unity and CMock installed and understand them well enough to try them for my little open source fixed point problem.
Yeah. So this is the part where I should insert something really important.
So we took this class, or we built this class as if it was an Agile project.
So what you're seeing right now is the first public iteration of it, which means that it's focusing completely on Unity. And the version two that has all the extra cmoc stuff
is coming out soon um but is not actually out yet and because we're we're getting feedback on the
way we're teaching it and the thing the material and all the other stuff and then we're using that
to drive how we develop the second part of the course so if you were to take the class right now, it would
hopefully teach you Unity really well
and leave you wanting to learn
CMock, but it wouldn't actually teach you CMock
yet.
Well, you can't do everything at once.
I know, exactly. And, you know,
it was this big thing, like, we're putting
all this time into it.
What if nobody actually watches it and we've wasted
all this time? But we've had enough people watches it and we've wasted all this time?
But we've had enough people sign up now that we're like, okay, we can make part two.
What are the best comments you've gotten from it?
You can say the worst if you want.
Those are always very memorable.
You know, we've gotten a lot less feedback than i was hoping
we would overall um most people we had we had one lesson in particular that got a lot of criticism
and we we uh rebuilt it and we're just pushing that release out and the criticism was well
deserved and we it was not up to the standards of the rest of the class.
But most people, their general feedback seems to be that they really like the pacing.
They think that the class itself is useful.
And I think the biggest complaint is that part two isn't available yet.
So I find that to be a pretty big compliment too.
Asking for more is a very big compliment.
Yes, exactly.
So I'm looking at that as a positive and not as a, what's wrong with you?
You're not done yet.
All right.
Well, I think we have kept you for almost long enough,
but Christopher, do you have any other questions?
Something just popped into my head
and it's going back to detailed questions. So we're kind of enough, but Christopher, do you have any other questions? Something just popped into my head, and this is going back to detailed questions,
so we're kind of away from that section.
But I remember in school hearing and learning about programming languages
that had programming and design by contract as part of their makeup.
Oh, yeah.
And it seems to me this is kind of an attempt to bolt that on to C,
which is completely a free-for-all.
Is that a true assessment, or are these slightly different things?
I mean, they're slightly different, but I think they're both driving at the same
root idea, in that you're trying to specify what the constraints are in using all of your
individual functions and modules and everything, right? I mean, they're both really trying to answer that. And there are C-like languages that do that,
including digital Mars's D, which I'm really hoping at some point becomes more common in
the embedded world because I love playing with it. But, you know, anyways.
It just, it strikes me that these could be language features.
Yes, yeah, for sure.
And it is of some languages, but not our beloved sea, right?
It's just too lazy to learn new languages.
No, that's not true.
We're experts in this.
Well, yeah, there's that too.
We'll learn a little bit new language
so we can fix the other languages.
Yeah, and I think that's
certainly true that people do that.
I have a challenge
to myself. I try to learn a new language at least
a little bit every single year.
That's probably pretty good practice.
It is.
I feel like I've learned a lot.
I haven't learned most of those languages well, but you learn something every time you learn a new language.
So you are an embedded software consultant.
Yes.
And you're doing a lot of non-embedded software.
Yeah. Uh, right.
But I do find it to be way more fun.
I enjoy the constraints of an embedded system, and I really, really love having something physical happen
when I do something, you know?
Yes.
Yeah.
I don't know.
There is so...
Okay, this is what my perspective of non-embedded software is.
And it's a very limited perspective because obviously I don't do a lot of it.
But non-embedded seems to all be about the SDKs that you're working with.
Nobody writes anything from scratch, I don't think, in the non-embedded world.
They're all dealing with a pile of libraries and APIs and whatnot.
And they're just working with learning all of these APIs and how they all work and all the nuances.
And that's the whole challenge, I think, of regular software.
Yes.
Well, that's sort of back to learning new languages.
You end up having to learn huge SDKs.
Right.
Although I am finding that in Embedded when I look at, I mean, even Arduino or Embed or any of the places where you can just go.
CMSIS is one of those.
Yeah, that's a big SDK.
But there are just so many out there all all
the bluetooth stuff i've been using lately and the wi-fi you just have to learn the library
yeah it is it is definitely getting more common in our world too
do you have any last thoughts you'd like to leave us with
um boy i wish i had something really witty to say right now. This has been fun, but I, uh, I don't know.
I hope people will give unit testing a try if they haven't already.
And, um, if not, I hope they still enjoy their embedded software.
Just keep it away from us.
Exactly.
My guest has been Mark Vandervoord, maker of Things and Ones and Zeros.
He's also the author of Embedded Testing with Unity and CMock,
and a much longer title that I'm not going to remember,
and an instructor of using Unity, and soon an instructor of using CMock.
And if you would like to know more, there are links in the show notes.
Thank you, Mark, for being here.
Thank you. This was fun.
Thank you also to Christopher Waite for co-hosting and producing.
Special thank you to listener and previous guest, Chris Zweck, for suggesting we invite Mark on.
And also thank you for listening. Finally, thank you to Planet Labs for sponsoring our contest. Don't forget to send them your resume, embeddedfm at planet.com. And don't forget to send me your satellite idea to enter the contest. That is hitting the show notes, hitting the something, hitting the link on embedded.fm
or emailing us show at embedded.fm. I have a final quote for you from Theodore Roosevelt.
This one is sort of related, but probably more related to what I've been doing with my life
lately. Far and away the best prize that life has to offer is the chance to work hard at work
worth doing.