Categories
Projects

Planning a D&D Session Like Planning a Sprint

When I was new to running D&D games I was often frustrated because I couldn’t get to key moments in the session, the players never did what I wanted, and I often over-prepared material that never saw the light of day unless I forced it on them Clockwork Orange style.

Now that I’m more experienced, those things still happen, except I don’t waste (as much) time preparing stuff that doesn’t get used. I estimate my encounters much like I estimate software, and because I do this I am able to make my sessions very rich and flexible at the same time. Here’s how:

1. Make a list of potential scenes or encounters that could come up in the session

This step is similar to writing stories. We don’t need to get very detailed about it though. At this point keep it high level. Here’s an example using a session where I’m planning for a dragon to attack the city where the players are located. Its their 2nd day there, so I expect them to want to do some town business as well.

Examples:

  • Waking at the Inn
  • Shopping in the marketplace
  • Visiting the potion shop
  • Visiting the mayor’s
  • Altercation with guards
  • Players get arrested
  • Encounter with a pickpocket
  • Dragon attacks the city
  • Players fight the dragon
  • Players run from the dragon

2. Estimate encounter size using story points (fibonacci scale)

The number of points I will give each potential scene is based on the fibonacci scale (1,2,3,5,8,13, …). These number are used in estimating work in software development, because the work is often unpredictable. So we measure them in numbers that are relative to other stories, rather than by absolute values, like number of minutes.

This applies well to scenes in D&D because they are equally unpredictable. The “this should be quick” statement is just as wrong whenever its said while prepping a session.

I don’t want to go too deep into story pointing, so I’ll just give you my scale for reference. Keep in mind that I estimate about 12 points per session:

pointsdescription
1Quick exchange with an NPC. A combat encounter that lasts less than one round. A simple trap or obstacle.
2An exchange that will probably have some back-and-forth. A combat encounter that lasts 1-2 rounds. A trap or obstacle that will require some interaction to pass.
3A lengthy exchange with an NPC or lore drop. A combat encounter that will last a few rounds.
5A long series of social encounters that takes up almost half the session. Like a large party or dinner. A long combat encounter that takes up about half of the session.
8A combat encounter that takes up most of the session. You might have time for 1 or 2 other quick scenes.
13A massive combat encounter that spans multiple sessions.

Remember, these numbers are totally made up, they’re completely relative to me and my game. Your idea of what makes a 1 or 3 might be different and your budget may be totally different. You also have to consider party size and how long your players take on their turns.

Given this scale, I’ll assign points to each scene I previously brainstormed:

  • Waking at the inn – 3 points
    For whatever reason the players are always prone to ordering food, chatting with the staff, tipping insanely high amounts of money, and getting distracted at the inn.
  • Shopping in the marketplace – 3 points
    The players already sent me their shopping lists. But I know if they go here they will gab it up with every shopkeeper and haggle on every purchase.
  • Visiting the potion shop – 2 points
    One player has to follow up about a special potion, so I know they will chat a bit here.
  • Visiting the mayor’s – 5 points
    There are so many people to talk to here it will probably eat up half the session.
  • Altercation with guards – 3 points
    The guards here are really strong compared to the players, so I don’t think this encounter will drag out. Either the players will run or they’ll get shut down and arrested pretty quickly. But you know, never underestimate the players, I guess. They could definitely find a way to drag this out.
  • Players get arrested – 3 points
    Them getting arrested could definitely derail things, but with the dragon coming to attack the city, a chance for escape will be easy to present.
  • Encounter with a pickpocket – 3 points
    The pickpocket is not very tough so the players should stop them pretty easily, or they might succeed on escaping the players.
  • Dragon attacks the city – 1 point
    The description of the dragon appearing and attacking the city does not need to draw out. I might present them with a couple of skill checks here.
  • Players fight the dragon – 8 points
    This dragon is a very important NPC that the players have history with. This should be a meaningful battle that the players remember.
  • Players run from the dragon – 3 points
    As much as I hope they don’t run, you never know. But this could be a fun and interesting set of challenges itself. But unless they fail to escape the dragon this should be easier than fighting it.

3. Prioritize Scenes

“Art is the elimination of the unnecessary.”

– Pablo Picasso

Just like stories on our Jira or Trello board, we should consider which stories are at the top of the stack. We’ll judge them by how likely they are to happen and how important they are to the story.

(For this next step, I don’t really write stuff this on paper and do all this math. I just do a a quick mental calculation to help prioritize what to prepare the most and this is what that process looks like broken down)

Here are the encounters listed by the two dimensions.

In order of priorityIn order of likelihood
1. Dragon attacks the city
2. Players fight the dragon
3. Players run from the dragon
4. Shopping in the marketplace
5. Visiting the potion shop
6. Altercation with guards
7. Players get arrested
8. Visiting the mayor’s
9. Encounter with a pickpocket
10. Waking at the Inn
1. Waking at the Inn
2. Dragon attacks the city
3. Players fight the dragon
4. Shopping in the marketplace
5. Visiting the potion shop
6. Encounter with a pickpocket
7. Altercation with guards
8. Players get arrested
9. Visiting the mayor’s
10. Players run from the dragon

I can now use a simple formula to order the priority of scenes for preparation: (10 - (order of priority)) + (10 - (order of likelihood)) = score , which when applied to above gives us a new list, ordered by highest score first:

Dragon attacks the city (17) – this is the most important thing to plan. Its going to lead to pivotal changes in the campaign and I know its going to happen as long as the players don’t leave the city. The dragon arriving is just a one point story and should happen even if the players will end up fighting it next session.
Players fight the dragon (15) – I expect the players will take on the dragon and defend the city, so I want to prepare a really cool encounter. This is going to be a well-thought out encounter with maps and environmental hazards.
Shopping in the marketplace (12) – I know this is going to happen because the players are very eager to spend some gold, so I may as well make this as interesting and fun as possible.
Visiting the potion shop (10) – One player let me know he’ll do this. It doesn’t need to be a very memorable scene but I should be prepared for it.
Waking at the Inn (9) – I will try to skip this but will prepare NPC names just in case. Everything else will be improvised.
Players run from the dragon (7) – I don’t think this will happen but I should be prepared with some ideas for an interesting encounter if it does happen.
Altercation with guards (7) – going to have some guard stat blocks prepared, but nothing more than that.
Players get arrested (5) – if this really happens I’m just going to improvise. Jail happens, then a wall crumbles when the dragon attacks and they can walk out.
Encounter with pickpocket (5) – I will prepare a name for the NPC and a few details and will improvise the rest. If there is more to do with underground connections I may set this up to be a hook for other things.
Visiting the mayor’s (3) – At this point I really hope the players don’t go here. Its the last thing I want to prepare. They did mention wanting to meet him but I think if I don’t bring it up it won’t happen. I’ll have a list of NPC names prepared and if they come here I will improvise. If I feel like I’m struggling to improv I’ll drop the dragon attack. I really don’t want to waste time prepping this.

4. Break Scenes Down into Smaller Scenes

Just like with user stories in software development, we want to have smaller stories. So at this point I will consider if anything that is 5 points or higher can be broken down into smaller scenes.

The only scene I have that is 5 points or more is the dragon fight, but I do think I can break that down into multiple scenes that could take place across the course of this fight.

Something like

1. Dragon starts sweeping attack of the city – description of the dragons approach and initial attacks
2. Innocent bystander about to be crushed – as the buildings are coming down a player notices a pile of rubble about to fall on a civilian
3. Soldiers huddling in fear – as the players move through the city they discover a company of soldiers hiding in fear
4. Meet the City Mage – If the players end up unsure what to do they encounter one of the mages who points where the guard is forming at attack on the dragon.
5. Dragon fights the players from the air – the players join the guards in their ranged attacks on the dragon
6. The Dragon speaks – once the players hurt the dragon enough to capture its attention, it will parlay for a moment
7. The Final Confrontation – Once the players have the Dragon’s attention, it focuses on them in a final confrontation.
8. The Dragon Flees – Once the dragon is below half its HP it will attempt to escape

Breaking down big encounters into smaller scenes makes them more interesting and helps keep the players attention. Conversely, huge scenes that take up the whole session without changing the beat are what get players looking at their phones while they wait for their turn to come back around. Another way I could break this up is to have the Dragon move across the city, destroying or looking for something in particular, and the players have to move across town to catch up and fight it. That would break up the scenes in a similar way with less planning. But since this is my #1 focus I will take the time to prepare interesting little challenges throughout the battle.

5. Prepare Each Scene

Now that I have prioritized the scenes and broken them down into smaller scenes, I can prepare each scene in the order of highest to lowest priority. I’ll plan rich details and robust maps for the most important scenes, and may just improvise the scenes with lowest priority.

6. Run the Session and Adjust as you Go

Because we are agile we will reassess and readjust as we go. So imagine the tavern encounter does blow up and takes up half the session. I would consider dropping the dragon scene into the middle of what they’re doing. Since I’ve estimated my prepared encounters, I know which I can bring in for the remainder of the session.

For example, it’s possible the marketplace encounter ends up taking half the session and everyone ends up having such a great time that I no longer have room for an 8 point dragon encounter. That’d take too long. So with about 1/3 of the session left I can pull in the pickpocket encounter and the guard encounter, leaving the 1 point dragon appearance as the final scene, and we end on a cliffhanger. That sounds awesome too.

Either way, by preparing the session in this way I feel ready for the players to turn the session any way they want while making the content detailed and well thought-out. I avoided a lot of wasted time by not over-prepping the tavern, pickpocket, or guard scenes.

Categories
Projects

Function Calling Example with OpenAi Chat Completions API


I’m working on some stuff using function calling with the chat completions API from OpenAI, so I thought I would write a quick example of how to do this, for anyone who needs the help. Personally I haven’t found a lot of examples online of how to do this, so I imagine this simple example might be helpful to some.

I may expand on this with more detailed instructions later but I’m just providing this basic example in python for now.

import openai

# the 'prompt' for the chat completions API is a list of messages
chat_completions_prompt = [
  {'role': 'ai', 'message': 'what foods do you like/dislike?'},
  {'role': 'user', 'message': 'My favorite foods are apples, bananas, and carrots, but I don't like fish'}
]

# define the response data structure using jsonschema 
# https://json-schema.org/
user_preferences_function_json_schema = {
  "type": "object",
  "properties": {
    "likes": {"type": "array", "items": {"type": "string"}}
    "dislikes": {"type": "array", "items": {"type": "string"}}
  },
  "required": ["likes", "dislikes"]
}

# this is how you define a function to send to the API
get_user_preferences_open_ai_api_function = {
  name: 'get_user_preferences',
  description: 'organize user preferences into the correct categories',
  parameters: user_preferences_function_json_schema
}

# here is the actual completions call
# https://platform.openai.com/docs/api-reference/completions for reference
chat_completion = openai.ChatCompletion.create(
    model='gpt-3.5-turbo-0613',
    temperature=0,
    messages=chat_completions_prompt,
    functions=[get_user_preferences_open_ai_api_function],
    function_call={'name': 'get_user_preferences'}, # this can be 'none' or 'auto' but passing this object will ensure the function is called every time
)

# unless specified by the 'n' property in the api call, you'll only get one choice in the response
# the arguments property of function_call should be a data structure as defined in the json schema you provided
user_preferences = completion_response["choices"][0]["message"]["function_call"]["arguments"] 

print(user_preferences)

# expected output:
#
# {
#   "likes": ["apples", "bananas", "carrots"],
#   "dislikes": ["fish"]
# }
#
Categories
Projects

Code Smells To Be Aware of In Code Reviews

“Code smells” are what you detect when you have a “WTF” moment as you review code. Early in your software development career, you may get a negative feeling, like a “Spidey Sense,” that something in the code is wrong, but you might not be able to articulate the exact problem. Most of these problems can be described as “code smells.” If you are aware of common code smells, it can give you a good idea of what’s wrong and what to change.

Rigidity: Code that is difficult to change because it is too tightly coupled.

Causes:

  • Inappropriate use of inheritance or subclassing
  • Overuse of global variables
  • Over-reliance on low-level details
  • Tight coupling between modules or classes

Remedies:

  • Use interfaces to decouple components
  • Refactor code to use composition instead of inheritance
  • Use dependency injection to reduce coupling between modules
  • Use design patterns like the Observer or Strategy patterns to reduce tight coupling

Needless Complexity: Code that is overly complicated and difficult to understand.

Causes:

  • Over-engineering or over-architecting
  • Lack of clarity in the code
  • Complex conditional statements
  • Long methods or classes

Remedies:

  • Simplify the code by removing unnecessary features
  • Break up long methods into smaller, more manageable ones
  • Simplify complex conditional statements using boolean algebra or the Strategy pattern
  • Use meaningful variable and method names to improve code clarity

Duplicated Code: Code that is repeated multiple times within the same codebase.

Causes:

  • Lack of code reuse
  • Copy-pasting code
  • Insufficient refactoring

Remedies:

  • Use inheritance, composition, or interfaces to promote code reuse
  • Extract common functionality into separate methods or classes
  • Use a code refactoring tool to identify and eliminate duplicate code
  • Use code templates or snippets to avoid copy-pasting

Fragility: A codebase that is overly sensitive to changes in other parts of the system, leading to bugs and unintended consequences.

Causes:

  • Tight coupling between different parts of the system
  • Violation of the Open-Closed Principle
  • Inadequate encapsulation

Remedies:

  • Use interfaces to promote loose coupling and reduce dependencies
  • Use dependency injection to promote modularity and reduce coupling
  • Use design patterns like the Observer or Mediator patterns to decouple different parts of the system
  • Use automated tests to catch regressions and ensure that changes don’t introduce new bugs

By addressing fragility in a codebase, developers can make it more robust and easier to work with, even as the system evolves and changes over time.

Shotgun Surgery: Changes to one part of the codebase that require changes to multiple other parts.

Causes:

  • Tight coupling between different modules or classes
  • Insufficient modularity or abstraction
  • Lack of clear separation of concerns

Remedies:

  • Use interfaces or dependency injection to reduce coupling
  • Use design patterns like the Observer or Mediator patterns to reduce tight coupling
  • Refactor the codebase to promote modularity and abstraction
  • Use the Single Responsibility Principle to ensure clear separation of concerns

Feature Envy: A class that uses methods or data of another class more than its own.

Causes:

  • Insufficient encapsulation
  • Inappropriate use of inheritance or subclassing
  • Tight coupling between different classes or modules

Remedies:

  • Refactor the code to promote encapsulation and reduce coupling
  • Use interfaces to decouple components
  • Use composition instead of inheritance where appropriate
  • Use the Law of Demeter to ensure that classes only use methods and data of objects they directly depend on

Large Class: A class that has become too large and difficult to understand or maintain.

Causes:

  • Violation of the Single Responsibility Principle
  • Inadequate encapsulation
  • Insufficient modularity

Remedies:

  • Break up the class into smaller, more manageable classes
  • Use composition instead of inheritance to promote modularity
  • Use interfaces to promote encapsulation and reduce coupling
  • Use design patterns like the Facade or Adapter patterns to simplify complex interactions

Long Method: A method that has become too long and difficult to understand or maintain.

Causes:

  • Inadequate encapsulation
  • Violation of the Single Responsibility Principle
  • Insufficient modularity

Remedies:

  • Break up the method into smaller, more manageable methods
  • Use interfaces to promote encapsulation and reduce coupling
  • Use composition instead of inheritance to promote modularity
  • Use design patterns like the Template Method pattern to promote code reuse

Data Clumps: Multiple data items that are frequently used together, but not grouped into a single object.

Causes:

  • Insufficient modularity
  • Lack of abstraction
  • Poor design

Remedies:

  • Group related data items into a single object
  • Use design patterns like the Composite or Visitor patterns to promote modularity and abstraction
  • Use composition instead of inheritance to promote code reuse and modularity

Primitive Obsession: Overuse of primitive types (like strings or integers) instead of creating custom objects to represent concepts.

Causes:

  • Insufficient abstraction
  • Lack of clarity in the code
  • Poor design

Remedies:

  • Create custom objects to represent concepts instead of using primitive types
  • Use interfaces to promote modularity and abstraction
  • Use design patterns like the Builder or Factory patterns to create custom objects
  • Use meaningful variable and method names to improve code clarity

Switch Statements: Overuse of switch statements, which can make code difficult to understand and maintain.

Causes:

  • Poor design
  • Insufficient modularity
  • Lack of abstraction

Remedies:

  • Use polymorphism instead of switch statements to promote modularity and abstraction
  • Use design patterns like the Strategy or State patterns to avoid switch statements
  • Use meaningful variable and method names to improve code clarity
Categories
Projects

How to prevent Material-UI Console Errors for DataGridPro License in Unit Tests

If you use DataGridPro (formerly known as XGrid) from material-ui, you need to have a license key. If you don’t provide it at the time the component renders, it will render a watermark and log errors in your console.

When unit testing this component with Jest, since I’m not validating an actual license key, my tests became polluted with a ton of console errors. I found the best approach was to mock the licensing library in @mui.

Here’s how to mock the libraries to suppress those errors in. your unit tests:

Create the mock file here:

/__mocks__/@mui/x-license-pro.js

You only need to mock the following functions (this is the entire file contents)

export function useLicenseVerifier() {
    return 'Valid';
}
export function Watermark() {
    return null;
}

Note: at the time of writing I’m using the following package versions

"jest": "^26.6.3",
"@mui/x-data-grid-pro": "^5.17.6",
"@mui/x-license-pro": "^5.17.0",
Categories
Projects

Merging Material UI and styled-component themes and their types with TypeScript

Recently I ran into a problem with Material UI, styled-components, and TypeScript that I had a lot of trouble solving. Now that I have a working solution, I think its right to share what I did in case someone else runs into this problem.

The Scenario:

This is probably an uncommon scenario but probably not unique:

  1. The app is built mainly with React and Next.js, with most of the UI relying on Material UI (v4).
  2. We are using styled-components as a CSS-in-JS solution. I like this because it lets me use “real” css which I strongly prefer to the emotion style/style object syntax. Also, many of the components were built with styled-components before we adopted material UI, so it would be some effort to refactor that out.
  3. Since we introduced Material UI, we have been passing a single, unified theme object to both the styled-components theme provider and the material ui theme provider, which both wrap the entire app. This is done by passing the output of createTheme from material ui to both as the theme prop. This works quite nicely because it lets us use stuff like theme.breakpoints.down('md')
    in our styled-components CSS.
  4. We have just introduced TypeScript. This is where things get challenging.

The Problem

Once we started converting files to TypeScript (and forgive me if anything comes across as ignorant here because I’m pretty new to TypeScript and strongly typed languages in general), we had to create a declaration for the DefaultTheme in styled-components. Since we are using the theme provided by createTheme from Material UI in our styled-components app, the situation is pretty messy. The type Theme from material-ui is not compatible with the type DefaultTheme from styled components.

The Solution

Ultimately, here’s how I fixed it.

1. Declare the styled-components DefaultTheme with my own types, filling in the missing types from material ui ThemeOptions to fill in missing values

// types/styled-components.d.ts

declare module 'styled-components' {
    export interface DefaultTheme {
        palette: palette;
        overrides: overrides;
        componentVariables: componentVariables;
        breakpoints: breakpoints;
        typography: typography;
        spacing: ThemeOptions['spacing']; // this comes from Mui
        props: ThemeOptions['props']; // this comes from Mui
        mobileToDesktopBreakpoint: number;
    }
}

(each of the properties in the DefaultTheme interface references a uniquely defined type but I left them out of the example for brevity)

2. Create two themes, one for MUI and one for SC from the same ThemeOptions root object

For the styled-components theme I cherry-picked properties from the Theme object from createTheme. It looks like this:

// theme.ts

const themeOptions = {
/** 
    this is where all the definitions for our theme go, such as custom palette colors, componentOverrides, etc 
**/
}

const muiThemeOptions: ThemeOptions = {
  ...(themeOptions as ThemeOptions),
  spacing: 8,
};

const muiTheme = createTheme(muiThemeOptions);

const scTheme: DefaultTheme = {
  ...(themeOptions as DefaultTheme), // spread the props from themeOptions
  breakpoints: muiTheme.breakpoints, // add the properties from createTheme
  spacing: muiTheme.spacing, 
};

export {muiTheme, scTheme};
// _app.tsx

import {ThemeProvider as StyledComponentsThemeProvider} from 'styled-components';
import {ThemeProvider as MuiThemeProvider} from '@material-ui/core';
import {muiTheme, scTheme} from 'styles/theme/theme';

function App({Component}) {
    return (
    <MuiThemeProvider theme={muiTheme}>                   
        <StyledComponentsThemeProvider theme={scTheme}>
            <Component {...pageProps} />
        </StyledComponentsThemeProvider>
    </MuiThemeProvider> 
    );
}

3. Now we can use the mui theme values in our styled components

// SomeComponent.tsx

const StyledElement = styled.div`
    ${({theme}) => theme.breakpoints.down('md')} {
        left: -200px;
    }
`;

This solution came after some frustration around TypeScript telling me that I can’t use the Theme type as the DefaultTheme type that was expected to be passed to the styled-components theme provider. Since we had already merged themes before we were using TypeScript, in which case this was not an issue at all, my options were to figure out a way to merge the type definitions or refactor out all our uses of the MuiTheme properties in our styled-components. Our team finds it pretty useful to be able to use functions like theme.breakpoints.down() and theme.spacing() in our styled components, so this is definitely the solution we prefer for now.

Did this help you? Am I missing something or making a mistake in my understanding of types and TypeScript? Any other feedback? Let me know in the comments.

Categories
Projects

Nothing ever works and nobody ever does anything

These are actually two totally unrelated ideas, but I thought it would be nice to wrap up all my pessimism in a single post. Why do I think nothing ever works and nobody ever does anything? Because I’m right!

Find out here:

Post: Nothing ever works

Post: Nobody ever does anything

Categories
Projects

Nobody ever does anything

You might have noticed in your life that most people talk about their goals, wishes, and aspirations, but hardly any of them do anything about them. That’s because nobody ever does anything. It sounds ridiculous, but it’s true. If you were to survey 100 of your friends, 99 of them are not doing anything to further their goals. 99 of them are not starting the business or book or extra degree they constantly say they want.

Whats the takeaway here? Well the good thing is that its hardly any effort at all to do better than 99 percent of people. All you have to do is literally anything.

What should you do to further your goals? Literally anything. Pick up a book. Take an online tutorial. Write some code. Put a pen to a blank piece of paper. Then, when you’re done, you’ll have the satisfaction that you did what most people don’t: anything at all.

I truly believe that a little bit of effort sprinkled consistently over time, with a bit of passion mixed in is the recipe for success at anything you want to do. The reason most people don’t do this is because, like I said, nobody ever does anything.

Categories
Projects

Nothing ever works

This is also known as “Nick’s Law” (especially when I’m the one working on the code) and it’s a good thing to remember in software engineering. It’s kind of like Murphy’s law, but to a greater extreme.

You ever go up to a vending machine and try to buy a bottle of water, but the credit card reader doesn’t work? Of course it doesn’t. Nothing ever works. Or at least, at some point, whatever is working now will stop working. You have a printer at home? Does it ever work? Does it always work? If so, you’re lucky or just a stinking liar.

I hope its obvious that I’m being cheeky here. Most things work as we expect them to most of the time. Maybe a better law is “nothing always works as you expect” and I think you will definitely agree with that (oh crap, I think that’s just Murphy’s law. Oh well I’m still taking it).

So what’s the takeaway here? You guessed it. Defensive programming. Or even better, as Google likes to say, “programming over time” vs just “programming” (according to the authors of Software Engineering at Google). In that book they discuss Hyrums’ law, which says at some point every observable part of your API will be depended on by someone. If you combine these two ideas, you’ll see that

  1. Every part of your application will be depended on by someone
  2. Every part of your application will fail at some point

How do you prevent this? You can’t. Software is hard. Stuff breaks. But hopefully this shows you the importance of writing code that is easy to understand and maintain. Because at some point, someone will depend on it, and at some point, it will break.

Categories
Software Engineering

If you wanna be a great musician, you gotta know how to play with the band.

This is a software engineering analogy. Even if you can play the best guitar solos in the world, you’re pretty useless as a musician if you can’t perform with the rest of the band.

Great software engineers are great collaborators

This mentality sometimes comes as a shock to new engineers. People often sign up for this career path because they imagine its 99% technical and 1% collaborative, but in my experience that’s not even close to correct.

I once worked on a team where it was about 80/20. Everyone would show up and contribute in meetings, then retreat to their silos to work independently. The effect? Well for one, there were a lot of code conflicts. There was a lot of siloed knowledge. We spent a lot of time fixing bugs. I think the worst effect, and ultimately the main reason I left the team, there was no growth.

I think the really effective engineers are collaborating least at 50% of the time. That means contributing in meetings (not just attending), pairing or mobbing on features with other engineers, contributing to code reviews, and participating in design/modeling discussions. This also has the nice side effect of every team member continually improving their technical skills.

When it comes to software teams, there aren’t a lot of solo gigs. In software there are just too many pieces and too much complexity for an individual to be successful on their own. So you have to be able to play with the band.

A tale of three musical acts

Imagine three bands. The first band has five gifted musicians. Each one is an amazing soloist. But each one also thinks they carry the band. Never meeting to practice, they only communicate over text. Each band member does practice diligently on their own, but occasionally works on the wrong songs because of text message miscommunications.

Band two has four decent musicians and one prodigy guitarist. The prodigy doesn’t listen to anyone else in the band and constantly threatens to leave the band if their demands aren’t met. They are derisive to ideas from band-mates and often don’t show up to scheduled events. When they get paid the prodigy also demands a higher cut than the other members.

The third and final band is five decent musicians who really get along. None of them are prodigies but they all work hard on their craft. They all care immensely for the band and each other. They don’t have any contempt for band-mates with inferior skills and are forgiving of mistakes. They meet and practice together every day. They really enjoy trying out each others ideas and are honest and open about problems with their music or output. Sometimes they trade instruments for certain songs and are all happy sharing the spotlight.

Now, I’m not going to ask you which band you would rather listen to. Because if you’re a software engineer, you’re not the audience here. The question for you is which band would you rather play with? I hope the answer is as obvious to everyone else as it is to me.

Concession to brilliance

If you really are a prodigy, and you’re that good, then I have to concede there are places for you in the engineering world (not where I want to work) where you get to live the soloist life. Some people thrive in that environment. But in my 8+ years working in software, I’ve only met people who think they are that good. They will usually let you know. The true unicorn rockstar engineers I have worked with all know how to collaborate, trust, and work with other people.

Categories
Projects

Want to be a great software engineer? Build great engineering habits.

After doing a hackathon-style project recently, I recognized that our small innovation team was lead by their good habits. We could have built our project out of “throwaway code” and its possible that by doing so, we could have had a more interesting project completed. But in doing so, we wouldn’t have created any value for any user, we would only be left with a pile of tech-debt.

“It’s easier to do the right thing 100% of the time than 98% of the time.

Jonathan Spier, CEO of Rev

This quote rings especially true when writing software. If your default is to write code as a stream-of-consciousness without first taking a step back and building a sound mental-model, if you avoid testing, and never bother to refactor rot from your code, guess what kind of code you’ll be writing. That’s right, a rotten, untested, unintelligible code base that you can only be sure works on your machine right now.

So don’t let that be your habit. Start building good habits now, and do these things every time you write code. Even for your hackathon projects, even for your random ideas that might not live for another day. Make that your default, and you’ll always be writing good code. And when its time to fold your hackathon project into production, it will be production ready code.

Here are some of the good habits I recommend building into your process:

1. Create a model of your code before your write it

A useful model can be manifested in many ways. For some its a UML diagram, for others, it’s a mind map or work-flow. It could be sharpee on a napkin. Some people are great at building mental models and keeping it in their head (I’m not, so that doesn’t work for me, but it might work for you).

Whatever your method, these are the criteria for a good software model.

  • it can easily be understood by any other engineer on the project
  • it expresses a solution to a real business problem, in language that is used by non-technical people in the business
  • it leaves out implementation details, such as database technologies or specific libraries

2. Collaborate early and often

This is really important. The best way to do this is to pair on the start. Robert C. Martin, in his description of XP (extreme programming) says that you should pair 100% of the time and in an iteration, every engineer should have paired with every other engineer (Agile Software Development, Principles, Patterns, and Practices). On paper, pairing sounds like it would halve your output, but it practice, it will more than double it.

But since none of you are really going to dedicate yourself to pairing, you can at least collaborate as often as you can throughout the project. That means when you have created your model, share it with the team and get their feedback. When you have a good idea for how you will implement your feature, describe it in slack and get feedback.

Once you have a few commits, create your PR and start asking for feedback. You will always find something you can improve when you have more than one person looking at the code. It also forces you to write code that other people can understand. As a rule of thumb, I like to assume I am always wrong about my assumptions, always making a mistake somewhere, and am eager to let others on my team help me discover those issues. Its through this collaborative process that we write the best code of our lives.

3. Use test-driven-design

Everyone loves this idea on paper but almost every engineer I’ve ever worked with, even very experienced ones, want to dive right into implementation without considering tests, whatsoever.

The benefits of TDD are numerous and well documented. I’m not going to dive down that well in this article, but I can say that in-practice, following TDD will save you time and effort, and you’ll feel better about the code you’re writing as you write it.

This is a habit that is very hard to create. But I strongly encourage you, especially if you are early in your career, to start now. Every time you write a new piece of code, start by writing a test. Ask yourself some questions about what should the code do? How do you know it’s working?

Doing this as a habit means all the code you will ever write is testable, tested, and well thought-out before it was written. And you won’t find yourself scrambling to write tests at the end of a project, which literally everyone hates doing.

Other Habits?

What I’ve described are the general habits I think are most important for any software engineer. What are some other great habits to build into your routine? What are some bad habits to avoid? Let me know in the comments.

Categories
Projects

The “Reverse King Stahlman Method” in Writing Software

If you are from Southern California you’re likely familiar with the slogan from King Stahlman’s Bail Bonds:

“Better have me and not need me, than need me and not have me “

– Any book of matches

This phrase has many applications in life, but its very important not to use it when writing software. In fact, its better to not have anything in your code you don’t need right now.

I’m sorry to make you throw away your beautiful code, but until its serving a purpose, its vestigial. You should always use the reverse King Stahlman method:

“Better to need me and not have me, than have me and not need me”.

Writing code that isn’t useful today will lead to the following problems, even if you’re pretty sure the code will be needed:

  • Rigidity – Your code is now more difficult to refactor and less portable because there are additional methods or logic you need to continue to support (can’t let those unit tests fail!)
  • More test time – If you’re writing code you should be writing tests. Now you have to write tests for code that currently has no value. Those tests also take precious time on every build/deploy/etc.
  • Confusing code – The less stuff you have in your code, the easier it is to read and understand. For this reason alone you should remove anything in your code that isn’t being used. Also, when you have functions that are never called, its difficult to understand their purpose.

Reverse King Stahlman’s Exception

You can’t be dogmatic about any rules in writing software. JLAM (just like anything, man). So, you know, there are going to be some times when its okay to write some piece of code that is going to get used in the epic or series of stories you’re currently working on. There might be cases where adding something now can save you hours of work down the road. In those cases you can safely ignore the Reverse King Stahlman Method.

Categories
Team Activities

Engineering Team Activity: Starred Repos

The purpose of this activity is to encourage the team to look at code, think critically about code and project structure, and explore the development community.

Each team member will present a repository they think is excellent after some time spent exploring repositories.

After the team completes their research, they will discuss each of the repos they chose and explain why they chose them. Everyone may have different criteria for how they determine the quality of a project.

Categories
Projects

Recruiting tips from the perspective of a software engineer

As a software engineer who really loves his job, I puzzled over the question “what would it really take to get me to do an interview?” The answer is probably not going to be well received by most recruiters, but here’s the truth.

I receive a large volume of recruitment messages via LinkedIn and email. Very few of them are good, most leave me shaking my head, and some are very annoying and frustrating. Based on my observations and what I know about myself, here are the things I think most recruiters could do better, in order from easiest to hardest to implement.

1. Understand what you’re asking of me

For this one, you don’t have to do anything. I just want you to have some empathy here. Please understand that technical interviews really suck.

The experience is rarely good. You get grilled on all kinds of trivia, you have to craft something and solve problems under a time limit with multiple people judging. Then, if you fail, you rarely get feedback or direction to succeed in the future.

Interviews take up a lot of time. In addition to the lengthy in-person portion, and any take-home component, we also have to spend hours studying and preparing. We get quizzed on all kinds of stuff that doesn’t come up day-to-day, so we have to be prepared for a spectrum of computer science trivia. It’s basically the equivalent of college exams.

Interviewing can put my job in jeopardy. It’s generally not in one’s best interests to be perfectly honest about taking time off to interview, so we have to be secretive about it. That means by asking me to interview, you’re asking me in some level to betray my employer.

I know that recruiting is often no picnic, so please don’t take this as a pity-party for software engineers. But I do want to make it clear that for us, this part of the process is horrendous, and you’re asking quite a bit of us to go through with an interview.

2. Keep it brief

I’m 100% going to ignore a paragraph of text about your company. I don’t care how much they’ve raised in the last year. I don’t care how “exciting” the position is according to you. Just tell me a couple of things that set you apart. Does the business have a crazy idea that no one has ever heard of? Are they offering a crazy salary range that could change my life? Is there some other awesome detail that is going to get me to take time from the job I love? What is the real value in the position that sets it apart and is enough to get me to go through the horrendous interview process and consider leaving the team I love? You can see how it’s a big ask.

3. Make it personal

Every one of the recruiters I’ve responded to in the last few years has made a silly, cute, or personal introduction. I would never expect this to work, but it does for me. I think I really just want to be interacted with like a human. When it’s obvious that you are copy/pasting or advertising the same exact message to me and a bunch of other candidates, I won’t consider it at all. My brain just says “skiiiiip” and I delete the message. The best way to get me to respond is by trying to start a real conversation. I suggest you try writing a unique message for each candidate or at least make your template seem like its a unique message you actually wrote for me.

3. Actually vet my skills

Another red flag that will cause an immediate eye-roll and “no thanks” from me is mentioning skills I don’t have. This is from a LinkedIn message I received recently:

As an engineer with extensive full stack experience, particularly with Javascript, Angular, Nodejs, and Graphql, you would be a great addition to our team. 

I have never worked with Angular. This is a message I will just ignore, it’s just spam at this point. I feel like if you can’t be bothered to check my skills on my LinkedIn profile before messaging me, you didn’t actually consider me for the position.

This kind of lazy demographic marketing is why I think the next item is the only way to recruit happily employed software engineers.

4. Offer an incentive to do the interview

This one is hard, I know, but so is everything you’re asking a happily-employed engineer.

Because interviews suck so much, I think you should to offer some kind of incentive to interview. It would still be a pretty hard sell, but I think if a company were to offer some compensation for my time, I would be more likely to take a call with them. Here are some of the incentives you could consider offering:

  • A donation to a charity of the candidate’s choice
  • Some kind of gift
  • Invitation to some kind of event
  • Enter a drawing
  • Make it a paid consultation

Disclaimer: I don’t know anything about recruiting

I’m telling you this based on my opinion and experience as a software engineer. I really don’t know what the day-to-day challenges for a recruiter look like. My ideas haven’t been tested for response rates and I’m not citing any data. Regardless, I hope you understand that this information is intended to help and give you some insight into the developer thought process. I’m happy to hear your thoughts in the comments.

Categories
Projects

Hi, welcome to my blog.

If you’re reading this, it’s probably because you know me personally, or you started clicking around after reading something that I shared, I guess. In either case, hi! I’m glad to see you here.

Categories
Projects

Misc. Design & Marketing Work

The following are a mixture of classwork and personal projects:

Categories
Projects

Jewelry Marketing Pieces

These are some of my various pieces of design work and product photography from when I was designing for South Sun Products.

Categories
Projects

Portrait and Event Photography

Samaria Daniel, my former photography partner, still shoots actively and maintains a photography business part-time. She has been featured by NBC for her nightlife photography and is a very talented visual artist. You can get a look at what she’s doing at her blog.

Some of My Photos: