On Thu, Jul 28, 2011 at 2:16 PM, BGB <[email protected]> wrote: > striving for simplicity can also help, but even simplicity can have costs: > sometimes, simplicity in one place may lead to much higher complexity > somewhere else. [...] > it is better to try to find a simple way to handle issues, rather than try > to
sweep them under the carpet or try to push them somewhere else. I like to call this the difference between 'simple' and 'simplistic'. It is unfortunate that it is so easy to strive for the former and achieve the latter. * Simple is better than complex. * Complex is better than complicated. * Complicated is better than simplistic. The key is that 'simple' must still capture the essential difficulty and complexity of a problem. There really is a limit for 'as simple as possible', and if you breach it you get 'simplistic', which shifts uncaptured complexity unto each client of the model. We can conclude some interesting properties: First, you cannot achieve 'simplicity' without knowing your problem or requirements very precisely. Second, the difference between simple and simplistic only becomes visible for a model, framework, or API when it is shared and scaled to multiple clients and use cases (this allows you to see repetition of the uncaptured complexity). I first made these observations in early 2004, and developed a methodological approach to achieving simplicity: (1) Take a set of requirements. (2) Generate a model that *barely* covers them, precisely as possible. (This will be simplistic.) (3) Explore the model with multiple use-cases, especially at large scales. (Developer stories. Pseudocode.) (4) Identify repetitions, boiler-plate, any stumbling blocks. (5) Distill a new set of requirements. (Not monotonic.) (6) Rinse, wash, repeat until I fail to make discernible progress for a long while. (7) At the end, generate a model that *barely* overshoots the requirements. This methodology works on the simple principle: it's easier to recognize 'simplistic' than 'not quite as simple as possible'. All you need to do is scale the problem (in as many dimensions as possible) and simplistic hops right out of the picture and slaps you in the face. By comparison, unnecessary complexity or power will lurk, invisible to our preconceptions and perspectives - sometimes as a glass ceiling, sometimes as an eroding force, sometimes as brittleness - but always causing scalability issues that don't seem obvious. Most people who live in the model won't even see there is a problem, just 'the way things are', just Blub. The only way to recognize unnecessary power or complexity is to find a simpler way. So, when initially developing a model, it's better to start simplistic and work towards simple. When you're done, at the very edges, add just enough power, with constrained access, to cover the cases you did not foresee (e.g. Turing-complete only at the toplevel, or only with a special object capability). After all, complicated but sufficient *is* better than simplistic or insufficient. I've been repeating this for 7 years now. My model was seeded in 2003 October with the question: *"What would it take to build the cyber-world envisioned in Neal Stephenson's Snow Crash?" *At that time, I had no interest in language design, but that quickly changed after distilling some requirements. I took a bunch of post-grad courses related to language design, compilers, distributed systems, and survivable networking. Of course, my original refinement model didn't really account for inspiration on the way. I've since become interested in command-and-control and data-fusion, which now has a major influence on my model. A requirement discovered in 2010 March led to my current programming model, Reactive Demand Programming, which has been further refined: temporal semantics were added initially to support precise multimedia synchronization in a distributed system, my temporal semantics have been refined to support anticipation (which is useful for ad-hoc coordination, smooth animation, event detection), and my state model was refined twice to support anticipation (via the temporal semantics) and live programming. I *had* to develop a methodological approach to simplicity, because the problem I so gleefully attacked is much, much bigger than I am. (Still is. Besides developing RDP, I've also studied interactive fiction, modular simulations, the accessibility issues for blind access to the virtual world, the possibility of CSS-like transforms on 3D structures, and so on. I have a potentially powerful idea involving multi-agent generative grammars for intelligent controlled creativity and stability in a shared, federated world. I doubt I'll finish *any* of that on my own, except maybe the generative grammars bit.) Most developers are clever, but lack perspective. Their eyes and noses are close to a problem, focused on a local problem and code-smells. When they build atop a *powerful* substrate - such as OOP or monads - composition and integration issues are opaque to them. A common consequence is that their algorithms or DSLs are *simplistic*: they work okay for *a specific* program or example, but they are difficult to integrate in a new context. *Too much power with too little perspective - that is the problem.* * * Developers have recognized this problem, at least implicitly, and so they build frameworks. A framework is an ad-hoc, slow, informally specified, bug-ridden language that is, critically, more constrained than full OOP. The idea is that we write code in the context of a framework, and the constraints imposed on us help with integration. Unfortunately, most frameworks are simplistic, built too close to a problem, and do not integrate nicely with other systems and frameworks. A common consequence is that developers spend more time working around a framework, or adapting between frameworks, than working within them. Still, the goal of frameworks is noble. Just, to make them work, we must start with a large set of diverse problems across many domains, and at enormous scales... millions of developers, integrating thousands of DSLs or frameworks. We need a general framework programming language, one that ensures a large number of compositional properties - most critically, those useful for system integration. This is, in a sense, what my RDP attempts to be. My pursuit of *reactive* programming stems from this requirement directly: if we have reactivity, then abstracting or composing a framework is little different than abstracting or composing any other object. Some people question the value of simplicity. They think complicated is 'good enough'. But these people don't understand that simplicity opens doors that we never realized were closed, raises glass ceilings we didn't realize we were struggling against, and removes performance barriers that we wrongly assumed to be a natural part of our environment (wow! who knew there was a racetrack under all this debris?). A subtle qualitative difference in our abstractions can make huge quantitative and qualitative differences in our emergent systems. Pursuit of simplicity, at scale, tells us just how ineffective and unscalable our systems are today... and offers great hope and optimism for tomorrow. Regards, Dave
_______________________________________________ fonc mailing list [email protected] http://vpri.org/mailman/listinfo/fonc
