When we write automated tests, we want to do it in the simplest way possible while achieving the highest level of quality for the time we invest in our tests. Unfortunately, this is easier said than done.
Writing tests can be hard. It’s hard figuring out what kinds of automated tests to write. We can write unit tests, integration tests, functional/acceptance tests, performance tests, or just do manual testing. We have to decide if developers are writing tests or if QA people are doing it (or both). It’s really complicated!
Let’s look at some ways that people sometimes tackle the testing problem and then discuss some different ways we can approach it.
The black box
On some projects, the team is testing a big black box. Usually this is where QA people are doing all the testing and developers aren’t writing automated tests. If you read my blog at all you know that I do not like this approach (unless time to market is really that important) because it leads to lots of bugs and makes refactoring anything really scary. In this scenario, QA testers typically only control the inputs and outputs into the black box (which is usually a user interface of some kind). This leads to problems like having to jump through a bunch of hoops just to test something that’s farther down the line of some complicated workflow.
If you’re a fan of test-driven development, you will write a lot of unit tests. In this case, you’re slicing your application up into very tiny, testable units (like at a class level) and mocking and stubbing the dependencies of each class. This gives you faster, less brittle tests. You still probably have QA people testing the black box as well, so now we’re using two different approaches, with is good.
I’m not satisfied
While each of the previous two approaches have their positives, they both have their negatives. I’ve already talked about the negatives of all manual QA black box testing, so I won’t go into that again (although I’m always up for a good rant). But writing lots of unit tests has its problems as well. For example:
- Tests with lots of mocks and stubs, and failing tests that fail because someone refactored a class any now my stubs and mocks are all hosed. You know the feeling.
- Testing an individual class or method is great, but my tests aren’t always testing something that has business value on its own.
You own your application. Your application does not own you (at least it shouldn’t). We also own the testing of our application and should be able to test it in any way that we can think of. The goal is high quality, low cost of maintaining the test suite, and speed to market. How can we best achieve this goal? (And don’t just give me the first textbook answer that pops in your head.)
There is no one-size-fits-all method for testing applications, and there isn’t even one single best way to test a single application. So what if we used many different approaches and broke our system up into chunks so that we can use each testing method to its fullest potential?
In this case, I’m dividing up my application into separate modules, each with its own purpose, function, and business value. Some may have a user interface component and other might just do some task behind the scenes. I can decide how to best test each module individually. Maybe some modules are done with all black-box acceptance testing, and other modules are done with lots of unit tests. Even within the black-box modules, I might still write unit tests. Of course, I’m still going to have some end-to-end tests (manual and/or automated) that test the whole system working together, but I don’t have to test the majority of the functionality this way.
My favorite kinds of tests are ones that test a system working together because I can specify the inputs and outputs and I don’t have to deal with tons of stubs and mocks. Now if you try to test the whole application end to end this way, it can be a bit cumbersome. But if you have a smaller module that you can test end-to-end, now you can have clean, readable, well-defined tests that don’t have tons of mocks, and the tests define some business function that the module needs to perform. My module might still work independent from the UI or the database, so I might still be able to stub those out and have fast tests. This feels like the kinds of tests I’ve always wanted – tests that test a module end-to-end but are able to run fast because I can still isolate dependencies.
Hey, look, it turns out that modular applications is a good idea in general! It’s way easier to deal with lots of smaller applications that work together than dealing with one monolithic application. Those of you with large solution files and long compilation time (I’m raising my hand) know the pain of dealing with large applications.
The emerging blob
We like to talk about “emergent design” and that we can write tests first and let that drive the design of your code. That is true, but your codebase will evolve into a monolithic (albeit well-tested) blob of an application that assimilates all code into it’s large collective.
The only way you’re going to have a modular application is if you draw the lines in the sand up front. This can be really hard to do when you have a newer application and you don’t have a ton of insight to tell you how to keep things separate. Compounding the confusion is the fact that you might have a single database for the application as a whole, which I think is fine. You can multiple modules that use the same database, even the same tables. Sure, it would be better if you can keep the tables in separate databases, but sometimes that’s not possible or realistic.
You might start out with certain modules and then realize that you created a separation that is too painful to maintain. That’s OK, it’s much easier to combine two modules than it is it try and separate things into modules after the fact!
Once you’ve defined your modules, now you can decide how to test them (QA and devs should work together on this!).
This feels better
- Cleaner tests with fewer mocks that test mini-systems that provide some function or business value
- More modularity means I can change code without potentially breaking as many things
- Smaller solution files!
I really like how this sounds.
The “impostor syndrome“… is when you’re pretty sure that all the other coders you work with are smarter, more talented and more skilled than you are. You live in fear that people will discover that you are really faking your smarts or skills or accomplishments.
Ever feel like this?
If you do, you’re not alone. But this feeling is not healthy and probably isn’t accurate.
I know people who are like this, and you probably do too. It tends to manifest itself when people feel that they need to work extra hours in order to provide a perceived amount of value that matches the amount of value provided by people working normal hours.
Why does this happen? I believe it’s because people are comparing themselves to others (unhealthy) instead of looking at the amount of value that they do provide (healthy).
Look, if someone gave you a job or put you in a position, they did it because they see value in you and they think that you can do the job. You already convinced them that you can do it!
Now that you are past that point, let’s focus on the value that you provide. I’m guessing that you can probably come up with a list of value you provide at work. For example, maybe you can say that you’re a solid developer, you like helping users, you have a lot of knowledge of system X in your company, and you’re good at using ORM tools.
Think about the last time that someone left your company or your team. It was pain replacing them, wasn’t it? (Well, in some cases maybe that person leaving was a good thing.) But if that guy who left wasn’t a problem, it probably was a lot of work training someone new, learning all of the things that person knew, and trying to make up for the value that walked out the door. (As someone who just took over for someone who left, trust me, I know the feeling!)
Instead of comparing yourself with others, focus on what you’re good at and how you can provide more value! Come up with a plan of something that you want to do to provide value. Write down the steps that you’re going to take to accomplish it. Then when you make it happen, look back and enjoy the good feeling that comes with accomplishing something and providing value.
That’s what matters! That’s what your company wants from you. They don’t want you to be another (insert name here). They want you to be the best version of you that you can be.
Do you sometimes have that feeling that your life is running you instead of you running your life? Do you feel so bogged down with meetings and distractions at work that you feel like you’re unable to get anything accomplished? Are you feeling like you don’t have the discipline to accomplish your goals?
The answer to all of these questions involves focus. I firmly believe that I need to have a plan for achieving my goals and getting things done so that I can be in control of the situation rather than have the situation control me.
Focus at work
Most of feel (or have felt) that we have too many meetings and distractions. I’ve certainly felt that way a lot in the past. I’d like to tell you to just start skipping meetings, and while that might be a good idea in some cases, most of the time you can’t do that. What you can do is prioritize meetings and distractions so that you have time for the most important things.
If I’m working on a project, people expect me to get things done. So if all of my time is consumed by other things like meetings, production monitoring, asking questions, etc., then I’m not sticking to my promises. I started blocking off work time on my calendar. Actually our whole team blocked off 3 hours in the afternoon for “work time”, and if my day got to be half full with meetings, then I would just block off the rest. I decided that I needed at least half a day of time to get things done because that was important. I wasn’t dismissing everyone else, I was just making a conscious effort to decide what was most important.
I’ve also been getting better at saying no. Even if I’m not feeling swamped by deadlines and meetings, I still have a primary task that I’m focusing on. In order to maintain that focus, this means that I’ve started saying no to other people who need things done if I’m not the person who should be responsible for doing the work. I generally like to help people, so it’s been hard to do this. I’ve even started doing it with relatively easy tasks. Sure, I could spend 20 minutes and get that thing done for someone, but then they will keep coming back. This sounds somewhat selfish, but I’m making a conscious effort to focus on my task at hand.
Focus in life
There have been times when I have felt like my life was running me and that I was just treading water and trying to keep up. No one likes feeling like this.
I realize that I’m only somewhat in control of my life. I could get cancer tomorrow, or get hit by drunk driver. Thankfully those haven’t happened to me so far, so I want to proactive and intentional whenever I can.
The first thing to do is decide what you want your life to look like and then come up with a plan for success. Then you need to arrange your life and activities around those priorities. Time is a scarce resource for all of us, which means that at some point we have to think about what’s filling our day and eliminate things that aren’t important. With all of our electronic devices, it’s so easy to spend more and more time surfing the internet, reading blog posts, playing online games, and so on. Not that those are bad, but I’ve found that I need to cut some of those out so that I have more time to do the more important things I need to do.
The Manifesto for Software Craftsmanship states that they “are raising the bar of professional software development by practicing it and helping others learn the craft.” As a software developer, I take pride in my work and have high standards for myself, and I appreciate it when others do the same. But if those high standards turn into arrogance toward others, then maybe we’ve gone astray.
They told us back in grade school that you shouldn’t pull yourself up by putting others down, but even today that wisdom can be hard to remember. I admit that I’m guilty. If you work at a company that has any code that has been around for a few years, you’re going to find some horrible code, and it’s really easy to make fun of it. I still do it all the time, but I’m trying to stop.
Arrogance and software craftsmanship don’t mix. While the technical aspect of software development is extremely important, the human side of things is just as important. It doesn’t matter how good your code is if the software doesn’t meet the needs of the users. If you refer to people in the business as “stupid users”, how are you going to be able to understand what life is like in their shoes? If you know all of the SOLID principles but you have a bad attitude, your teammates would probably rather work with someone else.
People who don’t know what we do sometimes think of software developers as a bunch of people who sit in front of a computer all day and never interact with anyone. In my experience, that hardly ever happens, and in fact, we often get rid of cubicles in favor of more collaborative workspaces where we can communicate easier with other team members, and sometimes even have business users come sit near us so that we can have their constant feedback.
I remember a situation several months ago where I had to meet with some users to design some functionality. After the first few meetings, I had to present a potential design idea to them. Before I went into the meeting I had already thought of potential issues that the users might bring up and the rebuttals that I would give. The users expressed some concerns and I wasn’t winning them over.
I stopped after that meeting and took a step back. Maybe I was listening to the words coming out of their mouth but not actually hearing what it was that they were really saying. Maybe their concerns weren’t petty after all and they had good reason for bringing them up.
The next time we met, I tried to go in and just listen. I mean really listen, like let them talk without thinking about what I’m going to say next. I tried looking them in the eye and processing every word that they say, the feelings they were expressing, and the reasons why they believed that way. Then when they were done talking, then I would think about how I’m going to respond. And this time I finally saw what they were talking about. It really hit home when one of the users (who was excited about me finally getting it), said excitedly, “That’s what we’ve been saying for the last month!”
I’m glad that I finally got it right, but I’m disappointed that it took me so long to get there.
In my mind, in order to really consider yourself a craftsman (or craftswoman), we need to not only value technical expertise but skilled human interaction and communication skills, and that starts with having an empathetic attitude toward others instead of finding ways to put them down.
I read an interesting article in the Wall Street Journal the other day about “Must-Have Job Skills in 2013″. While this wasn’t necessarily referring solely to technical fields, it was still interesting. Here is their list of must-have job skills:
- Clear communications
- Personal branding
- Productivity improvement
It made me think of the software craftsmanship people and the importance that they place on things like code katas, learning new languages, etc. If you’re a developer and you spend time honing your craft, how much value are you placing on skills like:
- Being able to write a good requirements document
- Facilitating a requirements gathering session with business users
- Giving demos of your software to users (in their language)
- Coming up with estimates for a large set of functionality
- Being able to evaluate tools and frameworks and choose the best one for your project
Admittedly, it’s much easier to practice TDD than it is to practice requirements gathering. But these are skills that I feel are very important for developers. There are lots of people who can write code, even good code. If I don’t know how to use a language or framework, someone can teach me pretty quickly and I’ll pick it up. But can you also pitch in and help with requirements gathering, test planning, system architecture and design, and everything else that needs to be done on a project? Now that will set you apart.
When you think about learning new skills and investing in your career, just make sure that you don’t limit that to tools and technology.
Time is one thing in life that will always remain constant. You can acquire more knowledge or more money, or you can save today’s money and use it tomorrow. But you only get 24 hours a day, and you can’t carry them over to tomorrow.
Most people would agree that there are not enough hours in a day. There are plenty of things I would like to do, books I want to read, projects that I want to work on, that I just don’t have the time to do. The challenge is figuring out how to make sure that you’re spending your time on the things that are important to you.
Know your priorities
If you don’t know what your priorities are, you won’t know how to prioritize your life. That sounds obvious, but it’s really hard to actually do. Many people don’t really know what their priorities are, let alone how to execute on them.
Do what’s important first
Something or someone will fill your day if you won’t. Personally, I hate the days where I feel like I didn’t get anything done that I wanted to get done because I was constantly reacting to things that came my way. Sometimes this is inevitable, but you can control it. For example, I expect that I should have at least half of my day available to do work (i.e. not stuck on meetings), so when a day is half full, I block out the rest of it so that no one can schedule me for a meeting. I do that because I need that time to accomplish what I feel is important and what people are expecting me to accomplish.
Live out your priorities
People are a priority to me, so if someone wants to go to lunch, I may or may not have time for that, but I usually go anyway and then find a way to everything else in around it. I have other friends who will go out of their way to make time to eat lunch when they’re really busy. That shows me something – that I’m valuable enough to be made a priority in their life. I love that.
My team is also a priority for me. This goes back to shunning meetings. I feel that in my current role, it’s more important for me to be with my team than to sit in a meeting with people from another team, so I block off my schedule and try to get out of meetings if I don’t feel that it’s valuable for me or the meeting organizer. (Sometimes people like to schedule 30 minute meetings for things that could be solved with a 10 minute hallway conversation.)
Own your life
I want to control my life and time as much as I can. I don’t want my life to control me because then I’m not able to do the things that I feel are important. The more proactive I am, the more likely I am to succeed at this.
I saw this in a job posting the other day, describing the work environment at the company:
We pair a lot, but not all the time. We test a lot, but not all the time. The key is being able to explain your practices with rational argument.
I love this. There are practices like testing that I hold in high regard, but nothing should be done all the time. As the posting says, “the key is being able to explain your practices with rational argument.”
Can you explain why you do something like TDD? That’s probably easy for you. But can you explain when you shouldn’t use that practice? That’s a little harder to do, and maybe because you’re holding onto some ideal that says you should test all the time or have 100% test coverage.
For every idea or practice that you find valuable, you should also be able to explain when it doesn’t apply. If you can’t explain when not to do it, I would say that you don’t really understand when and why you should use it.
I’ve talked about it for a long time, but I finally refactored my resume. I read a lot of resumes, and most of the time they annoy me because I get annoyed by the way that it’s written, even if the candidate is qualified. Yet my resume was more or less the same thing, so I figured I needed to take my own advice and do something about it. Here’s the thought process that led me to the end result (which you can see here).
Go to any tech conference and you get the big bag of vendor pamphlets trying to sell you their product or consulting services. These papers are very colorful and attractive and professional looking. What you don’t find is a black and white piece of paper with a list of 50 bullet points that enumerates their achievements.
We really are no different from those companies. We are trying to sell our services to potential employers or clients. So why aren’t we making our resumes look more like marketing material?
When I read a resume, I pretty much know whether I want to hire someone or not. The interview is just there to confirm my assumptions and potentially break the tie between two candidates. So if your resume is poorly done, you’re already behind the 8-ball before I even get to talk to you.
Answer the right question
Most resumes are answering the wrong question. The question to answer is not, “What did you do?”, the question is, “What sets you apart from the other candidates?”, or, “What experience that you have that can help our team/company improve?”
If you’re a QA person, don’t put “Entered bugs into bug tracking system” on your resume. That is something you did, true, but (a) I assume that a QA person uses a bug tracking system and (b) it doesn’t tell me anything about how you can help my team.
More is less
The way I see it, there are two kinds of people reading your resume. There are those who are briefly glancing at it to decide if they want to learn more. There are those who want to learn more and/or interview you and they will read more of it. No one ever reads it all.
With that in mind, only put things on there that you want someone to read. I know that sounds obvious, but apparently people are not good at it. You want to make it easy for the people glancing over your resume to want to read more, and you want to make it easy for the people doing the interview to find what’s important.
Everything on your resume has a value — but that value can be negative. When I read a resume before an interview, I read through the last couple work assignments and cross out everything I read that doesn’t add value. Then I’m left with the statements that have value. I would’ve much rather just read the good stuff without having the black out all of the cruft.
Also, I don’t really care what you did in 2003. Chances are you were using a technology that is not the technology being used in the job you’re applying for. Just tell me the things that have relevance, either because it’s a similar skill to what the team needs or because it’s something that you did relatively recently.
No more than 2 pages
I’ve never found anything meaningful on page 3 of a resume, so don’t have one. You don’t have to list every place you’ve worked and you don’t have to list every single thing that you did there. This is particularly challenging for consultants because we tend to move from project to project. Remember, you just have to give me enough information to make me want to work with you, you don’t have to tell me your life story.
Write it so someone would want to hire you for the job you want
If I think about my ideal project, it would probably involve Agile, TDD, either .NET or Ruby on Rails, and working in a team environment with people who care about their craft. I tried to make my resume reflect that. On the first page, I highlight how I’ve led Agile projects, I do TDD training and like unit testing and acceptance testing, and how I’ve used Ruby on Rails and ASP.NET MVC, which is my .NET tool of choice. I put a link to my GitHub account because people who tend to think like me like to see that developers hack on stuff and like to be able to look at actual code they’ve written. I also have a link to my blog so that people can learn more about the things I like (and don’t like). While I don’t claim to be great at design, I’ve tried to add some flair so that people can see that I am creative and am capable of thinking outside the box, which I think is an important quality for a software developer.
I actually went through this process when I created the first page of my resume. I made sure I highlighted all of the important stuff that I mentioned and left off everything that was not on that list. There’s room on page 2 for the other less important details.
Things I don’t want to do are nowhere to be found on either page. I’ve done C++, WebForms, and TFS build server administration. I really don’t want to do those things again if I can help it, so I’m not going to list those things anywhere. The people hiring someone for my ideal job wouldn’t care about those things.
You are selling yourself. There is nothing that mandates that your resume be a sea of bullet points or that you must list everything you’ve ever done. You are much smarter than that, so be creative and come up with your own marketing material. Then walk into the interview knowing that they have the important information they need to want to give you the job.
I came across this post the other day that went on and on railing on things that the author found unacceptable in today’s web frameworks, specifically Rails and ASP.NET MVC. It covered the whole gamut of issues, from abstract base classes in ASP.NET MVC to mega-controllers in MVC frameworks.
I’ve thought a lot of the same things too, to various extents. For example, I’ve never understood why controllers existed. Why can’t we just define routes that are handled by route handler classes that use conventions and REST and things like that? Yet I continue to use controllers in web apps. It made me think, at what point is something bad enough to do something about it and when do I just live with it?
This is the kind of question that makes software development so difficult, but at the same time a lot of fun. Today we were looking at a piece of code that needed to be refactored. We couldn’t figure out what the right way was to implement it, nor could we decide if it was worth the time to even do anything about it.
How do you decide what to do in this situation? The way I see it, you have to look at the return on investment on everything you do. In my controller example, I could invest the time to implement some non-controller solution. On a large enough project, I would probably get a good return on investment compared to using controllers.
But then again, you could argue that since controllers are towards the outer layers of the stack, maybe you can live with it. I care much more about the sanctity of the domain model because that’s the heart of my application. So is it really worth the time or not?
But it gets more complicated than that. Let’s say it takes me a week to implement the non-controller solution. During that time I’m not delivering any client facing features, and that might not sit too well with the people paying for your project. I was in this situation once, and the project almost got cancelled. Thankfully I pulled it out and was on the project for a year and a half and my framework investments more than paid off. But those first few weeks were nerve racking.
So what’s the answer to my original question? I guess it depends. As does pretty much everything else in software development. Which means that you don’t get an easy way out and you are going to have to use your head.
I still think I’m right about the return on investment thing. But at the same time you need to be shrewd about it.
Older Posts »