summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorAhmed Abdelhalim <[email protected]>2024-09-05 02:08:31 +0200
committerAhmed Abdelhalim <[email protected]>2024-10-01 23:11:09 +0200
commit80a3645bd84fd7f692d662c1380ec31c95972a9b (patch)
treedae983a8b31c47a1a31ff6e5c60b52044b6c79e8 /content
parent86621240143374869e1f99f860ea334c54f05445 (diff)
slowftware development blog post
Diffstat (limited to 'content')
-rw-r--r--content/blog/slowftware-development.md398
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