|Off the bat with a subtle Nash equilibrium / Magic card reference. This can only be good, right?|
I’ve been thinking about this topic for a while. About building things.
|// Here be Dragons|
|That's how you get Easter Eggs like this I suppose.|
|Ain't easy being Worth.|
|Of course we will.|
Why?Step one. Why? ”Always start with why.”
Why do we want to build this deck? In a larger context, this could be defined as an epic; essentially a large user story that can be broken down to a number of smaller user stories. A user story is one (or a few) sentences written in everyday language that captures the ”who”, ”what”, and ”why” of a project; in this case the deck. It is most commonly defined as ”As a <role>, I want <goal>, so that <benefit>”.
As an Old School Mtg player who enjoys trying different strategies, I want to build a monored Sligh deck, so that I can play it with friends and lend it out during tournaments.
As a Netflix user, I want to be able to resume a program I’ve previously watched, so that I won’t have to search the buffer whenever I return to a program.
As a Vintage player, I want a deck that have a favorable matchup against the most popular decks in the current meta, so that I can win tournaments with it.
|Solid choice two years ago, but doesn't beat Mentors nor Eldrazis today.|
I’ve worked at a lot of projects where employees - certainly including myself - can’t explain exactly what that the product is. Or at the very least, we have different ideas of what it is, and what words mean. We need to find a common language and a common model everybody understands. As a smarter man than myself said, ”The worst bugs, the major technical debt, are mostly modelling errors”.
|It will get worse over time.|
The values objects and entities of a card will be different for different products. If we go to morphling.de to check out Vintage decks, those lists don’t care what edition the cards are from or what their rarity is. If we search for a card at the ChannelFireball store, those cards wouldn't need to store specific rule FAQs for the card (like they do at Gatherer search). And if we play a card in the Duel of the Planeswalkers app, that card doesn’t care about its real life prize tag, but cares a lot about how the card interacts in an actual game of Magic.
Knowing the components we work with will eventually save us time and a help us avoid a myriad of bugs and refactoring. If we neither know why we do something nor what it is that we do, we’re in for a hard time down the road.
|A Sorrow's Path, if you will.|
RequirementsLet’s say we’ve reached a basic idea overview of the who, why, and what. Let’s build that Sligh deck I’ve been thinking about for a couple of months.
As an Old School Mtg player who enjoys trying different strategies, I want to build a monored Sligh deck, so that I can play it with friends and lend it out during tournaments.
That’s our epic user story. This story will then be broken down in smaller tasks with unambiguous requirements.
Software requirements can go deep, easily becoming a faceless set of rules no one at the team really cares about. On the other side of the coin, we might skip the requirements all together, or make them fluffy rants of uselessness that can’t reasonably be verified without bias (”The deck should be good”).
IEEE (Institute of Electrical and Electronics Engineers) define a requirements as
- A condition or capability needed by a user to solve a problem or achieve an objective.
- A condition or capability that must be met or possessed by a system or system component to satisfy a contract, standard, specification, or other formally imposed document.
- A documented representation of a condition or capability as in 1 or 2.
The road trip now has a few feature requirements. Where to stay each night, where to travel, and what the end of the line will look like. This might make you feel less excited about the trip. It would probably be more enjoyable if you had collaborated with the requirements, in particular as you will commit a big part of your time to it. Maybe you know about a great bed and breakfast on the road that your friend didn’t even look up, or maybe you know a lot more about cars than your friend who already booked one. What if you don't care about magnets, and with a small detour you could have caught an unplugged session of Neurosis in addition to the Insane Clown Posse festival.
|Everybody gets pitchforks.|
When we write the requirements, they should be unambiguous, testable and understandable for both technical and non-technical personnel. I think that it's a good idea to use some form of Gherkin syntax when writing requirements. It makes them easy to transform from plain text to testable code; using Cucumber, RBehave or similar tools. With Gherkin syntax, we write our requirements on Given-When-Then form. E.g. ”Given that I’m driving my car at crusing speed; When I press my foot on the break pedal; Then the car should slow down.”
|It’s funny because this is kind of like a car and the banding ability is like collaboration.|
Some requirements regarding the road trip are fairly unnecessary to state. At what time should you eat dinner each day? What color should the seats of the car have? These are either not pertinent to the experience of the trip, or will restrain your agility during it.
Let’s look at the very specific requirements that must be true for most every Magic deck. Things like
Given a constructed Magic deck,
When I count the number of cards in the main deck
Then that number must be at least 60
...and such. If we go deep enough, we see that the requirements could define things like what a Magic card even is (we don’t want to accidentally build a deck with Jack of Clubs or Charizad), or what constructed Magic is (”Hey, in 5-color you have to play like 300 cards!”, no one just screamed). But we are not trying to write Principia Mathematica here, we simply want to write requirements that makes sense to an end user. Testing of the smallest units of truth is done during the feature development part of the process (i.e. unit testing). What we're looking for here is something more like this:
Story: 93/94 Sligh deck
As an Old School Mtg player who enjoys trying different strategies
I want to build a monored Sligh deck
So that I can play it with friends and lend it out during tournaments
Scenario 1: We want to be able to lend the Sligh deck to other players in tournaments if we don't play it ourselves. As such, we want to have zero overlap between this deck and the Project M and Monogreen decks.
Given one player playing the Project M deck
And one player is playing the Monogreen deck
When one player is playing the Sligh deck
Then all decks should be fully constructed without proxies
Scenario 2: We have access to a decent card pool, and should be able to build a solid Sligh deck without spending too much additional money on the project.
Given we need to buy cards to finish the Sligh deck
When we calculate the total cost for acquiring the cards
Then that sum cannot be higher than $100
Hey! Did you actually read that? Is anyone still here? I assume that the two guys still reading are Bjørn-Einar Bjartnes (who shares my unhealthy joy of both software development and building Sligh decks), and Shaman Ben Perry (who could just enjoy the absurd nihilism of writing 26 pages of software development theory on a supposed Magic blog, laughing in the face of reason and clickbaits). You’ll get a deck list in about 2000 words. Also, I guess that Ydwen Efreet is a criminally undervalued card if you want to go do one of those new-fangled buyout thingies (NB: Please don’t buyout Ydwen Efreet).
|Nothing like a picture of a wall of text to alleviate the monotony of a wall of text. Did some syntax highlighting though.|
There are some other requirements we should note as well, called non-functional requirements. These requirements are used to judge the operation of our product, rather than specific behaviors. In software development, this could be the average response time of pressing a like-button at Facebook. The number of people whom could stream Stranger Things on Netflix without the video lagging for more than 1% of them. How frequently your Magic online client will crash. The most critical of the non-functional requirements are often referred to as the Key Performance Indicators (KPI) of the product.
|If you like testing non-functional requirements, some stuff Netflix do is basically nerd porn.|
|This is deploying it to a larger market without load testing it. Obama doesn't approve.|
Off to development“About time to get that mo-fo'ing co-so of a deck. Why not just start here!?1” Because if we start here our twitter feed will become a peanut gallery of angry nerds, and we’ll lose a lot of revenue to Hearthstone due to buggy decks. Or some other analogy.
Your requirements should drive your implementation, not reflect it.
Just like a carpenter wouldn't grab a stack of wood and a hammer and start pounding away to build a chair, we can't just grab an IDE and swordfish away to build a webpage. If the chair were to be stable and fit with the rest of the furnishings, we need to first work out of what the finished product should look like. Write requirements on how to saw up the planks. Having documentation of the product and how to make it doesn't make the carpenter less of a craftsman. Give me and Ed Carpenter (real guy!) the exact same detailed instructions on how to make a chair, and I can assure you that Ed's will look better. Give Patrick Chapin and a random new player at the local FNM the same instructions to build a competitive standard deck, and Chapin will come out on top.
|That is what happens when the brewmaster brew.|
The first step in building a 93/94 deck list may be to make sure that the deck is actually legal in the format.
foreach (card c in slighdeck)
Assert(slighdeck.decksize() >= 60)
...and so on. These kind of tests are called unit tests. Unit tests are the lowest level of testing, verifying the smallest testable parts of the product. It’s written by developers in the same language as the feature code. In an ideal world, most every line of feature code have unit tests.
Starting with an empty deck list, of course all these tests will fail. But we write the tests firsts, and when they start passing we know that we're getting somewhere. Writing test before we start will actually speed up the development process a lot and help us avoid late surprises. The earlier we find the bugs, the cheaper they will be to fix.
|Guess bugs are like Power in that aspect.|
As we want things to fail early, we could implement a few of the feature requirements already here as unit tests. Let’s write unit tests that check our mana curve. No need to wait until playtesting to see if we made mistakes in the theory.
Assert( (slighdeck.NumOfPermanentsWithManaCost(1) >= 8) && (slighdeck.NumOfPermanentsWithManacost(1) <= 13) )
We’ll do the same for all the examples in the feature requirements regarding mana costs and card types. Let’s write a deck list to make those tests green.
|Make it green!|
In deck building, current best practice is to approach the task with four sets of eyes. These are eerily similar to the best practices of creating software products.
I’m a big fan of George Baxter and the other pioneers in deck building theory from the 90s. But I think that the greatest contributor to the subject is Patrick Chapin. In his book Next Level Deckbuilding, he gives far deeper insight to the processes and art of deck building that I could ever hope to do here. In the book, Patrick defines the four paths as this:
- Top-Down. What is there?
- Bottom-Up. What is not there?
- Forward. What’s the gameplan from turn one and forward?
- Backward. How did we get to the winning position?
If we're playing mono-red, we have access to a few powerful cards we can cast more easily than other decks. Ydwen Efreet is deceptively strong, and we will always have the right colored mana to cast Fork or Ball Lightning. Gauntlet of Might could pull a lot of weight here as well.
Bottom-Up. What's not there? What’s useless and inefficient? We might need to playtest to see this well, but we have a few hints already. The two-drops on the curve are sorely lacking. I wish I could play seven Ironclaw Orcs.
|The powercreep these days...|
What’s not there for our opponents? Life gain is lacking in the format. Apart from Mirror Universe and Ivory Tower, dealing damage here is basically the same as getting poison counters in the Modern format. You won't get rid of it. Ivory Tower and the red circle of protection could be an issue, but people don’t play those maindeck, and we should be able to race Mirror Universe. To handle the viable life gain alternatives, we should probably look to Manabarbs and Shatter/Detonate in the sideboard. Pyroclasm isn’t here. In the current meta, few or none play Moat or Wrath of God. This could help make the deck viable.
What else is not here? Looking at our requirements of not taking cards from our other assembled decks, we won’t play Mox Ruby, Black Lotus nor Library of Alexandria. Having a budget of less than $100 in new cards makes us unable to play Gauntlet of Might.
|Might be that Dragon Whelp is a better 4-drop anyway...|
If we have attacked for more than ten damage by turn five, we should have a lot of board presence turn four. Without moxen nor Lotus, everything above three-drops are curiosities. We'll only cast one or two four-drops before we win, so we don’t need many. Turn three we attack with two creatures. Hopefully a one-drop and a two drop. Could be two one-drops and a factory. Turn two we drop a threat or attack with a factory. Could also go for a one-drop creature and a bolt.
Forward: We need a land drop and threat turn one. If our land drop is Mishra’s Factory, it is much preferable to be able to use the mana than to not. Black Vise seems like an obvious include, maybe Brass Man as well? Turn two we attack with the Factory and our one-drop, or even better, play a two-drop. If we don’t have a factory, we need either two-drops or two one-drops to make our mana useful. Making our mana useless is how we lose, our cards are weak in a vacuum and we need tempo to win.
|This might work.|
As Eric Ries put it:
"We spend a lot of time planning. We even make contingency plans for what to do if the main plan goes wrong. But what if the plan goes right, and we still fail? This is the most dreaded kind of failure, because it tricks you into thinking that you’re in control and that you’re succeeding."
|Forethought is 19/20.|
What if the deck is simply not competitive in the local market? What if a majority of the meta is Tax Edge with 4 maindeck Ivory Towers or Power Monolith combo? Then the value of lending it out during tournaments would be very slim as most anyone wouldn't be interested in borrowing it.
What if the deck is utterly unenjoyable for your friends and they don't want to play against it? Like if your play group enjoy casual kitchen table vintage, Duel Decks and such, and this one guy shows up with Draw-Go or Uba Stax. Sligh could possibly hit that point, as its game plan is to win before the opponent gets do do his or her thing. If we make a "perfect" Sligh deck that no-one want to face outside a tournament, we haven't got the value we looked for either.
Focus on value. If we realize that the product doesn't give the value we're looking for, pivot. We could just scrap the Sligh curve and go for midrange. Or maybe just build an Erhnam Burn'em or Dead Guy instead. No need to waste time and money on something that doesn't give us any benefit.
Project M deck back in 2012:
|63-card deck list on an airplane sick bag.|
|Feedback can be painful. Data help us avoid bias.|
|Project M v1.0, January 2013.|
Every new iteration should go quickly from learning to playing. How long does it take between that we realize that we should cut 2 Swamps and 2 Plains for 4 City of Brass to improve the early game, to that we hold that new version of the deck in our hand?
Test and releaseLet's go back to the Sligh deck.
|The MVP for the Sligh deck.|
A mock object is a simulated object that mimic behavior of real objects. It could be a crash test dummy mimicking a human when testing car safety, proxy cards for playtesting, or a preconstructed reply from a function mimicking a data base request. We could test a lot of our functionality before we have everything in place.
What do we not need yet? Physical cards and a real opponent for two. Lets build the deck in an online deck builder to see how well it matches up against the goldfish opponent and how well it mulligans.
|Those lands can't be right...|
Even as a one-drop colorless card, Brass Man seems underwhelming. We rarely have the mana to untap him. Many of our three-drops are also kinda slow; cards like Ball Lightning would better follow our game plan. Atog looks plain bad as well, in particular without the Brass Men.
Whenever we come up with a new idea to improve the deck (or when we've finished writing a few lines of software code) it should quickly become a part of the solution. Making this happen continuously all the way to the finished deck is called continuous delivery. That process aims at building, testing, and releasing software fast and frequently. To make this go safe and painless, we use build automation tools. Continuous integration tools like Jenkins or TeamCity helps us check in our code to a mainline shared by the team multiple times a day, while checking that the new changes didn't break the product too badly (e.g. by running unit tests and integration tests).
We rebuild to this:
|This online deck builder is basically a continuous integration tool. It checks that I have the right amount of cards, that the deck is legal in the format, and can show me the mana curve as well as helping me draw sample hands.|
Now, actually putting together a deck can go fairly fast if we have the structure and architecture in place. If we don't, it can take hours upon hours. Are our cards organized in binders in a way that help us find them quickly? Do we know where that fourth Thoughtseize we're pretty sure that we own could be? Have we spent time or resources on acquiring a solid card pool, or will we have to buy new components to build the deck (or start making proxies for this stage)? Do we have 75 matching sleeves somewhere?
|Is this our data base?|
- Is it scary to make changes to your deck? Are you afraid it won't work? Do you want to spend days testing it manually before trying it out in a tournament? (Lacking automated test coverage)
- If you rebuild the deck and it doesn't work that well anymore, can you quickly return it to the previous build that worked? Have you thrown away your old deck list or traded away the cards? (Version control and rollback plans)
- Is it hard to build decks because you have to move cards from deck to the next all the time, or your decks shares a lot of cards between them? (Dependencies)
- Do you feel comfortable with your sideboard, knowing what to board in and out in most matchups? What could go wrong? (Risk analysis)
|Constructed: Undead Party Crasher|
|Top8 Draft: URb Control|
The less testing we have to do manually here, the faster we can take the deck to production. If we have a team, we ask them to help us out to save time. If we can in some way automate the testing of our requirements, we do that in all cases it makes sense in terms of time and cost. We can reuse those tests every time we tweak our product, so it's an investment that will pay dividends down the road.
As for the Sligh deck, we have something we can use in production now. While it's not "done-done", it delivers the value we were looking for while not having any major bugs or other issues. We'll play this deck with friends, maybe lend it out during tournaments, and see when the benefits of changing the deck further will be worth the cost of doing so. The first step will probably be to replace two Shatters with Detonates and the Digging Teams with Goblin Artisans and Goblins of the Flarg. After that we try to find a second Goblin King. The build-measure-learn loop never stops. We will continuously tweak this deck as long as there's joy in using it.