• 0 Posts
  • 15 Comments
Joined 1 year ago
cake
Cake day: June 14th, 2023

help-circle








  • Yep, absolutely.

    In another project, I had some throwaway code, where I used a naive approach that was easy to understand/validate. I assumed I would need to replace it once we made sure it was right because it would be too slow.

    Turns out it wasn’t a bottleneck at all. It was my first time using Java streams with relatively large volumes of data (~10k items) and it turned out they were damn fast in this case. I probably could have optimized it to be faster, but for their simplicity and speed, I ended up using them everywhere in that project.


  • I’ve got so many more stories about bad optimizations. I guess I’ll pick one of those.

    There was an infamous (and critical) internal application somewhere I used to work. It took in a ton of data, putting it in the database, and then running a ton of updates to populate various fields and states. It was something like,

    • Put all data in x table with batch y.
    • Update rows in batch y with condition a, set as type a. (just using letters as placeholders for real states)
    • Update rows in batch y that haven’t been updated and have condition b, set as type b.
    • Update rows in batch y that haven’t been updated and have condition c, set as type c.
    • Update rows in batch y that have condition b and c and condition d, set as type d.
    • (Repeat many, many times)

    It was an unreadable mess. Trying to debug it was awful. Business rules encoded as a chain of sql updates are incredibly hard to reason about. Like, how did this row end up with that data??

    Me and a coworker eventually inherited the mess. Once we deciphered exactly what the rules were and realized they weren’t actually that complicated, we changed the architecture to:

    • Pull data row by row (instead of immediately into a database)
    • Hydrate the data into a model
    • Set up and work with the model based on the business rules we painstakingly reverse engineered (i.e. this row is type b because conditions x,y,z)
    • Insert models to database in batches

    I don’t remember the exact performance impact, but it wasn’t markedly faster or slower than the previous “fast” SQL-based approach. We found and fixed numerous bugs, and when new issues came up, issues could be fixed in hours rather than days/weeks.

    A few words of caution: Don’t assume that building things with a certain tech or architecture will absolutely be “too slow”. Always favor building things in a way that can be understood. Jumping to the wrong tool “because it’s fast” is a terrible idea.

    Edit: fixed formatting on Sync



  • This is a very strange article to me.

    Do some tasks run slower today than they did in the past? Sure. Are there some that run slower without a good reason? Sure.

    But the whole article just kind of complains. It never acknowledges that many things are better than they used to be. It also just glosses over the complexities and tradeoffs people have to make in the real world.

    Like this:

    Windows 10 takes 30 minutes to update. What could it possibly be doing for that long? That much time is enough to fully format my SSD drive, download a fresh build and install it like 5 times in a row.

    I don’t know what exactly is involved in Windows updates, but it’s likely 1) a lot of data unpacking, 2) a lot of file patching, and 3) done in a way that hopefully won’t bork your system if something goes wrong.

    Sure, reinstalling is probably faster, but it’s also simpler. If your doctor told you, “The cancer is likely curable. Here’s the best regimen to get you there over the next year”, it would be insane to say, “A YEAR!? I COULD MAKE A WHOLE NEW HUMAN IN A YEAR!” But I feel like the article is doing exactly that, over and over.



  • I’m somewhat confused by your statements, so perhaps I don’t understand.

    Function/objects that allow changing their behavior by passing different objects into them, based on some interface, is called dependency injection. Some subset of behavior is determined by this passed behavior. E.g. To keep a logger class from having to understand how to write logs, you could create a WriteTo interface and various implementations like WriteToDatabase, WriteToFile, WriteToStdout, WriteToNull.

    When you create this example logger, you’ll need to make a choice of what object to pass when you write the code. e.g. new Logger(new WriteToDatabase(config)) But maybe you don’t want to make that decision yet – you want to let a config file decide which writer(s) to create. The pattern to pick between dependencies at runtime is called a factory. In this case, you might make a WriterFactory to pick the right writer, or perhaps a LoggerFactory to hide the creation of both Writer and Factory objects.

    So, a factory is only really a facade to hide the runtime switching of how an object is created.

    Also, the term dependency injection often gets confused with what you see in various Java / C# / and various frameworks in other languages – those usually use what’s called a “DI Container” or “IoC Container”. These manage and facilitate how dependency injection happens within the project, often with various annotations (e.g.@Autowired). These containers are powerful, but sometimes complicated.

    However, you can absolutely still do DI without DI containers, and I think advocating for not using DI generally (and related patterns like factories) is rather misguided.


  • I’ve found pair programming to be fantastic, but only when used rarely in certain situations.

    If you’ve got a good rapport with a teammate and a legacy project has landed in your lap neither of you understand, I’ve found pair programming to be the fastest way to figure out how it works. As you work together, you’ll both understand different parts of it better and be able to quickly figure out what’s going on. I guess this is probably less pair-programming and more like collaborative dissection of code though.

    I’ve also used it to help onboard people on a project fairly quickly. This is more tricky and much less comfortable to do, so I do my best to stay in tune with what they need from me, and tends to be me coding for a bit and them following along and asking questions. Eventually, they want to start writing some code, and a day or so of switching back and forth is as far as I’ve usually taken that. I think it’s useful to break down barriers when working with (especially new) people, to make mistakes in front of them, and build good rapport.

    I’ve not used it much beyond those situations, but I’d definitely use it in these ways again.