diff options
| author | Ahmed Abdelhalim <[email protected]> | 2024-09-05 02:08:31 +0200 |
|---|---|---|
| committer | Ahmed Abdelhalim <[email protected]> | 2024-10-01 23:11:09 +0200 |
| commit | 80a3645bd84fd7f692d662c1380ec31c95972a9b (patch) | |
| tree | dae983a8b31c47a1a31ff6e5c60b52044b6c79e8 /content/blog/slowftware-development.md | |
| parent | 86621240143374869e1f99f860ea334c54f05445 (diff) | |
slowftware development blog post
Diffstat (limited to 'content/blog/slowftware-development.md')
| -rw-r--r-- | content/blog/slowftware-development.md | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/content/blog/slowftware-development.md b/content/blog/slowftware-development.md new file mode 100644 index 0000000..92c0826 --- /dev/null +++ b/content/blog/slowftware-development.md @@ -0,0 +1,398 @@ +--- +title: Slowftware Development +date: 2024-09-30 +draft: false +--- + +# Going fast, slowly +I recently came across an almost [10-year-old blog post][3] on Varnish HTTP Cache +(which was released almost 20 years ago). +In that post, the author shares the LoC (Lines of Code) analysis of Varnish and talks about the average +LoC per hour per developer and how the LoC metric has been used before to judge productivity. + +And although the content of the blog post is quite captivating, and although the LoC metrics themselves are quite +interesting and worth looking at, (for example, ~22% is documentation and ~22% is testing), but ultimately what +captivated me the most, is the following quote +(which I hadn't heard before reading this post): + +> "Perfection is attained, not when there is nothing more to add, but when there is nothing more to remove." <br> +> --- _Antoine de Saint-Exupéry’s observation_ + +**So how does a perfect software look?** + +It's a well-known fact, that software development is quite messy, and unlike any other branch of engineering, it's +also the most tolerating failures and short-comings in design (it shouldn't, but that's a topic for another time). + +There is no perfect software, and there will be none in the future, but there are many good software products +(and software developers) out there, and for anything good to develop, it needs time, **lots** of time. + +The time required is dependent on many factors, including but not limited to, the developer's previous experiences, +the understanding of the problem, the time needed to theorize a solution, and the time needed to code that +solution. + +The first factor, "previous experience," isn't controllable. (at least not for this post purposes).<br> +The last factor, "time to code," is the least important, it can be adjusted (with hiring) or planning costs for the +estimated time required.<br> +The other two factors are the most influential. And the ones that are affecting how correct the "time to code" +estimation will be.<br> +If you don't understand the problem at hand or have developed the wrong solution +(whether it's technically the wrong implementation or design, or conceptually solving the wrong problem), the time spent +grows (linearly at best).<br> + +So, _sometimes_ it's faster to be slower in understanding the problem, theorizing a solution, mapping the solution +components to the proper design patterns, and then starting to code that solution. + +There will always be a discussion on the time this will take and how much market value is being lost because we +are not reacting fast. +That's not to -[anecdotally][9]- mention the cost of having multiple planes nose-dive +because the software solution that needed to be implemented quickly to capitalize on the market wasn't properly designed +with redundancies and proper quality control. + +Now you start to see how going slower is **faster** and **cheaper**.<br> +[Working-backwards](#working-backwards) will help with that, +but let's assume (for now) that one understood the problem correctly, how to "slowly" write the best solution? + +# Worse is better +In 1989, Professor [Richard P. Gabriel][4] wrote an [essay][5] to describe the dynamics of software acceptance. +It is the argument that software quality does not necessarily increase with functionality: that there is +a point where less functionality ("worse") is a preferable option ("better") in terms of practicality and usability. +Software that is limited, but simple to use, may be more appealing to the user and market than the reverse. + +In his [essay][5], he sums up the worse-is-better philosophy as: +- **Simplicity**: the design must be simple, both in implementation and interface. It is more important for the +implementation to be simple than the interface. Simplicity is the most important consideration in a design. +- **Correctness**: the design must be correct in all observable aspects. It is slightly better to be simple than correct. +- **Consistency**: the design must not be overly inconsistent. Consistency can be sacrificed for simplicity +in some cases, but it is better to drop those parts of the design that deal with less common circumstances +than to introduce either implementational complexity or inconsistency. +- **Completeness**: the design must cover as many important situations as is practical. All reasonably expected +cases should be covered. Completeness can be sacrificed in favor of any other quality. In fact, completeness must +be sacrificed whenever implementation simplicity is jeopardized. Consistency can be sacrificed to achieve completeness +if simplicity is retained; especially worthless is consistency of interface. + +And although the philosophy itself advocates for better, but a variation of it was adopted early on by Facebook +and attributed to its founder, Mark Zuckerberg:<br> +"Move fast and break things and the idea was if unless you're breaking some stuff, you aren't moving fast enough". They +used to build software as quickly as possible, even sacrificing correctness for the sake of a quick release.<br> +Another variation was used to justify releasing inferior technology or product sooner than better later. + +The essence of the philosophy is, + +> **when tradeoffs are required in a software system, +> priority should go to implementation simplicity at the expense of completeness or correctness.** + +--- [source][8]. + +This was observed in the [UNIX philosophy][13] +- Make it easy to write, test, and run programs. +- Write programs that do one thing and do it well. +- Write programs to work together. + +And also propagated to many modern languages. For example, [the zen of python][6] emphasizes: +- Beautiful is better than ugly. +- Explicit is better than implicit. +- Simple is better than complex. +- Complex is better than complicated. +- If the implementation is hard to explain, it's a bad idea. +- If the implementation is easy to explain, it may be a good idea. + +Now, taking the goals of simplicity then correctness as the highest priorities in the solution,<br> +how to "slowly" write a "worse" solution? + +# The Agile Manifesto +In 2001, _The Agile Alliance_, a group of 17 software practitioners met at a resort to discuss lightweight development +methods (i.e., Extreme Programming, Scrum, Lean), these lightweight development methods evolved +in reaction to the prevailing _heavyweight_ methods (often referred to collectively as waterfall). + +They wrote down the [Manifesto for Agile Software Development][15], and the 12 +[Principles behind the Agile Manifesto][16]. And although these lightweight methods already preceded the publication +of the Agile Manifesto, they came to be collectively referred to as the agile software development methods. + +Few things have reached far and beyond the reach of the agile manifesto in software development, and fewer things +have had more impact than the agile manifesto in recent years on software development and work methodologies +(both good and bad). + +Over the years, there has been criticism and debate over the agile values, and how they can undermine various +disciplines of the software development process, namely documentation and testing. One example is: + +> In a letter to IEEE Computer, Steven Rakitin expressed cynicism about agile software development, +> calling it "yet another attempt to undermine the discipline of software engineering" and translating +> "**working software over comprehensive documentation**" as "we want to spend all our time coding. +> Remember, real programmers don't write documentation." +> +> This is disputed by proponents of agile software development, who state that developers should write documentation +> if that is the best way to achieve the relevant goals, but that there are often better ways to achieve those goals +> than writing static documentation. + +--- [source][17]. + +Personally, I think that most of the criticism, is targeted towards the interpretation or to be more specific, +the miss-interpretation of the agile principles. That's not to say that there are no merits to the criticism, +but to actually inspect and try to correct the shortcomings of the agile framework. + +In an [article][18] titled, "**Have we taken agile too far?**", [Colin Bryar][19] and [Bill Carr][20] write about +their criticism of agile process, especially in the crucial early stages. + +> Agile is a powerful process for product development, but many organizations are taking it too far and using it +> to avoid careful planning and preparation. + +They elaborate on this deposition that "**Speed Isn't Everything**", they inspect a miss-interpretation of the principle +"**Sustainable development, able to maintain a constant pace**", where the focus is on maintaining a constant pace +rather than being sustainable. + +> The fundamental problem with agile, as many companies use it, is that its relentless pace biases developers. +> They want to get out a minimum viable product in only a few weeks, so they skimp on scoping out just what the +> product should accomplish. Or worse, in our experience, they make two kinds of compromises. +> +> First, rather than take the time and uncertainty to develop a new capability, they go with the skills they currently +> have. They accept their existing constraints, which automatically limits the potential for a high-growth offering. +> +> Second, they curtail their ambitions on the product. Instead of a major breakthrough, they tend toward only +> incremental improvements on existing offerings. Or if they do go bold, their minimum viable product isn’t really +> viable at all, so customers can’t give realistic feedback. The developers haven’t had time to do their homework +> and prepare something that’s sustainable. + +In order to avoid these miss-interpretations and reap the benefits of using agile, they suggest: + +> We’re not arguing that companies should throw agile out the window. It’s still a highly effective tool for product +> development, especially software-driven offerings. Many of its principles and processes have been used successfully +> by Amazon and other companies.<br> +> ...<br> +> The best solution, then, is to combine agile with something like working backwards. Amazon, for example, has learned +> to use the working backwards process for idea development, but then follow agile to build and ship the product. + +# Working Backwards + +Working backwards is a systematic way of vetting ideas to create new products. It starts by defining the +customer experience, then iteratively work backwards from there until the team achieves the clarity of thought +around what to build. + +In their book titled "[**Working Backwards**][21]", authors [Colin Bryar][19] and [Bill Carr][20], describe (among +many other principles and practices) the "working backwards" strategy and how it was developed, its key tenets, and +the practices that emerged from working backwards (i.e., the banning of PowerPoint presentations at Amazon). + +> Working backwards emerged in 2004: Amazon’s e-commerce strategies had proven successful, and the company was +> aggressively seeking new opportunities with a large potential market. Where should it look? +> +> Rather than jumping into developing a plausible product — what an agile mindset might encourage — the company preached +> going slow to go fast. +> +> The working backwards approach requires a fully realized vision of a proposed product, embodied in a written press +> release for the product’s launch. This felt wrong, even unnatural, to software developers and product managers who +> wanted to get going on coding already. +> +> The practice has stuck: To this day Amazon works backwards from what it thinks will delight customers, even if it +> currently lacks the capabilities to make that product. The Kindle e-reader, +> AWS cloud computing services, and the Echo voice assistant with Alexa all came from working backwards. + +--- [source][18]. + +The brilliance of this strategy, is that the iterative process of drafting, reviewing, and refining the PR/FAQ documents +forces the teams and management to take the time to deeply understand not only the problem at hand, +but also the vision of what the product **is** to be, not what the product **might** be +(when developed with agile MVP principles). + +It ensures that everyone involved in the development process, from engineers to marketers, is focused on delivering a +product that genuinely meets customer needs (which is a core principle in agile, +but occasionally miss-placed and miss-used). + +But back to the question: How to "slowly" write an "agilely working-backwards worse" solution? + +# The Big Ball of Mud +> If you think good architecture is expensive, try bad architecture. + +In a [paper][10] published in 1997, Authors [Brian Foote][11], and [Joseph Yoder][12] +examine the most frequently deployed architecture, dubbed "The BIG BALL OF MUD" + +> A BIG BALL OF MUD is a casually, even haphazardly, +> structured system. Its organization, if one can call it that, is dictated more by expediency than design. Yet, +> its enduring popularity cannot merely be indicative of a general disregard for architecture. + +In this paper, the authors examine many of the forces that affect the architecture, including: +- Time. +- Experience. +- Turnover. +- Skill. +- Complexity. +- Change. +- Cost. + +And how these forces can affect the development life-cycles.<br> +The uniqueness of this paper is that it actually doesn't describe the resulting systems as anti-patterns. + +> These are not anti-patterns, at least in the customary sense. They are not straw men. Instead, they seek to +> examine the gap between what we preach and what we practice.<br> +> ...<br> +> BIG BALL OF MUD might be thought of as an anti-pattern, since our intention is to show how passivity in +> the face of forces that undermine architecture can lead to a quagmire. However, its undeniable popularity +> leads to the inexorable conclusion that it is a pattern in its own right. It is certainly a pervasive, recurring +> solution to the problem of producing a working system in the context of software development. It would +> seem to be the path of least resistance when one confronts the sorts of forces discussed above. + +They go even further as to observe that this specific pattern might have a survival advantage over good code, not a +position most companies want to be in, since the cost to maintain, and time to fix bugs increases drastically the longer +the project runs. More over, it can (and almost always) lead to the "TOTAL REWRITE" (which is also as expensive if not +even more expensive, and takes a lot of time too). + +> As per CONWAY’S LAW [Coplien 1995], architects depart in futility, while engineers who have mastered the muddy details +> of the system they have built in their images prevail. [Foote & Yoder 1997] went so far as to observe that inscrutable +> code may, in fact, have a survival advantage over good code, by virtue of being difficult to comprehend and change. +> This advantage can extend to those programmers who can find their ways around such code. + +There are always exceptions of course, for example, the paper mentions how the [Wiki-Web code at c2.com][22] has its +humble origins as a "THROWAWAY CODE" that succeeded beyond the author's expectation, but this is not the rule. The +observations in the paper, and the prevalence of the "BIG BALL OF MUD" or some dialect of it, can almost always be +traced back to the previous forces mentioned, and how their application always undermines the architecture of the system +and results in these undesirable patterns. + +And although the publishing of this paper precedes the publishing of the Agile manifesto, it's hard not to see the +similarities between the common miss-interpretation of the agile principles, and the causes/forces that lead to +develop big balls of mud. + +**A good takeaway from this paper, is how important software architecture is to maintaining a healthy system, that +can be cost-efficiently maintained and relatively fast to fix.** + +> It is not our purpose to condemn BIG BALLS OF MUD. Casual architecture is natural during the early +> stages of a system’s evolution. The reader must surely suspect, however, that our hope is that we can +> aspire to better. By recognizing the forces and pressures that lead to architectural malaise, and how and +> when they might be confronted, we hope to set the stage for the emergence of truly durable artifacts that +> can put architects in dominant positions for years to come. The key is to ensure that the system, its +> programmers, and, indeed the entire organization, learn about the domain, and the architectural +> opportunities looming within it, as the system grows and matures. + +In other words: +> Don't leave "broken windows" (bad designs, wrong decisions, or poor code) unrepaired. Fix each one as soon as it is +> discovered. If there is insufficient time to fix it properly, then board it up. Perhaps you can comment out the +> offending code, or display a "Not Implemented" message, or substitute dummy data instead. Take some action to prevent +> further damage and to show that you're on top of the situation. +> +> We've seen clean, functional systems deteriorate pretty quickly once windows start breaking. There are other factors +> that can contribute to software rot, and we'll touch on some of them elsewhere, but neglect accelerates the rot faster +> than any other factor. + +--- [source][23] + +If the architecture is clear (having boundaries) and clean (following design patterns), it's easy-_ish_ to fix the code, +even if the code is complex or complicated. But if the architecture is not clear or clean, even the most crystal clear +and clean code will eventually become a big ball of mud, it's the law of entropy. + +It is worth mentioning here that, having a design pattern reference guide at arm's length, can go a long way toward +identifying the design pattern(s) that could be employed to solve different or common programming problems. Personally, +I keep the refactoring.guru [book][24] (and [website][25]) close by. + +But back to the question: How to “slowly” write an “agilely working-backwards worse” solution that isn't a "big ball of +mud"? + +# Re-disposable code +In a series of blog posts titled: +1. [Write code that is easy to delete, not easy to extend.][26] +1. [Write code that’s easy to delete, and easy to debug too.][27] +1. [Repeat yourself, do more than one thing, and rewrite everything.][28] + +The [author][29] suggests that instead of focusing on code reusability, one should focus more on code disposability. +The reasoning behind this, is not that it's just more fun to delete code down the line (although it's really fun), but +with the main focus on disposability, it results in a system that is actually more reusable, and less tightly coupled. + +They start with the following quote: +> Every line of code is written without reason, maintained out of weakness, and deleted by chance.<br> +> --- Jean-Paul Sartre’s Programming in ANSI C. + +They then give the steps that one can use when developing a disposable system. These steps are summarized in the +beginning as follows: +> To write code that’s easy to delete: repeat yourself to avoid creating dependencies, but don’t repeat yourself +> to manage them. Layer your code too: build simple-to-use APIs out of simpler-to-implement but clumsy-to-use parts. +> Split your code: isolate the hard-to-write and the likely-to-change parts from the rest of the code, and each other. +> Don’t hard code every choice, and maybe allow changing a few at runtime. +> Don’t try to do all of these things at the same time, and maybe don’t write so much code in the first place. + +These steps and concepts not only embrace the resulting "balls of mud" and keep them at bay, but also utilize the +resulting effects they have on the system to improve system usability by improving the system disposability. +> A system where you can delete parts without rewriting others is often called loosely coupled, +> but it’s a lot easier to explain what one looks like rather than how to build it in the first place.<br> +> ...<br> +> A healthy code base doesn’t have to be perfectly modular. The modular bit makes it way more fun to write code, +> in the same way that Lego bricks are fun because they all fit together. **A healthy code base has some verbosity, +> some redundancy, and just enough distance between the moving parts so you won’t trap your hands inside.** +> +> Code that is loosely coupled isn’t necessarily easy-to-delete, but it is much easier to replace, +> and much easier to change too. + +One of the interesting ideas, is the discectomy between clean and boring code, and how sometimes clean code +isn't desirable since it's harder to debug than boring code, or as the author puts it: +> The problem is that “clean” is highly contextual in meaning. Clean code can be hard-coded into a system, +> and sometimes a dirty hack can written in a way that’s easy to turn off. Sometimes the code is clean because +> the filth has been pushed elsewhere. Good code isn’t necessarily clean code.<br> +> ...<br> +> Instead of clean, we want boring code where change is obvious.<br> +> ...<br> +> It is not to say that clean code is bad, but sometimes the practice of clean coding is more akin to sweeping +> problems under the rug. Debuggable code isn’t necessarily clean, and code that’s littered with checks +> or error handling rarely makes for pleasant reading.<br> +> ...<br> +> **Code that’s easy to debug is easy to explain.** + +Another interesting idea, is the miss-interpretation of "[Don't Repeat Yourself (DRY)][30]" as "Don't Copy Paste". There +is a complete post about miss-using DRY and how it complicates the system design and, in return, makes the system less +reusable and less disposable. + +A healthy level of repetition and redundancy can a lot of times help in maintaining a system that is disposable and +reusable; the "[Avoid Hasty Abstraction (AHA)][31]" is an example of this. + +It can also be seen how these concepts are changing depending on the situation. Sometimes DRY is better than AHA because +it is encapsulating a ball of mud that can be disposable or replaced, yet sometimes AHA is better because [a wrong +abstraction][32] is even more expensive than no abstraction. + +**The bottom line is: There are no silver bullets, use your own judgment.** So +how to “slowly” write a “boring agilely working-backwards worse” solution that is a "disposable small ball of mud"? + +# Slowftware development +_pronounced: /sloʊf(t)ˌwɛə/_: is the answer to the previous question by using the previously mentioned concepts to: +- work-backwards from the customer's or client's point of view. +- identify the right problem that needs to be solved. +- simplify that solution. +- iterate on the simplified solution with different stakeholders. +- start conceptualizing an architecture -based on design patterns if possible-. + +Then, once the theorized solution has been decided: +- write a disposable boring code, that is also easy to debug (and test). +- follow the agile principles, not the agile framework meetings. + +Iterate with the customer, once a meaningful chunk of the work has been delivered, welcome late changes, while +rewriting your code to be more boring, more disposable and more testable. + +Put simply, use the previously mentioned concepts and techniques, to develop disposable, reusable, sustainable +software in a true agile manner -which occasionally can happen in an agile framework-.<br> +Apply those ideas to make both the development environment and output products better, and more sustainable.<br> +Make sure that when you are moving, you are moving into the right direction towards a clear goal, +and not just moving.<br> + +[3]: https://varnish-cache.org/docs/trunk/phk/thatslow.html +[4]: https://en.wikipedia.org/wiki/Richard_P._Gabriel +[5]: https://www.dreamsongs.com/RiseOfWorseIsBetter.html +[6]: https://peps.python.org/pep-0020/ +[7]: https://lkml.iu.edu/hypermail/linux/kernel/1510.3/02866.html +[8]: https://cs.stanford.edu/people/eroberts/courses/cs181/projects/2010-11/WorseIsBetter/index.php/Worse-is-better.html +[9]: https://en.wikipedia.org/wiki/Maneuvering_Characteristics_Augmentation_System#Scrutiny +[10]: https://joeyoder.com/PDFs/mud.pdf +[11]: http://www.laputan.org/ +[12]: https://joeyoder.com/ +[13]: https://en.wikipedia.org/wiki/Unix_philosophy +[14]: https://en.wikipedia.org/wiki/Agile_software_development#History +[15]: https://agilemanifesto.org/ +[16]: https://agilemanifesto.org/principles.html +[17]: https://en.wikipedia.org/wiki/Agile_software_development#Code_vs._documentation +[18]: https://hbr.org/2021/04/have-we-taken-agile-too-far +[19]: https://www.amazon.com/stores/author/B08FRTFQD8/about +[20]: https://www.amazon.com/stores/author/B08HW23WY6/about +[21]: https://www.amazon.com/Working-Backwards-Insights-Stories-Secrets/dp/1250267595 +[22]: https://wiki.c2.com/ +[23]: https://blog.codinghorror.com/the-broken-window-theory/ +[24]: https://refactoring.guru/design-patterns/book +[25]: https://refactoring.guru/design-patterns +[26]: https://programmingisterrible.com/post/139222674273/write-code-that-is-easy-to-delete-not-easy-to +[27]: https://programmingisterrible.com/post/173883533613/code-to-debug +[28]: https://programmingisterrible.com/post/176657481103/repeat-yourself-do-more-than-one-thing-and +[29]: https://mastodon.social/@tef +[30]: https://en.wikipedia.org/wiki/Don't_repeat_yourself +[31]: https://en.wikipedia.org/wiki/Don't_repeat_yourself#AHA +[32]: https://sandimetz.com/blog/2016/1/20/the-wrong-abstraction |
