diff options
| author | Owen Jacobson <owen.jacobson@grimoire.ca> | 2015-12-09 20:40:42 -0500 |
|---|---|---|
| committer | Owen Jacobson <owen.jacobson@grimoire.ca> | 2015-12-09 20:40:42 -0500 |
| commit | f82d259e7bda843fb63ac1a0f6ff1d6bfb187099 (patch) | |
| tree | 502ebf27ea72cf8c6025b880bfdb35db00ce8b92 /.html/dev | |
| parent | 75a219a061b60bb32948b8a2b71c8ccf1dc19a62 (diff) | |
Remove HTML from the project. (We're no longer using Dokku.)
Diffstat (limited to '.html/dev')
| -rw-r--r-- | .html/dev/_list.html | 122 | ||||
| -rw-r--r-- | .html/dev/buffers.html | 202 | ||||
| -rw-r--r-- | .html/dev/builds.html | 270 | ||||
| -rw-r--r-- | .html/dev/comments.html | 98 | ||||
| -rw-r--r-- | .html/dev/commit-messages.html | 163 | ||||
| -rw-r--r-- | .html/dev/debugger-101.html | 178 | ||||
| -rw-r--r-- | .html/dev/entry-points.html | 134 | ||||
| -rw-r--r-- | .html/dev/gnu-collective-action-license.html | 133 | ||||
| -rw-r--r-- | .html/dev/index.html | 122 | ||||
| -rw-r--r-- | .html/dev/liquibase.html | 151 | ||||
| -rw-r--r-- | .html/dev/merging-structural-changes.html | 156 | ||||
| -rw-r--r-- | .html/dev/rich-shared-models.html | 187 | ||||
| -rw-r--r-- | .html/dev/shutdown-hooks.html | 127 | ||||
| -rw-r--r-- | .html/dev/stop-building-synchronous-web-containers.html | 135 | ||||
| -rw-r--r-- | .html/dev/trackers-from-first-principles.html | 297 | ||||
| -rw-r--r-- | .html/dev/twigs.html | 112 | ||||
| -rw-r--r-- | .html/dev/webapp-versions.html | 111 | ||||
| -rw-r--r-- | .html/dev/webapps.html | 91 | ||||
| -rw-r--r-- | .html/dev/whats-wrong-with-jenkins.html | 172 | ||||
| -rw-r--r-- | .html/dev/why-scm.html | 147 |
20 files changed, 0 insertions, 3108 deletions
diff --git a/.html/dev/_list.html b/.html/dev/_list.html deleted file mode 100644 index f242c8e..0000000 --- a/.html/dev/_list.html +++ /dev/null @@ -1,122 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /dev - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /dev</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="twigs">Branches and Twigs</a></li> - - <li><a href="trackers-from-first-principles">Bugs, Tasks, and Tickets from First Principles</a></li> - - <li><a href="comments">Comment Maturity Model</a></li> - - <li><a href="entry-points">Entry Points</a></li> - - <li><a href="shutdown-hooks">Falsehoods Programmers Believe About Shutdown Hooks</a></li> - - <li><a href="debugger-101">Intro to Debuggers</a></li> - - <li><a href="liquibase">Liquibase</a></li> - - <li><a href="merging-structural-changes">Merging Structural Changes</a></li> - - <li><a href="builds">Nobody Cares About Your Build</a></li> - - <li><a href="buffers">Observations on Buffering</a></li> - - <li><a href="rich-shared-models">Rich Shared Models Must Die</a></li> - - <li><a href="webapp-versions">Semver Is Wrong For Web Applications</a></li> - - <li><a href="whats-wrong-with-jenkins">Something's Rotten in the State of Jenkins</a></li> - - <li><a href="stop-building-synchronous-web-containers">Stop Building Synchronous Web Containers</a></li> - - <li><a href="gnu-collective-action-license">The GPL As Collective Action</a></li> - - <li><a href="webapps">Webapps From The Ground Up</a></li> - - <li><a href="why-scm">Why we use SCM systems</a></li> - - <li><a href="commit-messages">Writing Good Commit Messages</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/buffers.html b/.html/dev/buffers.html deleted file mode 100644 index 839eefd..0000000 --- a/.html/dev/buffers.html +++ /dev/null @@ -1,202 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Observations on Buffering - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - buffers - - </li> - - </ol> - - - - <div id="article"> - <h1 id="observations-on-buffering">Observations on Buffering</h1> -<p>None of the following is particularly novel, but the reminder has been useful:</p> -<ul> -<li> -<p>All buffers exist in one of two states: full (writes outpace reads), or empty - (reads outpace writes). There are no other stable configurations.</p> -</li> -<li> -<p>Throughput on an empty buffer is dominated by the write rate. Throughput on a - full buffer is dominated by the read rate.</p> -</li> -<li> -<p>A full buffer imposes a latency penalty equal to its size in bits, divided by - the read rate in bits per second. An empty buffer imposes (approximately) no - latency penalty.</p> -</li> -</ul> -<p>The previous three points suggest that <strong>traffic buffers should be measured in -seconds, not in bytes</strong>, and managed accordingly. Less obviously, buffer -management needs to be considerably more sophisticated than the usual "grow -buffer when full, up to some predefined maximum size."</p> -<p>Point one also implies a rule that I see honoured more in ignorance than in -awareness: <strong>you can't make a full buffer less full by making it bigger</strong>. Size -is not a factor in buffer fullness, only in buffer latency, so adjusting the -size in response to capacity pressure is worse than useless.</p> -<p>There are only three ways to make a full buffer less full:</p> -<ol> -<li> -<p>Increase the rate at which data exits the buffer.</p> -</li> -<li> -<p>Slow the rate at which data enters the buffer.</p> -</li> -<li> -<p>Evict some data from the buffer.</p> -</li> -</ol> -<p>In actual practice, most full buffers are upstream of some process that's -already going as fast as it can, either because of other design limits or -because of physics. A buffer ahead of disk writing can't drain faster than the -disk can accept data, for example. That leaves options two and three.</p> -<p>Slowing the rate of arrival usually implies some variety of <em>back-pressure</em> on -the source of the data, to allow upstream processes to match rates with -downstream processes. Over-large buffers delay this process by hiding -back-pressure, and buffer growth will make this problem worse. Often, -back-pressure can happen automatically: failing to read from a socket, for -example, will cause the underlying TCP stack to apply back-pressure to the peer -writing to the socket by delaying TCP-level message acknowledgement. Too often, -I've seen code attempt to suppress these natural forms of back-pressure without -replacing them with anything, leading to systems that fail by surprise when -some other resource – usually memory – runs out.</p> -<p>Eviction relies on the surrounding environment, and must be part of the -protocol design. Surprisingly, most modern application protocols get very -unhappy when you throw their data away: the network age has not, sadly, brought -about protocols and formats particularly well-designed for distribution.</p> -<p>If neither back-pressure nor eviction are available, the remaining option is to -fail: either to start dropping data unpredictably, or to cease processing data -entirely as a result of some resource or another running out, or to induce so -much latency that the data is useless by the time it arrives.</p> -<hr> -<p>Some uncategorized thoughts:</p> -<ul> -<li> -<p>Some buffers exist to trade latency against the overhead of coordination. A - small buffer in this role will impose more coordination overhead; a large - buffer will impose more latency.</p> -<ul> -<li> -<p>These buffers appear where data transits between heterogenous system: for - example, buffering reads from the network for writes to disk.</p> -</li> -<li> -<p>Mismanaged buffers in this role will tend to cause the system to spend - an inordinate proportion of latency and throughput negotiating buffer - sizes and message readiness.</p> -</li> -<li> -<p>A coordination buffer is most useful when <em>empty</em>; in the ideal case, the - buffer is large enough to absorb one message's worth of data from the - source, then pass it along to the sink as quickly as possible.</p> -</li> -</ul> -</li> -<li> -<p>Some buffers exist to trade latency against jitter. A small buffer in this - role will expose more jitter to the upstream process. A large buffer in this - role will impose more latency.</p> -<ul> -<li> -<p>These tend to appear in <em>homogenous</em> systems with differing throughputs, - or as a consequence of some other design choice. Store-and-forward - switching in networks, for example, implies that switches must buffer at - least one full frame of network data.</p> -</li> -<li> -<p>Mis-managed buffers in this role will <em>amplify</em> rather than smoothing out - jitter. Apparent throughput will be high until the buffer fills, then - change abruptly when full. Upstream processes are likely to throttle - down, causing them to under-deliver if the buffer drains, pushing the - system back to a high-throughput mode. <a href="http://www.bufferbloat.net">This problem gets worse the - more buffers are present in a system</a>.</p> -</li> -<li> -<p>An anti-jitter buffer is most useful when <em>full</em>; in exchange for a - latency penalty, sudden changes in throughput will be absorbed by data - in the buffer rather than propagating through to the source or sink.</p> -</li> -</ul> -</li> -<li> -<p>Multimedia people understand this stuff at a deep level. Listen to them when - designing buffers for other applications.</p> -</li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/buffers.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/buffers.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/builds.html b/.html/dev/builds.html deleted file mode 100644 index 5626a4e..0000000 --- a/.html/dev/builds.html +++ /dev/null @@ -1,270 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Nobody Cares About Your Build - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - builds - - </li> - - </ol> - - - - <div id="article"> - <h1 id="nobody-cares-about-your-build">Nobody Cares About Your Build</h1> -<p>Every software system, from simple Python packages to huge enterprise-grade -systems spanning massive clusters, has a build—a set of steps that must be -followed to go from a source tree or a checked-out project to a ready-to-use -build product. A build system's job is to automate these steps.</p> -<p>Build systems are critical to software development.</p> -<p>They're also one of the most common avoidable engineering failures.</p> -<p>A reliable, comfortable build system has measurable benefits for software -development. Being able to build a testable, deployable system at any point -during development lets the team test more frequently. Frequent testing -isolates bugs and integration problems earlier, reducing their impact. Simple, -working builds allow new team members to ramp up more quickly on a project: -once they understand how one piece of the system is constructed, they can -apply that knowledge to the entire system and move on to doing useful work. If -releases, the points where code is made available outside the development -team, are done using the same build system that developers use in daily life, -there will be fewer surprises during releases as the “release” build process -will be well-understood from development.</p> -<h2 id="builds-have-needs-too">Builds Have Needs, Too</h2> -<p>In 1947, Abraham Maslow described a <a href="http://en.wikipedia.org/wiki/Maslow's_hierarchy_of_needs">hierarchy of -needs</a> for a -person's physical and mental well-being on the premise that all the items at -the lowest level of the hierarchy must be met before a person will be able to -focus usefully on higher-level needs. Maslow's hierarchy begins with a set of -needs that, without which, you do not have a person (for long)—physiological -needs like “breathing,” “food,” and “water.” At the peak, there are extremely -high-level needs that are about being a happy and enlightened -person—“creativity,” “morality,” “curiosity,” and so on.</p> -<p><img alt="A three-tier pyramid. At the bottom: Automatable. Repeatable. Standardized. -Extensible. Understood. In the middle tier: Simple. Fast. Unit tests. Part of -the project. Environment independent. At the top: Metrics. Parallel builds. -Acceptance tests. Product caching. IDE -integration." src="/media/dev/builds/buildifesto-pyramid.png"></p> -<p>Builds, and software engineering as a whole, can be described the same way: at -the top of the hierarchy is a working system that solves a problem, and at the -bottom are the things you need to have software at all. If you don't meet -needs at a given level, you will eventually be forced to stop what you're -doing at a higher level and face them.</p> -<p>Before a build is a build, there are five key needs to meet:</p> -<ul> -<li><strong>It must be repeatable</strong>. Every time you start your build on a given source - tree, it must build exactly the same products without any further - intervention. Without this, you can't reliably decide whether a given build - is “good,” and can easily wind up with a build that needs to be run several - times, or a build that relies on running several commands in the right - order, to produce a build.</li> -<li><strong>It must be automatable</strong>. Build systems are used by developers sitting at - their desks, but they’re also used by automatic build systems for nightly - builds and continuous integration, and they can be made into parts of other - builds. A build system that can only be run by having someone sit down at a - keyboard and mouse and kicking it off can’t be integrated into anything - else.</li> -<li><strong>It must be standardized</strong>. If you have multiple projects that build - similar things—for example, several Java libraries—all of them must be built - the same way. Without this, it's difficult for a developer to apply - knowledge from one project to another, and it's difficult to debug problems - with individual builds.</li> -<li><strong>It must be extensible</strong>. Not all builds are created equal. Where one build - compiles a set of source files, another needs five libraries and a WSDL - descriptor before it can compile anything. There must be affordances within - the standard build that allow developers to describe the ways their build is - different. Without this, you have to write what amounts to a second build - tool to ensure that all the “extra” steps for certain projects happen.</li> -<li><strong>Someone must understand it</strong>. A build nobody understands is a time bomb: - when it finally breaks (and it will), your project will be crippled until - someone fixes it or, more likely, hacks around it.</li> -</ul> -<p>If you have these five things, you have a working build. The next step is to -make it comfortable. Comfortable builds can be used daily for development -work, demonstrations, and tests as well as during releases; builds that are -used constantly don't get a chance to “rust” as developers ignore them until a -release or a demo and don’t hide surprises for launch day.</p> -<ul> -<li><strong>It must be simple</strong>. When a complicated build breaks, you need someone who - understands it to fix it for you. Simple builds mean more people can - understand it and fewer things can break.</li> -<li><strong>It must be fast</strong>. A slow build will be hacked around or ignored entirely. - Ideally, someone creating a local build for a small change should have a - build ready in seconds.</li> -<li><strong>It must be part of the product</strong>. The team responsible for developing a - project must be in control of and responsible for its build. Changes to it - and bugs against it must be treated as changes to the product or bugs in the - product.</li> -<li><strong>It must run unit tests</strong>. Unit tests, which are completely isolated tests - written by and for developers, can catch a large number of bugs, but they're - only useful if they get run. The build must run the unit test suite for the - product it's building every build.</li> -<li><strong>It must build the same thing in any environment</strong>. A build is no good if - developers can only get a working build from a specific machine, or where a - build from one developer's machine is useless anywhere else. If the build is - uniform on any environment, any developer can cook up a build for a test or - demo at any time.</li> -</ul> -<p>Finally, there are “chrome” features that take a build from effective to -excellent. These vary widely from project to project and from organization to -organization. Here are some common chrome needs:</p> -<ul> -<li><strong>It should integrate with your IDEs</strong>. This goes both directions: it should - be possible to run the build without leaving your IDE or editor suite, and - it should be possible to translate the build system into IDE-specific - configurations to reduce duplication between IDE settings and the build - configuration.</li> -<li><strong>It should generate metrics</strong>. If you gather metrics for test coverage, - common bugs, complexity analysis, or generate reports or documentation, the - build system should be responsible for it. This keeps all the common - administrative actions for the project in the same place as the rest of the - configuration, and provides the same consistency that the system gives the - rest of the build.</li> -<li><strong>It should support multiple processors</strong>. For medium-sized builds that - aren’t yet large enough to merit breaking down into libraries, being able to - perform independent build steps in parallel can be a major time-saver. This - can extend to distributed build systems, where idle CPU time can be donated - to other peoples’ builds.</li> -<li><strong>It should run integration and acceptance tests</strong>. Taking manual work from - the quality control phase of a project and running it automatically during - builds amplifies the benefits of early testing and, if your acceptance tests - are good, when your project is done.</li> -<li><strong>It should not need repeating</strong>. Once you declare a particular set of build - products “done,” you should be able to use those products as-is any time you - need them. Without this, you will eventually find yourself rebuilding the - same code from the same release over and over again.</li> -</ul> -<h2 id="what-doesnt-work">What Doesn’t Work</h2> -<p>Builds, like any other part of software development, have -antipatterns—recurring techniques for solving a problem that introduce more -problems.</p> -<ul> -<li><strong>One Source Tree, Many Products</strong>. Many small software projects that - survive to grow into large, monolithic projects are eventually broken up - into components. It's easy to do this by taking the existing source tree and - building parts of it, and it's also wrong. Builds that slice up a single - source tree require too much discipline to maintain and too much mental - effort to understand. Break your build into separate projects that are built - separately, and have each build produce one product.</li> -<li><strong>The Build And Deploy System</strong>. Applications that have a server component - often choose to automate deployment and setup using the same build system - that builds the project. Too often, the extra build steps that set up a - working system from the built project are tacked onto the end of an existing - build. This breaks standardization, making that build harder to understand, - and means that that one build is producing more than one thing—it's - producing the actual project, and a working system around the project.</li> -<li><strong>The Build Button</strong>. IDEs are really good at editing code. Most of them - will produce a build for you, too. Don't rely on IDE builds for your build - system, and don't let the IDE reconfigure the build process. Most IDEs don't - differentiate between settings that apply to the project and settings that - apply to the local environment, leading to builds that rely on libraries or - other projects being in specific places and on specific IDE settings that - are often buried in complex settings dialogs.</li> -<li><strong>Manual Steps</strong>. Anything that gets done by hand will eventually be done - wrong. Automate every step.</li> -</ul> -<h2 id="what-does-work">What Does Work</h2> -<p>Similarly, there are patterns—solutions that recur naturally and can be -applied to many problems.</p> -<ul> -<li><strong>Do One Thing Well</strong>. The UNIX philosophy of small, cohesive tools works - for build systems, too: if you need to build a package, and then install it - on a server, write three builds: one that builds the package, one that takes - a package and installs it, and a third that runs the first two builds in - order. The individual builds will be small enough to easily understand and - easy to standardize, and the package ends up installed on the server when - the main build finishes.</li> -<li><strong>Dependency Repositories</strong>. After a build is done, make the built product - available to other builds and to the user for reuse rather than rebuilding - it every time you need it. Similarly, libraries and other inward - dependencies for a build can be shared between builds, reducing duplication - between projects.</li> -<li><strong>Convention Over Extension</strong>. While it's great that your build system is - extensible, think hard about whether you really need to extend your build. - Each extension makes that project’s build that much harder to understand and - adds one more point of failure.</li> -</ul> -<h2 id="pick-a-tool-any-tool">Pick A Tool, Any Tool</h2> -<p>Nothing here is new. The value of build systems has been -<a href="http://www.joelonsoftware.com/articles/fog0000000043.html">discussed</a> -<a href="http://www.gamesfromwithin.com/articles/0506/000092.html">in</a> -<a href="http://c2.com/cgi/wiki?BuildSystem">great</a> -<a href="http://www.codinghorror.com/blog/archives/000988.html">detail</a> elsewhere. -Much of the accumulated build wisdom of the software industry has already been -incorporated to one degree or another into build tools. What matters is that -you pick one, then use it with the discipline needed to get repeatable results -without thinking.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/builds.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/builds.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/comments.html b/.html/dev/comments.html deleted file mode 100644 index 4f891c9..0000000 --- a/.html/dev/comments.html +++ /dev/null @@ -1,98 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Comment Maturity Model - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - comments - - </li> - - </ol> - - - - <div id="article"> - <h1 id="comment-maturity-model">Comment Maturity Model</h1> -<blockquote> -<ul> -<li>Beginners comment nothing</li> -<li>Apprentices comment the obvious</li> -<li>Journeymen comment the reason for doing it</li> -<li>Masters comment the reason for not doing it another way</li> -</ul> -</blockquote> -<p>Richard C. Haven, via <a href="http://cluefire.net/">cluefire.net</a></p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/comments.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/comments.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/commit-messages.html b/.html/dev/commit-messages.html deleted file mode 100644 index 45a580e..0000000 --- a/.html/dev/commit-messages.html +++ /dev/null @@ -1,163 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Writing Good Commit Messages - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - commit-messages - - </li> - - </ol> - - - - <div id="article"> - <h1 id="writing-good-commit-messages">Writing Good Commit Messages</h1> -<p>Rule zero: “good” is defined by the standards of the project you're on. Have a -look at what the existing messages look like, and try to emulate that first -before doing anything else.</p> -<p>Having said that, here are some things that will help your commit messages be -useful later:</p> -<ul> -<li> -<p>Treat the first line of the message as a one-sentence summary. Most SCM - systems have an “overview” command that shows shortened commit messages in - bulk, so making the very beginning of the message meaningful helps make - those modes more useful for finding specific commits. <em>It's okay for this to - be a “what” description</em> if the rest of the message is a “why” description.</p> -</li> -<li> -<p>Fill out the rest of the message with prose outlining why you made the - change. The guidelines for a good “why” message are the same as <a href="comments">the - guidelines for good comments</a>, but commit messages can be - signifigantly longer. Don't bother reiterating the contents of the change in - detail; anyone who needs that can read the diff themselves.</p> -</li> -<li> -<p>If you use an issue tracker (and you should), include whatever issue-linking - notes it supports right at the start of the message, where it'll be visible - even in shortlogs. If your tracker has absurdly long issue-linking syntax, - or doesn't support issue links in commits at all, include a short issue - identifier at the front of the message and put the long part somewhere out - of the way, such as on a line of its own at the end of the message.</p> -</li> -<li> -<p>Pick a tense and a mood and stick with them. Reading one commit with a - present-tense imperative message (“Add support for PNGs”) and another commit - with a past-tense narrative message (“Fixed bug in PNG support”) is - distracting.</p> -</li> -<li> -<p>If you need rich commit messages (links, lists, and so on), pick one markup - language and stick with it. It'll be easier to write useful commit - formatters if you only have to deal with one syntax, rather than four. - (Personally, I use Markdown on projects I control.)</p> -<ul> -<li>This also applies to line-wrapping: either hard-wrap everywhere, or - hard-wrap nowhere.</li> -</ul> -</li> -</ul> -<h2 id="an-example">An Example</h2> -<pre><code>commit 842e6c5f41f6387781fcc84b59fac194f52990c7 -Author: Owen Jacobson <owen.jacobson@grimoire.ca> -Date: Fri Feb 1 16:51:31 2013 -0500 - - DS-37: Add support for privileges, and create a default privileged user. - - This change gives each user a (possibly empty) set of privileges. Privileges - are mediated by roles in the following ways: - - * Each user is a member of zero or more roles. - * Each role implies membership in zero or more roles. If role A implies role - B, then a member of role A is also a transitive member of role B. This - relationship is transitive: if A implies B and B implies C, then A implies - C. This graph should not be cyclic, but it's harmless if it is. - * Each role grants zero or more privileges. - - A user's privileges are the union of all privileges of all roles the user is a - member of, either directly or transitively. - - Obviously, a role that implies no other roles and grants no priveleges is - meaningless to the authorization system. This may be useful for "advisory" - roles meant for human consumption. - - This also introduces a user with the semi-magical name '*admin' (chosen - because asterisks cannot collide with player-chosen usernames), and the group - '*superuser' that is intended to hold all privileges. No privileges are yet - defined. -</code></pre> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/commit-messages.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/commit-messages.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/debugger-101.html b/.html/dev/debugger-101.html deleted file mode 100644 index a19476a..0000000 --- a/.html/dev/debugger-101.html +++ /dev/null @@ -1,178 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Intro to Debuggers - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - debugger-101 - - </li> - - </ol> - - - - <div id="article"> - <h1 id="intro-to-debuggers">Intro to Debuggers</h1> -<p>(Written largely because newbies in <a href="http://evanchooly.com">##java</a> never seem -to have this knowledge.)</p> -<p>A “debugger” is a mechanism for monitoring and controlling the execution of -your program, usually interactively. Using a debugger, you can stop your -program at known locations and examine the <em>actual</em> values of its variables -(to compare against what you expected), monitor variables for changes (to see -where they got the values they have, and why), and step through code a line at -a time (to watch control flow and verify that it matches your expectations).</p> -<p>Pretty much every worthwhile language has debugging support of some kind, -whether it's via IDE integration or via a command-line debugger.</p> -<p>(Of course, none of this helps if you don't have a mental model of the -“expected” behaviour of the program. Debuggers can help you read, but can't -replace having an understanding of the code.)</p> -<h2 id="debugging-your-first-program">Debugging Your First Program</h2> -<p>Generally, you start running a debugger because you have a known problem -- an -exception, or code behaving strangely -- somewhere in your program that you -want to investigate more closely. Start by setting a <em>breakpoint</em> in your -program at a statement slightly before the problem area.</p> -<p>Breakpoints are instructions to the debugger, telling it to stop execution -when the program reaches the statement the breakpoint is set on.</p> -<p>Run the program in the debugger. When it reaches your breakpoint, execution -will stop (and your program will freeze, rather than exiting). You can now -<em>inspect</em> values and run expressions in the context of your program in its -current state. Depending on the debugger and the platform, you may be able to -modify those values, too, to quickly experiment with the problem and attempt -to solve it.</p> -<p>Once you've looked at the relevant variables, you can resume executing your -program - generally in one of five ways:</p> -<ul> -<li> -<p><em>Continue</em> execution normally. The debugger steps aside until the program - reaches the next breakpoint, or exits, and your program executes normally.</p> -</li> -<li> -<p>Execute the <em>next</em> statement. Execution proceeds for one statement in the - current function, then stops again. If the statement is, for example, a - function or method call, the call will be completely evaluated (unless it - contains breakpoints of its own). (In some debuggers, this is labelled “step - over,” since it will step “over” a function call.)</p> -</li> -<li> -<p><em>Step</em> forward one operation. Execution proceeds for one statement, then - stops again. This mode can single-step into function calls, rather than - letting them complete uninterrupted.</p> -</li> -<li> -<p><em>Continue to end of function</em>. The debugger steps aside until the program - reaches the end of the current function, then halts the program again.</p> -</li> -<li> -<p><em>Continue to a specific statement</em>. Some debuggers support this mode as a - way of stepping over or through “uninteresting” sections of code quickly and - easily. (You can implement this yourself with “Continue” and normal - breakpoints, too.)</p> -</li> -</ul> -<p>Whenever the debugger halts your program, you can do any of several things:</p> -<ul> -<li> -<p>Inspect the value of a variable or field, printing a useful representation - to the debugger. This is a more flexible version of the basic idea of - printing debug output as you go: because the program is stopped, you can - pick and choose which bits of information to look at on the fly, rather than - having to rerun your code with extra debug output.</p> -</li> -<li> -<p>Inspect the result of an expression. The debugger will evaluate an - expression “as if” it occurred at the point in the program where the - debugger is halted, including any local variables. In languages with static - visibility controls like Java, visibility rules are often relaxed in the - name of ease of use, allowing you to look at the private fields of objects. - The result of the expression will be made available for inspection, just - like a variable.</p> -</li> -<li> -<p>Modify a variable or field. You can use this to quickly test hypotheses: for - example, if you know what value a variable “should” have, you can set that - value directly and observe the behaviour of the program to check that it - does what you expected before fixing the code that sets the variable in a - non-debug run.</p> -</li> -<li> -<p>In some debuggers, you can run arbitrary code in the context of the halted - program.</p> -</li> -<li> -<p>Abort the program.</p> -</li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/debugger-101.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/debugger-101.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/entry-points.html b/.html/dev/entry-points.html deleted file mode 100644 index 717c320..0000000 --- a/.html/dev/entry-points.html +++ /dev/null @@ -1,134 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Entry Points - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - entry-points - - </li> - - </ol> - - - - <div id="article"> - <h1 id="entry-points">Entry Points</h1> -<p>The following captures a conversation from IRC:</p> -<blockquote> -<p><a href="https://twitter.com/derspiny">Owen J</a>: Have you run across the idea -of an "entry point" in a runtime yet? (You've definitely used it, just -possibly not known it had a name.)</p> -<p><a href="https://twitter.com/aeleitch">Alex L</a>: I have not!</p> -<p><a href="https://twitter.com/derspiny">Owen J</a>: It's the point where the -execution of the outside system -- the OS, the browser, the Node -runtime, whatever -- stops and the execution of your code starts. Some -platforms only give you one: C on Unix is classic, where there's only -two entry points: main and signal handlers (and a lot of apps only use -main). JS gives you <em>a shit fucking ton</em> of entry points.</p> -<p><a href="https://twitter.com/derspiny">Owen J</a>: In a browser, the pageload -process is an entry point: your code gets run when the browser -encounters a <code><script></code> tag. So is every event handler. There's none -of your code running when an event handler starts, only the browser -is running. So is every callback from an external service, like -<code>XmlHttpRequest</code> or <code>EventSource</code> or the <code>File</code> APIs. In Node, the top -level of your main script is an entry point, but so is every callback -from an external service.</p> -<p><a href="https://twitter.com/aeleitch">Alex L</a>: Ahahahahahahaha oh my -god. There is no way for me to contain them all. <em>everything the light -touches.</em></p> -<p><a href="https://twitter.com/derspiny">Owen J</a>: This is important for -reasoning about exception handling! <em>In JS</em>, exception handling only -propagates one direction: towards the entry point of this sequence of -function calls.</p> -<p><a href="https://twitter.com/aeleitch">Alex L</a>: Yes. This is what <em>I</em> call a -stack trace.</p> -<p><a href="https://twitter.com/derspiny">Owen J</a>: If an exception escapes from -an entry point, the JS runtime logs it, and then the outside runtime -takes over again. That's one of the ways callbacks from external -services fuck up the idea of a stack trace as a map of control flow.</p> -<p><a href="https://twitter.com/aeleitch">Alex L</a>: Huh. Yes. Yes I can see -that. I mean, in my world, control flow is a somewhat handwavey idea -right now. I'm starting to understand why so many people hate JS-land.</p> -<p><a href="https://twitter.com/derspiny">Owen J</a>: Sure. But, for example, a -promise chain is a tool for restructuring control flow. In principle, -error handling should provide <em>some</em> kind of map of that, to allow -programmers -- you -- to diagnose how a program reached a given error -state and maybe one day fix the problem. In THIS future, none of them -do that well, though.</p> -<p><a href="https://twitter.com/aeleitch">Alex L</a>: Yes. Truly the darkest -timeline, but this reviews why I am having these concerns.</p> -</blockquote> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/entry-points.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/entry-points.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/gnu-collective-action-license.html b/.html/dev/gnu-collective-action-license.html deleted file mode 100644 index f2adbea..0000000 --- a/.html/dev/gnu-collective-action-license.html +++ /dev/null @@ -1,133 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - The GPL As Collective Action - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - gnu-collective-action-license - - </li> - - </ol> - - - - <div id="article"> - <h1 id="the-gpl-as-collective-action">The GPL As Collective Action</h1> -<p>Programmers, like many groups of subject experts, are widely afflicted by the -belief that all other fields of expertise can be reduced to a special case of -programming expertise. For a great example of this, watch <a href="https://xkcd.com/1494/">programmers argue -about law</a> (which can <em>obviously</em> be reduced to a rules -system, which is a programming problem), -<a href="https://www.reddit.com/r/Bitcoin/comments/2e5a7k/could_the_blockchain_be_used_to_prove_consensual/">consent</a> -(which is <em>obviously</em> about non-repudiatable proofs, which are a programming -problem), or <a href="https://github.com/google/deepdream">art</a> (which is <em>obviously</em> -reducible to simple but large automata). One key symptom of this social pattern -is a disregard for outside expertise and outside bodies of knowledge.</p> -<p>I believe this habit may have bitten Stallman.</p> -<p>The GNU Public License presents a simple, legally enforceable offer: in return -for granting the right to distribute the licensed work and its derivatives, the -GPL demands that derivative works also be released under the GPL. The <em>intent</em>, -as derived from -<a href="http://www.gnu.org/philosophy/open-source-misses-the-point.en.html">Stallman’s commentaries</a> -on the GPL and on the social systems around software, is that people who <em>use</em> -information systems should, morally and legally, be entitled to the tools to -understand what the system will do and why, and to make changes to those tools -as they see fit.</p> -<p>This is a form of <em>collective action</em>, as implemented by someone who thinks of -unions and organized labour as something that software could do better. The -usual lens for critique of the GPL is that GPL’d software cannot be used in -non-GPL systems (which is increasingly true, as the Free Software Foundation -catches up with the “as a Service” model of software deliver) <em>by developers</em>, -but I think there’s a more interesting angle on it as an attempt to apply the -collective bargaining power of programmers as a class to extracting a -concession from managerial -- business and government -- interests, instead. In -that reading, the GPL demands that managerial interests in software avoid -behaviours that would be bad for programmers (framed as “users”, as above) as a -condition of benefitting from the labour of those programmers.</p> -<p>Sadly, Stallman is not a labour historian or a union organizer. He’s a public -speaker and a programmer. By attempting to reinvent collective action from -first principles, and by treating collective action as a special case of -software development, the GPL acts to divide programmers from non-programming -computer users, and to weaken the collective position of programmers vis-à-vis -managerial interests. The rise of “merit”-based open source licenses, such as -the MIT license (which I use heavily, but advisedly), and the increasing -pervasiveness of the Github Resume, are both simple consequences of this -mistake.</p> -<p>I’m pro-organized-labour, and largely pro-union. The only thing worse than -having two competing powerful interests in the room is having only one powerful -interest in the room. The GPL should be part of any historical case study for -the unionization of programmers, since it captures so much of what we do wrong.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/gnu-collective-action-license.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/gnu-collective-action-license.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/index.html b/.html/dev/index.html deleted file mode 100644 index f242c8e..0000000 --- a/.html/dev/index.html +++ /dev/null @@ -1,122 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - ls /dev - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - <span class="list-crumb">list</span> - - </li> - - </ol> - - - - <div id="listing"> - <h1><code>ls /dev</code></h1> - - - - - <div id="pages"> - <h2>Pages</h2> - <ul> - - <li><a href="twigs">Branches and Twigs</a></li> - - <li><a href="trackers-from-first-principles">Bugs, Tasks, and Tickets from First Principles</a></li> - - <li><a href="comments">Comment Maturity Model</a></li> - - <li><a href="entry-points">Entry Points</a></li> - - <li><a href="shutdown-hooks">Falsehoods Programmers Believe About Shutdown Hooks</a></li> - - <li><a href="debugger-101">Intro to Debuggers</a></li> - - <li><a href="liquibase">Liquibase</a></li> - - <li><a href="merging-structural-changes">Merging Structural Changes</a></li> - - <li><a href="builds">Nobody Cares About Your Build</a></li> - - <li><a href="buffers">Observations on Buffering</a></li> - - <li><a href="rich-shared-models">Rich Shared Models Must Die</a></li> - - <li><a href="webapp-versions">Semver Is Wrong For Web Applications</a></li> - - <li><a href="whats-wrong-with-jenkins">Something's Rotten in the State of Jenkins</a></li> - - <li><a href="stop-building-synchronous-web-containers">Stop Building Synchronous Web Containers</a></li> - - <li><a href="gnu-collective-action-license">The GPL As Collective Action</a></li> - - <li><a href="webapps">Webapps From The Ground Up</a></li> - - <li><a href="why-scm">Why we use SCM systems</a></li> - - <li><a href="commit-messages">Writing Good Commit Messages</a></li> - - </ul> - </div> - - - - </div> - - - - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev">See this directory on Bitbucket</a>. - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/liquibase.html b/.html/dev/liquibase.html deleted file mode 100644 index 64b19c5..0000000 --- a/.html/dev/liquibase.html +++ /dev/null @@ -1,151 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Liquibase - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - liquibase - - </li> - - </ol> - - - - <div id="article"> - <h1 id="liquibase">Liquibase</h1> -<p>Note to self: I think this (a) needs an outline and (b) wants to become a “how -to automate db upgrades for dummies” page. Also, this is really old (~2008) -and many things have changed: database migration tools are more -widely-available and mature now. On the other hand, I still see a lot of -questions on IRC that are based on not even knowing these tools exist.</p> -<hr> -<p>Successful software projects are characterized by extensive automation and -supporting tools. For source code, we have version control tools that support -tracking and reviewing changes, marking particular states for release, and -automating builds. For databases, the situation is rather less advanced in a -lot of places: outside of Rails, which has some rather nice -<a href="http://wiki.rubyonrails.org/rails/pages/understandingmigrations">migration</a> -support, and <a href="http://code.google.com/p/django-evolution/">evolutions</a> or -<a href="http://south.aeracode.org">South</a> for Django, there are few tools that -actually track changes to the database or to the model in a reproducible way.</p> -<p>While I was exploring the problem by writing some scripts for my own projects, -I came to a few conclusions. You need to keep a receipt for the changes a -database has been exposed to in the database itself so that the database can -be reproduced later. You only need scripts to go forward from older versions -to newer versions. Finally, you need to view <abbr title="Data Definition Language">DDL</abbr> statements as a degenerate -form of diff, between two database states, that's not combinable the way -textual diff is except by concatenation.</p> -<p>Someone on IRC mentioned <a href="http://www.liquibase.org/">Liquibase</a> and -<a href="http://migrate4j.sourceforge.net/">migrate4j</a> to me. Since I was already in -the middle of writing a second version of my own scripts to handle the issues -I found writing the first version, I stopped and compared notes.</p> -<p>Liquibase is essentially the tool I was trying to write, only with two years -of relatively talented developer time poured into it rather than six weeks.</p> -<p>Liquibase operates off of a version table it maintains in the database itself, -which tracks what changes have been applied to the database, and off of a -configuration file listing all of the database changes. Applying new changes -to a database is straightforward: by default, it goes through the file and -applies all the changes that are in the file that are not already in the -database, in order. This ensures that incremental changes during development -are reproduced in exactly the same way during deployment, something lots of -model-to-database migration tools have a problem with.</p> -<p>The developers designed the configuraton file around some of the ideas from -<a href="http://www.amazon.com/Refactoring-Databases-Evolutionary-Addison-Wesley-Signature/dp/0321293533">Refactoring -Databases</a>, -and provided an <a href="http://www.liquibase.org/manual/home#available_database_refactorings">extensive list of canned -changes</a> -as primitives in the database change scripts. However, it's also possible to -insert raw SQL commands (either <abbr title="Data Definition Language">DDL</abbr>, or <abbr title="Data Manipulation Language">DML</abbr> queries like <code>SELECT</code>s and -<code>INSERT</code>s) at any point in the change sequence if some change to the database -can't be accomplished with its set of refactorings. For truly hairy databases, -you can use either a Java class implementing your change logic or a shell -script alongside the configuration file.</p> -<p>The tools for applying database changes to databases are similarly flexible: -out of the box, liquibase can be embedded in a fairly wide range of Java -applications using servlet context listeners, a Spring adapter, or a Grails -adapter; it can also be run from an ant or maven build, or as a standalone -tool.</p> -<p>My biggest complaint is that liquibase is heavily Java-centric; while the -developers are planning .Net support, it'd be nice to use it for Python apps -as well. Triggering liquibase upgrades from anything other than a Java program -involves either shelling out to the <code>java</code> command or creating a JVM and -writing native glue to control the upgrade process, which are both pretty -painful. I'm also less than impressed with the javadoc documentation; while -the manual is excellent, the javadocs are fairly incomplete, making it hard to -write customized integrations.</p> -<p>The liquibase developers deserve a lot of credit for solving a hard problem -very cleanly.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/liquibase.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/liquibase.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/merging-structural-changes.html b/.html/dev/merging-structural-changes.html deleted file mode 100644 index a019d9c..0000000 --- a/.html/dev/merging-structural-changes.html +++ /dev/null @@ -1,156 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Merging Structural Changes - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - merging-structural-changes - - </li> - - </ol> - - - - <div id="article"> - <h1 id="merging-structural-changes">Merging Structural Changes</h1> -<p>In 2008, a project I was working on set out to reinvent their build process, -migrating from a mass of poorly-written Ant scripts to Maven and reorganizing -their source tree in the process. The development process was based on having -a branch per client, so there was a lot of ongoing development on the original -layout for clients that hadn't been migrated yet. We discovered that our -version control tool, <a href="http://subversion.tigris.org/">Subversion</a>, was unable -to merge the changes between client branches on the old structure and the -trunk on the new structure automatically.</p> -<p>Curiousity piqued, I cooked up a script that reproduces the problem and -performs the merge from various directions to examine the results. Subversion, -sadly, performed dismally: none of the merge scenarios tested retained content -changes when merging structural changes to the same files.</p> -<h2 id="the-preferred-outcome">The Preferred Outcome</h2> -<p><img alt="Both changes survive the -merge." src="/media/dev/merging-structural-changes/ideal-merge-results.png"></p> -<p>The diagram above shows a very simple source tree with one directory, <code>dir-a</code>, -containing one file with two lines in it. On one branch, the file is modified -to have a third line; on another branch, the directory is renamed to <code>dir-b</code>. -Then, both branches are merged, and the resulting tree contains both sets of -changes: the file has three lines, and the directory has a new name.</p> -<p>This is the preferred outcome, as no changes are lost or require manual -merging.</p> -<h2 id="subversion">Subversion</h2> -<p><img alt="Subversion loses the content -change." src="/media/dev/merging-structural-changes/subversion-merge-results.png"></p> -<p>There are two merge scenarios in this diagram, with almost the same outcome. -On the left, a working copy of the branch where the file's content changed is -checked out, then the changes from the branch where the structure changed are -merged in. On the right, a working copy of the branch where the structure -changed is checked out, then the changes from the branch where the content -changed are merged in. In both cases, the result of the merge has the new -directory name, and the original file contents. In one case, the merge -triggers a rather opaque warning about a “missing file”; in the other, the -merge silently ignores the content changes.</p> -<p>This is a consequence of the way Subversion implements renames and copies. -When Subversion assembles a changeset for committing to the repository, it -comes up with a list of primitive operations that reproduce the change. There -is no primitive that says “this object was moved,” only primitives which say -“this object was deleted” or “this object was added, as a copy of that -object.” When you move a file in Subversion, those two operations are -scheduled. Later, when Subversion goes to merge content changes to the -original file, all it sees is that the file has been deleted; it's completely -unaware that there is a new name for the same file.</p> -<p>This would be fairly easy to remedy by adding a “this object was moved to that -object” primitive to the changeset language, and <a href="http://subversion.tigris.org/issues/show_bug.cgi?id=898">a bug report for just such a -feature</a> was filed in -2002. However, by that time Subversion's repository and changeset formats had -essentially frozen, as Subversion was approaching a 1.0 release and more -important bugs <em>without</em> workarounds were a priority.</p> -<p>There is some work going on in Subversion 1.6 to handle tree conflicts (the -kind of conflicts that come from this kind of structural change) more -sensibly, which will cause the two merges above to generate a Conflict result, -which is not as good as automatically merging it but far better than silently -ignoring changes.</p> -<h2 id="mercurial">Mercurial</h2> -<p><img alt="Mercurial preserves the content -change." src="/media/dev/merging-structural-changes/mercurial-merge-results.png"></p> -<p>Interestingly, there are tools which get this merge scenario right: the -diagram above shows how <a href="http://www.selenic.com/mercurial/">Mercurial</a> handles -the same two tests. Since its changeset language does include an “object -moved” primitive, it's able to take a content change for <code>dir-a/file</code> and -apply it to <code>dir-b/file</code> if appropriate.</p> -<h2 id="git">Git</h2> -<p>Git also gets this scenario right, <em>usually</em>. Unlike Mercurial, Git does not -track file copies or renames in its commits at all, prefering to infer them by -content comparison every time it performs a move-aware operation, such as a -merge.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/merging-structural-changes.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/merging-structural-changes.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/rich-shared-models.html b/.html/dev/rich-shared-models.html deleted file mode 100644 index c4d167c..0000000 --- a/.html/dev/rich-shared-models.html +++ /dev/null @@ -1,187 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Rich Shared Models Must Die - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - rich-shared-models - - </li> - - </ol> - - - - <div id="article"> - <h1 id="rich-shared-models-must-die">Rich Shared Models Must Die</h1> -<p>In a gaming system I once worked on, there was a single class which was -responsible for remembering everything about a user: their name and contact -information, their wagers, their balance, and every other fact about a user -the system cared about. In a system I'm working with now, there's a set of -classes that collaborate to track everything about the domain: prices, -descriptions, custom search properties, and so on.</p> -<p>Both of these are examples of shared, system-wide models.</p> -<p>Shared models are evil.</p> -<p>Shared models <em>must be destroyed</em>.</p> -<p>A software system's model is the set of functions and data types it uses to -decide what to do in response to various events. Models embody the development -team's assumptions and knowledge about the problem space, and usually reflect -the structure of the applications that use them. Not all systems have explicit -models, and it's often hard to draw a line through the code base separating -the code that is the model from the code that is not as every programmer sees -models slightly differently.</p> -<p>With the rise of object-oriented development, explicit models became the focus -of several well-known practices. Many medium-to-large projects are built -“model first,” with the interfaces to that model being sketched out later in -the process. Since the model holds the system's understanding of its task, -this makes sense, and so long as you keep the problem you're actually solving -in mind, it works well. Unfortunately, it's too easy to lose sight of the -problem and push the model as the whole reason for the system around it. This, -in combination with both emotional and technical investment in any existing -system, strongly encourages building <code>new</code> systems around the existing -model pieces even if the relationship between the new system is tenuous at -best.</p> -<ul> -<li>Why do we share them?<ul> -<li>Unmanaged growth<ul> -<li>Adding features to an existing system</li> -<li>Building new systems on top of existing tools</li> -</ul> -</li> -<li>Misguided applications of “simplicity” and “reuse”</li> -<li>Encouraged by distributed object systems (CORBA, EJB, SOAP, COM)</li> -</ul> -</li> -<li>What are the consequences?<ul> -<li>Models end up holding behaviour and data relevant to many applications</li> -<li>Every application using the model has to make the same assumptions</li> -<li>Changing the model usually requires upgrading everyone at the same time</li> -<li>Changes to the model are risky and impact many applications, even if the - changes are only relevant to one application</li> -</ul> -</li> -<li>What should we do instead?<ul> -<li>Narrow, flat interfaces</li> -<li>Each system is responsible for its own modelling needs</li> -<li>Systems share data and protocols, not objects</li> -<li>Libraries are good, if the entire world doesn't need to upgrade at the - same time</li> -</ul> -</li> -</ul> -<p>It's easy to start building a system by figuring out what the various nouns it -cares about are. In the gambling example, one of our nouns was a user (the guy -sitting at a web browser somewhere), who would be able to log in, deposit -money, place a wager, and would have to be notified when the wager was -settled. This is a clear, reasonable entity for describing the goal of placing -bets online, which we could make reasonable assumptions about. It's also a -terrible thing to turn into a class.</p> -<p>The User class in our gambling system was responsible for all of those things; -as a result, every part of the system ended up using a User object somewhere. -Because the User class had many responsibilities, it was subject to frequent -changes; because it was used everywhere, those changes had the capability to -break nearly any part of the overall system. Worse, because so much -functionality was already in one place, it became psychologically easy to add -one more responsibility to its already-bloated interface.</p> -<p>What had been a clean model in the problem space eventually became one of a -handful of “glue” pieces in a <a href="http://www.laputan.org/mud/mud.html#BigBallOfMud">big ball of -mud</a> program. The User -object did not come about through conscious design, but rather through -evolution from a simple system. There was no clear point where User became -“too big”; instead, the vagueness of its role slowly grew until it became the -default behaviour-holder for all things user-specific.</p> -<p>The same problem modeling exercise also points at a better way to design the -same system: it describes a number of capabilities the system needed to be -able to perform, each of which is simpler than “build a gaming website.” Each -of these capabilities (accept or reject logins, process deposits, accept and -settle wagers, and send out notification emails to players) has a much simpler -model and solves a much more constrained of problem. There is no reason the -authentication service needs to share any data except an identity with the -wagering service: one cares about login names, passwords, and authorization -tickets while the other cares about accounting, wins and losses, and posted -odds.</p> -<p>There is a small set of key facts that can be used to correlate all of pieces: -usernames, which uniquely identify a user, can be used to associate data and -behaviour in the login domain with data and behaviour in the accounting and -wagering domain, and with information in a contact management domain. All of -these key facts are flat—they have very little structure and no behaviour, and -can be passed from service to service without dragging along an entire -application's worth of baggage data.</p> -<p>Sharing model classes between many services creates a huge maintenance -bottleneck. Isolating models within the services they support helps encourage -clean separations between services, which in turn makes it much easier to -understand individual services and much easier to maintain the system as a -whole. Kindergarten lied: sharing is <em>wrong</em>.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/rich-shared-models.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/rich-shared-models.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/shutdown-hooks.html b/.html/dev/shutdown-hooks.html deleted file mode 100644 index 7917e81..0000000 --- a/.html/dev/shutdown-hooks.html +++ /dev/null @@ -1,127 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Falsehoods Programmers Believe About Shutdown Hooks - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - shutdown-hooks - - </li> - - </ol> - - - - <div id="article"> - <h1 id="falsehoods-programmers-believe-about-shutdown-hooks">Falsehoods Programmers Believe About Shutdown Hooks</h1> -<p>Shutdown hooks are language features allowing programs to register callbacks to run during the underlying runtime's orderly teardown. For example:</p> -<ul> -<li> -<p>C's <a href="http://man7.org/linux/man-pages/man3/atexit.3.html"><code>atexit</code></a>,</p> -</li> -<li> -<p>Python's <a href="https://docs.python.org/library/atexit.html"><code>atexit</code></a>, which is subtly different,</p> -</li> -<li> -<p>Ruby's <a href="http://www.ruby-doc.org/core-2.1.3/Kernel.html#method-i-at_exit"><code>Kernel.at_exit</code></a>, which is different again,</p> -</li> -<li> -<p>Java's <a href="http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#addShutdownHook-java.lang.Thread-">Runtime.addShutdownHook</a>, which is yet again different</p> -</li> -</ul> -<p>(There's an example in your favourite language.)</p> -<p>The following beliefs are widespread and incorrect:</p> -<ol> -<li> -<p><strong>Your shutdown hook will run.</strong> Non-exhaustively: the power can go away. The OS may terminate the program immediately because of resource shortages. An administrator or process management tool may send <code>SIGKILL</code> to the process. All of these things, and others, will not run your shutdown hook.</p> -</li> -<li> -<p><strong>Your shutdown hook will run last.</strong> Look at the shapes of the various shutdown hook APIs above: they all allow multiple hooks to be registered in arbitrary orders, and at least one <em>outright requires</em> that hooks run concurrently.</p> -</li> -<li> -<p><strong>Your shutdown hook will not run last.</strong> Sometimes, you win, and objects your hook requires get cleaned up before your hook runs.</p> -</li> -<li> -<p><strong>Your shutdown hook will run to completion.</strong> Some languages run shutdown hooks even when the original termination request came from, for example, the user logging out. Most environments give programs a finite amount of time to wrap up before forcibly terminating them; your shutdown hook may well be mid-run when this occurs.</p> -</li> -<li> -<p><strong>Your shutdown hook will be the only thing running.</strong> In languages that support “daemon” threads, shutdown hooks may start before daemon threads terminate. In languages with concurrent shutdown hooks, other hooks will be in flight at the same time. On POSIX platforms, signals can still arrive during your shutdown hook. (Did you start any child processes? <code>SIGCHLD</code> can still arrive.)</p> -</li> -<li> -<p><strong>You need a shutdown hook.</strong> Closing files, terminating threads, and hanging up network connections are all done automatically by the OS as part of process destruction. The behaviour of the final few writes to a file handle aren't completely deterministic (unflushed data can be lost), but that's true even if a shutdown hook tries to close the file.</p> -</li> -</ol> -<p>Programs that rely on shutdown hooks for correctness should be treated as de-facto incorrect, much like object finalization in garbage-collected languages.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/shutdown-hooks.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/shutdown-hooks.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/stop-building-synchronous-web-containers.html b/.html/dev/stop-building-synchronous-web-containers.html deleted file mode 100644 index 85a1e52..0000000 --- a/.html/dev/stop-building-synchronous-web-containers.html +++ /dev/null @@ -1,135 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Stop Building Synchronous Web Containers - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - stop-building-synchronous-web-containers - - </li> - - </ol> - - - - <div id="article"> - <h1 id="stop-building-synchronous-web-containers">Stop Building Synchronous Web Containers</h1> -<p>Seriously, stop it. It's surreally difficult to build a sane ansynchronous service on top of a synchronous API, but building a synchronous service on top of an asynchronous API is easy.</p> -<ul> -<li> -<p>WSGI: container calls the application as a function, and uses the return - value for the response body. Asynchronous apps generally use a non-WSGI - base (see for example <a href="http://bottlepy.org/docs/dev/async.html">Bottle</a>).</p> -</li> -<li> -<p>Rack: container calls the application as a method, and uses the return - value for the complete response. Asynchronous apps generally use a non-Rack - base (see <a href="https://github.com/rkh/async-rack/issues/5">this Github ticket</a>).</p> -</li> -<li> -<p>Java Servlets: container calls the application as a method, passing a - callback-bearing object as a parameter. The container commits and closes - the response as soon as the application method returns. Asynchronous apps - can use a standard API that operates by <em>re-invoking</em> the servlet method as - needed.</p> -</li> -<li> -<p>What does .Net do?</p> -</li> -</ul> -<p>vs</p> -<ul> -<li>ExpressJS: container calls the application as a function, passing a - callback-bearing object as a parameter. The application is responsible for - indicating that the response is complete.</li> -</ul> -<h2 id="synchronous-web-containers-are-bad-api-design">Synchronous web containers are bad API design</h2> -<ul> -<li> -<p>Make the easy parts easy (this works)</p> -</li> -<li> -<p>Make the hard parts possible (OH SHIT)</p> -</li> -</ul> -<h2 id="writing-synchronous-adapters-for-async-apis-is-easy">Writing synchronous adapters for async APIs is easy</h2> -<pre><code>def adapter(request, response_callback): - synchronous_response = synchronous_entry_point(request) - return response_callback(synchronous_response) -</code></pre> -<p>Going the other way is more or less impossible, which is why websocket -support, HTML5 server-sent event support, and every other async tool for the -web has an awful server interface.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/stop-building-synchronous-web-containers.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/stop-building-synchronous-web-containers.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/trackers-from-first-principles.html b/.html/dev/trackers-from-first-principles.html deleted file mode 100644 index 13ddac4..0000000 --- a/.html/dev/trackers-from-first-principles.html +++ /dev/null @@ -1,297 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Bugs, Tasks, and Tickets from First Principles - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - trackers-from-first-principles - - </li> - - </ol> - - - - <div id="article"> - <h1 id="bugs-tasks-and-tickets-from-first-principles">Bugs, Tasks, and Tickets from First Principles</h1> -<p>Why do we track tasks?</p> -<ul> -<li>To communicate about what should, will, has, and will not be done.<ul> -<li>Consequently, to either build consensus on what to do next or to dictate - it.</li> -</ul> -</li> -<li>To measure and communicate progress.</li> -<li>To preserve information for future use.<ul> -<li>Otherwise we'd just remember it in our heads.</li> -<li>Wishlist tasks are not a bad thing!</li> -</ul> -</li> -</ul> -<p>Bugs/defects are a kind of task but not the only kind. Most teams have a “bug -tracker” that contains a lot more than bugs. Let's not let bugs dictate the -system.</p> -<ul> -<li>Therefore, “steps to reproduce” should not be a required datum.</li> -</ul> -<p>Bugs are an <em>important</em> kind of task.</p> -<p>Tasks can be related to software development artifacts: commits, versions, -builds, releases.</p> -<ul> -<li>A task may only be complete as of certain commits/releases/builds.</li> -<li>A task may only be valid after (or before) certain commits/releases/builds.</li> -</ul> -<p>Communication loosely implies publishing. Tracking doesn't, but may rely on -the publishing of other facts.</p> -<h2 id="core-data">Core Data</h2> -<p>Tasks are only useful if they're actionable. To be actionable, they must be -understood. Understanding requires communication and documentation.</p> -<ul> -<li>A protocol-agnostic <em>name</em>, for easily identifying a task in related - conversations.<ul> -<li>These names need to be <em>short</em> since they're used conversationally. Long - issue names will be shortened by convention whether the tracker supports - it or not.</li> -</ul> -</li> -<li>An actionable <em>description</em> of the task.<ul> -<li>Frequently, a short <em>summary</em> of the task, to ease bulk task - manipulation. Think of the difference between an email subject and an - email body.</li> -</ul> -</li> -<li>A <em>discussion</em>, consisting of <em>remarks</em> or <em>comments</em>, to track the evolving - understanding alongside the task.</li> -</ul> -<p>See <a href="#speciation">speciation</a>, below.</p> -<h2 id="responsibility-and-ownership">Responsibility and Ownership</h2> -<p>Regardless of whether your team operates with a top-down, command-oriented -management structure or with a more self-directed and anarchistic process, for -every task, there is notionally one person currently responsible for ensuring -that the task is completed.</p> -<p>That relationship can change over time; how it does so is probably -team-specific.</p> -<p>There may be other people <em>involved</em> in a task that are not <em>responsible</em> for -a task, in a number of roles. Just because I developed the code for a feature -does not mean I am necessarily responsible for the feature any more, but it -might be useful to have a “developed by” list for the feature's task.</p> -<p>Ways of identifying people:</p> -<ul> -<li>Natural-language names (“Gianna Grady”)</li> -<li>Email addresses</li> -<li>Login names</li> -<li>Distinguished names in some directory</li> -<li>URLs</li> -</ul> -<p>Task responsibility relationships reflect real-world responsibility, and help -communicate it, but do not normally define it.</p> -<h2 id="workflow">Workflow</h2> -<p>“Workflow” describes both the implications of the states a task can be in and -the implications of the transitions between states. Most task trackers are, at -their core, workflow engines of varying sophistication.</p> -<p>Why:</p> -<ul> -<li>Improve shared understanding of how tracked tasks are performed.</li> -<li>Provide clear hand-off points when responsibility shifts.</li> -<li>Provide insight into which tasks need what kinds of attention.</li> -<li>Integration points for other behaviour.</li> -</ul> -<p>States are implicitly time-bounded, and joined to their predecessor and -successor states by transitions.</p> -<p>Task state is decoupled from the real world: the task in a tracker is not the -work it describes.</p> -<p>Elemental states:</p> -<ul> -<li>“Open”: in this state, the task has not yet been completed. Work may or may - not be ongoing.</li> -<li>“Completed”: in this state, all work on a task has been completed.</li> -<li>“Abandoned”: in this state, no further work on a task will be performed, but - the task has not been completed.</li> -</ul> -<p>Most real-world workflows introduce some intermediate states that tie into -process-related handoffs.</p> -<p>For software, I see these divisions, in various combinations, frequently:</p> -<ul> -<li>“Open”:<ul> -<li>“Unverified”: further work needs to be done to decide whether the task - should be completed.</li> -<li>“In Development”: someone is working on the code and asset changes - necessary to complete the task. This occasionally subsumes preliminary - work, too.</li> -<li>“In Testing”: code and asset changes are ostensibly complete, - but need testing to validate that the task has been completed - satisfactorially.</li> -</ul> -</li> -<li>“Completed”:<ul> -<li>“Development Completed”: work (and possibly testing) has been completed - but the task's results are not yet available to external users.</li> -<li>“Released”: work has been completed, and external users can see and use - the results.</li> -</ul> -</li> -<li>“Abandoned”:<ul> -<li>“Cannot Reproduce”: common in bug/defect tasks, to indicate that the - task doesn't contain enough information to render the bug fixable.</li> -<li>“Won't Complete”: the task is well-understood and theoretically - completable, but will not be completed.</li> -<li>“Duplicate”: the task is identical to, or closely related to, some other - task, such that completing either would be equivalent to completing - both.</li> -<li>“Invalid”: the task isn't relevant, is incompletely described, doesn't - make sense, or is otherwise not appropriate work for the team using the - tracker.</li> -</ul> -</li> -</ul> -<p>None of these are universal.</p> -<p>Transitions show how a task moves from state to state.</p> -<ul> -<li>Driven by external factors (dev work leads to tasks being marked completed)<ul> -<li>Explicit transitions: “mark this task as completed”</li> -<li>Implicit transitions: “This commit also completes these tasks”</li> -</ul> -</li> -<li>Drive external factors (tasks marked completed are emailed to testers)</li> -</ul> -<p>States implicitly describe a <em>belief</em> or a <em>desire</em> about the future of the -task, which is a human artifact and may be wrong or overly hopeful. Tasks can -transition to “Completed” or “Abandoned” states when the work hasn't actually -been completed or abandoned, or from “Completed” or “Abandoned” to an “Open” -state to note that the work isn't as done as we thought it was. <em>This is a -feature</em> and trackers that assume every transition is definitely true and -final encourage ugly workarounds like duplicating tickets to reopen them.</p> -<h2 id="speciation">Speciation</h2> -<p>I mentioned above that bugs are a kind of task. The ways in which bugs are -“different” is interesting:</p> -<ul> -<li>Good bugs have a well-defined reproduction case - steps you can follow to - demonstrate and test them.</li> -<li>Good bugs have a well-described expected behaviour.</li> -<li>Good bugs have a well-described actual behaviour.</li> -</ul> -<p>Being able to support this kind of highly detailed speciation of task types -without either bloating the tracker with extension points (JIRA) or -shoehorning all features into every task type (Redmine) is hard, but -necessary.</p> -<p>Supporting structure helps if it leads to more interesting or efficient ways -of using tasks to drive and understand work.</p> -<p>Bugs are not the only “special” kind of task:</p> -<ul> -<li>“Feature” tasks show up frequently, and speciate on having room for - describing specs and scope.</li> -<li>“Support ticket” tasks show up in a few trackers, and speciate dramatically - as they tend to be tasks describing the work of a single incident rather - than tasks describing the work on some shared aspect, so they tend to pick - up fields for relating tickets to the involved parties. (Arguably, incident - tickets have needs so drastically different that you should use a dedicated - incident-management tool, not a task/bug tracker.)</li> -</ul> -<p>Other kinds are possible, and you've probably seen them in the wild.</p> -<p>Ideally, speciation happens to support <em>widespread</em> specialized needs. Bug -repro is a good example; every task whose goal is to fix a defect should -include a clear understanding of the defect, both to allow it to be fixed and -to allow it to be tested. Adding specialized data for bugs supports that by -encouraging clearer, more structured descriptions of the defect (with implicit -“fix this” as the task).</p> -<h2 id="implementation-notes">Implementation notes</h2> -<p>If we reduce task tracking to “record changes to fields and record discussion -comments, on a per task basis,” we can describe the current state of a ticket -using the “most recent” values of each field and the aggregate of all recorded -comments. This can be done ~2 ways:</p> -<ol> -<li>“Centralized” tracking, where each task has a single, total order of - changes. Changes are mediated through a centralized service.</li> -<li>“Decentralized” tracking, where each task has only a partial order over the - history of changes. Changes are mediated by sharing sets of changes, and by - appending “reconciliation” changes to resolve cases where two incomparable - changes modify the same field/s. The most obvious partial order is a - digraph.</li> -</ol> -<p>Centralized tracking is a well-solved problem. Decentralized tracking so far -seems to rely heavily on DSCM tools (Git, Mercurial, Fossil) for resolving -conflicts.</p> -<p>The “work offline” aspect of a distributed tracker is less interesting in as -much as task tracking is a communications tool. Certain kinds of changes -should be published and communicated as early as possible so as to avoid -misunderstandings or duplicated work.</p> -<p>Being able to separate the mechanism of how changes to tasks are recorded from -the policy of which library of tasks is “canonical” is potentially useful as -an editorial tool and for progressive publication to wider audiences as work -progresses.</p> -<p>Issue tracking is considerably more amenable to append-only implementations -than SCM is, even if you dislike history-editing SCM workflows. This suggests -that Git is a poor choice of issue-tracking storage backends...</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/trackers-from-first-principles.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/trackers-from-first-principles.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/twigs.html b/.html/dev/twigs.html deleted file mode 100644 index 66f5e97..0000000 --- a/.html/dev/twigs.html +++ /dev/null @@ -1,112 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Branches and Twigs - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - twigs - - </li> - - </ol> - - - - <div id="article"> - <h1 id="branches-and-twigs">Branches and Twigs</h1> -<h2 id="twigs">Twigs</h2> -<ul> -<li>Relatively short-lived</li> -<li>Share the commit policy of their parent branch</li> -<li>Gain little value from global names</li> -<li>Examples: most “topic branches” are twigs</li> -</ul> -<h2 id="branches">Branches</h2> -<ul> -<li>Relatively long-lived</li> -<li>Correspond to differences in commit policy</li> -<li>Gain lots of value from global names</li> -<li>Examples: git-flow 'master', 'develop', &c; hg 'stable' vs 'default'; - release branches</li> -</ul> -<h2 id="commit-policy">Commit policy</h2> -<ul> -<li>Decisions like “should every commit pass tests?” and “is rewriting or - deleting a commit acceptable?” are, collectively, the policy of a branch</li> -<li>Can be very formal or even tool-enforced, or ad-hoc and fluid</li> -<li>Shared understanding of commit policy helps get everyone's expectations - lined up, easing other SCM-mediated conversations</li> -</ul> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/twigs.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/twigs.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/webapp-versions.html b/.html/dev/webapp-versions.html deleted file mode 100644 index 0a39463..0000000 --- a/.html/dev/webapp-versions.html +++ /dev/null @@ -1,111 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Semver Is Wrong For Web Applications - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - webapp-versions - - </li> - - </ol> - - - - <div id="article"> - <h1 id="semver-is-wrong-for-web-applications">Semver Is Wrong For Web Applications</h1> -<p><a href="http://semver.org">Semantic Versioning</a> (“Semver”) is a great idea, not least -because it's more of a codification of existing practice than a totally novel -approach to versioning. However, I think it's wrong for web applications.</p> -<p>Modern web applications tend to be either totally stagnant - in which case -versioning is irrelevant - or continuously upgraded. Users have no, or very -little, choice as to which version to run: either they run the version currently -on the site, or no version at all. Without the flexibility to choose to run a -specific version, Semver's categorization of versions by what compatibility -guarantees they offer is at best misleading and at worst irrelevant and -insulting.</p> -<p>Web applications must still be <em>versioned</em>; internal users and operators must be -able to trace behavioural changes through to deployments and backwards from -there to <a href="commit-messages">code changes</a>. The continuous and incremental nature -of most web development suggests that a simple, ordered version identifier may -be more appropriate: a <a href="builds">build</a> serial number, or a version <em>date</em>, or -otherwise.</p> -<p>There are <em>parts</em> of web applications that should be semantically versioned: as -the Semver spec says, “Once you identify your public API, you communicate -changes to it with specific increments to your version number,” and this remains -true on the web: whether you choose to support multiple API versions -simultaneously, or to discard all but the latest API version, a semantic version -number can be a helpful communication tool <em>about that API</em>.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/webapp-versions.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/webapp-versions.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/webapps.html b/.html/dev/webapps.html deleted file mode 100644 index aada593..0000000 --- a/.html/dev/webapps.html +++ /dev/null @@ -1,91 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Webapps From The Ground Up - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - webapps - - </li> - - </ol> - - - - <div id="article"> - <h1 id="webapps-from-the-ground-up">Webapps From The Ground Up</h1> -<p>What does a web application do? It sequences side effects and computation. (This should sound familiar: it's what <em>every</em> program does.)</p> -<p>Modern web frameworks do their level best to hide this from you, encouraging code to freely intermix computation, data access, event publishing, logging, responses, <em>asynchronous</em> responses, and the rest. This will damn you to an eternity of debugging.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/webapps.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/webapps.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/whats-wrong-with-jenkins.html b/.html/dev/whats-wrong-with-jenkins.html deleted file mode 100644 index 1b9ab6e..0000000 --- a/.html/dev/whats-wrong-with-jenkins.html +++ /dev/null @@ -1,172 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Something's Rotten in the State of Jenkins - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - whats-wrong-with-jenkins - - </li> - - </ol> - - - - <div id="article"> - <h1 id="somethings-rotten-in-the-state-of-jenkins">Something's Rotten in the State of Jenkins</h1> -<p>Automated, repeatable testing is a fairly widely-accepted cornerstone of -mature software development. Jenkins (and its predecessor, Hudson) has the -unique privilege of being both an early player in the niche and -free-as-in-beer. The blog space is littered with interesting articles about -continuous builds, automated testing, and continuous deployment, all of which -conclude on “how do we make Jenkins do it?”</p> -<p>This is unfortunate, because Jenkins has some serious problems, and I want it -to stop informing the discussion.</p> -<h2 id="theres-a-plugin-for-that">There's A Plugin For That</h2> -<p>Almost everything in the following can be addressed using one or more plugins -from Jenkins' extensive plugin repository. That's good - a build system you -can't extend is kind of screwed - but it also means that the Jenkins team -haven't felt a lot of pressure to address key problems in Jenkins proper.</p> -<p>(Plus, the plugin ecosystem is its own kind of screwed. More on that later.)</p> -<p>To be clear: being able to fix it with plugins does not make Jenkins itself -<em>good</em>. Plugins are a non-response to fundamental problems with Jenkins.</p> -<h2 id="no-granularity">No Granularity</h2> -<p>Jenkins builds are atomic: they either pass en suite, or fail en suite. Jenkins has no built-in support for recording that basic compilation succeeded, unit tests failed, but linting also succeeded.</p> -<p>You can fix this by running more builds, but then you run into problems with -...</p> -<h2 id="no-gating">No Gating</h2> -<p>... the inability to wait for multiple upstream jobs before continuing a -downstream job in a job chain. If your notional build pipeline is</p> -<ol> -<li>Compile, then</li> -<li>Lint and unit test, then</li> -<li>Publish binaries for testers/users</li> -</ol> -<p>then you need to combine the lint and unit test steps into a single build, or -tolerate occasionally publishing between zero and two copies of the same -original source tree.</p> -<h2 id="no-pipeline">No Pipeline</h2> -<p>The above are actually symptomatic of a more fundamental design problem in -Jenkins: there's no build pipeline. Jenkins is a task runner: triggers cause -tasks to run, which can cause further triggers. (Without plugins, Jenkins -can't even ensure that chains of jobs all build the same revisioins from -source control.)</p> -<p>I haven't met many projects whose build process was so simple you could treat -it as a single, pass-fail task, whose results are only interesting if the -whole thing succeeds.</p> -<h2 id="plugin-the-gap">Plugin the Gap</h2> -<p>To build a functional, non-trivial build process on top of Jenkins, you will -inevitably need plugins: plugins for source control, plugins for -notification, plugins for managing build steps, plugins for managing various -language runtimes, you name it.</p> -<p>The plugin ecosystem is run on an entirely volunteer basis, and anyone can -get a new plugin into the official plugin registry. This is good, in as much -as the barrier to entry <em>should</em> be low and people <em>should</em> be encouraged to -scratch itches, but it also means that the plugin registry is a swamp of -sporadically-maintained one-offs with inconsistent interfaces.</p> -<p>(Worse, even some <em>core</em> plugins have serious maintenance deficits: have a -look at how long -<a href="https://issues.jenkins-ci.org/browse/JENKINS-20767">JENKINS-20767</a> was open. -How many Jenkins users use Git?)</p> -<h2 id="the-plugin-api">The Plugin API</h2> -<p>The plugin API also, critically, locks Jenkins into some internal design -problems. The sheer number of plugins, and the sheer number of maintainers, -effectively prevents any major refactoring of Jenkins from making progress. -Breaking poorly-maintained plugins inevitably pisses off the users who were, -quite happily, using whatever they'd cooked up, but with the maintainership -of plugins so spread out and so sporadic, there's no easy way for the Jenkins -team to, for example, break up the <a href="https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/jenkins/model/Jenkins.java">4,000-line <code>Jenkins</code> class</a>.</p> -<h2 id="what-is-to-be-done">What Is To Be Done</h2> -<p>Jenkins is great and I'm glad it exists. Jenkins moved the state of the art -for build servers forward very effectively, and successfully out-competed -more carefully-designed offerings that were not, in fact, better: -<a href="http://continuum.apache.org">Continuum</a> is more or less abandoned, and when -was the last time you saw a -<a href="http://cruisecontrol.sourceforge.net">CruiseControl</a> (caution: SourceForge) -install?</p> -<p>It's interesting to compare the state of usability in, eg., Jenkins, to the -state of usability in some paid-product build systems -(<a href="https://www.atlassian.com/software/bamboo">Bamboo</a> and -<a href="https://www.jetbrains.com/teamcity/">TeamCity</a> for example) on the above -points, as well as looking at the growing number of hosted build systems -(<a href="https://travis-ci.org">TravisCI</a>, <a href="https://magnum-ci.com">MagnumCI</a>) for -ideas. A number of folks have also written insightful musings on what they -want to see in the next CI tool: Susan Potter's -<a href="https://github.com/mbbx6spp/carson">Carson</a> includes an interesting -motivating metaphor (if you're going to use butlers, why not use the whole -butler mileu?) and some good observations on how Jenkins lets us all down, -for example.</p> -<p>I think it's time to put Jenkins to bed and write its successor.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/whats-wrong-with-jenkins.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/whats-wrong-with-jenkins.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file diff --git a/.html/dev/why-scm.html b/.html/dev/why-scm.html deleted file mode 100644 index d278190..0000000 --- a/.html/dev/why-scm.html +++ /dev/null @@ -1,147 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title> - The Codex » - Why we use SCM systems - </title> - - <link - rel='stylesheet' - type='text/css' - href='http://fonts.googleapis.com/css?family=Buenard:400,700&subset=latin,latin-ext'> - <link - rel="stylesheet" - type="text/css" - href="../media/css/reset.css"> - <link - rel="stylesheet" - type="text/css" - href="../media/css/grimoire.css"> -</head> -<body> - -<div id="shell"> - - <ol id="breadcrumbs"> - - <li class="crumb-0 not-last"> - - <a href="../">index</a> - - </li> - - <li class="crumb-1 not-last"> - - <a href="./">dev</a> - - </li> - - <li class="crumb-2 last"> - - why-scm - - </li> - - </ol> - - - - <div id="article"> - <h1 id="why-we-use-scm-systems">Why we use SCM systems</h1> -<p>I'm watching a newly-minted co-op student dealing with her first encounter -with Git, unhelpfully shepherded by a developer to whom everything below is -already second nature, so deeply that the reasoning is hard to articulate. It -is not going well.</p> -<p>I have the same problem, and it could be me trying to give someone an intro to -Git off the top of my head, but it's not, today. For next time, here are my -thoughts. They have shockingly little to do with Git.</p> -<h2 id="assumptions">Assumptions</h2> -<ul> -<li>You're working on a software project.</li> -<li>You know how to read and write code.</li> -<li>You're human.</li> -<li>You have end users or customers - people other than yourself who care about - your code.</li> -<li>Your project is going to take more than a few minutes to reach end of life.</li> -</ul> -<h2 id="the-safety-net">The safety net</h2> -<p>Having a record of past states and known-good states means that, when (WHEN) -you write some code that doesn't work, and when (WHEN) you're stumped as to -why, you can throw your broken code away and get to a working state again. It -also helps with less-drastic solutions by letting you run comparisons between -your broken code and working code, which helps narrow down whatever problem -you've created for yourself.</p> -<p>(Aside: if you're in a shop that “doesn't use source control,” and for -whatever insane reason you haven't already run screaming, this safety net is a -good reason to use source control independently of the organization as a -whole. Go on, it's easy; modern DSCM tools like Mercurial or Git make -importing “external” trees pretty straightforward. Your future self thanks -you.)</p> -<h2 id="historical-record">Historical record</h2> -<p>Having a record of past, released states means you can go back later and -recover how your project has changed over time. Even if your commit practices -are terrible, when (WHEN) your users complain that something stopped working a -few months ago and they never bothered to mention it until now, you have some -chance of finding out what caused the problem. Better practices around <a href="commit-messages">commit -messages</a> and other workflow-related artifacts improve your -chances of finding out <em>why</em>, too.</p> -<h2 id="consensus">Consensus</h2> -<p>Every SCM system and every release process is designed to help the humans in -the loop agree on what, exactly, the software being released looks like and -whether or not various releasability criteria have been met. It doesn't matter -if you use rolling releases or carefully curate and tag every release after -months of discussion, you still need to be able to point to a specific version -of your project's source code and say “this will be our next release.”</p> -<p>SCM systems can help direct and contextualize that discussion by recording the -way your project has changed during those discussion, whether that's part of -development or a separate post-“freeze” release process.</p> -<h2 id="proposals-and-speculative-development">Proposals and speculative development</h2> -<p>Modern SCM systems (other than a handful of dismal early attempts) also help -you <em>propose</em> and <em>discuss</em> changes. Distributed source control systems make -this particularly easy, but even centralized systems can support workflows -that record speculative development in version control. The ability to discuss -specific changes and diffs, either within a speculative line of development or -between a proposed feature and the mainline code base, is incredibly powerful.</p> -<h2 id="the-bottom-line">The bottom line</h2> -<p>It's about the people, not the tools, stupid. Explaining how Git works to -someone who doesn't have a good grasp on the relationship between source -control tools and long-term, collaborative software development won't help.</p> - </div> - - - -<div id="comments"> -<div id="disqus_thread"></div> -<script type="text/javascript"> - /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ - var disqus_shortname = 'grimoire'; // required: replace example with your forum shortname - - /* * * DON'T EDIT BELOW THIS LINE * * */ - (function() { - var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; - dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; - (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); - })(); -</script> -<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> -<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> -</div> - - - - <div id="footer"> - <p> - - The Codex — - - Powered by <a href="http://markdoc.org/">Markdoc</a>. - -<a href="https://bitbucket.org/ojacobson/grimoire.ca/src/master/wiki/dev/why-scm.md">See this page on Bitbucket</a> (<a href="https://bitbucket.org/ojacobson/grimoire.ca/history-node/master/wiki/dev/why-scm.md">history</a>). - - </p> - </div> - -</div> -</body> -</html>
\ No newline at end of file |
