• Delegation Not Abdication

    A common mistake for early managers is to delegate work ineffectively. They try to do what they think their direct reports would want—assign a task and be completely hands-off. It’s the right instinct but seldom yields the right results. Problems occur when mistaking abdication for delegation.

    Delegation is ensuring the person has what they need to accomplish the task and setting expectations about what needs to be done. If the person doesn’t have the ability or resources to do the work then it won’t get done and you’ve failed to delegate. If the person doesn’t know what needs to be done or you don’t check to make sure it is done well, you’ve failed to delegate.

    As a manager, you are responsible for results. If your reports fail, you’ve failed. You need to successfully enable people to do work, check it, and make sure what comes out is of high quality.

    Delegation is an active process. Abdication is a passive process.

    See also:


    Published

  • Squash Migrations Using Alembic and Postgres

    Over time, a Python project accumulates many migrations using alembic. This can slow down tests (you need to run all migrations every time you create a test DB) and it’s very unlikely you will ever rollback past a certain point in time.

    There’s no straightforward way of squashing migrations into one that I could find in alembic. I found that I couldn’t use the trick of running alembic revision --autogenerate because we don’t use ORM models to represent the entire schema. Instead, the combination of pg_dump and alembic stamp gives a similar result that allows us to squash everything into one migration.

    Get the schema of DB as SQL

    First we need to get the schema as a set of SQL statements using pg_dump. This needs to be done on the database that matches the actual schema in production (or maybe run it on production). Unless you are meticulous about using DB migrations, there might be some drift between the schema in your local database and what’s actually in production.

    pg_dump -s --user {your app user} {name of db} > squash.sql
    

    Verify and clean up

    For my purposes, I removed the auto-generated SET statements, removed the auto-generated ownership statements (otherwise test DBs run using a different user would fail), and tried loading it in a clean DB to see if the tables match.

    Create a migration and wrap the generated SQL statements

    Generate a new migration that runs the generated pg_dump SQL.

    The migration should look something like this:

    # revision identifiers, used by Alembic.
    revision = "123456789"
    down_revision = None
    branch_labels = None
    depends_on = None
    
    
    def upgrade():
        with open(f"{PROJECT_ROOT_DIR}/alembic/versions/squash.sql", "r") as f:
            for stmt in f.read().split(";\n"):
                if not stmt:
                    continue
                op.execute(stmt)
    

    Delete all previous migrations

    You can now delete all of the old migrations and try out the new squashed migration to see that it takes a clean DB and produces the expected schema using alembic upgrade head.

    Note: check very closely that the squashed migration actually gets your DB into the shape you want. For me, I needed to add some extra calls to pre-populate some data that were snuck in from previous migrations using handwritten INSERT statements.

    Skip the migration in production

    [WIP I haven’t verified this yet!] You don’t want to run the squashed migration in production. To skip it, run alembic stamp head which will mark the latest migration as the lastest version. New migrations can be applied on top safely using the usual alembic revision commands.


    Published

  • How to Ramp Up a Software Engineer

    To get a new software engineer up to speed quickly, several things must already be in place. An assigned buddy who can be the first point of contact for questions or issues that arise. A manager with a written ramp up plan for the new employee with clear guidance on performance expectations. A self-serve development environment with clear documentation for getting your code base running locally.

    An assigned buddy helps to make the first few weeks of getting started easier. They will set up time with the new hire on their first day to point them in the right direction. They can help troubleshoot issues the new hire may encounter. They will assign small tasks to get exposure to the code base. They’re also a friendly face that they don’t have to feel bad about asking questions.

    Giving explicit permission that it’s is okay to ask questions and take the buddy’s time is very important. When you are new, defaulting to “I don’t want to bother people” is common, but is a detriment to getting up to speed. Remote teams in particular, need to be more deliberate about everything.

    The manager of the new engineer is responsible for making sure the new hire understands what is expected of them. The simplest way to do that is to share a 30/60/90 plan and review it at the first one-on-one meeting. The first 30 days should be about solving small tasks that have already been flagged from the backlog which are self-contained and less than a day of work for a fully ramped engineer. At 60 days, they should start working on a medium size project that is has already been scoped out (i.e. there is a reasonable level of technical details worked out so that such that it looks like a list of small tasks). For career level engineers, at 90 days, it’s time to lead a project that they scope out and deliver with one or two other engineers.

    The plan gives the manager and new hire something to check in on regularly to make sure expectations are being met. If expectations are not being met according the timeline, share feedback and make an adjustment. If the new hire is repeatedly not meeting expectations it’s time to part ways.

    A common mistake is to move on to working on projects too early. Shipping small things (1 small thing per day) builds familiarity with the code base and problem domain. Getting things done is the foundation of just about everything and it is much more difficult to assess how it’s going when they start working on larger, more complicated projects.

    It’s likely that your systems and working environment will cause an otherwise successful engineer to fail. Parting ways early if it isn’t working out is best for both parties—you need engineers to hit the ground running and they deserve to work at a place that maximizes their ability to do great work.

    A self-serve development environment should be in place so that a new engineer can ship to production on the first day. For example, running a single command to get a fully working local environment (as much as I don’t like docker, it’s still the best for this) and having an easy way to deploy to production. Without this, even the most experienced engineers will spend days if not weeks, struggling to get the right toolchain and packages installed.

    See also:


    Published

  • Illusion of Explanatory Depth

    People feel they understand things better than they actually do. This leads to biases and poor decision-making because of overconfidence in their knowledge.

    A simple way to combat the illusion of explanatory depth is to ask yourself to explain something you just encountered. As you start to analyze it in more detail you can see your ability to explain phenomena diminish. On the contrary, explaining in layers makes the illusion worse when you successfully explain the higher level layer of abstraction and then proceed to lower levels (e.g. explaining how a computer works by starting with the layer of how the peripherals fit together like a keyboard, mouse, and display).

    According to this study, the illusion of explanatory depth might be a coping mechanism for reducing cognitive load. It might be beneficial for example to have a sparse representation of causal relations that are good enough for everyday purposes.

    See also:


    Published

  • AI for Notes

    Now that my Zettelkasten has over a thousand notes, I’d like to try to quite literally create the experience of a conversation with my second brain. The AI interface should be conversational rather than search queries. It should draw from the knowledge in my notes and respond in natural language. Finally, it should be useful in helping me make connections between ideas I hadn’t thought of before.

    How should I build it?

    You can find all the code for these experiments in org-ai repo on GitHub.

    I tried several ways to do this and I’m still tinkering with the best way to do it. Here are my attempts so far.

    The first thing I tried was to build a model using txtai trained on my notes. This let me search for similarities between notes with a very simple shell script.

    The results are decent for a search-like experience that does more than simple keyword matching. For example, searching for “semantic search” gives results for full-text search and SEO (the latter doesn’t mention the word “search” at all).

    $ Enter search query:
    semantic search
    -----------------------
    SQLite can also be used for full-text search using the FTS5 plugin making it a portable static site search engine like [[id:3D014256-4844-4591-8F9D-7878A1993210][stork-search]] for significantly larger datasets.
    -----------------------
    There are three kinds of SEO: technical, programmatic, and editorial. Technical SEO is about setting up the right infrastructure for pages including page speed, internal link architecture, redirects, and so on. Programmatic SEO generates pages automatically from a database (e.g. a page for each address on a real estate website) and sometimes comes from UGC, user generated content. Editorial SEO is content written by a person about a set of topics to drive traffic around relevant keywords.
    -----------------------
    [[https://stork-search.net][Stork Search]] is a full text search engine written in [[id:8F056F38-B79C-4D79-B10E-204D7A7952BF][Rust]] that compiles to [[id:515D33F5-7C7A-469A-89AB-5CD8E489AEEF][WebAssembly]]. That makes it compatible with static websites like notes.alexkehayias.com. The file size is relatively small (less than 1MB) for an index with hundreds of notes and the search results are fast.
    

    While this does tick the box for helping to make connections (I hadn’t thought about how semantic search is also SEO), it’s not conversational and doesn’t really draw from my notes so much as cite the paragraphs with the highest relevance.

    Using OpenAI GPT models

    Next, I’ll try to train GPT-3 by OpenAI on my notes to see if I can get close to a ChatGPT experience. I’ll use conditional generation where the prompt is the title of the note and the response the note.

    I need to prepare the data by converting from org-mode to jsonl formatted for fine-tuning.

    • Extract the body of the text
    • Replace links (with what??)
    • Insert stop words

    The results of fine-tuning the ada model were pretty abysmal (total cost $0.40):

    % openai api fine_tunes.create -t tuning_prepared.jsonl -m ada --suffix "org-ai"
    % python3 src/chat.py
    > What's the connection between remote work and prosperity?
    
    Self-regulating machines that can be programmed. There are two urgency bounds (e.g. self-soothing, work-life balance) as a way of disallowing automation and thus bringing more efficiency to work. People tend to focus on the immediate, but this is also important right now with robotics being highly automated and human interaction becoming heavily digitized—after all, AI shouldn’t need people’s full attention to function properly because it will save us from ourselves!
    

    Trying it with the davinci model (total cost $34.12):

    openai api fine_tunes.create -t tuning_prepared.jsonl -m davinci --suffix "org-ai"
    

    The results were not much better. The answer just didn’t make sense and I couldn’t rely on them to be accurate.

    Using langchain, embeddings, and a vector database

    Next, I tried langchain along with ChatGPT. Rather than try to fine-tune a model, I wanted to use ChatGPT’s superior comprehension skills alongside a vector database by doing a similarity search based on the query and then summarizing the results with a large language models. Langchain makes (you guessed it) chaining models together easy.

    A document index is built up using langchain’s built-in tools for embeddings. I created an index based on each org-roam note by extracting the metadata and body then using OpenAI to generate the embeddings. The index is then generated using FAISS (a local vector DB that’s easy to use).

    The results are so much better!

    % python3 src/chat.py
    > What's the connection between remote work and prosperity? Use my notes.
    
    Remote work has the potential to increase economic opportunity by decoupling work and place. Additionally, a survey of 12,000 people found that remote work can increase employee happiness by up to 20%. However, remote work can also have negative impacts, such as decreasing tax revenue for cities and creating inequality in access to high-speed internet and a conducive work environment. Remote work can result in a 30% increase in hours worked and a 20% decrease in productivity, and that half of Millennials and Gen Z would consider quitting if employers don't allow remote work.
    

    If we look closer at the logging you can see the exact notes that were looked at:

    > Entering new AgentExecutor chain… { “action”: “Find Notes”, “action_input”: “What’s the connection between remote work and prosperity?” } Observation: Remote work has the potential to increase economic opportunity by decoupling work and place, according to a note on decoupling work and place (/notes/2023-04-06–14-16-44Z–decoupling_work_and_place.org). Additionally, a survey of 12,000 people found that remote work can increase employee happiness by up to 20%, as noted in a study on remote work and happiness (/notes/2022-05-24–15-49-02Z–remote_work_is_correlated_with_happiness.org). However, remote work can also have negative impacts, such as decreasing tax revenue for cities and creating inequality in access to high-speed internet and a conducive work environment, as noted in a note on remote work becoming a political issue (/notes/2022-07-11–14-08-52Z–remote_work_will_become_a_political_issue.org). A note on the market value of remote work (/notes/2021-08-12–13-56-31Z–what_is_the_market_value_of_working_remote.org) provides additional insights, including that remote work can result in a 30% increase in hours worked and a 20% decrease in productivity, and that half of Millennials and Gen Z would consider quitting if employers don’t allow remote work.

    SOURCES:

    • /notes/2023-04-06–14-16-44Z–decoupling_work_and_place.org
    • /notes/2022-05-24–15-49-02Z–remote_work_is_correlated_with_happiness.org
    • /notes/2022-07-11–14-08-52Z–remote_work_will_become_a_political_issue.org
    • /notes/2021-08-12–13-56-31Z–what_is_the_market_value_of_working_remote.org

    Published

  • When to Outsource Work

    Not all work is outsourceable but tasks that are can help a business scale and save money. Work that is frequent, repeatable, and needs limited knowledge about the business to perform are good candidates for outsourcing (e.g. a process for tagging data). Work that is core to the business is a bad candidate for outsourcing (e.g. product engineering).

    Frequent and repeatable tasks

    Outsourcing a task needs to be well-defined. Things that come up infrequently and are not repeatable aren’t easy to write down and therefore not easy to share with others.

    Infrequent tasks also mean there is a longer feedback loop for improvement. The more reps you get doing anything, the better you will be at it. The same goes for outsourcing.

    Limited knowledge required

    Training is important and the more knowledge it takes to perform a task the more effort it will take. It’s not impossible, people are more than capable of learning about new things and tooling to find answers is getting better, but ideal tasks for outsourcing don’t need a ton of knowledge to perform.

    Not core to the business

    This is the big one! If you are trying to outsource something that is the crown jewel of the business, that’s a mistake. When you need to be the best in the world, outsourcing is not going to get you there. For example, a software company that outsources all software engineering is unlikely to have enough control and vision to build a world-class software product.

    An easy way to find out if something is core to the business is to ask yourself, “If my customers found out this was outsourced, what would they think?” What if SpaceX used outsourced rocket engines? What if OpenAI outsourced language models?


    Published

  • Choosing the Best SEO Strategy

    Which of the three kinds of SEO works best depends on the business, but these days editorial content performs the best. Previously, having highly optimized technical SEO with the right tags and keywords was enough to rank highly in search results, but not anymore. Not every company has a natural fit for programmatic content that matches what people are searching for (e.g. Zillow with a page for each address). However, every company can write editorial content.

    See also:


    Published

  • Imitating High-Status People Doesn't Work

    People tend to closely emulate individuals of high-status but the counter signaling they pick up on doesn’t work unless you are already high-status. For example, being an asshole to others because Steve Jobs was famously demanding and extremely blunt doesn’t work unless you are also a widely accepted product visionary, or spending many hours a day reading because that’s what Warren Buffet does won’t work unless you have decades of value investing experience.

    These high-status individuals can afford to counter signal but this can be very risky for others. For example, being an asshole to VCs would be an extremely risky thing to do if you’re not already a successful entrepreneur (even if you could get away with it, I don’t recommend it).

    Read Be Wary of Imitating High-Status People Who Can Afford to Countersignal.

    See also:


    Published

  • Truth-Tellers, Liars, and Bullshitters

    Truth-tellers need to know the truth so they can say it. Liars need to know the truth so they can lie about it. Bullshitters don’t concern themselves with the truth so they can perform whatever serves them.

    Bullshitters are particularly problematic.

    We are starting to see this in AI tools like ChatGPT. The truth is not a consideration so much as providing a useful response (the performance). These tools certainly seem to fall under the “bullshitters” category.

    We also see this in politics where the truth doesn’t matter, just the performance to an audience, serving their needs at that moment. If they were merely a liar, it would be easy to dispute that they lie because they know the truth.

    Paraphrased some of this from The Secret Commonwealth by Philip Pullman.

    See also:


    Published

  • How to Do Keyword Research

    This is a work in progress about how to do initial keyword research for SEO.

    1. Make a list of competitors (direct competitors and audience competitors)
    2. Look at the list of keywords they rank for and the search traffic received
    3. Search for keywords that are related to your product (see which sites pop up in search results). Look at the list of other keywords these websites rank for.
    4. Make a list of keywords that have high traffic and relevant
    5. Come up with a list of competitors or adjacent websites
    6. Look at what keywords they rank for that would be relevant to you
    7. Add the keywords to your competitive list
    8. Then do some searches for keywords from your competitive list and see which ones have high traffic. Add those to a new keyword list. You’re looking for keywords that have high volume per month.
    9. Next choose the top keywords and look up what the CPC is (cost per click) you’ll want ones that are specific and have some volume but are not expensive (less than $1 CPC is ideal)

    Published

  • Consistency Is Potency

    The more consistent something is, the more potent it becomes. It might sound boring to say the same things over and over again, but it leads to better results. Said another way, it’s difficult to get anything of value by being inconsistent.

    Some examples:

    • Branding and marketing messages are about saying the same thing thousands of times so they are imprinted on you (also, it’s not like you hear a different jingle every time!)
    • Good UX is following patterns consistently so users don’t need to think about how they should interact
    • Habits that you do every day add up to bigger results
    • Growing or investing consistently leads to compounding over time

    Published

  • Three Kinds of SEO

    There are three kinds of SEO: technical, programmatic, and editorial. Technical SEO is about setting up the right infrastructure for pages including page speed, internal link architecture, redirects, and so on. Programmatic SEO generates pages automatically from a database (e.g. a page for each address on a real estate website) and sometimes comes from UGC, user generated content. Editorial SEO is content written by a person about a set of topics to drive traffic around relevant keywords.

    From The ultimate guide to SEO on Lenny’s Podcast.

    See also:


    Published

  • Stutz (Literary Notes)

    Stutz is a documentary that is ostensibly about therapy, but is really about the endearing relationship between Jonah Hill and his therapist.

    Notes

    • Life force pyramid
      • Body
      • People
      • Yourself
      • If you’re lost don’t try and figure it out, work on those three things: work out, initiate relationships with people, write (journal)
    • Part X
      • Antisocial part of you, wants to keep you from changing and growing
      • Voice of impossibility
      • Tells you who you are
      • Can’t get rid of it, always there
      • Pain, uncertainty, constant worry
      • Need it to grow though, from adversity
      • Learn to love the process of nullifying pain, uncertainty, constant worry
    • String of pearls
      • I’m the one that puts the next pearl on the string
      • line, circle, line, circle, it’s a series of actions
      • You keep going, all actions are equivalent, just the next action, all the same size
      • The winner who is willing to go through uncertainty and accept the consequence
      • In the pearl there’s a small turd, can’t think about the turd inside the pearl, pearl around every turd there’s good even in the bad
    • Shadow, the version of yourself you want to hide from the world the most
      • You can see yourself that way even with so much other success
      • It’s the part you are ashamed of
      • First you need to find your shadow, visualize a time you felt inferior/embarrassed/ashamed of, the part you wish you were not but you are and can’t get rid of it
      • Talk to your shadow, how did you deal with him
      • Shadow needs attention from you only, what can you do to make up for not paying attention to him?
      • Anything high stakes, have a conversation with the shadow and tolerate what happens, other people’s opinion feels way less
      • Constantly relate to it, respect it, otherwise it will become destructive
      • Looking for wholeness
    • The snapshot (the realm of illusion)
      • You are looking for the perfect snapshot (moment, wife, job, perfect x)
      • No movement, no depth but you’ve told yourself something magical happens if you get to that
      • But, pain, uncertainty, and constant worry
      • Drive for success is trying to get to that snapshot but depressing when it doesn’t live up to
    • The maze
      • Always involves other people
      • Example when someone always wants to talk about another person,
      • Quest for fairness puts your life on hold but it’s a maze that doesn’t let you move forward
      • You can’t get that time back
      • You’re not going to get it from others, but satisfied by active love
      • Imagine you are in a universe filled with love, dense with love, feel yourself taking in all of that love and place all of the love in the universe in your heart
      • See the person you hate/despise and send all that love towards the other person, hold nothing back, feel it enter their body and become one, you can become one with anyone
      • It’s not for forgiveness, not for them, it’s so you can move forward
    • Radical acceptance
      • When something goes wrong, need a reflex to squeeze the juice out of the lemon, find the use from it
      • What am I going to do about it now
      • Not allowed to make a judgment, find something positive about it
      • Faith that there is something of value, everything becomes more meaningful
      • You get meaning from small things, all events have value, if you do that there is tremendous opportunity
      • Like a plan going through the cloud, can’t judge everything by your current experience
      • Every thought affects your mood
        • Grateful flow, remembering the sun above the clouds even if you can’t see it
        • Process of creating things you are grateful for, smaller the better so you feel the gratefulness
        • Keep naming things, then stop naming and feel the feeling take over, that’s grateful flow
        • Make it a creative act, dig to find things, it helps. Don’t say the same things over and over
        • Be grateful as much as possible, part X tells you not to be
    • Loss processing
      • Worrying about loss
      • Potency of non-attachment, pursue it but also willing to lose it
      • Pick something you’ve become too attached to that you are afraid to let go of it
      • Imagine a tree, you are grasping a branch, you’re afraid to let go, but you do and you fall, say you are willing to lose everything and you hit the sun and your body burns up, you’re radiating a loving feeling and you see all the suns everywhere saying “we are everywhere” all you can do is give you can never take
      • Not trying to be detached, move towards that one thing can take away your sense of wholeness
    • The secret of life is that you won’t figure it out ever, happiness is how you accept that, then what you do about it

    Published

  • When to Do SEO

    Before investing in SEO, evaluate whether or not it has the potential to have a large impact on your business. Not every business benefits in the same magnitude from SEO. The way to tell is by seeing if there is already a big market and your site has existing authority.

    To tell if it’s already a big market, look at product competitors and audience competitors to see how much traffic they have. Product competitors are direct competitors or ones that have significant overlap with your business. Audience competitors are sites that reach the same kinds of personas or segments that buy your product.

    Using Similarweb, you can see how much traffic sites are getting. Make a Fermi estimate to see what that traffic would do for your business by taking to amount of traffic, an estimated conversion rate, and avg revenue.

    Next, evaluate your exiting site for search engine authority—non-search engine traffic and backlinks. Getting growth from SEO is more successful when you have existing traffic and referrals. You can check for traffic by going to Similarweb and putting in your website. You can check for backlinks using a tool like Ahrefs or Semrush. Generally speaking, you should have 1000 visitors per day and 1000 referring sites.

    From The ultimate guide to SEO on Lenny’s Podcast.

    See also:


    Published

  • What Does Customer Success Do at a Startup?

    At an early-stage B2B SaaS startup, customer success has one responsibility: make sure customers don’t churn. The causes of churn are bad onboarding (users fail to find value quickly enough) and not making contact frequently. Both should be addressed by customer success.

    Bad onboarding can be solved in many ways, but customer success puts in place a repeatable process that bridges the gap from being sold to realizing value. Even a self-serve product that could allow users to onboard themselves, benefit from having customer success identify key actions users need to take to be successful and, often manually, drive users to it. No product has perfect self-serve flows and customer success overcomes technical hurdles.

    Making contact frequently builds a relationship, uncovers issues users are facing, and reminds users of the value they are getting from the product. If the only time you are getting in touch is for renewals, you need to sell the product all over again. Tactics like quarterly check-ins with top customers, helping users adopt new features, and responding to support tickets create a more durable relationship—even if problems arise.

    Eventually, when the startup becomes more mature, customer success might evolve into something that is less onboarding + support and more up-sell and renewals driven.

    See also:


    Published

  • Turn Every Weakness Into a Strength

    When building products, we’re constantly aware of how imperfect the things we build are. When telling users about your product, that’s not a very good thing to lead with. Instead, turn weaknesses into strengths.

    For example, in the early years of Stripe, large enterprises looked at the offering and felt that it wasn’t “enterprise-ready”. Rather than shy away from this area of weakness, they embraced it with the mantra ‘Stripe is for Startups’. When speaking with enterprises, they didn’t bother trying to convince them that Stripe was enterprise-ready, instead they said “don’t you want to work more like a startup?” They turned a weakness into a strength until they eventually closed the gaps.

    This is very powerful lesson in product and marketing. If you can fix it, then fix it quickly. If you can’t (or no time soon) embrace it and turn it into a strength.


    Published