10 Things About the SDET Role

Unfortunately, there are still lots of developers that remain unconvinced of the usefulness of automated testing, particularly if they have to author the tests themselves. Enter the Software Development Engineer in Test (SDET), or Software Engineer in Test (SET). There are varying opinions about the roles and responsibilities of an SDET. This post is not likely to conform to [your favorite company]’s description, but I expect that it will have a lot in common.

SDETs are subject-matter experts in the testability of code.

This requires them to know …

1) … what kinds of tests to write.

There are different ways to test a product. Most products require a combination of different types of tests. Common types include unit, integration, and functional–Google uses small, medium, and large.

2) … approximately how many of each kind of test is needed.

Different types of tests have different strengths, weaknesses, and ROIs. Things like how long a test takes to execute, maintain, or create affects how many of each of the various types yield the greatest value.

3) … techniques for refactoring product code so that it is testable.

Especially with legacy code, it is common to have to break dependencies before you can properly test a unit of code. For functional tests, the product needs to include hooks (e.g. identifiers for UI components, backdoors for initializing state, etc.) to facilitate testing.

4) … that bad tests are much worse than no tests.

Bad tests might require excessive amount of work to maintain, all fail at once making it hard to locate the source of the issue, or render false positives/negatives leading to distrust of the tests.

I think bad tests are a major source of skepticism among developers. A lot of developers have been burned by their first attempts to automate testing that resulted in unreliable, unmaintainable tests.

5) … how to choose great tools.

Different products require different testing tools. For example, MOQ and RhinoMocks are sufficient mocking libraries for green field development in C#. However, a legacy system in C# might require something like TypeMock Isolator to be able to get poorly designed code under tests.

You want to choose tools that make it easy to write good tests.

6) … how to mentor others.

The benefits of testable code go beyond testability. SDETs need to be able to explain why the code changes are not merely in support of testing, but actually improve the quality of the code.

SDETs are not …

7) … lesser/beginner developers.

Based on the items above, I wouldn’t expect a beginner programmer to fill those shoes. Would you? I think this comes from developers that think product code is more important than test code. In my experience, writing tests and making code testable is often more challenging than writing product code that works.

8) … the only ones writing tests.

Quality needs to be a priority of the entire team. It is hard to have high levels with quality without tests. Also, product developers nearly always outnumber SDETs by a significant ratio (1:4 on my current team) and the amount of test code usually exceeds the amount of product code. That being the case, developers have to write tests, too, if you want a shot at adequate test coverage.

9) … forbidden to touch product code.

As mentioned in #3, a product often has to be changed to make it testable. Even when using TDD, you might have to add hooks for functional tests to facilitate testing.

Also, it shouldn’t surprise you that working within a code base makes you better equipped to test it. Refactoring has always been a quick way for me to familiarize myself with a code base. I think that SDETs should spend time implementing features, too–just not as much time as product developers.

10) … permanent as a role.

I believe that if the SDET role is properly realized in an organization that it will eventually phase itself out. As product developers begin to see the value of testing and incorporate it into their daily routine, there will be less of a need for a distinction between product developers and SDETs.

Share

The Gilded Rose Kata for Swift

If you have never worked through the Gilded Rose kata, you’ve been missing out; it is canon when it comes to coding katas. It is unusual because it provides an initial implementation. Your mission, if you choose to accept it, is to add functionality to this legacy code. By the way, it is a huge mess! In order to make the work manageable, you’ll first have to refactor the existing code.

I wasn’t able to find the initial code in Swift, so I took a couple of minutes to port it. I used the code provided by Emily Bache as a starting point. You should definitely check out her repository if you want to try the kata in different languages.

rose

Share

Overclocking Your Brain

“How are you able to work on coding chops after a full day of programming at work? I am mentally exhausted by the time I get home and just can’t get motivated to tackle something new.” …, or something like that, is what I’ve heard from several people recently.

My answer: drugs.

Well, not exactly. I’m certainly not doing anything illegal. But, I have found some legal “nutritional supplements” that help me shake off the mental fatigue that I frequently encounter after coding my brains out at work.

Acetylcholine

Before I go any further, I feel obligated to remind you that there are no magic bullets. There is no substitution for genuine curiosity and tenacity. But, there may be things that give you a little nudge every now and then…

Enter nootropics. For the past few months, I’ve experimented with different combinations and dosages of nootropics with noticeable effect. I go to work, write the best code I know how to write, come home, spend some quality time with my family, then get back to writing code and mastering my craft. On those nights that I can’t shake the mental fog with a cup of green tea, I’ll put a little Noopept under my tongue and off I go. No kidding, it is almost like starting the day over sometimes. If I wake up feeling mentally sluggish, I might mix some Oxiracetam and CDP Choline in a glass of water. And there are lots and lots of different products available.

Again, taking supplements and sitting in front of the TV isn’t going to help you. Drinking protein shakes and sitting on your butt won’t make you muscular, either. But, if you’re pushing the limits of your mental endurance, it might be worth your time to do some investigation–there is plenty of research data available for different nootropics.

One more thing. I’m not a doctor, or in any way qualified to give medical advice. If you decide to experiment with nootropics, you need to do your own research. It might also be wise to consult with a doctor to make sure there aren’t known interactions with any other medications you are taking.

Share

Watch it.

I recently completed another technical review for The Pragmatic Bookshelf, which has produced (and continues to produce) great technical books. I jumped at the chance to review Jeff Kelley’s new book because it covered a topic that has been greatly anticipated by the Apple community: the Apple Watch.

jkwatch

Even if you have no intention of developing an app for the Apple Watch, I would recommend picking up a copy of Developing for Apple Watch: Your App on Their Wrists.

So, why would you want the book even though you don’t intend to create a Watch app?

1) Jeff gives great insight into the architecture and interactions between the watch and the phone to which it is tethered. Understanding different architectures and designs will certainly give you better intuition into why other things are the way they are in the Appleverse.

2) The code is written in both Obj-C and Swift. This is valuable because of the newness of Swift–there are lots of great libraries that have been written in Obj-C over the years that haven’t been ported to Swift, yet. Being able to make use of these libraries is essential.

3) How do you know you don’t want to write a Watch app if you don’t even know what the device can or can’t do? Learning about it may give you that one in a million idea.

It is an quick read, so if you want to give your brain a quick ++, Jeff’s book is a good choice.

Happy learning.

Share

States That Matter

IceI’ve been spending a little time reviewing design patterns recently, so I thought I would post an example I’ve been working on for the State design pattern. Essentially, the pattern makes it easy for you to change behavior of an object as its state changes.

I didn’t want to copy someone else’s example, so I hope you find this one interesting.

I’m going to create a Water class that has three different states: solid, liquid, and gas. The only difference in behaviors for the states will be their descriptions, which change as the temperature of the water changes. Of course, I don’t think anyone would ever utilize the state pattern for such a simple case, but I’m hoping that it is easy to follow.

The first class I’ll introduce is the Water class. It has an internal state that tracks the temperature and description of the water.

class Water : Printable {
    
    private var state: State! = nil
    
    init() {
        state = Liquid(temperature: 105, water: self)
    }
    
    var temperature: Double {
        get {
            return state.temperature
        }
        set(value) {
            state.temperature = value
        }
    }
    
    var description : String {
        get {
            return state.description
        }
    }
}

 
Next, we’ll need the State class. It provides scaffolding for the various states and also includes some logic that can be shared among states.

class State : Printable {
    
    var water: Water
    
    init(water: Water){
        self.water = water
    }
    
    private(set) var temperature: Double = 0.0 {
        didSet {
            stateChangeCheck()
        }
    }
    
    var description : String {
        get {
            fatalError("\(__FUNCTION__) requires override by subclass.")
        }
    }
    
    private func isSolid() -> Bool {
        return temperature <= 32
    }
    
    private func isLiquid() -> Bool {
        return temperature > 32 && temperature < 212
    }
    
    private func isGas() -> Bool {
        return temperature >= 212
    }
    
    private func stateChangeCheck() {
        fatalError("\(__FUNCTION__) requires override by subclass.")
    }
}

 
Finally, we implement the three states.

class Liquid : State {
    
    init(temperature: Double, water: Water) {
        super.init(water: water)
        self.temperature = temperature
    }
    
    override var description : String {
        get {
            return "Liquid"
        }
    }
    
    private override func stateChangeCheck() {
        if isSolid() {
            water.state = Solid(temperature: temperature, water: water)
        } else if isGas() {
            water.state = Gas(temperature: temperature, water: water)
        }
    }
}

class Solid : State {
    
    init(temperature: Double, water: Water) {
        super.init(water: water)
        self.temperature = temperature
    }
    
    override var description : String {
        get {
            return "Solid"
        }
    }
    
    private override func stateChangeCheck() {
        if isLiquid() {
            water.state = Liquid(temperature: temperature, water: water)
        } else if isGas() {
            water.state = Gas(temperature: temperature, water: water)
        }
    }
}

class Gas : State {
    
    init(temperature: Double, water: Water) {
        super.init(water: water)
        self.temperature = temperature
    }
    
    override var description : String {
        get {
            return "Gas"
        }
    }
    
    private override func stateChangeCheck() {
        if isSolid() {
            water.state = Solid(temperature: temperature, water: water)
        } else if isLiquid() {
            water.state = Liquid(temperature: temperature, water: water)
        }
    }
}

 
I’ve put all of these classes in the same file so that I can use the “private” keyword like I would use the “protected” keyword in other languages. Doing this makes it possible to expose temperature and description, without exposing things I don’t want to expose, like state. Remember, “private” is a little different in Swift than it is in other languages: it limits access to code in the same file (not the same class.)

Let’s see how it works:

var water = Water()
println(water.temperature) // 105.0
println(water.description) // Liquid

water.temperature -= 115
println(water.temperature) // -10.0
println(water.description) // Solid

water.temperature += 225
println(water.temperature) // 215.0
println(water.description) // Gas

 
And there you have it!

Share

Hello, Android!?

Wait! This blog is called The Swift Learner… Why is there a post with “Android” in the title?

Actually, I try not to be a one trick pony; I’m proud to be a polyglot programmer. Also, if you’re building iOS apps, you might consider releasing for Android as well, since it represents a large percentage of the market share.

eband4_xlargecoverIf this sounds interesting to you, I know just the place for you to get started. A few months ago, I had the pleasure of being a technical reviewer for the 4th Edition of Ed Burnette’s new book, “Hello, Android: Introducing Google’s Mobile Development Platform“. It is my opinion that the best way to learn new programming languages, APIs, SDKs, etc. is to use them. Ed’s book will have you writing lots of code that will take you from beginner all the way to releasing your first app in the Google Play store. I know because I worked every exercise in the book. It also taught me how to play Ultimate Tic-Tac-Toe, which I hadn’t encountered before.

As part of a team that just released an Android app, I can tell you that “Hello, Android” does a great job explaining how Android apps work. It also does a good job employing best practices in its examples. Anyway, I hope you find it as useful as I did.

Share

Get Off My Lawn! (Code Ownership)

Ever met a programmer that is territorial about his or her code? Are you that programmer? I’m going to take a couple of minutes to explain why I think that’s a bad idea.

First, let’s consider why a programmer might want to keep other programmers out of “their” code (or, at least, what I assume is their reasoning when I encounter it.)

In order of suspected likelihood:

  1. They don’t trust the other programmers on their team.
  2. They don’t have confidence in their own abilities and are afraid of getting “found out.”
  3. They think that being the only person that understands a particular piece of code grants them job security.

Assuming one of the reasons above is why a person wants exclusive code ownership, here is what they might be missing:

  1. If you don’t trust your team members, you should find out why you feel that way. Perhaps it is an opportunity to mentor someone. This is as beneficial, if not more, to you as it is to them. You gain better understanding of something when you teach it. Also, any decent manager will recognize the value of an employee that improves the people around them.
  2. If you lack confidence in your abilities, maybe you need a mentor. It is much easier to improve if you enlist the help of others trying to reach the same goal. Also, if you involve others and the code ends up failing, the blame is shared by the team and not just you.
  3. Nobody is irreplaceable. I don’t care how good you are or how much you know, there is always someone else that can pick up where you left off. Actually, the easier it is for someone else to learn your code, the better job you did. The reverse is true, too.

One last thing. If you’re working for someone other than yourself, the code probably doesn’t belong to you anyway. It belongs to whoever paid for it.

Share

Allergies and Dependency Inversion

A couple months ago, I posted about the Law of Demeter and how to keep your classes from requiring knowledge of its dependencies’ dependencies. The code for that post was contrived and I only refactored it far enough to demonstrate the Law of Demeter. However, after posting the article on LinkedIn, someone correctly pointed out that I neglected the Dependency Inversion Principle.

The Dependency Inversion Principle tells us that our higher-level modules should not depend on our lower-level modules. Let’s give dependency injection a try to demonstrate the principle.

Consider the following code:

class LawnService {
    func serviceLawn() {
        Employee().mowGrass()
    }
}

class Employee {
    func mowGrass(){
        LawnMower().cut()
    }
}

class LawnMower {
    func cut(){
        println("Hello allergies!")
    }
}

LawnService().serviceLawn()

 

So, what problems does the example code present?

  1. Isolating the different classes for testing purposes is not possible because of dependency on concrete classes.
  2. The code is not very flexible. What if I wanted to have multiple kinds of lawn mowers?

Let’s start with making it possible to isolate individual classes for testing purposes and see if that technique helps us with our second problem, too.

I need to be able to inject a stub or mock into LawnService, so that I can test it without testing the concrete Employee class. If I make a protocol for the employee and provide a mechanism for injecting an instance into the LawnService class, I should be able to do just that.

// Added a field for an instance of employee 
// that will use whatever concrete is passed 
// in on construction
class LawnService {
    var employee: LawnServiceEmployee
    
    init(_ employee: LawnServiceEmployee) {
        self.employee = employee
    }
    
    func serviceLawn() {
        self.employee.mowGrass()
    }
}

// Extract protocol for lawn service employees
protocol LawnServiceEmployee {
    func mowGrass()
}

// Employee now implemented the new protocol
class Employee: LawnServiceEmployee {
    func mowGrass(){
        LawnMower().cut()
    }
}

// A stub class used for testing
class EmployeeStub: LawnServiceEmployee {
    func mowGrass(){
        // do nothing, we're a stub
    }
}

// Nothing new here
class LawnMower {
    func cut(){
        println("Hello allergies!")
    }
}

// Injecting our real Employee 
// implementation
LawnService(Employee()).serviceLawn()

// Injecting our fake Employee
// implementation for tests
LawnService(EmployeeStub()).serviceLawn()

 

Also, I find it convenient to provide a default implementation if I know I’ll be using a particular concrete most of the time.

class LawnService {
    var employee: LawnServiceEmployee
    
    // Notice that we default to an instance of 
    // Employee
    init(employee: LawnServiceEmployee = Employee()) {
        self.employee = employee
    }
    
    func serviceLawn() {
        self.employee.mowGrass()
    }
}

// This call instantiates Employee and uses it
// rather that requiring it to be passed into
// the init
LawnService().serviceLawn()

 

Let’s do the same thing for lawn mowers, but this time we’ll provide real types instead of a testing fake.

class LawnService {
    var employee: LawnServiceEmployee
    
    init(employee: LawnServiceEmployee = Employee()) {
        self.employee = employee
    }
    
    func serviceLawn() {
        self.employee.mowGrass()
    }
}

protocol LawnServiceEmployee {
    func mowGrass()
}

// Added a field for an instance of lawn mower
// that will use whatever concrete is passed
// in on init
class Employee: LawnServiceEmployee {
    var lawnMower: LawnMower
    
    // defaulting to RidingMower may not be 
    // a good idea...
    init(lawnMower: LawnMower = RidingMower()){
        self.lawnMower = lawnMower
    }
    
    func mowGrass(){
        RidingMower().cut()
    }
}

// Extract protocol for lawn mowers
protocol LawnMower {
    func cut()
}

// One type of lawn mower
class RidingMower: LawnMower {
    func cut(){
        println("Riding along on my gas hog")
    }
}

// Another type of lawn mower
class ReelMower: LawnMower {
    func cut(){
        println("Getting some exercise")
    }
}

var mower = ReelMower()
var employee = Employee(lawnMower: mower)
LawnService(employee: employee).serviceLawn()

 

That’s all well and good, but I think I can clean things up a little more by creating a different kinds of lawn services: an eco-friendly lawn service and a standard lawn service.

class LawnService {
    private var employee: LawnServiceEmployee
    
    init(employee: LawnServiceEmployee) {
        self.employee = employee
    }
    
    func serviceLawn() {
        self.employee.mowGrass()
    }
}

// Standard lawn service has employees
// using riding lawn mowers
class StandardLawnService: LawnService {
    init() {
        var employee = Employee(lawnMower: RidingMower())
        super.init(employee: employee)
    }
}

// Eco-friendly lawn service has employees 
// using reel mowers
class EcoFriendlyLawnService: LawnService {
    init() {
        var employee = Employee(lawnMower: ReelMower())
        super.init(employee: employee)
    }
}

protocol LawnServiceEmployee {
    func mowGrass()
}

class Employee: LawnServiceEmployee {
    var lawnMower: LawnMower
    
    init(lawnMower: LawnMower){
        self.lawnMower = lawnMower
    }
    
    func mowGrass(){
        self.lawnMower.cut()
    }
}

protocol LawnMower {
    func cut()
}

class RidingMower: LawnMower {
    func cut(){
        println("Riding along on my gas hog")
    }
}

class ReelMower: LawnMower {
    func cut(){
        println("Getting some exercise")
    }
}

StandardLawnService().serviceLawn()
EcoFriendlyLawnService().serviceLawn()
Share

Empty or Optional Arrays

I’ve briefly mentioned Swift’s requirement that non-optional variables have a non-nil value in a previous post. I wanted to briefly share what I find to be a best practice: don’t use optional arrays.

So, what is the big difference between these the following declarations?

var heroes: [String] = []
var villains: [String]? = nil

 
What happens when we try to append?

// "Ned Stark" is added to our list of heroes
// exactly what we wanted
heroes.append("Ned Stark")

// nothing happens; the variable is nil
// it is like this line doesn't exist
villains?.append("Petyr Baelish")

 
So, how do we make it so we can add villains?

// add a nil check and create the array if it is nil
if villains == nil {
    villains = []
}

// now we can add a villain
villains?.append("Gregor Clegane")

 
This is just one example of many that requires checking for nil when an optional is in play. In most cases, however, being able to assume that our array is never nil can reduce the amount of checking that we have to perform. This makes our code cleaner and more robust.

What about a function that returns an empty array versus an optional array?

func getVillains() -> [String]? {
    return ["Cersei Lannister", "The Others"]
}

// Unwrapping an array works fine
for villain: String in getVillains()! {
    println(villain)
}

// What if we return nil?
func getVillains() -> [String]? {
    return nil //["Cersei Lannister", "The Others"]
}

// Unwrapping a nil will cause a crash
for villain: String in getVillains()! {
    println(villain)
}

// The correct way to handle the optional array is
// to add a check. This, of course, increases 
// complexity and decreases readability
if let checkedVillains = getVillains() {
    for villain: String in checkedVillains {
        println(villain)
    }
}

 
How would this look if we used an empty array instead?

func getHeroes() -> [String] {
    return ["Tyrion Lannister", "Jon Snow"]
}

// works fine if the array has contents
for hero: String in getHeroes() {
    println(hero)
}

func getHeroes() -> [String] {
    return []//["Tyrion Lannister", "Jon Snow"]
}

// no problems or extra checks required 
// for empty array
for hero: String in getHeroes() {
    println(hero)
}

 
There may be cases where you need to distinguish between a nil and an empty array, requiring the use of an optional. Most of the time, I have found that it just adds extra work.

Share

Exploring Swift’s Generics: Part Deux

Unlike the Mel Brooks movie, History of the World, Part I, the “Exploring Swift’s Generics: Part 1” post will get its sequel. Since I deferred the discussion of protocols, that will be the subject of Part II.

Here is the code that we’ll reuse from the previous example:

class Magic {
    func cast() -> String {
        return ""
    }
}

class BlackMagic: Magic {
    override func cast() -> String {
        return ""
    }
}

class WhiteMagic: Magic {
    override func cast() -> String {
        return ""
    }
}

class Fire: BlackMagic {
    override func cast() -> String {
        return "Fire!"
    }
}

class Ice: BlackMagic {
    override func cast() -> String {
        return "Ice!"
    }
}

class Cure: WhiteMagic {
    override func cast() -> String {
        return "Cure!"
    }
}

class Antidote: WhiteMagic {
    override func cast() -> String {
        return "Antidote!"
    }
}

 
The thing that I found strangest about trying to implement a generic protocol is that you can’t. Protocols use a different syntax altogether. When working with protocols, we’ll use what are called “associated types” to achieve generic-like functionality via the typealias keyword.

Here is how we define the protocol (“mage protocol” sounds pretty awesome, doesn’t it?):

protocol MageProtocol {
    typealias MagicType: Magic

    func castAll(items: [MagicType])
}

 
Notice that we are able to specify a constraint for our type alias, which will come in handy.

Here is one way we could use our protocol to create a mage that only casts black magic:

class BlackMage: MageProtocol {
    typealias MagicType = BlackMagic
    
    func castAll(items: [BlackMagic]) {
        for item in items {
            println(item.cast())
        }
    }
}

BlackMage().castAll([Fire(), Ice()])

 
One shortcoming, in my opinion, of inheriting from a generic class in Swift is that the subclass has to be generic as well. In the case of the protocol, however, there is no need for a generic.

That is not to say that we cannot take advantage of generics:

class Mage<T: Magic> : MageProtocol {
    typealias MagicType = T
    func castAll(items: [T]) {
        for item in items {
            println(item.cast())
        }
    }
}

Mage<WhiteMagic>().castAll([Cure()])

 
Pay attention to the fact that I had to specify a constraint for the generic type that was compatible with the protocol’s type alias.

It seems to me that implementing a protocol with associated types, rather than inheriting from a generic base class, is the cleaner solution (review “Exploring Swift’s Generics: Part 1” for examples of inheriting from a generic class causing weirdness.)

Happy swifting…

Share