1. CSS @scope

    Introduction

    CSS @scope is a new at-rule for natively handling ā€œscopeā€ in CSS True to its name, it allows you to scope, or limit the reach of your selectors to specific html regions. The idea is that this lets you express ownership of styles that span multiple elements. This has been a long requested CSS feature, and tool like CSS Modules exist specifically for this feature alone. With @scope, you can now do this in native CSS with no tooling

    Keep Reading
  2. Modern web dev

    Modern web dev is 3 things:

    • Design engineering: The ability to express visual design and interaction design in the actual physical product
    • Peripheral engineering: The ability to utilitize the various platforms features offered to us. This is almost always netcode, but is also things like wasm and cookies and pwa and so on
    • Operations engineering: The ability to host and release the product These are horizontal skills. Feature development pierces into all 3
    Keep Reading
  3. Optimize down not up

    A theory Iā€™ve had about tech libraries I think since lambda first dropped. You can do stack improvements in 2 ways. Bottom up, where you build on a better solution from the get go, or top down, where you migrate an existing system to a better solution. I think top down is the way to go. It technically reaults in more work involved in migration, but when youā€™re at that point you can much more objectively evaluate if something like lambda will be a solution that works for you. This is true for so many things in tech, and Iā€™m thinking about it again with stuff like htmx.

    Keep Reading
  4. React in 2024

    Lately there have been a slew of articles coming out either bashing or at least calling into question the current state and direction of React. As someone whoā€™s used React for work and play for quite a long while now (2015)

    1. React is still great at what it was built for
    2. React is improving at solving problems outside itā€™s original scope
    3. React is still complicated to use
    Keep Reading
  5. Meta CSS

    Iā€™ve been doing a lot of experimentation lately on design engineering, and specifically how to better leverage CSS. This started when I was working on rebuilding my personal site, and I wanted to drastically cut back on the degree of build tools I was using, and try and see how far I could get with just modern vanilla CSS. As it turns out, you can get pretty far these days. CSS custom properties and nesting in particular were the single golden features that allowed me to finally, completely move on from SASS. At first things were great. I followed all the CSS methodologies and techniques I had learned over the years:

    Keep Reading
  6. How I write CSS in 2024

    In 2024, I've developed an approach to CSS styling that I really enjoy, but also haven't seen done anywhere else. It is built on the following principles

    1. It's just CSS. No build tooling like SASS, or PostCSS required
    2. It's modern CSS. It leverages modern CSS features like nesting, variables, and selectors such as :has() and :where()
    3. It makes component-oriented design easy
    4. It's built on general styling principles The methodology is built in layers that I will explain below
    Keep Reading
  7. The many kinds of functions

    Something Iā€™ve been thinking about a lot lately while Iā€™ve been working with the Ramda library has been the different kinds of functions there are. In functional programming, there are names for different kinds of functions that share a common use case. I think knowing about them can be a useful thing to know, even if you donā€™t program in Haskell or the like.

    Keep Reading
  8. Edge Hosting Options in 2024

    Deno Deploy

    Pros

    • Doesnā€™t require a build process to deploy. Just upload your code and itā€™s good to go
    • Includes things for building real edge apps, like KV and CRON

    Cons

    • There is no caching layer built-in. All requests, even for static assets, will trigger a separate function call. This has 2 really bad consequences:

    Keep Reading
  9. Historical Schisms

    Something that came to mind while I was watching a video. The video mentioned how there were opponents to the development of the CIA at the time, and secret government systems in general. I found this very interesting because I always assumed opposition to that sort of thing developed after the fact as a reaction the wrongdoing This is like the third time Iā€™ve run into this phenomena:

    Keep Reading
  10. How I made my personal site

    Content

    This site is first and foremost built around content. I have no formal structure or schedule to my writing. The only general rule of thumb I follow is to lean on the side of writing more, even the insignificant. The getting things done framework talks about getting things out of your head and onto paper, and Iā€™ve found that to be very helpful for keeping my thoughts clear; both as an software engineer who has to keep a lot in brain ram, and as someone with ADHD. The vast majority of my creative writing is done on my phone while Iā€™m on the move; on the bus/train, while walking, or while waiting in line. I tend to do my best thinking while Iā€™m in motion. I do all my writing in a mix of Google Keep and Notion. I primarily use Google Keep out of long-term habit. It was the first note-taking app I got used to all the way back in high school on an old samsung galaxy phone. I discovered Notion in 2017, but for a while the mobile app was fairly complicated and slow on my android phones, which created a lot of friction for me as a largely impulse-driven writer. Nowadayā€™s though I have a modern iPhone and the Notion app has come a long way, so this may change in the future All of the content you see on this site comes directly from my Notion. I consider it my reliable long-term knowledge archive. My Notion is extremely simple, I just use pages and links mainly, no databases or anything of the sort. You can definitely over-organize your Notion if youā€™re not careful (I have many times), so keeping the structure flat and simple helps me focus more on the content than the tool.

    Keep Reading
  11. Letā€™s Build our own with macro in Elixir

    The current with macro sucks because itā€™s impossible to know which function the error is coming from, which makes it harder to know how to handle it. Build an improved macro that gives you the unintended input, and which function in the sequence it came from

    Keep Reading
  12. Behaviors vs Protocols

    Original Thoughts (not sure when I wrote this):

    • Behaviors for effects, protocols for data
    • Behaviors map the same functions and data to different implementions. If the functions are the same, and the data coming in and out is the same, the only difference is the effects being run on the data. This can be seen in how, most of the time, behaviors are written for testing purposes
    • Protocols map the same API to different types of data. For example, an enumable that can work on numbers, string, objects, etc. Itā€™s a type of polymorphism, similar to generics but more than that. It allows custom types to extend a common API. For example, if you had a create function imported like from core import create you could implement the create logic for every type you wanted. Then you wouldn't have to have a million create methods How I feel now (Aug, 2023):
    • Itā€™s not as clear cut as behaviors for effects and protocols for data.
    • There are practical differences between the two, and I can illustrate it with the Enum protocol
      • If Enum were a behavior, the way you would implement it would be to create a new module, with a struct for the data type you want.
      • When you now call Enum, you have to pass your data structure, and the module that handles it. This is more work than itā€™s worth and kinda defeats the point of the behavior
    Keep Reading
  13. Abstract Data Types in Elixir

    Something that took me a long time to understand in elixir was when protocols were appropriate to use. Basically, they are a way of defining abstract data types, without being bound to a specific data structure. So they define a type through its behavior, not it's structure There are 2 examples that really made this sync in for me. The first is how you can make a queue protocol, and then implement it 2 different ways depending on the underlying struct The second is how ranges are defined in terms of structs, yet still implement the enum protocol. The third is how you can invent your own numbers by defining and implementing a ā€œnumberā€ protocol. A number is anything that supports the ā€œadditionā€ and ā€œsubtractionā€ protocols for example. That's a bit contrived, but it helps illustrate the point that you can define something in terms of what it does, just as much as you can define something in terms of what it is Types are defined in terms of their behavior, rather than in terms of sets of values. Golang has it right with this. You add both structs and interfaces with the type keyword.

    Keep Reading
  14. The table is not the model

    Something that really took me a lot of effort to wrap my head around was the reality that how you model and understand data, and how that data is best persisted, are two distinct concepts and should be handled separately. Often timeā€™s we view the database tables as our source of truth, and write our APIā€™s around the schemaā€™s it provides. The catch is that, as your application getā€™s more complex, you realize that you need to wrangle that schema more and more to fit more complex transformations. This can often lead to over-fetching data, because you only need small pieces of data from a bunch of different tables. Alternatively, database tables, or serializations schemaā€™s to be more broad, should be an afterthought when designing your application. Design with a model first, and then figure out how to best persist it, not the other way around. A good practice Iā€™ve taken to is designing my models to work in-memory first where I have the full freedom of my programming language, and then once the functions are figured out, I get to work on persistence. More often than not I find that the model canā€™t be perfectly modelled to any particular storage system, so you have to make tradeoffs. But I think this is a good thing, because it forces you to think more about storage solutions in the context of your specific data needs, and less about how to compromise your internal model for the sake of your storage solution. This is the solution to the problem I had when I began working at MP and had to argue about the best storage solution for our company.

    Keep Reading
  15. How to do client authentication in 2021

    When only a single server and database is involved in the application, OAuth2.0/OIDC is overkill. It's easier to just use regular session to control access to your backend API. The primary use case of OIDC is if you need to support enterprise SAML, or if you want other sites to support "Sign up with X" for your service.

    Keep Reading
  16. Elixir Meetup Talk

    Hey, Iā€™m Jacob!!!!!!!! šŸ˜„ Today Iā€™d like to talk about Elixir at Discord, but as a larger theme I sorta wanna talk about using Elixir at work, and sorta take you on a journey of how I started using it at work, how itā€™s been, and whether I would recommend it to others. And to illustrate that, Iā€™m gonna be sharing a couple case studies and war stories/campfire stories

    Keep Reading
  17. Elixir @ Discord and Marriage Pact

    Elixir Meetup Talk

    Talks/speakers to learn from:

    • Code Aesthetic
    • No Boilerplate
    • Anything from Dan Abramov or Kent C. Dodds

    So just by show of hands:

    • How many of you have used elixir before, either for experimenting or personal projects or whatever
    • Now of those, how many have used or use elixir at work
    Keep Reading
  18. Creativity Under Pressure

    • I love doing design work, but only as a hobby or on personal projects. Doing design as work or under pressure is an extreme nightmare for me. I get much more stressed about quality and speed, and constantly want to change the design completely, which isnā€™t realistic in a work environment
    • Engineering work isnā€™t as fulfilling, but Iā€™m much more consistent with it, especially in a work environment. I think this is because you typically engineer to a spec, so there is a clearly defined goal you can measure your success against. Theres a sort of liberating freedom in not having to design, because your contributions are much more clearly defined and success is clearer cut. But at the same time, I think design sense is essential for product development. Engineers should be able to make good design decisions
    Keep Reading
  19. Dependency Injection is a good solution to the wrong problem

    • I think I believe that dependency injection (DI) is a solid approach to the problem of managing effects. But I think the real solution is to circumvent the problem altogether
    • DI for the sake of testing should use a different mechanism
    • DI for managing effects should be replaced with stateful objects/servers
    Keep Reading
  20. Reactive vs Proactive product development

    • Iā€™ve noticed that there are kinda two approaches to deciding what the work priority on a product team should be
    • The reactive approach is to build what users ask for, or to build solutions to observed problems. This often short term thinking, but is also builds the product more in the direction of what people are asking for
    • The proactive approach is to build based on personal taste, stakeholder request, or personal assumptions. This is often longer term thinking, but can run the risk of building in the wrong direction
    • I think agile and lean engineering pushes teams to do more of the former, and less of the latter. But tbh, I think a mix of both is required. How and where to strike that balance I have no idea, and I imagine is team and product dependant as well
    • Iā€™m curious about how taste driven companies manage it. What comes to mind is Linear, and Valve
    Keep Reading
  21. Demonstration of managed effects in Elixir

    Overview

    • Build modules around data structures! You want to think of your program as just algorithms and data structures
    • Think of your application as one massive reducer that takes in the state of the world and your request as input, and outputs an updated state of the world
    • You create a data structure to represent the state of the world
    • Updating the state of the world can be handled by 1 all-encompassing module that takes the state and action and returns a new state, or more interestingly it can be split into contexts
    • Each context defines a protocol for what its ā€œsliceā€ of the world needs to be able to do. The thinking is that by having each context require only the pieces it needs, the context modules become radically simpler, decoupled, and easier to test. It can also help you naturally figure out your service boundaries if you eventually build out additional services
    • You then implement each contexts protocol for your state struct
    • Effects are run in the protocol implementations. This means in testing you can create alternate implementations that run more manageable effects
    • Protocol implementations are also the most tricky part to get right because they are effectful, and have to do some magic behind the scenes
    Keep Reading
  22. Refactoring

    Refactoring Effects

    An app is just a reducer of the world state and a command Services should just be viewed as opaque data structures. Ex, typeform is just a big dict of workspaces, forms, and responses Wrap all services up as one opaque ā€œworld stateā€ data structure. Pass this in to all top-level functions. Think of it like the conn/token pattern in elixir Use in-memory data structures to test, effectful one in production Alt, use in-memory handler in testing, live handler in prod

    Keep Reading
  23. Jan 15, 2023

    Something I thought about earlier this week that I wanna better wrap my head around is the idea of reactive records, or reactive tables.

    The basic idea is that instead of having general handler functions that manipulate a lot of tables all at once, you instead have messages that each table can opt-in to subscribing to. This would mean that update logic is spread out over more non-colocated pieces, but it also means that each update piece is easier to wrap your head around.

    Keep Reading
  24. Jan 8, 2023

    Wanna build a little MVP thatā€™s just a thin layer on top of Plug I think a good starting goal is just to use like a To-Do app as an example application

    To-Do API spec

    Keep Reading
  25. Jan 9, 2023

    Rex!

    A simple and intuitive data validation library for Elixir

    In all my musings on an independent framework I got hung up on parameter validation.

    One of the big things that spawned the idea in me to build my own framework was that I wanted to turn this:

    def create_article(conn, %{"author" => author, "content" => content}) do
    	with {:ok, article} <- Library.create_article(author, content)
    end

    Into this:

    Keep Reading
  26. Play with your players desires

    Related to the core game loop. For it to be a loop, it needs positive feedback. And that feedback needs to be in service to someone people intrinsically want, ideally without direction. Perfect example is Minecraft. You wanna build stuff. You may not even be that creative, but you at least want a tiny shelter at first. So you go to the mines, get what you want, and build it. But the experience of the mines and of building reinforces your imagination for what you can build. So you wanna go back in the mines, and the loop begins. At MP I think we struggled with this because we started coming up for loops with Checkmate, but couldn't define and build around what people really wanted. It's easy to say insights about their friends, but what kinds of insights? Can it grow? Can it evolve? Can it be sought out without user educa

    Keep Reading
  27. Don't be scrappy

    I feel like the term MVP has really been misused to mean ā€œbuild something that mostly works, and then ship it to see how it faresā€. More often than not, Iā€™ve seen this lead to either great ambitions with their foot shot because there wasn't any polish, or projects that are built on rough foundations and fail to innovate over time. Build good shit, just build it small, cut out all the bullshit and just include what's essential and meaningful

    Keep Reading
  28. The table is not the model 2

    • A cool example of this I stumbled upon was in Checkmate. In Checkmate, the data structure I try to expose to the client is a graph. And, on the backend I try and represent the entirety of all clients as a graph as well. But I noticed that the client graph may not be a 1-to-1 slice of the server graph.

    Keep Reading
  29. The Language defines the API

    Through reading about DDD, Iā€™ve learned the power in being self-aware of your teamā€™s language when describing a problem. The terms they use, and more importantly the terms they donā€™t use, define how they think about the problem at hand. As developers, I think one of our supreme goals and challenges is to build a system that fits that mental model as closely as possible. The language you use defines the API you build

    Keep Reading
  30. Finding the right pacing

    Weā€™ve noticed at MP that 2 weeks isn't a good cycle system for us. It's too short for us to deliver anything we find meaningful. We end up cutting corners and running over, and it's just not a fun experience. We want to experiment with longer time frames to find a better balance between working fast but delivering chunks of work that move the needle

    Keep Reading
  31. Agreeing on estimations

    Managers and workers fundamentally have a clash of incentives when it comes to laying out deadlines. Workers are paid regardless of how much value is delivered, so they are incentivized to make deadlines as far away as possible. Managers have to deliver as much value in as short a time as possible, so they are incentivized to make deadlines as short as possible. How do you reconcile this?

    Keep Reading
  32. Product Science

    I think I prefer my job to be product science, rather than product development. Product science is such a term I vibe with

    Keep Reading
  33. Fast is overrated

    I've worked with quite a handful of early stage companies at this point, and something I've had religiously beaten into me is the importance of speed. Putting as many good ideas into production as quickly as possible is the key to success, so they say. But I donā€™t think I've seen any companies do speed right. I think speed is overrated, and what really matters is adaptability, and consistency

    Keep Reading
  34. Donā€™t let good get in the way of great

    Most teamā€™s are pretty good at prioritizing good ideaā€™s over bad oneā€™s. But to succeed in a startup, you need to be able to put the great ideaā€™s, the oneā€™s that will truly catapult your business, over the good ideaā€™s, the oneā€™s that have some growth, but nothing particularly spectacular.

    Keep Reading
  35. Paper-Cut issues

    When building products there are often issues that are never urgent, but get progressively harder to resolve for every day they aren't. Migrating a database table is an example. These problems can often cause death via 1000 paper-cuts when left unattended to. So the question is, at what point do you resolve them? I feel like you can learn so much about a company and their culture by how they handle paper cut issues. It speaks a lot to engineer empowerment and whether engineers have an active desire to improve their product. Like do they just solve it, or make a ticket to do it later? This also applys at a larger scale to things like C++ vs Rust. Rust kinda grew due to all the paper cut issues that accumulated over time with C++. But perhaps this is inevitable and just the nature of software. Like nothing can be perfectly designed in realtime, so adapting to change is the priority. And in things like programming languages you cant really ever undo a decision

    Keep Reading
  36. The Train Track Problem meets software

    What do you do as a manager when it is 5PM on a Friday and a critical bug is found? Do you ask someone to suffer by staying late? Or do you let the userā€™s suffer by not fixing the issue until later?

    Keep Reading
  37. The 1-feature app

    I think all meaning of the term MVP has been lost People need a more concrete way of building and testing ideas The 1-feature-app is a constraint designed to keep scope down, and put more focus on testing

    Keep Reading
  38. The Time-Complexity Tradeoff

    • With the rise of modern cloud computing tech and off-the-shelf services, it's becoming more complicated to make the decision between "implementing it yourself" and "use the service"
    • The two fundamental job of an engineer is to deliver value while minimizing complexity
      • Complexity comes from two sources, an expansion of the problem domain (intended complexity) and the imperfection of compute resources (unintended complexity)
    Keep Reading
  39. The Great Database Debate

    Another issue that came up in Marriage Pact. We are in the process of building out our first real infrastructure, including a repository to hold user data long-term. Since there was very little existing code, we had full reign over what we wanted our tech stack to be (with the exception that we host most of it on AWS). The first major decision was choice of database. Myself, and 2 other devs wanted to use PostgreSQL. The dev who was largely responsible for our cloud/backend operations wanted to use DynamoDB. This actually turned into quite the heated debate, with solid arguments made on both sides. Unfortunetly, while we were debating, time was ticking, and the eventual solution we arrived at was to go with what the backend dev wanted, despite not really feeling ok with it. I found the exchange really interesting, because it's a conflict I've now encountered on every greenfield project I've worked on, across multiple teams. So the question becomes, how do you solve problems like this in an efficient matter, where both sides have strong arguments, and both sides believe they are correct?

    Keep Reading
  40. How evil designs get made

    Lots of lessons learned here from Marriage Pact. Talked about Hooked a lot, and made an active effort to design addictive skinner boxes, without any discussion of the ethics. Ethics are a difficult topic to bring up, because choosing not to use these tactics could mean your business fails

    Keep Reading
  41. Optimize at scale, not for scale - Don't optimize for scale

    Most of my work is in building MVP's and greenfield projects, and the most common technical concern I receive is "Will it scale?". The very mention of that question can spur pretty heated debates. Should we build an Express server, or go with Serverless functions? Do we use PostgreSQL, MongoDB, or DynamoDB? Should we put everything in a vm and scale vertically, or should we Dockerize everything to make horizontal scaling easier? Should we use Ruby+Rails, or maybe Elixir+Phoenix? Should we build our own auth system, or use Firebase Auth? Hopefully I'm not offending anyone by making these comparisons, I realize there may be some false equivalencies since not all projects are the same, and every technology has it's sweet spot. But, many developers have to grapple with questions like this every time they start a new project, myself included. Many teams fear "The Big Rewrite" Very few large companies are still running on the infrastructure they started with.

    Keep Reading
  42. Build ideas not features

    A lot of companies love to build MORE features to improve the quality of an app. But every feature adds complexity. I think a better approach is to build a feature to evaluate an idea, and then use the feature to evaluate if the idea should be changed, added on top of, or removed

    Keep Reading
  43. Abstraction is like building Lego's in reverse

    The dream of every programmer is to have their system built like legos. Where all they do is mix and match the legos together to build different things. In reality though we play the role of both the Lego builder and the Lego designer. We not only build legos into different things, we also decide what the pieces are. And it's deciding what the pieces are that really sucks. But something I realized is that, most often when building software systems, we build with big legos first, and slowly make our pieces smaller and smaller over time. Like if we wrote a JSON parsing library, the library would be the one piece. But if we then also needed to support XML parsing, the best idea would be to make a pluggable parser with a JSON and XML module. So we now have more pieces. But what's interesting is that the parser and the json module are now split, despite having the same functionality. Why do we build things that way? Why not start by building with a pluggable parser piece and a JSON plugin piece? I think the answer is that it's usually bad practice to pre-emptively build things in pieces, for 2 reasons:

    Keep Reading
  44. Write your own tasks

    Early on I felt that having a central place where teams wrote up tasks was the perfect way to do development. But, while I still think that thinking things through is a smart move, I am less persuaded by the centralized write and execute style. Writing operationally-perfect feature specs is draining, and so are executing on them. It makes you feel like a code monkey. Plus, it just doesnā€™t jive with some people. At MP, we have found that giving individuals the freedom to write their own specs in the way that best suits them to be more effective for our small, rapidly changing product development environment

    Keep Reading
  45. No empty buttons

    Something I learned from Evan, but I see it a lot working in startups. It's very emblematic of the wrong startup philosophy, shipping unpublishable work. Every feature published to users should be usable, even in the very beginning

    Keep Reading
  46. Debug driven development

    Some people say integration tests and unit tests, ive found that that isnt really a good name because it doesnt well convey what im using them for. I prefer specs and tests. Specs are less about verifying correctness of code, and moreso about documenting and keeping track of product features. This enables you to change code internals while knowing if it breaks or conflicts with the previous features you wrote. Tests are about automated debugging, and are the first line of defense. If something in my app is broken, and i have a rough idea of what systems it might be affecting, i can run the test suite on that section of code to start weeding out potential root causes of the issue.
    In a perfect world specs could be used as a source of documentation, or a way to generate documentation, but that may be a pipe dream.
    Debuggable code is very easy to isolate. Code is easy to isolate when it runs no effects whatsoever, or if it does it only does one, and the effect is the focus of the code Debuggable code is very transparent. You can know what data is in the system when it fails, so its easy to reproduce later Debuggable code has easy to understand intent. You can easily build an intuition about how a piece of code should work, so you can quickly discern why the code is deviating from how its intended to function. Related, theres a lot of internet discourse about how to document code, and how it should convey why the code is there, not what it does. (1) if you feel the need to convey what a piece of code does, its a good sign you need to refactor the code, usually but not always by just puting the weird logic in an isolated function with a good name. (2) i think what should be commented is intent; what are you trying to do here. Note, this is different from docstrings or the like, which help consumers understand what a piece of code does. Comments discuss internals Debuggable code is consolidated. You can see an entire stack of functionality from a single file or folder, and dont have to jump around and understand how a whole bunch of unrelated systems work in order to understand how the faulty system works Isolate
    Expose
    Consolidate
    Document

    Keep Reading
  47. Syntax is not the answer

    • If Rust has taught me anything about language design, itā€™s that trying to create the ā€œbestā€ syntax for everything, results in programs that donā€™t use the best syntax for anything. It just makes programs hard to read, and even harder to write well
    • Rustā€™s solution to the most complex language programming language in wide use today (C++) is to create the second most complex programming language in wide use today.
    • Macroā€™s arenā€™t the answer either. The problem with macroā€™s, regardless of how elegantly well a language chooses the implement them (and some definitely do), is that theyā€™re typically only well understood by the person that wrote them, leaving the rest of us to dig into docs and articles in an attempt to intuit just what voodoo this code is actually doing. This is especially difficult for new programmers to a language. Not only must they learn the ins and outs of a languages existing syntax, they must also try to wrap their heads around all the ways its being extended
    • Of course there are very good reasons for more syntax, namely specificity, and readability.
    • Specificity lets you be more exact on what exactly you want a computer to do, which is often important in situations like systems programming where you often want a high degree of control over memory layout and CPU instructions. A good example of this is the dyn vs impl keywords in Rust. They both fulfil the same purpose conceptually, but have different practical performance implications.
    • Readability is more broad. Sometimes syntax is added so that a particular data structure is easier to express. A good example of this is JSX, which makes it easier to read html than the equivalent representation as JavaScript objects and function calls. Syntax can also be added to make algorithms easier to read as well. For example, in Python you can write a for loop, or you can create a list comprehension.
    Keep Reading
  48. Tunnel vision work

    Iā€™ve noticed that, from working so much, itā€™s given me a sort of tunnel vision, where I donā€™t really see myself outside of work. But thereā€™s really a whole world out there outside of what you do. Reading has helped me get rid of the tunnel vision, and be more present in a holistic sense, as a person in the world with infinite opportunity

    Keep Reading
  49. Good architecture is something you feel, not something you see

    Something I've noticed after many hours of researching software architecture is that good architecture is felt, not seen. Looking at complex DDD folder structures LOOKS like good organization, until you actually try adding a feature and it requires changing like 100 things. By contrast, architecture that looks like a jumble of flat files can actually be very easy to change and organize

    Keep Reading
  50. Speed is the result, not the rule

    The tantamount conventional startup wisdom is to build small and build fast. I donā€™t disagree with this sentiment, but I do think many companies have run into the ā€œas soon as a metric becomes a goal, itā€™s no longer a good metricā€. Many companies expect their team members to work fast, but often it forces them into a position of prioritizing speed above happiness, curiosity, planning, and quality. I prefer the belief that speed is the result, not the rule. If you have a framework for consistently shipping, and your team is healthy, motivated, and inspired, speed will take care of itself. As a leader, if speed is not what you want it to be (and more than likely it wonā€™t be), I err on the side of first ruthlessly reprioritizing, and if that doesnā€™t work to hire, and if that doesnā€™t work to be transparent with the team on where weā€™re at, and let them know what crunching will and wont get us

    Keep Reading
  51. Micro-delay Hell

    Something I've experienced with every remote team I've worked with is the "micro-delay" phenomenon. Essentially, because most (if not all) conversation among remote teams is handled asynchronously (most commonly through Slack), it can take a very long time to make any meaningful decisions. The problem is that any one engagement isn't so long that it's a problem. A reply can usually come within 1 hour, to as long as 1 day. But, these engagements tend to stack on top of each other, meaning it can take upwards of a week to have any meaningful discourse. If the team was fully in-person, this situation would quickly dissolve, as I could easily just go talk to someone and have a quick chat. Part of the problem is that most of the remote teams I've worked on aren't full time, so the in-person solution would only alleviate the problem, not solve it. There are some interesting solutions I've seen implemented that solve this problem. The team at Admiral uses an always-on camera system during working hours. So even though the team is distributed, they are still effectively in the same room with each other. Another solution is "office hours", where team members have no-appointment-necessary timeslots where anyone can stop by and have conversation. I feel like this system is more realistic for part-time teams.

    Keep Reading
  52. Multi-disciplinary teams work

    Probably one of the best things I've have noticed while working on Marriage Pact. I've often read that you should build with cross-disciplinary teams, but seeing it in action really gives me a better appreciation for it. When you have people all faced with the same problem, but coming from vastly differing perspectives, they will solve problems in ways each individual contributor would never even think to entertain. I've noticed this most on the product team, where my 2 colleagues come from a more traditional design background (whereas I have a more software-oriented background). There are entire concepts they will throw out simply because they thought it was technically impossible, only to find out it could be done with relative ease. Or moreover, they will simply accept certain hardships in their process because they can't reason about a way to improve it as a designer. And the reverse is true for me as well.

    Keep Reading
  53. Top-Down Innovation

    An issue that was presented to us at Marriage Pact. To make a strong pitch for investors, we need to show strong levels of engagement. This has created a push from management onto the product team to come up with ways to engage our audience on a more regular basis. But this creates a problem, because there doesn't seem to be a whole lot of interest from our audience to engage on a daily basis with our product. There is a disconnect between what our investors need, and what our users want. So the question is, are we solving a real problem?

    Keep Reading
  54. Resume Driven Development

    A phenomenon I have noticed among many of my friends and colleagues in college. Resume Driven Development is essentially the theory of learning about and implementing technology based on it's likelihood to land you a job in the future.

    Keep Reading
  55. Trust People

    Something Iā€™ve noticed over the course of many projects and having worked with many different teams. Giving people individual agency and trust is the way to creating better products. Dictation, where a manager or leader imposes a vision onto others, results in subpar creative thinking, and can really burn out a team. When engineers and designers are reduced to cogs that take some input and are expected to produce some output, they will feel it, and their sense of personal fulfilment and professional investment in an idea will diminish.

    Keep Reading
  56. Studio Reach Postmortem

    Lessons Learned:

    • Find the best people. Good people are more important than good management structure
    • Startups live or die by their momentum. One of the fundamental jobs of a leader is to maintain momentum
    • Everyone should be talking with the audience. Everyone should be involved in the creative process. Nobody should be pushing rocks
    • Compromise on Scope, not Quality
    Keep Reading
  57. Startup Cosplay

    A startup cosplayer is someone who looks and acts like the kind of "entrepreneur" you would see in a movie or on Instagram. Although they may want to run a successful startup, their primary motivation for doing so is not to solve a problem, but so they can look, act, and "feel" like a startup founder. You should really be wary of people who are like this. For one, they can poison the mind. I experienced this first hand the first couple years I was in college. I went to a lot of "networking" events, where people in flashy suits talked about how much "business" they were doing. I began to associate the two in my head. To be a startup meant to have the aesthetic of a startup, and to be a founder meant taking on the persona of a startup founder. I think this gave me a lot of insecurity for a while, because my small business was easily forgotten compared to all the big cool things these startups were doing (or rather, were gonna do). But, as I met more and more founders and business owners across the startup landscape, I realized that those people were largely putting on a show. The most successful founders I met didn't look or act anything like what I've been describing. On the contrary, they were less formal, more passionate about their work, and, most importantly, kinder. I've found a good way to tell the difference between someone who is genuinely passionate about their startup, and someone who is performing startup cosplay, is by how wholeheartedly kind they are to people. I've noticed that a lot of startup cosplayers engage in "toxic positivity". You've probably seen what I'm talking about online; its the "I wake up at 2AM to start work and you should too #RiseAndGrind" type. For a time, these people really got under my skin, because from the outside, these looked like the kind of people who were really making it. But, again, most really good people who work in startups don't act like this. There are certainly a lot who wake up early and spend way too many hours working during the day, but there is a difference between having a lifestyle and projecting a lifestyle. I've also found that startup cosplayers tend to be kind in a very transactional sort of way. My favorite example of this is the ulterior-motive-lunch trick. Every few months or so, an acquaintance I've met will reach out with something along the lines of "Hey man, haven't heard from you in a while, would you be down to get lunch later this week and catch up?". When the day arrives, the conversation almost always goes along the lines of this formula: Get food ā†’ engage in small talk, maybe catch up on what they have been dong for work ā†’ "ok, so there is this thing I've been thinking of doing" ā†’ pitch about idea that they want to involve me in. Now to be fair, in isolation I think there is nothing inherently nefarious about this sort of behavior. But, you need to keep an eye on it, because if you find that the only discourse you have with someone pertains to work, they are viewing you less as a person and more as a resource.

    Keep Reading
  58. The Designer-Developer

    See also, Renaissance developers Itā€™s the idea that a software engineer should be product oriented, and have an active hand in the design and direction of a product.

    Keep Reading
  59. The Carlos Problem - Feature Driven Development

    ā€œFeature Factoryā€ is a more common term for this Basically, itā€™s a belief by management or leadership that the success of a product is a function of itā€™s feature count, which simply isnā€™t true. Adding more to something can definitely improve it, but it can just as easily do the opposite

    Keep Reading
  60. Software Mileage

    Software mileage is one of my favorite ideaā€™s. Early on in a projects development, youā€™ll be faced with an immense amount of decisions to be made about ā€œthe stackā€œ. What programming language do I use, what hosting platform, what frameworks, tools, and libraries. You also may think this when desiring to learn a new tool of the trade, like pick up a new programming language or framework. When youā€™re in this situation, as I have been in many MANY times, I like to use the ā€œmileageā€ theory of software usefulness. In essense, the mileage theory is the complexity or difficulty involved with some thing, divided by how long you think youā€™ll be able to use it before you have to replace it. Take for example, PostgreSQL. Postgres is one of the most advanced data management systems ever invented. It will take some time to pick up and learn itā€™s quirks, especially if you donā€™t know SQL going in. However, once you get a grip on it, Postgres will more than likely serve you for a very long time, even if your project goes to the moon. And moreover, if it doesnā€™t youā€™ll more than likely be able to apply those skills again to a new project. High skill, but high lifespan, so the mileage is good.

    Keep Reading
  61. The many types of Python classes

    • Classes are bit of an overloaded term in Python, and should be used with care
    • Classes as Data
      • The vast majority of the time, you should use classes in Python to create custom, stateless, immutable data types
      • You should use @dataclass(frozen=true), this helps denote that the class is purely for use as a transparent data structure.
      • The only methods on these types of classes should be for implementing protocols. They should read from self but never write to it. Moreover, they should never execute side effects
      • These classes can inherit from one or multiple protocol classes, but only those
    Keep Reading
  62. Trust your instincts about people

    Paul Graham is a bit of a weird dude, especially in recent years, especially on Twitter X, but I do believe he has some good, hard earned wisdom on building products and working with people.

    This particular quote Iā€™ve found to be exceptionally true in my professional and personal life:

    Keep Reading
  63. Algorithms Study in Rust

    • A series of small posts about different core data structures and their performance comparison, but implemented in Rust [[Suffix Treeā€™s for finding Strings in Linear Time (Really fast Bad-Word Search)]]
    Keep Reading
  64. The Growth-Oriented Startup

    The Who

    Startup Teams can vary in size from 4 or 5 to well over 100, but must include the following components

    1. The Growth Lead
      • In early stage startups, this is typically the founder
      • Responsible for managing the team, and brings the enthusiasm
      • Final decider on what growth experiments are run
      • Creates and keeps track of company goals & metrics, and whether team is meeting them
      • Runs a growth meeting once a week to review goals, experiment results, and progress
      • Must be focused on a single goal that typically correlates to core metrics, and keeps the process from being derailed
    Keep Reading
  65. All About Landing Pages

    Introduction

    • Landing Pages are the storefront or book cover of your product or service
    • The primary purpose of a landing page is to maximize conversion rate, or the % of visitors who arrive at your site that complete the acquisition event (i.e. signup for your product)
      • Remember to do your homework on what a standard conversion rate is for your industry, as it can vary widely. For SaaS apps this hovers around 3%, for TurboTax it's as high as 70%
    Keep Reading
  66. All About User Interviews

    Introduction

    • All members of a founding team need to participate in user discussion, including technical founders. This process CANNOT be outsourced
    • Personal interviews need to be carried out most frequently in stages 0, 1, and 2. Keep interviewing until you simply have too many users to keep track of, then transition to wider-net analysis tools
    Keep Reading
  67. All About Analytics

    • Do not worry about setting up analytics until you're ready to move out of stage 1 and open your product up outside your small test group. Until then, your growth formula will be too fluid to warrant the time necessary to set everything up
    • Analytics should be built around your growth formula and your growth funnel
      • You should ideally set up tracking for each factor in your growth formula
    Keep Reading
  68. How to Prioritize Time & Work

    TIP: Beware of Fake Progress, actions that may give you more eyes or legitimacy, don't actually move the needle of progress for your team in the near future, and thus shouldn't count as "progress".

    Examples include:

    • Winning Awards
    • Optimizing BS metrics
    • Meeting Famous People
    • Pitch Competitions
    • Press Announcements
    Keep Reading
  69. Measuring Startup Success

    The fundamental goal of a startup is to grow it's primary metric

    1. Don't worry about metrics pre-launch. Instead, focus on running an experiment with a single independent variable like a science experiment
    2. Find a primary Metric, and a few secondary metrics to track
      • Too many metrics and things become foggy, only 1 doesn't give the full story
      • These are sometime's called KPI's
      • Should give you a good understanding of the overall health of your business
      • This is usually either revenue/unit of time, or active users/unit of time, preferably revenue since wallets don't lie
        • If not revenue, base if off something with as few degrees of separation from revenue as possible
          • Ex: Facebook could use daily active users, since it's revenue is specifically dependent on active usage
    Keep Reading