• A Little Bit Broken Is Still Broken

    Engineers and product people tend to think about issues as frequency distributions. How many users does this impact? How severe is it? But this misses one inescapable truth from a user’s perspective: a little bit broken is still broken.

    I was staying at a hotel recently that highlights the point.

    The shower worked but would occilate between lukewarm, cold, and burning hot. I could still bathe by hiding from the shower head every 3 seconds. Needless to say, it was frustrating and uncomfortable.

    I could imagine this problem being triaged by a product team.

    “A user is reporting a temperature issue with the shower.”

    “Well, how many users have this problem?”

    “Only one.”

    “How bad is it?”

    “There is a workaround and they can still bathe.”

    “We’ll come back to it.”

    The simple solution to avoiding these kinds of low-fidelity histogram-based prioritization is to use the product. Within 1 minute of actually trying to use it for themselves, this figurative product team would put this issue directly at the top of the list.

    See also:


  • Ephemeral Jump Box Using AWS Session Manager

    Sometimes you need a “jump box” that you can SSH into and get shell-level access to a production environment. That might be for debugging and maintenance or part of a deploy process.

    This comes with a tradeoff. If you are using a private AWS subnet (which you should use for security), you need to open up access for the jump box making it a big target for attackers.

    Ideally, you could get access to a production environment only when access is needed and done as securely as possible. AWS Session Manager has pretty much all the ingredients to do that but we only want to allow connections temporarily on a new server (not an existing server with the Session Manager plugin installed).

    For that we need to combine that with ECS so we can spin up a brand new server, connect to it securely, and then shut it down when we’re done.

    How to create an ephemeral jump box with AWS ECS and Session Manager

    1. Make sure the plugin is installed locally.
    2. Create a new ECS task (a new server) using the same definition as the production instance you want to access (or create a new definition just for bastion boxes)
         aws ecs run-task --cluster {YOUR CLUSTER NAME} --task-definition {YOUR TASK DEFINITION NAME} --count 1 --launch-type FARGATE --enable-execute-command --network-configuration '{"awsvpcConfiguration": {"subnets": [{LIST OF SUBNETS YOU NEED ACCESS TO}], "assignPublicIp": "ENABLED"}}' --overrides '{"containerOverrides": [{"name": "shell", "command": ["sleep", "{TIME IN SECONDS BEFORE SHUTTING DOWN}"]}]}'
      
    3. Grab the task ARN from the output, wait for the task to start running, and connect
         aws ecs wait tasks-running --cluster {YOUR CLUSTER NAME} --task "{TASK ARN}"
         aws ecs execute-command --cluster {YOUR CLUSTER NAME} --task "{TASK ARN}" --command "bash" --interactive 2>/dev/null
      
    4. Stop the task (or wait for it to expire)
         aws ecs stop-task --cluster {YOUR CLUSTER NAME} --task "{TASK ARN}"
      

  • Intent-Based Outcome Specification

    A new paradigm for user interfaces is starting to take shape with the rise of AI powered tools. Rather than a loop of sending a command, receiving the output, and continuing (like graphical user interfaces), an intent-based outcome specification is telling the computer what the outcome should be—“open the door” instead of “check auth, unlock, open latch, extend door”.

    This has many challenges (chatbots lack affordances), especially because many people are not articulate enough to describe what they want. AI can help interpret vague language, but designers will need to develop patterns for refinement (maybe by mashing up other UI paradigms).

    Read AI: First New UI Paradigm in 60 Years.


  • How to Send Email as Someone Else in HubSpot

    Sometimes you want another email to be able to send email as you in HubSpot. For example, having a BDR send follow-up notes to prospects you haven’t heard from in a while, or setting appointments. This isn’t possible out of the box with HubSpot, but if you are using Gmail, there is a workaround.

    However, you should probably just set up a shared inbox in HubSpot!

    1. Add an email delegate in Gmail
    2. Confirm the delegation request from the email
    3. Connect the delegate email to HubSpot HubSpot -> Settings -> Email -> Connect personal email
    4. An alias should now be available to send emails in HubSpot when you click the “From” field
    5. Sending via personal email accounts will prepend the HubSpot user’s name so to change the name to match, go to Profile & Preferences -> Global and change your first name and last name. Log out and then back in so the email name change takes effect

  • When to Write a Brief

    Sometimes you should try to build the thing instead of writing about the thing. While I’m a staunch believer that writing is a super power (especially for remote teams), it can make small problems seem bigger than they actually are. Knowing when to reach for a brief can be difficult to pin down.

    When should you write a brief or just build?

    If it’s obvious and small (days not weeks), skip the brief and build it. You don’t want to make more work for yourself.

    If you have an idea of what to do but are not feeling clear about how important it is, write a short brief. It’s okay to write in order to justify your idea—in fact, writing to convince others can be clarifying (and sometimes convinces you it’s not important after all).

    If you catch yourself thinking of a solution disguised as a problem. Write a brief to get to the bottom of what’s actually going on.

    If it’s a technical problem, taking the first few steps to build it and then write a brief. It might be necessary to try to make a prototype just to know the shape of the problem so you can write about it. Code can be very if you can write software fast and it might turn out to be not that hard at all.

    If you have a vague understanding of a problem, write the intro of a brief to quickly identify what you don’t know.

    (Tips for writing a brief is covered in how to write for remote teams).


  • Taxonomy of Platforms

    Technology platforms exhibit one or more of the following models.

    Platform models and key challenges:

    • API as platform APIs deliver abstract away difficult problems adjacent to the user’s core business such as payments (e.g Stripe) or running on multiple operating systems (e.g. Java). The key challenge of API platforms is change over time—broadening capabilities while abstracting away the messy details.
    • User experience as platform Rich user experiences with novel capabilities and near-universal adoption define the work of entire professions (e.g. Figma). The key challenge is moving users over to new UX over time (who moved my cheese?) and evolving into an API platform (frontend UX and backend implementation tend to be harder to decouple than one thinks).
    • App as platform A product that is so good at solving a critical problem ends up defining how the problem is solved for others.

    …More soon!

    • Data storage as platform
    • Horizontal or Vertical
    • Customization
    • Connectors and integrations
    • App store
    • Marketplaces and networks
    • Open source

    From The Ultimate Guide to Platforms Steven Sinofsky.


  • How to Make Python Functions Extensible

    Let’s say you have a python function that is used widely throughout your code base. You need to make changes to it. You change the arguments and everything breaks. You painstakingly update all call sites and hope that, when the tests pass, it’s all working as expected.

    Is there a better way?

    Consider the function foo.

    def foo(a, b, c):
        pass
    
    foo(1, 2, 3)
    

    If you want to add another argument to foo you might update it like so.

    def foo(a, b, c, d):
        pass
    
    foo(1, 2, 3, 4)
    

    You need to update all of the call sites because d is a required positional argument. That’s not too bad because there are a small number of arguments and it’s easy to update by just adding an argument to the end.

    Now let’s say you need to update foo with argument e which is sometimes None. Oh, and you realized that c can also be None.

    def foo(a, b, c, d, e):
        pass
    
    foo(1, 2, None, 4, None)
    

    Now we have several problems:

    1. Every call site needs to be updated again
    2. The argument list is getting longer, what is argument 3 again?
    3. It’s easy to make a mistake updating calls to foo because ordering matters—python will happily take foo(1, 2, 4, 3, 5)

    Finally, you want to refactor because the argument list is getting long and they aren’t in a logical order causing frequent instances of problem 3.

    def foo(a, b, e, g, c, f, d, h):
        pass
    
    foo(1, 2, None, 7, None, 6, 4, None)
    

    A more extensible way to do this is to use keyword arguments kwargs.

    The ordering of arguments doesn’t matter. If you change the order of arguments in the function, you won’t need to update every call site.

    def foo(a, b, e, g, c, f, d, h):
        pass
    
    foo(e=None, a=1, h=None, g=7, c=None, f=6, b=2, d=4)
    

    Using kwargs with default values can be omitted, perfect for indicating what is actually optional when calling foo. Python will insist that these arguments go last (making it possible to still reach for calling the function with positional args.

    def foo(a, b, d, f, g, c=None, e=None, h=None):
        pass
    
    foo(a=1, b=2, d=4, f=6, g=7)
    

    Extending foo with another optional argument is now super easy—no need to update every call to foo (unless it needs to use the new optional argument). Notice how the example function call hasn’t changed even though we added argument i which also altered the argument ordering.

    def foo(a, b, d, f, g, c=None, e=None, i=None, h=None):
        pass
    
    foo(a=1, b=2, d=4, f=6, g=7)
    

    To take it one step further, you can require keyword arguments so the function can’t be called with positional arguments.

    def foo(*, a, b, d, f, g, c=None, e=None, i=None, h=None):
        pass
    
    # This will throw an error
    foo(1, 2, 4, 6, 7)
    
    # This will not
    foo(a=1, b=2, d=4, f=6, g=7)
    

    Neat!


  • AI Models at the Edge

    Today, most large language models are run by making requests over the network to a provider like OpenAI which has several disadvantages. You have to trust the entire chain of custody (e.g. network stack, the provider, their subprocessors etc.). It can be slow or flakey and therefore impractical for certain operations (e.g. voice inference, large volumes of text). It can also be expensive—providers are charging per API call and experiments can result in a surprising bill (my useless fine-tuned OpenAI model cost $36).

    Open-source tools for running AI models locally (or “at the edge”) are being built to solve that. Utilities like ggml an llama.cpp lets you run models on commodity hardware like your laptop or even a phone. They also have all the advantages of open source AI—pushing the boundary of where these models run and improving it by having increasing access.

    I’m very excited about the interest in AI at the edge because driving the cost to near zero (at least for the folks with the skillset to tinker) and removing the network stack creates will encourage more people to try and build new things.


  • Who You Try to Impress Is Who You Become

    I don’t recall where I heard this, but who you try to impress is who you become so choose who you want to impress wisely.

    Early in life it’s a fairly common experience to do something dumb so someone thinks you’re cool. Later in life you realize that’s a bad deal—why would you let someone else dictate what you do and set you on downward path? Yet, this happens all the time at work, at home, your friend group, your spouse, and so on.

    Be mindful of the influence of who you are trying to impress as it might just change your life!


  • Colleges and Upward Mobility

    Attending college is still a major force in upward mobility for children with parents in the bottom quintile of income to reach the top quintile of income. A recent working paper from NBER looked at the role of colleges in explaining upward mobility outcomes.

    Looking at the top 10 colleges for upward mobility in the US I was surprised to see my alma mater Pace University (which also happens to be one of the only for-profit schools on the list) and SUNY Stonybrook (roughly 20 minutes from where I grew up).


  • Context Ascribes Value

    Context matters in the way that people recognize value. For example, a world-class classical musician performing in the street is unlikely to be recognized for their brilliance compared to performing in Carnegie Hall. When they are on the street, they are a street performer barely noticed by rushing commuters. When they are in a concert hall, they are in the context of classical performers compared to every other classical musician in the world.

    From Obviously Awesome (literature notes).


  • Obviously Awesome (Literature Notes)

    How to do positioning

    1. Make a short list of your best customers
    2. Form a positioning team Must be driven by the leader of the business and the leaders of each business function or it won’t be adopted
    3. Let go of baggage
      • Everyone must be on the same page about what positioning means, each component of positioning, and styles of positioning depending on the market
      • Get agreement that the product was created with a certain market and audience in mind but may no longer be best positioned that way
    4. List true competitive alternatives from the customers' point of view
      • What would your best customers replace you with if you didn’t exist?
      • Aim for 2-5 groups of alternatives
    5. Isolate unique attributes/features that make you different and better than alternatives
      • Focus on provable facts rather than unqualified values like “outstanding customer service” or “ease of use”
      • Concentrate on attributes that customers care about when evaluating whether or not to make a purchase.
    6. From attributes, create value themes
      • Feature -> Benefit -> Value
        • Feature: something your product does or has
        • Benefit: what a feature enables a customer to do
        • Value: how the feature maps to the customers' goal
      • Group into themes from the perspective of a customer
    7. Determine who cares a lot
      • Segment the features and values by best-fit customers by asking who cares and why?
      • A segment needs to be big enough to meet business goals and has important, specific, unmet needs that are common to the segment
    8. Find a market frame of reference that puts your strengths at the center and determine how to position in it
      • A market needs to be something that already exists in the minds of customers and highlights your strengths
      • Abductive: choose a market category by isolating key features/values and asking, “What types of products typically have those features?” and “What category of products typically deliver that value?”
      • Adjacent and growing: look at a market adjacent to where you have been positioning yourself—ones where there are already blurry lines and feature overlap
      • Ask customers: be careful with this, they may have already tried to make sense of you and failed, they will only try to position you in markets linked to their industry and job function
      • Positioning styles
        • Head to head: aim to be the leader in a category that already exists. If there is a leader, beat the leader and convince customers your solution is best. Even better if there is no leader.
          • You don’t have to teach buyers and can rely on what they already know
          • You need to fit within their existing definition if you want to win
        • Big fish, small pond: Win a well-defined segment of the market, serving an underserved segment of the market whose requirements are not met by the current market leader, then expand until you can compete with the established leader
          • It’s much easier to gain traction, be more targeted, and be accretive (each subsequent customer is directly applicable to the next, word of mouth)
          • Subsegment needs to be easily identifiable, it should be easy to make a list of prospective buyers
          • It has to be possible to demonstrate that there is a very specific and important unmet need
          • You can fully solve their specific pain better than the leader
        • Create a new game: create a new market category—prove the new category deserves to exist, define the parameters of the market in customers' minds, position yourself as the leader in it
          • Should only be used when you have evaluated every possible existing market category and conclude you can’t position there
          • Can only work if you are large and powerful enough to get the attention of customers, media, and analysts to make the case for why a new market category deserves to exist
          • New markets emerge from change—new technology, economic changes, politics, preferences, or a combination of those
          • Your product must be inarguably new and different from what exists
          • It often takes a long time to do well, but if successful it can be huge
    9. Layer on a trend (maybe)
      • If the trend doesn’t reinforce your positioning, it can muddy the waters (cool but confusing, lies, good but boring)
      • The trend needs to clearly connect to your product
    10. Capture your positioning and share it across the organization
      • Write a document with enough detail that it can be used by marketing, sales, and product (1-pager, positioning canvas)

      • Positioning Canvas

    11. Create a sales story
      • Define the problem your solution was designed to solve
      • Describe how customers are attempting to solve the problem today and where current solutions fall short
      • In a perfect world, the features of a perfect solution would look like…
      • Introduce the product and position it in the market
      • Talk about each value theme in more depth about how the solution enables value
      • Wrap up by addressing common objections, case study, current customers and next steps
    12. Make a messaging document Write out the messaging that every new campaign or material should be reviewed against
    13. Product roadmap and pricing Adjust the product feature set to align with the market category and get your pricing inline with market how the market expects it to be priced
    14. Check in on positioning every six months or after a major event that could change the competitive landscape (e.g. a new large competitor, regulatory change, attitudes, technology)

  • Make Two Offers

    Making two offers with different tradeoffs sets the framing of the negotiation and reduces the amount of back and forth. For example, making two job offers to the same candidate—one high salary but lower equity and one lower salary but higher equity—and asking them to pick—eliminates a lot of the need to negotiate (which most people don’t like to do). Using this strategy makes it more transparent to the other party how to model the deal and empowers them to decide.

    See also:

    • If negotiation is a coordination problem then making multiple offers at the same time accelerates finding the Schelling point
    • The poverty of compromise
    • Salary negotiations are more balanced between parties (you’ve probably done several and can ask others), you should be skeptical of this strategy in a negotiation with high information asymmetry