DailyDogo 963 🐶
DailyDogo 962 🐶
DailyDogo 961 🐶
DailyDogo 960 🐶
DailyDogo 959 🐶
DailyDogo 958 🐶
DailyDogo 957 🐶
DailyDogo 956 🐶
DailyDogo 955 🐶
#100DaysToOffload Reflexions After Two Weeks Of Having Accepted My Ineffectiveness
(I started #100DaysToOffload on the first of June and have written - not including this one - 12 Posts. I guess that’s enough to make it? About a third of my days are spent pressing publish on a blog post. So far so good. Before I finished this paragraph, I was thinking that I was too slow …)
I had reasons to maybe reflect more inwardly for a moment, which is why I didn’t write for a couple of weeks or so. Things at work didn’t go so well, which was mostly because of me being told I was slow (and having been shown incontrovertible evidence proving this) and having to learn and having to un-learn and to accept a new truth about myself: That I am being slow and me being good (as good as I am which is good but not evenly good and certainly not fast) at my work was and is mostly a result of being slow and willing to make up for it by working longer. Which is not a mode of working that is economical and that pays the bills.
In a big company this might not matter as much. You’re embedded within a team, within a project and within a department, which will protect you somewhat from being directly exposed to your impact on the company’s bottom line. But the smaller the company the more directly the way in which you’re contributing to the value that is being created by that company is noticeable. You’ll feel it way quicker and more directed towards yourself if things are out of order if it happens to be cause by the way you work. In my case being called ineffective repeatedly over my first year at the new job was both shocking and accompanied by disbelief and dread. But I only needed to look at my estimates, the time it actually took to implement a feature and how many of the hours the company could actually charge the customer and compare that with my coworkers. The feedback was real and objective. It still took me almost a year to accept it.
As you can imagine: Realizing that you’re slow and ineffective had and still has all sorts of cascading side effects. I reexamine what I believe to know about myself and what I think is true about the nature of work and live in general. Contemplative sense-making has become more of an important part of a good live for me than the only way of being. I notice others that are slower and see companions. Like my barber, for example. And I appreciate that she takes her time. Whereas before I was sure that any criticism of a slow life is just an uninformed un-thought-through opinion, I now come to recognize - intellectually, if not yet experientially/emotionally - that you can maybe also want to be effective instead (or in addition). I still bristle at the insinuation that living an exploratory, tranquil live has anything to do with wasted effort, but I will have to somehow figure out a way to combine economical pressures with the qualities that make a live, no, my live, worth living: Reflexion, focussed attention, taking my time, craftspersonship, exploration, deep understanding, empathy, diversity. I kind of still don’t know what this all means.
I’m willing to find out, though. And what I do understand: That not being effective is what holds me back in my career, maybe in live. So I will have to go through this crucible. I am not making money in a contemplative career - I am no writer, academic, critic or whatever. So I can’t just turn around and proclaim that a fiber of the reality I live in is somehow “wrong” as if there is a choice to be made by me. I may bring myself to call it a negative or bad aspect of a modern, digital, data-driven and market-oriented society, but this still means I’ll have to live with it and master it to the best of my abilities.
DailyDogo 954 🐶
DailyDogo 953 🐶
DailyDogo 952 🐶
I have an iPhone XS and am looking to upgrade soon-ish. What would be the best next iPhone for me? What would give me the best bang for the buck and which recent model is not worth the price?
(iPhone XS 64 gb planning to get more storage)
DailyDogo 951 🐶
DailyDogo 950 🐶
DailyDogo 949 🐶
DailyDogo 948 🐶
DailyDogo 947 🐶
DailyDogo 946 🐶
DailyDogo 945 🐶
DailyDogo 944 🐶
#100DaysToOffload Difference Between Productivity And Efficiency
As I’m trying to figure out how to become more efficient, I need to figure out what that even means, especially because efficiency can be easily confused with productivity. So let’s have some term definitions:
- Productivity measures how high the volume of production in a given time frame is
- Efficiency measure the degree of avoidance of effort during production
So productivity is about how much you can do in a given time and efficiency is about how to avoid extra steps and still get the same job done.
Productivity can be a trap sometimes because it speeds us up to get more done, where a better way would be to do less without producing less output.
In programming, we have two types of work: analytical and implementation work. I think that in both cases there are ways to limit the amount of unnecessary effort.
If the work is analytical, the question is alway what do I need to know right now to make it work? Knowing a little too much about a given module without knowing it all, might make me want to change the code more than I need to. Instead, I should write down what I have learned in my notes system. “How to run the importer without downloading images” could be an example. I would want to know more than that, maybe also how to change the importer, so that it excepts a parameter to not having to monkey around in config files, but knowing where to go and what to comment out is enough and gets the job done.
If the work is implementational (is that a word? now it is!), then there are many ways to exert extra effort: I could create new classes, interfaces, services, methods, refactor unwieldy code, add parameter and return types, make a piece of code behave more according to the architecture, add missing tests, … the list is endless. So far I always looked for best practices within the company or outside the company if there was no consensus yet on how to do things. But best practices add up to become an endless list of what to do and how.
This imagined list of things to do when touching or creating code can have a cascading effect, because change begets more change.
I will have to keep my eyes open for things that I do that strictly speaking don’t need to be done to be a more effective programmer.
#100DaysToOffload Hub "Efficient Programming"
Changelog
- 2024-06-23 - Created this note
- 2024-07-04 - Added “Reflexions After Two Weeks Of Having Accepted My Ineffectiveness”
Note
See Post Hubs for an explanation of these kind of posts.
The efficiency part is where my main problem lies: In order to deliver on time I will need to learn to cut corners and leave messy code as it is and even add my own mess on top of the rest at times.
This doesn’t seem to enable delivering greatness. After having read Slow Productivity recently, that has a completely different philosophy about work - “do fewer things”, “work at a natural pace”, “obsess over quality” are its main points - this job stands at odds with this philosophy (that I am whole heartedly agree with).
I now think that this is not the correct framing. It’s reasonable to assume that I will work for the rest of my career in situations that demand - more or less - efficiency. “Delivering greatness”, in part, is about making it happen under economic constraints. Entrepreneur or salaried worker: This means that I need to be a good investment to be allowed to work on whatever I deem “high quality greatness"™. — Quality And Efficiency
This post was a first attempt at framing the problem of being an ineffective programmer. Before this one, I wrote a very emotional one that was mostly fueled by fear of getting fired for taking too long at work:
It sucks to admit, but I am pretty slow, when just measured on delivered features compared to many others. The main reason is that I am unable, maybe also unwilling, to “just deliver”. — Just Deliver
I am now trying to figure out what makes me inefficient and how I could become more efficient.
After two weeks sitting with the problem I think my framing of overcoming my own ineffectiveness is correct: I will not be able to escape it and it’s good to challenge myself:
#100DaysToOffload Categorizing Code Changes
In an effort to become more efficient, I wondered how I have tackled issues at work so far:
Here’s a little categorization of how I approach different kinds of code changes.
(Disclosure: I don’t do this literally, but intuitively …)
First, I ask myself if the change is trivial or not. Is it just something really small and contained, like changing a constant or what is returned from a method? Or a small visual change? This is so easy that I generally only do that change and nothing else. Maybe I add a type hint or update some kind of documentation if it exists. But that’s it. Hard to get more efficient here.
If the change is more complex, I subdivide this category immediately into two subcategories: is it something entirely new or is it a substantial change of existing code.
What makes these two cases different is the kind of analysis (and implementation; see below) I’m doing. If it’s new stuff, I try to imagine what a good, modern, sustainably maintainable version of the app or website I’m working on might be in general. What would be a good, extendable starting point? Very often the tech stack is set, but the question becomes how to use what is given in the intended/best™ way.
For example I recently was asked to implement a CRUD-App as part of the admin interface of a website. After some probing on what the appropriate tech stack might look like - since I hadn’t yet done a greenfield implementation in this project - I knew what tech stack template to fill out. I decided what layers I needed, what build system to use for the frontend, how to bundle the backend code, how to test the code and how to run those tests in a pipeline on push. Some of these things were realized easily, others took longer, for some of them I had ideas for what modern best practices looked like, for others I had to research them. Because the system this crud app was a part of monolithic “portlet” system that subdivides the contents of a page into reusable widgets, we had to take this into account, even though we didn’t need that much complexity. In the end, I built a relatively modern portlet-compatible crud app. While implementing the core features I learned more about the entities we were dealing with and how they connected to the rest of the website, which meant doing revisions of the main model a bunch of times and it turned out that the JavaScript module had to be relatively complex because we wanted some interactivity that I knew about but hadn’t thought about hard enough beforehand. So yeah. Lots of extra work upfront to make working with this crud app nicer later and a good amount of revisions during the main implementation phase of the mvp to fulfill the architectural and quality criteria I had set for myself.
If it’s a complex code change the cuts across lots of different already existing modules or classes, the question is more how we can make these classes friendlier to accept change in the future in general and how my changes could be implemented in such a way that they themselves can be changed easily. So not only the integration code but also the feature code should be extendable, readable and hopefully easier to reason about after I touched it.
Another task I had was to repair and update a multi-tenant system’s copy tenant functionality. This was a complex task that cut through a big chunk of code. It was extra complex because the legacy system had some quirks you needed to know about and was very hard to test, because some of the classes were autogenerated and copying a tenant took minutes to complete. After a long and sometimes arduous process of trying to understand how the system worked and how its data was organized, I reimplemented the copy tenant functionality that had previously been based on copying its mostly hierarchical data on assumptions that didn’t hold true anymore, so that it would not presume things that would lead to broken tenants, fixed a handful of bugs and unexpected behaviors on the way, but also made sure that the button “copy tenant” basically did what it did before, only now finally correctly. I’m not going to lie: I had tons of help to accomplish this herculean task and it’s not humility that makes me give credit for most of the actual implementation in the end to one of my lead programmers. Big chunks of time were spent understanding the legacy code, figuring out where it went wrong and figuring out where and how to put the corrected code in a mostly non invasive way.
So both kinds of complex change consisted of chunks of implementation and blocks of analysis. Both types had some work that was extra in some way. So let’s look at the details of that.
The implementation of new software consists of creating lots of new files, folders and “hooks” that connect the new to the old. We can always immediately work within best practices: Clear separation of concerns, no spaghetti code, native type hints throughout and tests from the start to name just a few.
Implementation blocks in already existing code of varying degrees of decay is different. We talk about refactoring and just making a sensible “hole”, for us to fill with new features. We may need to change what a method returns, introduce a new service, rework an existing class, by adding properties, methods or making it conform to a new interface to make it more easily replaceable, change were business logic is located, accessed, or what it decides in what way. There are many ways to work with existing code. Some of them are about making the aforementioned hole for our new logic and some of them are about making it easier to comprehend the legacy code. I have yet to work in a project that actually took the time to do systematic refactoring that goes beyond just making a thing work. It’s all rather piecemeal.
The analysis parts are also pretty different: The new stuff consists mostly of understanding the modern best practices in the context of the concrete implementation I’m supposed to do. How does Vite want me to work? How does a modern Symfony bundle look? Should models have fluent setters/getters? Should models be immutable? Many of these kinds of questions are about how to bring ideal conditions into my concrete implementation. On top of best practice questions are questions about how things work. Like Vite for example. It took me some time to figure out how Vite’s library mode actually worked. How Vitest worked. How and why modern Symfony bundle practices wouldn’t work within the context of our legacy system, etc. The last example is also a good example of how we have to figure out how these best practices and technology options out there in the world actually map onto our concrete case. Because sometimes they don’t and we have to figure what that means for the project.
Analysis of old code often means just groking what it does and how it can be changed. If you know nothing like I did when I started working on the copy tenant functionality you may need to figure out the bigger picture as well as the details of the thing you’re actually supposed to change. This has many dimensions to it. From guessing intentions of programmers that came before me, over parsing of algorithms and business logic, following call stacks and simply figuring out where to look to understanding the data that flows through a given system, there is always a lot going on.
When it comes to complex changes especially, but also trivial ones can exhibit this, there is always an amount of extra work involved. This extra work might be part of the analysis blocks or part of the implementation blocks.
This extra work could be adding a code quality tool. Or it could be cleaning up a a method, while making sense of it. Or it could be taking the time to really get into understanding the details of how validation is done. Some of this extra work makes essential work easier. Most of it makes the essential work more fun, I find.
Analyzed like this it becomes more clear to me, that part of my problem of being inefficient is that I enjoy the extra work and that I am kind of stubbornly hoping when embarking on a new programming adventure that the extra work could be my main work. In other words: I am behaving irrationally!
Going forward I’ll have to limit the amount of extra work I do (e.g. less fucking around). That has to be part of the solution. Another point is that figuring out what to do and not fucking around and explore has been traditionally hard for me. I think (hope) that writing things down in a composable way using my trusty notes system will help me figuring out things faster, since I will be able to rediscover what I already figured out before.