From b0c376d2a7ded722cd49f88e515c53632ec75730 Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Wed, 28 May 2014 16:11:01 -0400 Subject: Typographic fixes around double quotes. --- wiki/12factor/7-port-binding.md | 8 +-- wiki/12factor/index.md | 4 +- wiki/cool-urls-can-change.md | 16 +++--- wiki/dev/builds.md | 14 ++--- wiki/dev/commit-messages.md | 12 ++-- wiki/dev/debugger-101.md | 16 +++--- wiki/dev/liquibase.md | 6 +- wiki/dev/merging-structural-changes.md | 16 +++--- wiki/dev/rich-shared-models.md | 10 ++-- wiki/dev/trackers-from-first-principles.md | 78 +++++++++++++------------- wiki/dev/twigs.md | 6 +- wiki/dev/why-scm.md | 8 +-- wiki/devops/autodeploy.md | 8 +-- wiki/devops/glassfish-and-upstart.md | 18 +++--- wiki/devops/puppet-2.7-to-3.1.md | 8 +-- wiki/devops/self-daemonization-sucks.md | 6 +- wiki/email.md | 4 +- wiki/ethics/lg-smart-tv.md | 14 ++--- wiki/ethics/linkedin-intro.md | 16 +++--- wiki/ethics/musings.md | 16 +++--- wiki/git/config.md | 12 ++-- wiki/git/pull-request-workflow.md | 4 +- wiki/git/scratch.md | 6 +- wiki/git/stop-using-git-pull-to-deploy.md | 8 +-- wiki/git/survival.md | 10 ++-- wiki/git/theory-and-practice/index.md | 12 ++-- wiki/git/theory-and-practice/objects.md | 14 ++--- wiki/git/theory-and-practice/refs-and-names.md | 12 ++-- wiki/gossamer/index.md | 26 ++++----- wiki/gossamer/mistakes.md | 6 +- wiki/java/a-new-kind-of.md | 20 +++---- wiki/java/install/centos.md | 2 +- wiki/java/install/ubuntu.md | 2 +- wiki/java/kwargs.md | 6 +- wiki/mysql/broken-xa.md | 6 +- wiki/mysql/choose-something-else.md | 66 +++++++++++----------- wiki/packaging-ideas.md | 6 +- wiki/people/rape-culture-and-men.md | 20 +++---- wiki/people/rincewind.md | 6 +- 39 files changed, 264 insertions(+), 264 deletions(-) (limited to 'wiki') diff --git a/wiki/12factor/7-port-binding.md b/wiki/12factor/7-port-binding.md index 2daf342..a756496 100644 --- a/wiki/12factor/7-port-binding.md +++ b/wiki/12factor/7-port-binding.md @@ -8,11 +8,11 @@ Factor 7 is over-specific: * It presupposes the existence of a front-end routing layer, without providing any insight into how to deploy, configure, provision, or manage one. -* It demands HTTP (by name) rather than a more flexible "any well-standardized - protocol", without explaining why. (Web apps can have non-HTTP internal +* It demands HTTP (by name) rather than a more flexible “any well-standardized + protocol,” without explaining why. (Web apps can have non-HTTP internal components.) -* It dismisses the value of "pre-existing" container ecosystems that don't +* It dismisses the value of “pre-existing” container ecosystems that don't work the way Heroku does. Have a giant, well-managed [Glassfish](http://glassfish.org) cluster that you deploy components to? TOO BAD, not Heroku-like enough for these guys even though many aspects run @@ -21,7 +21,7 @@ Factor 7 is over-specific: * It dismisses the value of unix-as-a-container. Unix domain sockets with controlled permissions? Psh, let's go through the network stack instead. SysV IPC? (Yeah, I know.) Network. Pipes? Network. There's an implicit - exception for "intra-process" communication, but it's never really + exception for “intra-process” communication, but it's never really identified or reasoned about. * Have you _seen_ the kinds of process control interfaces developers invent, diff --git a/wiki/12factor/index.md b/wiki/12factor/index.md index 9fa7e22..6e75732 100644 --- a/wiki/12factor/index.md +++ b/wiki/12factor/index.md @@ -1,7 +1,7 @@ # 12-Factor Apps Some folks over at [Heroku](http://heroku.com/) wrote up their perceived best -practices for building "software as a service"-style applications and called +practices for building “software as a service”-style applications and called it [The Twelve-Factor App](http://www.12factor.net). It's a good read, and has lots of good advice in it. @@ -15,5 +15,5 @@ I have a few thoughts on it. ----- At some point around sections 6 or 7, the goodness of the advice is overtaken -by the "be more like Heroku specifically"-ness of the advice, to the detriment +by the “be more like Heroku specifically”-ness of the advice, to the detriment of their point. diff --git a/wiki/cool-urls-can-change.md b/wiki/cool-urls-can-change.md index 54795f9..b0c489b 100644 --- a/wiki/cool-urls-can-change.md +++ b/wiki/cool-urls-can-change.md @@ -7,21 +7,21 @@ When I wrote [Nobody Cares About Your Build](http://codex.grimoire.ca/2008/09/24/nobody-cares-about-your-build/), I set up a dedicated publishing platform - Wordpress, as it happens - to host it, and as part of that process I put some real thought into the choice of -"permalink" schemes to use. I opted to use a "dated" scheme, baking the +“permalink” schemes to use. I opted to use a “dated” scheme, baking the publication date of each article into its name - into its URL - for all eternity. I'm a big believer in the idea that a URL should be a long-term name for the appropriate bit of data or content, and every part of a dated scheme -"made sense" at the time. +“made sense” at the time. This turned out to be a mistake. The web is not, much, like print media. Something published may be amended; you don't even have to publish errata or a correction, since you can correct -the original mistake "seamlessly". This has its good and its +the original mistake “seamlessly.” This has its good and its [bad](http://en.wikipedia.org/wiki/Memory_hole) parts, but with judicious use and [a public history](https://github.com/ojacobson/grimoiredotca), amendment is more of a win than a loss. However, this plays havoc with the idea of a -"publication" date, even for data that takes the form of an article: is the +“publication” date, even for data that takes the form of an article: is the publication date the date it was first made public, the date of its most recent edit, or some other date? @@ -33,9 +33,9 @@ willing to commit to. Had I left the date out of the URLs, I'd feel more free to judiciously amend articles in place and include, in the content, a short amendment summary. -The W3C's informal suggestions on the subject state that "After the creation +The W3C's informal suggestions on the subject state that “After the creation date, putting any information in the name is asking for trouble one way or -another." I'm starting to believe that this doesn't go far enough: _every_ +another.” I'm starting to believe that this doesn't go far enough: _every_ part of a URL must have some semantic justification for being there, dates included: @@ -44,7 +44,7 @@ included: render stable, the meaningless blob renders the name immemorable. 2. *Each part must be stable*. This is where I screwed up worst: I did not - anticipate that the "date" of an article could be a fluid thing. It's + anticipate that the “date” of an article could be a fluid thing. It's tempting to privilege the first date, and it's not an unreasonable solution, but it didn't fit how I wanted to address the contents of articles. @@ -59,7 +59,7 @@ for resources that are, themselves, references to other URLs. HTTP is a good example, providing a fairly rich set of responses that all, fundamentally, tell a client to check a second URL for the content relevent to a given URL. In protocols like this, you can easily replace the content of a URL with a -reference to its new, "better" URL rather than abandoning it entirely. +reference to its new, “better” URL rather than abandoning it entirely. Names can evolve organically as the humans that issue them grow a better understanding of the problem, and don't always have to be locked in stone from diff --git a/wiki/dev/builds.md b/wiki/dev/builds.md index f559459..8f334a1 100644 --- a/wiki/dev/builds.md +++ b/wiki/dev/builds.md @@ -29,9 +29,9 @@ 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 +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. +person—“creativity,” “morality,” “curiosity,” and so on. ![A three-tier pyramid. At the bottom: Automatable. Repeatable. Standardized. Extensible. Understood. In the middle tier: Simple. Fast. Unit tests. Part of @@ -50,7 +50,7 @@ Before a build is a build, there are five key needs to meet: * **It must be repeatable**. 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 + 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. * **It must be automatable**. Build systems are used by developers sitting at @@ -69,7 +69,7 @@ Before a build is a build, there are five key needs to meet: 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. + tool to ensure that all the “extra” steps for certain projects happen. * **Someone must understand it**. 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. @@ -77,7 +77,7 @@ Before a build is a build, there are five key needs to meet: 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 +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. * **It must be simple**. When a complicated build breaks, you need someone who @@ -100,7 +100,7 @@ release or a demo and don’t hide surprises for launch day. uniform on any environment, any developer can cook up a build for a test or demo at any time. -Finally, there are "chrome" features that take a build from effective to +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: @@ -125,7 +125,7 @@ organization. Here are some common chrome needs: builds amplifies the benefits of early testing and, if your acceptance tests are good, when your project is done. * **It should not need repeating**. Once you declare a particular set of build - products "done", you should be able to use those products as-is any time you + 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. diff --git a/wiki/dev/commit-messages.md b/wiki/dev/commit-messages.md index 6661671..6b3702d 100644 --- a/wiki/dev/commit-messages.md +++ b/wiki/dev/commit-messages.md @@ -1,6 +1,6 @@ # Writing Good Commit Messages -Rule zero: "good" is defined by the standards of the project you're on. Have a +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. @@ -8,13 +8,13 @@ Having said that, here are some things that will help your commit messages be useful later: * 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 + 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. _It's okay for this to - be a "what" description_ if the rest of the message is a "why" description. + be a “what” description_ if the rest of the message is a “why” description. * 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 [the + change. The guidelines for a good “why” message are the same as [the guidelines for good comments](comments), 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. @@ -27,8 +27,8 @@ useful later: of the way, such as on a line of its own at the end of the message. * 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 + present-tense imperative message (“Add support for PNGs”) and another commit + with a past-tense narrative message (“Fixed bug in PNG support”) is distracting. * If you need rich commit messages (links, lists, and so on), pick one markup diff --git a/wiki/dev/debugger-101.md b/wiki/dev/debugger-101.md index 8698c3b..6d7e773 100644 --- a/wiki/dev/debugger-101.md +++ b/wiki/dev/debugger-101.md @@ -3,7 +3,7 @@ (Written largely because newbies in [##java](http://evanchooly.com) never seem to have this knowledge.) -A "debugger" is a mechanism for monitoring and controlling the execution of +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 _actual_ values of its variables (to compare against what you expected), monitor variables for changes (to see @@ -14,7 +14,7 @@ Pretty much every worthwhile language has debugging support of some kind, whether it's via IDE integration or via a command-line debugger. (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 +“expected” behaviour of the program. Debuggers can help you read, but can't replace having an understanding of the code.) ## Debugging Your First Program @@ -43,8 +43,8 @@ program - generally in one of five ways: * Execute the _next_ 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.) + contains breakpoints of its own). (In some debuggers, this is labelled “step + over,” since it will step “over” a function call.) * _Step_ forward one operation. Execution proceeds for one statement, then stops again. This mode can single-step into function calls, rather than @@ -54,8 +54,8 @@ program - generally in one of five ways: reaches the end of the current function, then halts the program again. * _Continue to a specific statement_. 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 + way of stepping over or through “uninteresting” sections of code quickly and + easily. (You can implement this yourself with “Continue” and normal breakpoints, too.) Whenever the debugger halts your program, you can do any of several things: @@ -67,7 +67,7 @@ Whenever the debugger halts your program, you can do any of several things: having to rerun your code with extra debug output. * Inspect the result of an expression. The debugger will evaluate an - expression "as if" it occurred at the point in the program where the + 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. @@ -75,7 +75,7 @@ Whenever the debugger halts your program, you can do any of several things: like a variable. * 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 + 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. diff --git a/wiki/dev/liquibase.md b/wiki/dev/liquibase.md index 6e5e97d..01e989f 100644 --- a/wiki/dev/liquibase.md +++ b/wiki/dev/liquibase.md @@ -1,7 +1,7 @@ # Liquibase -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) +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. @@ -74,4 +74,4 @@ The liquibase developers deserve a lot of credit for solving a hard problem very cleanly. *[DDL]: Data Definition Language -*[DML]: Data Manipulation Language \ No newline at end of file +*[DML]: Data Manipulation Language diff --git a/wiki/dev/merging-structural-changes.md b/wiki/dev/merging-structural-changes.md index f597d39..a47fdcc 100644 --- a/wiki/dev/merging-structural-changes.md +++ b/wiki/dev/merging-structural-changes.md @@ -40,21 +40,21 @@ 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 +triggers a rather opaque warning about a “missing file”; in the other, the merge silently ignores the content changes. 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 +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. -This would be fairly easy to remedy by adding a "this object was moved to that -object" primitive to the changeset language, and [a bug report for just such a +This would be fairly easy to remedy by adding a “this object was moved to that +object” primitive to the changeset language, and [a bug report for just such a feature](http://subversion.tigris.org/issues/show_bug.cgi?id=898) 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 @@ -73,8 +73,8 @@ change.](/media/dev/merging-structural-changes/mercurial-merge-results) Interestingly, there are tools which get this merge scenario right: the diagram above shows how [Mercurial](http://www.selenic.com/mercurial/) handles -the same two tests. Since its changeset language does include an "object -moved" primitive, it's able to take a content change for `dir-a/file` and +the same two tests. Since its changeset language does include an “object +moved” primitive, it's able to take a content change for `dir-a/file` and apply it to `dir-b/file` if appropriate. ## Git diff --git a/wiki/dev/rich-shared-models.md b/wiki/dev/rich-shared-models.md index 7309dbe..7fac072 100644 --- a/wiki/dev/rich-shared-models.md +++ b/wiki/dev/rich-shared-models.md @@ -23,7 +23,7 @@ models slightly differently. 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 +“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 @@ -37,7 +37,7 @@ best. * Unmanaged growth * Adding features to an existing system * Building new systems on top of existing tools - * Misguided applications of "simplicity" and "reuse" + * Misguided applications of “simplicity” and “reuse” * Encouraged by distributed object systems (CORBA, EJB, SOAP, COM) * What are the consequences? * Models end up holding behaviour and data relevant to many applications @@ -69,16 +69,16 @@ functionality was already in one place, it became psychologically easy to add one more responsibility to its already-bloated interface. What had been a clean model in the problem space eventually became one of a -handful of "glue" pieces in a [big ball of +handful of “glue” pieces in a [big ball of mud](http://www.laputan.org/mud/mud.html#BigBallOfMud) 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 +“too big”; instead, the vagueness of its role slowly grew until it became the default behaviour-holder for all things user-specific. 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 +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 diff --git a/wiki/dev/trackers-from-first-principles.md b/wiki/dev/trackers-from-first-principles.md index cd4148f..d7c7a4c 100644 --- a/wiki/dev/trackers-from-first-principles.md +++ b/wiki/dev/trackers-from-first-principles.md @@ -10,11 +10,11 @@ Why do we track tasks? * Otherwise we'd just remember it in our heads. * Wishlist tasks are not a bad thing! -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 +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. -* Therefore, "steps to reproduce" should not be a required datum. +* Therefore, “steps to reproduce” should not be a required datum. Bugs are an _important_ kind of task. @@ -59,11 +59,11 @@ team-specific. There may be other people _involved_ in a task that are not _responsible_ 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. +might be useful to have a “developed by” list for the feature's task. Ways of identifying people: -* Natural-language names ("Gianna Grady") +* Natural-language names (“Gianna Grady”) * Email addresses * Login names * Distinguished names in some directory @@ -74,7 +74,7 @@ communicate it, but do not normally define it. ## Workflow -"Workflow" describes both the implications of the states a task can be in and +“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. @@ -93,10 +93,10 @@ work it describes. Elemental states: -* "Open": in this state, the task has not yet been completed. Work may or may +* “Open”: in this state, the task has not yet been completed. Work may or may not be ongoing. -* "Completed": in this state, all work on a task has been completed. -* "Abandoned": in this state, no further work on a task will be performed, but +* “Completed”: in this state, all work on a task has been completed. +* “Abandoned”: in this state, no further work on a task will be performed, but the task has not been completed. Most real-world workflows introduce some intermediate states that tie into @@ -104,29 +104,29 @@ process-related handoffs. For software, I see these divisions, in various combinations, frequently: -* "Open": - * "Unverified": further work needs to be done to decide whether the task +* “Open”: + * “Unverified”: further work needs to be done to decide whether the task should be completed. - * "In Development": someone is working on the code and asset changes + * “In Development”: someone is working on the code and asset changes necessary to complete the task. This occasionally subsumes preliminary work, too. - * "In Testing": code and asset changes are ostensibly complete, + * “In Testing”: code and asset changes are ostensibly complete, but need testing to validate that the task has been completed satisfactorially. -* "Completed": - * "Development Completed": work (and possibly testing) has been completed +* “Completed”: + * “Development Completed”: work (and possibly testing) has been completed but the task's results are not yet available to external users. - * "Released": work has been completed, and external users can see and use + * “Released”: work has been completed, and external users can see and use the results. -* "Abandoned": - * "Cannot Reproduce": common in bug/defect tasks, to indicate that the +* “Abandoned”: + * “Cannot Reproduce”: common in bug/defect tasks, to indicate that the task doesn't contain enough information to render the bug fixable. - * "Won't Complete": the task is well-understood and theoretically + * “Won't Complete”: the task is well-understood and theoretically completable, but will not be completed. - * "Duplicate": the task is identical to, or closely related to, some other + * “Duplicate”: the task is identical to, or closely related to, some other task, such that completing either would be equivalent to completing both. - * "Invalid": the task isn't relevant, is incompletely described, doesn't + * “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. @@ -135,14 +135,14 @@ None of these are universal. Transitions show how a task moves from state to state. * Driven by external factors (dev work leads to tasks being marked completed) - * Explicit transitions: "mark this task as completed" - * Implicit transitions: "This commit also completes these tasks" + * Explicit transitions: “mark this task as completed” + * Implicit transitions: “This commit also completes these tasks” * Drive external factors (tasks marked completed are emailed to testers) States implicitly describe a _belief_ or a _desire_ 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" +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. _This is a feature_ and trackers that assume every transition is definitely true and final encourage ugly workarounds like duplicating tickets to reopen them. @@ -150,7 +150,7 @@ final encourage ugly workarounds like duplicating tickets to reopen them. ## Speciation I mentioned above that bugs are a kind of task. The ways in which bugs are -"different" is interesting: +“different” is interesting: * Good bugs have a well-defined reproduction case - steps you can follow to demonstrate and test them. @@ -165,11 +165,11 @@ necessary. Supporting structure helps if it leads to more interesting or efficient ways of using tasks to drive and understand work. -Bugs are not the only "special" kind of task: +Bugs are not the only “special” kind of task: -* "Feature" tasks show up frequently, and speciate on having room for +* “Feature” tasks show up frequently, and speciate on having room for describing specs and scope. -* "Support ticket" tasks show up in a few trackers, and speciate dramatically +* “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 @@ -183,20 +183,20 @@ 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). +“fix this” as the task). ## Implementation notes -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 +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: -1. "Centralized" tracking, where each task has a single, total order of +1. “Centralized” tracking, where each task has a single, total order of changes. Changes are mediated through a centralized service. -2. "Decentralized" tracking, where each task has only a partial order over the +2. “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 + appending “reconciliation” changes to resolve cases where two incomparable changes modify the same field/s. The most obvious partial order is a digraph. @@ -204,16 +204,16 @@ Centralized tracking is a well-solved problem. Decentralized tracking so far seems to rely heavily on DSCM tools (Git, Mercurial, Fossil) for resolving conflicts. -The "work offline" aspect of a distributed tracker is less interesting in as +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. 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 +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. 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... \ No newline at end of file +that Git is a poor choice of issue-tracking storage backends... diff --git a/wiki/dev/twigs.md b/wiki/dev/twigs.md index ebc875c..c3c7505 100644 --- a/wiki/dev/twigs.md +++ b/wiki/dev/twigs.md @@ -5,7 +5,7 @@ * Relatively short-lived * Share the commit policy of their parent branch * Gain little value from global names -* Examples: most "topic branches" are twigs +* Examples: most “topic branches” are twigs ## Branches @@ -17,8 +17,8 @@ ## Commit policy -* Decisions like "should every commit pass tests?" and "is rewriting or - deleting a commit acceptable?" are, collectively, the policy of a branch +* Decisions like “should every commit pass tests?” and “is rewriting or + deleting a commit acceptable?” are, collectively, the policy of a branch * Can be very formal or even tool-enforced, or ad-hoc and fluid * Shared understanding of commit policy helps get everyone's expectations lined up, easing other SCM-mediated conversations diff --git a/wiki/dev/why-scm.md b/wiki/dev/why-scm.md index c6c8b86..5985982 100644 --- a/wiki/dev/why-scm.md +++ b/wiki/dev/why-scm.md @@ -27,11 +27,11 @@ 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. -(Aside: if you're in a shop that "doesn't use source control", and for +(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 +importing “external” trees pretty straightforward. Your future self thanks you.) ## Historical record @@ -51,11 +51,11 @@ 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". +of your project's source code and say “this will be our next release.” 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. +development or a separate post-“freeze” release process. ## Proposals and speculative development diff --git a/wiki/devops/autodeploy.md b/wiki/devops/autodeploy.md index eff9ea6..801c3eb 100644 --- a/wiki/devops/autodeploy.md +++ b/wiki/devops/autodeploy.md @@ -12,8 +12,8 @@ here?) then come back. No, seriously, _now_.) 3. You will be deploying your services to one or more _environments_. An -environment is an abstract thing: think "production", not -"web01.public.example.com". (If not, where, exactly, will your service run?) +environment is an abstract thing: think “production,” not +“web01.public.example.com.” (If not, where, exactly, will your service run?) 4. For each service, in each environment, there are one or more _servers_ to host the service. These servers are functionally identical. (If not, go pave @@ -22,7 +22,7 @@ and duct tape. An environment full of one-offs is the kind of hell I wouldn't wish on my worst enemy.) 5. For each service, in each environment, there is a canonical series of steps -that produce a "deployed" system. +that produce a “deployed” system. ----- @@ -35,4 +35,4 @@ that produce a "deployed" system. 5. Get the code running with the configuration. 6. Log to fucking syslog. 7. When the machine reboots, make sure the code comes back running the same - configuration. \ No newline at end of file + configuration. diff --git a/wiki/devops/glassfish-and-upstart.md b/wiki/devops/glassfish-and-upstart.md index 1c79b41..ce5d0eb 100644 --- a/wiki/devops/glassfish-and-upstart.md +++ b/wiki/devops/glassfish-and-upstart.md @@ -14,7 +14,7 @@ instance. These init scripts wrap `asadmin start-domain` and `asadmin start-local-instance`. However, the scripts it emits are (justifiably) minimalist, and it makes some very strong assumptions about the layout of your system's rc.d trees and about your system's choice of runlevels. The minimal -init scripts avoid any integration with platform "enhancements" (such as +init scripts avoid any integration with platform “enhancements” (such as Redhat's `/var/lock/subsys` mechanism and `condrestart` convention, or Debian's `start-stop-daemon` helpers) in the name of portability, and the assumptions it makes about runlevels and init layout are becoming @@ -27,17 +27,17 @@ Upstart's process tracking mechanism relies on services following one of three forking models, so that it can accurately track which children of PID 1 are associated with which services: -* No `expect` stanza: The service's "main" process is expected not to fork at - all, and to remain running. The process started by upstart is the "main" +* No `expect` stanza: The service's “main” process is expected not to fork at + all, and to remain running. The process started by upstart is the “main” process. * `expect fork`: The service is expected to call `fork()` or `clone()` once. - The process started by upstart itself is not the "main" process, but its + The process started by upstart itself is not the “main” process, but its first child process is. * `expect daemon`: The service is expected to call `fork()` or `clone()` twice. The first grandchild process of the one started by upstart itself is - the "main" process. This corresponds to classical Unix daemons, which fork + the “main” process. This corresponds to classical Unix daemons, which fork twice to properly dissociate themselves from the launching shell. Surprisingly, `asadmin`-launched Glassfish matches _none_ of these models, and @@ -69,7 +69,7 @@ the server's operation is correct, and that's probably true, but I've not tested its effect on outward-facing requests or on in-flight operations far enough to be comfortable with it. -I chose to run a "clean"(er) shutdown using `asadmin stop-domain`. This fits +I chose to run a “clean”(er) shutdown using `asadmin stop-domain`. This fits nicely in Upstart's `pre-stop` step, _provided you do not use Upstart's `respawn` feature_. Upstart will correctly notice that Glassfish has already stopped after `pre-stop` finishes, but when `respawn` is enabled Upstart will @@ -85,7 +85,7 @@ Yes, this does make it impossible to stop Glassfish, ever, unless you set a respawn limit. Fortunately, you don't actually want to use `respawn` to manage availability. -The `respawn` mode cripples your ability to manage the service "out of band" +The `respawn` mode cripples your ability to manage the service “out of band” by forcing Upstart to restart it as a daemon every time it stops for any reason. This means you cannot stop a server with `SIGTERM` or `SIGKILL`; it'll immediately start again. @@ -99,7 +99,7 @@ other commands anyways, so this is not a big limitation. ## Instances -Upstart supports "instances" of a service. This slots nicely into Glassfish's +Upstart supports “instances” of a service. This slots nicely into Glassfish's ability to host multiple domains and instances on the same physical hardware. I ended up with a generic `glassfish-domain.conf` Upstart configuration: @@ -150,4 +150,4 @@ Combined with a per-domain wrapper: * Syslog and logrotate integration would be useful. The configurations above spew Glassfish's startup output and stdout to `/var/log/upstart/glassfish-domain-FOO.log`, which may not be rotated by - default. \ No newline at end of file + default. diff --git a/wiki/devops/puppet-2.7-to-3.1.md b/wiki/devops/puppet-2.7-to-3.1.md index 69cedd2..aaaf302 100644 --- a/wiki/devops/puppet-2.7-to-3.1.md +++ b/wiki/devops/puppet-2.7-to-3.1.md @@ -35,9 +35,9 @@ Asking Puppet to upgrade Puppet went wrong on Ubuntu because of the way Puppet is packaged: there are three (ish) Puppet packages, and Puppet's resource evaluation bits try to upgrade and install one package at a time. Upgrading -only "puppetmaster" upgraded "puppet-common" but not "puppet", causing Apt to -remove "puppet"; upgrading only "puppet" similarly upgraded "puppet-copmmon" -but not "puppetmaster", causing Apt to remove "puppetmaster". +only “puppetmaster” upgraded “puppet-common” but not “puppet,” causing Apt to +remove “puppet”; upgrading only “puppet” similarly upgraded “puppet-copmmon” +but not “puppetmaster,” causing Apt to remove “puppetmaster.” The Puppet aptitude provider (which I use instead of apt-get) for Package resources also doesn't know how to tell aptitude what to do with config files @@ -45,7 +45,7 @@ during upgrades. This prevented Puppet from being able to upgrade pacakges even when running standalone (via `puppet apply`). Finally, something about the switchover from Canonical's Puppet .debs to -Puppetlabs' .debs caused aptitude to consider all three packages "broken" +Puppetlabs' .debs caused aptitude to consider all three packages “broken” after a manual upgrade ('aptitude upgrade puppet puppetmaster'). Upgrading the packages a second time corrected it; this is the path I eventually took with my production puppetmaster and nodes. diff --git a/wiki/devops/self-daemonization-sucks.md b/wiki/devops/self-daemonization-sucks.md index 73bc784..b527da8 100644 --- a/wiki/devops/self-daemonization-sucks.md +++ b/wiki/devops/self-daemonization-sucks.md @@ -1,6 +1,6 @@ # Self-daemonizing code is awful -The classical UNIX approach to services is to implement them as "daemons", +The classical UNIX approach to services is to implement them as “daemons,” programs that run without a terminal attached and provide some service. The key feature of a classical daemon is that, when started, it carefully detaches itself from its initial environment and terminal, then continues @@ -23,7 +23,7 @@ stop it, to an unsuspecting `init`, which has no idea how this specific daemon is special. The standard workaround has daemons write their own PIDs to a file, but a -file is "dead" data: it's not automatically updated if the daemon dies, and +file is “dead” data: it's not automatically updated if the daemon dies, and can linger long enough to contain the PID of some later, unrelated program. PID file validity checks generally suffer from subtle (or, sometimes, quite gross) race conditions. @@ -73,6 +73,6 @@ This is a great application of [DRY](http://c2.com/cgi/wiki?DontRepeatYourself), as the daemon management code only needs to be written once (in the daemon-managing daemon) rather than many times over (in each individual daemon). It also makes daemon -execution more predictable, since daemons "in production" behave more like +execution more predictable, since daemons “in production” behave more like they do when run attached to a developer's console during debugging or development. diff --git a/wiki/email.md b/wiki/email.md index c584452..d7450eb 100644 --- a/wiki/email.md +++ b/wiki/email.md @@ -10,8 +10,8 @@ thought-intensive](http://blog.ninlabs.com/2013/01/programmer-interrupted/). Managing interruptions and my attention means I have to triage emails based on only two things: who sent them, and what they wrote in the subject line. If I didn't answer yours, it's probably not personal: I probably glanced at it when -it arrived and mentally put it on the "later" pile instead of the "now" pile, -and "later" can be a very long time indeed. +it arrived and mentally put it on the “later” pile instead of the “now” pile, +and “later” can be a very long time indeed. If it was actually important that I read and respond to your email, and I couldn't tell that from the subject, what the hell is wrong with your writing? diff --git a/wiki/ethics/lg-smart-tv.md b/wiki/ethics/lg-smart-tv.md index 51fdbc9..f544f02 100644 --- a/wiki/ethics/lg-smart-tv.md +++ b/wiki/ethics/lg-smart-tv.md @@ -4,7 +4,7 @@ [According to a UK blogger](http://doctorbeet.blogspot.co.uk/2013/11/lg-smart-tvs-logging-usb-fil -enames-and.html), LG Smart TVs not only offer "smart" features, but also +enames-and.html), LG Smart TVs not only offer “smart” features, but also track your viewing habits _extremely_ closely by submitting events back to LG and to LG's advertising affiliates. @@ -18,7 +18,7 @@ The page comments additionally suggest that the TV sends back information whenever the menu is opened, as well. This information is used to provide targeted advertising, likely to offset -the operational cost of the TV's "intelligent" features. Consumer protections +the operational cost of the TV's “intelligent” features. Consumer protections around personal data and tracking have traditionally been very weak, so it's not entirely surprising that LG would choose to extract revenue this way instead of raising the price of the product to cover the operational costs and instead of offering the intelligent features as a subscription service, but this is extremely disappointing. @@ -60,10 +60,10 @@ habit-revealing data available for free, too. ## Icing on the cake -The TV's settings menu contains an item entitled "Collection of watching -info" which can be turned to "On" (the default, even if the customer rejects +The TV's settings menu contains an item entitled “Collection of watching +info” which can be turned to “On” (the default, even if the customer rejects the end-user license agreement on the television and disables the -"intelligent" features) or "Off". It would be reasonable to expect that this +“intelligent” features) or “Off.” It would be reasonable to expect that this option would stop the TV from communicating viewing habits to the internet; however, the setting appears to do very little. The article shows packet captures of the TV submitting viewing information to LG with the setting in @@ -74,7 +74,7 @@ _actually_ does or to clarify expectations around it. ## LG's stance is morally indefensible -From the blog post, LG's representative claims that viewers "agree" to this +From the blog post, LG's representative claims that viewers “agree” to this monitoring when they accept the TV's end-user license agreement, and that it's up to the retailer to inform the user of the contents of the license agreement. However: @@ -90,7 +90,7 @@ agreement. However: It is not reasonable to expect customers to assume their TV will track viewing habits publicly. This is not a behaviour that TVs have had over their multi-decade existence, and it's disingenuous for LG to act like the customer -"should have known" in any sense that the LG TV acts in this way. +“should have known” in any sense that the LG TV acts in this way. LG is hiding behind the modern culture of unfair post-sale contracts to impose a novel, deeply-invasive program of customer monitoring for their own diff --git a/wiki/ethics/linkedin-intro.md b/wiki/ethics/linkedin-intro.md index 1564959..20b8c5c 100644 --- a/wiki/ethics/linkedin-intro.md +++ b/wiki/ethics/linkedin-intro.md @@ -4,7 +4,7 @@ provided by LinkedIn that inserts LinkedIn relationship data into the user's incoming and outgoing mail. This allows, for example, LinkedIn to decorate incoming mail with a toolbar linking to the sender's LinkedIn account, and -automatically injects a short "signature" of your LinkedIn profile into +automatically injects a short “signature” of your LinkedIn profile into outgoing mail. These are useful features, and the resulting interaction is quite smooth. @@ -21,8 +21,8 @@ LinkedIn Intro's proxy mail server must be able to log into the user's real incoming mail server to retrieve mail, and often must log into the user's real outgoing mail server to deliver mail with correct SPF or DKIM validation. This implies that LinkedIn Intro must know the user's email credentials, which it -acquires from their mobile device. Since this is a "use" of a password, not -merely a "validation" of an incoming password, the password must be available +acquires from their mobile device. Since this is a “use” of a password, not +merely a “validation” of an incoming password, the password must be available _to LinkedIn_ as plain text. There are two serious problems with this that are directly LinkedIn's responsibilty, and a third that's indirect but important. (Some email providers - notably Google - support non-password, @@ -84,7 +84,7 @@ of either the sender's or the recipients' control. LinkedIn is in a position to claim that Intro users have given it _permission_ to be intrusive into their email in this way. -Very few people use a dedicated email account for "corporate networking" and +Very few people use a dedicated email account for “corporate networking” and recruiting activities. A CEO (LinkedIn's own example) recieves mail pertaining to many sensitive aspects of a corporation's running: lawsuit notices, gossip among the exec team, planning emails discussing the future of the company, @@ -99,7 +99,7 @@ Users in heavily-regulated industries, such as health care or finance, may be exposing their whole organization to government interventions by using Intro, as LinkedIn is not known to be HIPAA, SOX, or PCI compliant. -The resulting "who mailed what to whom" database is hugely valuable. I expect +The resulting “who mailed what to whom” database is hugely valuable. I expect LinkedIn to be banking on this; such a corpus of conversational data would greatly help them develop new features targetting specific groups of users, and could improve the overall effectiveness of their recommendation engine. @@ -127,7 +127,7 @@ All of the risks outlined above are manageable. With proper information, the end user can make an informed decision as to whether * to ignore Intro at all, or -* to use Intro with a dedicated "LinkedIn Only" email account, or +* to use Intro with a dedicated “LinkedIn Only” email account, or * to use Intro with everything LinkedIn's own marketing materials outline _absolutely none_ of these risks. @@ -159,7 +159,7 @@ its users' security needs. In particular: A breach in LinkedIn proper may not imply a breach in LinkedIn Intro, and vice versa, but there must be at least some data passing back and forth for Intro to operate. The nature and structure of the security mechanisms that permit -the "right" kind of data are not elaborated on; it's impossible to decide how +the “right” kind of data are not elaborated on; it's impossible to decide how well they actually insulate Intro from LinkedIn. Furthermore, a breach in LinkedIn Intro is still incredibly damaging even if it doesn't span LinkedIn itself. @@ -181,7 +181,7 @@ both government and private. If either of those conditions does not hold, it's worse. The software industry is young, and immature, and wealthy. There is no ethics -body to complain to; had the developers of Intro said "no", they would very +body to complain to; had the developers of Intro said “no,” they would very likely have been replaced by another round of developers who would help LinkedIn violate their users' privacy. That does not excuse LinkedIn; their product is vile, and must not be tolerated in the market. diff --git a/wiki/ethics/musings.md b/wiki/ethics/musings.md index e41276b..b9a899b 100644 --- a/wiki/ethics/musings.md +++ b/wiki/ethics/musings.md @@ -50,27 +50,27 @@ for society. ## Integrity is not about contracts or legislation Ethics, personal integrity, and group integrity are tangled together, but -modern Western conceptions of group integrity tend to revolve around "does -this group break the law or engender lawsuits," not "does this group act in -the best interests of people outside of it." +modern Western conceptions of group integrity tend to revolve around “does +this group break the law or engender lawsuits,” not “does this group act in +the best interests of people outside of it.” ## Assumptions -I've embedded some of my personal morality into the "ethics" articles in this +I've embedded some of my personal morality into the “ethics” articles in this section, in the absence of a published moral code. Those, obviously, aren't absolute, but you can reason about their validity if you assume that I -believe the "end user's" privacy and active consent take priority over the +believe the “end user's” privacy and active consent take priority over the technical cleverness or business value of a software system. ### Consent and social software -This has some complicated downstream effects: "active consent" means +This has some complicated downstream effects: “active consent” means something you can't handwave away by putting implied consent (for example, to future changes) in an EULA or privacy statement. I haven't written much that calls out this pattern because it's _pervasive_. -The "end user is the real product" business model most social networks +The “end user is the real product” business model most social networks operate on is fundamentally unethical under this code. It will always be more -valuable to the "real customers" (advertisers, analytics platforms, law +valuable to the “real customers” (advertisers, analytics platforms, law enforcement, and intelligence agencies) for users to be opted into new measurements by default, _assuming_ consent rather than obtaining it. diff --git a/wiki/git/config.md b/wiki/git/config.md index 511542a..9ee058b 100644 --- a/wiki/git/config.md +++ b/wiki/git/config.md @@ -13,7 +13,7 @@ Full documentation is under `git help config`, unless otherwise stated. * `git config push.default simple` - the default behaviour (called `matching`) of an unqualified `git push` is to identify pairs of branches by name and push all matches from your local repository to the remote. Given that - branches have explicit "upstream" configuration identifying which, if any, + branches have explicit “upstream” configuration identifying which, if any, branch in which, if any, remote they're associated with, this is dumb. The `simple` mode pushes the current branch to its upstream remote, if and only if the local branch name and the remote branch name match _and_ the local @@ -29,7 +29,7 @@ Full documentation is under `git help config`, unless otherwise stated. * `git config rebase.autosquash true` - causes `git rebase -i` to parse magic comments created by `git commit --squash=some-hash` and `git commit --fixup=some-hash` and reorder the commit list before presenting it for - further editing. See the descriptions of "squash" and "fixup" in `git help + further editing. See the descriptions of “squash” and “fixup” in `git help rebase` for details; autosquash makes amending commits other than the most recent easier and less error-prone. @@ -40,10 +40,10 @@ Full documentation is under `git help config`, unless otherwise stated. `always`) this only happens when the start point is a remote-tracking branch. -* `git config rerere.enabled true` - enable "reuse recorded resolution". The +* `git config rerere.enabled true` - enable “reuse recorded resolution.” The `git help rerere` docs explain it pretty well, but the short version is that - git can record how you resolve conflicts during a "test" merge and reuse the - same approach when resolving the same conflict later, in a "real" merge. + git can record how you resolve conflicts during a “test” merge and reuse the + same approach when resolving the same conflict later, in a “real” merge. ## For advanced users @@ -52,7 +52,7 @@ you no longer need them. * `git config advice.detachedHead` - if you already understand the difference between having a branch checked out and having a commit checked out, and - already understand what "detatched head" means, the warning on every `git + already understand what “detatched head” means, the warning on every `git checkout ...some detatched thing...` isn't helping anyone. This is also useful repositories used for deployment, where specific commits (from tags, for example) are regularly checked out. diff --git a/wiki/git/pull-request-workflow.md b/wiki/git/pull-request-workflow.md index 2d7e216..700eeb6 100644 --- a/wiki/git/pull-request-workflow.md +++ b/wiki/git/pull-request-workflow.md @@ -69,7 +69,7 @@ If you need my help here, stop now. If you find yourself needing something that's been added upstream, use _rebase_ to integrate it to avoid littering your feature branch with -"meaningless" merge commits. +“meaningless” merge commits. git checkout my-feature git fetch upstream @@ -77,7 +77,7 @@ _rebase_ to integrate it to avoid littering your feature branch with ### Publish your branch -When you're "done", publish your branch to your personal repository: +When you're “done,” publish your branch to your personal repository: git push origin my-feature diff --git a/wiki/git/scratch.md b/wiki/git/scratch.md index 61d2815..a26c98f 100644 --- a/wiki/git/scratch.md +++ b/wiki/git/scratch.md @@ -6,7 +6,7 @@ Git repos are stored in .git: fakegit$ mkdir .git -They have a "symbolic ref" (which are text files, see [`man +They have a “symbolic ref” (which are text files, see [`man git-symbolic-ref`](http://jk.gs/git-symbolic-ref.html)) named `HEAD`, pointing to the currently checked-out branch. Let's use `master`. Branches are refs under `refs/heads` (see [`man git-branch`](http://jk.gs/git-branch.html)): @@ -46,10 +46,10 @@ Does it work? Should you do this? **Of course not.** Anywhere you could run these commands, you could instead run `git init` or `git clone`, which set up a number of other structures, including `.git/config` and any unusual permissions options. -The key part here is that a directory's identity as "a git repository" is +The key part here is that a directory's identity as “a git repository” is entirely a function of its contents, not of having been blessed into being by `git` itself. -You can infer a lot from this: for example, you can infer that it's "safe" to +You can infer a lot from this: for example, you can infer that it's “safe” to move git repositories around using FS tools, or to back them up with the same tools, for example. This is not as obvious to everyone as you might hope; people diff --git a/wiki/git/stop-using-git-pull-to-deploy.md b/wiki/git/stop-using-git-pull-to-deploy.md index b9021bb..078c95b 100644 --- a/wiki/git/stop-using-git-pull-to-deploy.md +++ b/wiki/git/stop-using-git-pull-to-deploy.md @@ -3,13 +3,13 @@ ## The problem * You have a Git repository containing your project. -* You want to "deploy" that code when it changes. +* You want to “deploy” that code when it changes. * You'd rather not download the entire project from scratch for each deployment. ## The antipattern -"I know, I'll use `git pull` in my deployment script!" +“I know, I'll use `git pull` in my deployment script!” Stop doing this. Stop teaching other people to do this. It's wrong, and it will eventually lead to deploying something you didn't want. @@ -32,7 +32,7 @@ the intended deployment tree. Local changes (intentional or otherwise) will be preserved (and merged) into the deployment, for example; once this happens, the actual deployed commit will _never_ match the intended commit. -`git pull` will approximate the right thing "by accident": if the current +`git pull` will approximate the right thing “by accident”: if the current local branch (generally `master`) for people using `git pull` is always clean, and always tracks the desired deployment branch, then `git pull` will update to the intended commit exactly. This is pretty fragile, though; many git @@ -65,7 +65,7 @@ Quoting [Sitaram Chamarty](http://gitolite.com/the-list-and-irc/deploy.html): > Again, some people might want to detect this and abort the deployment. Sitaram's own documentation talks about how to accomplish these when -"deploying" straight out of a bare repository. That's unwise (not to mention +“deploying” straight out of a bare repository. That's unwise (not to mention impractical) in most cases; deployment should use a dedicated clone of the canonical repository. diff --git a/wiki/git/survival.md b/wiki/git/survival.md index d7a79c1..60d1b62 100644 --- a/wiki/git/survival.md +++ b/wiki/git/survival.md @@ -3,7 +3,7 @@ I think the `git` UI is pretty awful, and encourages using Git in ways that will screw you. Here are a few things I've picked up that have saved my bacon. -* You will inevitably need to understand Git's "internals" to make use of it +* You will inevitably need to understand Git's “internals” to make use of it as an SCM tool. Accept this early. If you think your SCM tool should not expose you to so much plumbing, [don't](http://mercurial.selenic.com) [use](http://bazaar.canonical.com) [Git](http://subversion.apache.org). @@ -23,7 +23,7 @@ will screw you. Here are a few things I've picked up that have saved my bacon. integrate upstream changes into topic branches. The resulting history can be very confusing to follow, especially if you integrate upstream changes frequently. - * You can leave topic branches "out of date" relatively safely. You can do + * You can leave topic branches “real” relatively safely. You can do a test merge to see if they still work cleanly post-integration without actually integrating upstream into the branch permanently. * You can use `git rebase` or `git pull --rebase` to transplant your @@ -47,10 +47,10 @@ will screw you. Here are a few things I've picked up that have saved my bacon. git branch -D test-merge-foo You can combine this with `git rerere` to save time resolving conflicts in - a later "real", permanent merge. + a later “real,” permanent merge. * You can use `git checkout -p` to build new, tidy commits out of a branch - laden with "wip" commits: + laden with “wip” commits: git fetch git checkout $(git merge-base origin/master foo) -b foo-cleaner-history @@ -67,7 +67,7 @@ will screw you. Here are a few things I've picked up that have saved my bacon. * Gotcha: The new, clean branch must diverge from its upstream branch (`origin/master`, in the example above) at exactly the same point, or the diffs presented by `git checkout -p foo` will include chunks that - revert changes on the upstream branch since the "dirty" branch was + revert changes on the upstream branch since the “dirty” branch was created. The easiest way to find this point is with `git merge-base`. ## Useful Resources diff --git a/wiki/git/theory-and-practice/index.md b/wiki/git/theory-and-practice/index.md index 03615de..f257b12 100644 --- a/wiki/git/theory-and-practice/index.md +++ b/wiki/git/theory-and-practice/index.md @@ -1,6 +1,6 @@ # Git Internals 101 -Yeah, yeah, another article about "how Git works". There are tons of these +Yeah, yeah, another article about “how Git works.” There are tons of these already. Personally, I'm fond of Sitaram Chamarty's [fantastic series of articles](http://gitolite.com/master-toc.html) explaining Git from both ends, and of [Git for Computer @@ -8,22 +8,22 @@ Scientists](http://eagain.net/articles/git-for-computer-scientists/). Maybe you'd rather read those. This page was inspired by very specific, recurring issues I've run into while -helping people use Git. I think Git's "porcelain" layer -- its user interface +helping people use Git. I think Git's “porcelain” layer -- its user interface -- is terrible, and does a bad job of insulating non-expert users from Git's internals. While I'd love to fix that (and I do contribute to discussions on that front, too), we still have the `git(1)` UI right now and people still get into trouble with it right now. Git follows the New Jersey approach laid out in Richard Gabriel's [The Rise of -"Worse is Better"](http://www.dreamsongs.com/RiseOfWorseIsBetter.html): given +“Worse is Better”](http://www.dreamsongs.com/RiseOfWorseIsBetter.html): given the choice between a simple implementation and a simple interface, Git chooses the simple implementation almost everywhere. This internal simplicity can give users the leverage to fix the problems that its horrible user interface leads them into, so these pages will focus on explaining the simple parts and giving users the tools to examine them. -Throughout these articles, I've written "Git does X" a lot. Git is -_incredibly_ configurable; read that as "Git does X _by default_". I'll try to +Throughout these articles, I've written “Git does X” a lot. Git is +_incredibly_ configurable; read that as “Git does X _by default_.” I'll try to call out relevant configuration options as I go, where it doesn't interrupt the flow of knowledge. @@ -39,4 +39,4 @@ out there and that you won't need this knowledge, well, you will. You can either learn it during a quiet time, when you can think and experiment, or you can learn it when something's gone wrong, and everyone's shouting at each other. Git's high-level interface doesn't do much to keep you on the sensible -path, and you will eventually need to fix something. \ No newline at end of file +path, and you will eventually need to fix something. diff --git a/wiki/git/theory-and-practice/objects.md b/wiki/git/theory-and-practice/objects.md index 985e5dd..1ad3f26 100644 --- a/wiki/git/theory-and-practice/objects.md +++ b/wiki/git/theory-and-practice/objects.md @@ -1,7 +1,7 @@ # Objects Git's basest level is a storage and naming system for things Git calls -"objects". These objects hold the bulk of the data about files and projects +“objects.” These objects hold the bulk of the data about files and projects tracked by Git: file contents, directory trees, commits, and so on. Every object is identified by a SHA-1 hash, which is derived from its contents. @@ -54,8 +54,8 @@ system. Revisions and their history are represented by `commit` objects, which c * The SHA-1 hash of the root `tree` object of the commit, * Zero or more SHA-1 hashes for parent commits, - * The name and email address of the commit's "author", - * The name and email address of the commit's "committer", + * The name and email address of the commit's “author,” + * The name and email address of the commit's “committer,” * Timestamps representing when the commit was authored and committed, and * A commit message. @@ -67,9 +67,9 @@ predictable order determined by the `git checkout` and `git merge` commands. ## Tags -Git's revision-tracking system supports "tags", which are stable names for +Git's revision-tracking system supports “tags,” which are stable names for specific configurations. It also, uniquely, supports a concept called an -"annotated tag", represented by the `tag` object type. These annotated tag +“annotated tag,” represented by the `tag` object type. These annotated tag objects contain * The type and SHA-1 hash of another object, @@ -106,8 +106,8 @@ for providing stable, meaningful names for commits. ## Storage -Objects are stored in two places in Git: as "loose objects", and in "pack -files". Newly-created objects are initially loose objects, for ease of +Objects are stored in two places in Git: as “loose objects,” and in “pack +files.” Newly-created objects are initially loose objects, for ease of manipulation; transferring objects to another repository or running certain administrative commands can cause them to be placed in pack files for faster transfer and for smaller storage. diff --git a/wiki/git/theory-and-practice/refs-and-names.md b/wiki/git/theory-and-practice/refs-and-names.md index 45f58f2..025ae88 100644 --- a/wiki/git/theory-and-practice/refs-and-names.md +++ b/wiki/git/theory-and-practice/refs-and-names.md @@ -2,15 +2,15 @@ Git's [object system](objects) stores most of the data for projects tracked in Git, but only provides SHA-1 hashes. This is basically useless if you want to -make practical use of Git, so Git also has a naming mechanism called "refs" +make practical use of Git, so Git also has a naming mechanism called “refs” that provide human-meaningful names for objects. There are two kinds of refs: -* "Normal" refs, which are names that resolve directly to SHA-1 hashes. These +* “Normal” refs, which are names that resolve directly to SHA-1 hashes. These are the vast majority of refs in most repositories. -* "Symbolic" refs, which are names that resolve to other refs. In most +* “Symbolic” refs, which are names that resolve to other refs. In most repositories, only a few of these appear. (Circular references are possible with symbolic refs. Git will refuse to resolve these.) @@ -27,7 +27,7 @@ namespace convention. The following namespaces are common: * `refs/heads/NAME`: branches. The branch name is the ref name with `refs/heads/` removed. Names generally point to commits. -* `refs/remotes/REMOTE/NAME`: "remote-tracking" branches. These are maintained +* `refs/remotes/REMOTE/NAME`: “remote-tracking” branches. These are maintained in tandem by `git remote` and `git fetch`, to cache the state of other repositories. Names generally point to commits. @@ -54,7 +54,7 @@ rather than sanity-checking the ref before using it. There are a handful of special refs used by Git commands for their own operation. These refs do _not_ begin with `refs/`: -* `HEAD`: the "current" commit for most operations. This is set when checking +* `HEAD`: the “current” commit for most operations. This is set when checking out a commit, and many revision-related commands default to `HEAD` if not given a revision to operate on. `HEAD` can either be a symbolic ref (pointing to a branch ref) or a normal ref (pointing directly to a commit), @@ -91,4 +91,4 @@ The following commands can be used to manipulate refs directly: pointing to ``. Additionally, you can see what ref a given name resolves to using `git -rev-parse --symbolic-full-name ` or `git show-ref `. \ No newline at end of file +rev-parse --symbolic-full-name ` or `git show-ref `. diff --git a/wiki/gossamer/index.md b/wiki/gossamer/index.md index ec9811e..7964d13 100644 --- a/wiki/gossamer/index.md +++ b/wiki/gossamer/index.md @@ -29,7 +29,7 @@ mistakes, not merely different mistakes, and certainly not more mistakes. The following is loosely inspired by [Rumor Monger](http://www.mememotes.com/meme_motes/2005/02/rumor_monger.html), at -"whole world" scale. +“whole world” scale. ## Design Goals @@ -141,13 +141,13 @@ legitimate. Gossamer maintains relationships between identities to allow users to _verify_ the identities of one another, and to publish attestations of that -to other Gossamer nodes. From this, Gossamer can recover much of GPG's "web -of trust". +to other Gossamer nodes. From this, Gossamer can recover much of GPG's “web +of trust.” **TODO**: revocation of identities, revocation of verifications. Both are important; novice users are likely to verify people poorly, and there should -be a recovery path less drastic than GPG's "you swore it, you're stuck with -it" model. +be a recovery path less drastic than GPG's “you swore it, you're stuck with +it” model. Gossamer encourages users to create additional identities as needed to, for example, support the separation of work and home conversations, or to provide @@ -181,7 +181,7 @@ the same identity. WON'T**. Identity keys protect the user's Gossamer identity, but they _also_ protect the user's private messages (see below) and other potentially identifying data. The export format must be designed to be as resilient as -possible, and Gossamer's software must take care to ensure that "used" +possible, and Gossamer's software must take care to ensure that “used” identity files are _automatically_ destroyed safely wherever possible and to discourage users from following practices that weaken their own safety unknowingly. @@ -236,7 +236,7 @@ clear. The author's bare identity is included in the encrypted part of the message, to allow the intended recipient to identify the sender. **TODO**: sign-then-encrypt, or encrypt-then-sign? If sign-then-encrypt, are -private messages exempted from the "drop broken messages" rule above? +private messages exempted from the “drop broken messages” rule above? ## Following Users @@ -304,7 +304,7 @@ three or more identities in this database, will automatically be filtered out from display. (Additionally, transitively-blocked users will automatically be added to the block database. Blocking is contagious.) (**TODO**: should Gossamer _drop_ blocked messages? How does that interact with the inevitable -"shared blocklist" systems that arise in any social network?) +“shared blocklist” systems that arise in any social network?) As with the follow list, the block database is encrypted using the node's identities. @@ -328,12 +328,12 @@ Gossamer bootstraps its network using a number of paths: * Gossamer nodes in the same broadcast domain discover one another using UDP broadcasts as well as Bonjour/mDNS. -* Gossamer can generate _locator_ strings, which can be shared "out of band" +* Gossamer can generate _locator_ strings, which can be shared “out of band” via email, SMS messages, Twitter, graffiti, etc. * Gossamer nodes share knowledge of nodes whenever they exchange messages, to allow the Gossamer network to recover from lost nodes and to permit nodes - to remain on the network as "known" nodes are lost to outages and entropy. + to remain on the network as “known” nodes are lost to outages and entropy. ### Locators @@ -357,7 +357,7 @@ the identity list.) ### Gossip -Each Gossamer node maintains a pair of "freshness" databases, associating +Each Gossamer node maintains a pair of “freshness” databases, associating some information with a freshness score (expressed as an integer). One freshness database holds the addresses of known Gossamer nodes, and another holds Gossamer messages. @@ -365,14 +365,14 @@ holds Gossamer messages. Whenever two Gossamer nodes interact, each sends the other a Gossamer node from its current node database, and a message from its message database. When selecting an item to send for either category, Gossamer uses a random -selection that weights towards items with a higher "freshness" score. +selection that weights towards items with a higher “freshness” score. (**TODO**: how?) When sending a fact, if the receiving node already knows the fact, both nodes decrement that fact's freshness by one. If the receiving node _does not_ already know the fact, the sending node leaves its freshness unaltered, and the receiving node sets its freshness to the freshest possible value. This -system encourages nodes to exchange "fresh" facts, then cease exchanging them +system encourages nodes to exchange “fresh” facts, then cease exchanging them as the network becomes aware of them. During each exchange, Gossamer nodes send each other one Gossamer node diff --git a/wiki/gossamer/mistakes.md b/wiki/gossamer/mistakes.md index 110fe29..23b731b 100644 --- a/wiki/gossamer/mistakes.md +++ b/wiki/gossamer/mistakes.md @@ -40,13 +40,13 @@ Gossamer's network protocol converges towards a total graph, where every node knows how to connect to every other node, and new information (new posts) rapidly push out to every single node. -If you've ever been privy to the Twitter "firehose" feed, you'll understand +If you've ever been privy to the Twitter “firehose” feed, you'll understand why this is a drastic mistake. Even a moderately successful social network sees on the order of millions of messages a day. Delivering _all_ of this directly to _every_ node _all_ of the time would rapidly drown users in bandwidth charges and render their internet connections completely unusable. -Gossamer's design also has no concept of "quiet" periods: every fifteen to +Gossamer's design also has no concept of “quiet” periods: every fifteen to thirty seconds, rain or shine, every node is supposed to wake up and exchange data with some other node, regardless of how long it's been since either node in the exchange has seen new data. This very effectively ensures that @@ -74,7 +74,7 @@ Gossamer node immediately forwards it to at least one other node to inject it into the network. This makes unencrypted Gossamer relatively vulnerable to traffic analysis for correlating Gossamer identities with human beings. -Someone at a network "pinch point" -- an ISP, or a coffee shop wifi router -- +Someone at a network “pinch point” -- an ISP, or a coffee shop wifi router -- can monitor Gossamer traffic entering and exiting nodes on their network and easily identify which nodes originated which messages, and thus which nodes have access to which identities. This seriously compromises the effectiveness diff --git a/wiki/java/a-new-kind-of.md b/wiki/java/a-new-kind-of.md index 48cee4b..6cc81e5 100644 --- a/wiki/java/a-new-kind-of.md +++ b/wiki/java/a-new-kind-of.md @@ -5,20 +5,20 @@ previews](http://jdk8.java.net/download.html) right now, and I think you should, even if you don't like Java very much. There's so much _potential_ in there. -## The "One More Thing" +## The “One More Thing” The Java 8 release comes with a slew of notable library improvements: the new [`java.time`](http://openjdk.java.net/jeps/150) package, designed by the folks behind the extremely capable Joda time library; [reflective access](http://openjdk.java.net/jeps/118) to parameter names; [Unicode 6.2](http://openjdk.java.net/jeps/133) support; numerous others. But all of -these things are dwarfed by the "one last thing": +these things are dwarfed by the “one last thing”: **Lambdas**. ## Ok, So..? -Here's the thing: all of the "modern" languages that see regular use - C#, +Here's the thing: all of the “modern” languages that see regular use - C#, Python, Ruby, the various Lisps including Clojure, and Javascript - have language features allowing easy creation and use of one-method values. In Python, that's any object with a `__call__` method (including function @@ -27,12 +27,12 @@ features allow _computation itself_ to be treated as a value and passed around, which in turn provides a very powerful and succinct mechanism for composing features. -Java's had the "use" side down for a long time; interfaces like `Runnable` are -a great example of ways to expose "function-like" or "procedure-like" types to +Java's had the “use” side down for a long time; interfaces like `Runnable` are +a great example of ways to expose “function-like” or “procedure-like” types to the language without violating Java's bureaucratic attitude towards types and objects. However, the syntax for creating these one-method values has always been so verbose and awkward as to discourage their use. Consider, for example, -a simple "task" for a thread pool: +a simple “task” for a thread pool: pool.execute(new Runnable() { @Override @@ -46,7 +46,7 @@ a simple "task" for a thread pool: Even leaving out the optional-but-recommended `@Override` annotation, that's still five lines of code that only exist to describe to the compiler how to package up a block as an object. Yuck. For more sophisticated tasks, this sort -of verbosity has lead to multi-role "event handler" interfaces, to amortize +of verbosity has lead to multi-role “event handler” interfaces, to amortize the syntactic cost across more blocks of code. With Java 8's lambda support, the same (dumb) example collapses to @@ -62,7 +62,7 @@ software. ## Event-Driven Systems -As an example, I knocked together a simple "event driven IO" system in an +As an example, I knocked together a simple “event driven IO” system in an evening, loosely inspired by node.js. Here's the echo server I wrote as an example application, in its entirety: @@ -83,7 +83,7 @@ example application, in its entirety: } } -It's got a bad case of Javascript "arrow" disease, but it demonstrates the +It's got a bad case of Javascript “arrow” disease, but it demonstrates the expressive power of lambdas for callbacks. This is built on NIO, and runs in a single thread; as with any decent multiplexed-IO application, it starts to have capacity problems due to memory exhaustion well before it starts to @@ -120,7 +120,7 @@ Terser **and** clearer than the corresponding try-with-resources version: ## Domain-Specific Languages I haven't worked this one out, yet, but I think it's possible to use lambdas -to implement conversational interfaces, similar in structure to "fluent" +to implement conversational interfaces, similar in structure to “fluent” interfaces like [UriBuilder](http://docs.oracle.com/javaee/6/api/javax/ws/rs/core/UriBuilder.html). If I can work out the mechanics, I'll put together an example for this, but diff --git a/wiki/java/install/centos.md b/wiki/java/install/centos.md index 7cbfacf..51c83f6 100644 --- a/wiki/java/install/centos.md +++ b/wiki/java/install/centos.md @@ -29,7 +29,7 @@ Applications that can't autodetect the JDK may need `JAVA_HOME` set to The [Java SE Development Kit 7](http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html) -tarballs can be installed by hand. Download the "Linux x64" `.tar.gz` version, +tarballs can be installed by hand. Download the “Linux x64” `.tar.gz` version, then unpack it in `/opt`: cd /opt diff --git a/wiki/java/install/ubuntu.md b/wiki/java/install/ubuntu.md index c74ff04..75d3478 100644 --- a/wiki/java/install/ubuntu.md +++ b/wiki/java/install/ubuntu.md @@ -56,7 +56,7 @@ enough not to be able to detect the JDK, you can set `JAVA_HOME` to The [Java SE Development Kit 7](http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html) -tarballs can be installed by hand. Download the "Linux x64" `.tar.gz` version, +tarballs can be installed by hand. Download the “Linux x64” `.tar.gz` version, then unpack it in `/opt`: cd /opt diff --git a/wiki/java/kwargs.md b/wiki/java/kwargs.md index bd78d85..d745010 100644 --- a/wiki/java/kwargs.md +++ b/wiki/java/kwargs.md @@ -123,7 +123,7 @@ Possibilities for syntax: * `foo(x := 5, y := 8, z := 2)` - `:=` is never a legal sequence of tokens in Java. Introduces one new operator-like construct; the new sequence `:=` - "looks like" assignment, which is a useful mnemonic. + “looks like” assignment, which is a useful mnemonic. * `foo(x ~ 5, y ~ 8, z ~ 2)` - `~` is not a binary operator and this is never legal right now. This avoids introducing new operators, but adds a novel @@ -133,7 +133,7 @@ Possibilities for syntax: * `foo(.x = 5, .y = 8, .z = 2)` - using `=` as the keyword binding feels more natural. Parameter names must be legal identifiers, which means the leading dot is unambiguous. This syntax is not legal anywhere right now (the dot - always has a leading expression). The dot is a "namespace" symbol already. + always has a leading expression). The dot is a “namespace” symbol already. To support this, the class file format will need to record the names of parameters, not just their order. This is a breaking change, and generated @@ -149,4 +149,4 @@ from debug information, where present.) * Inheritance. It is legal for a superclass to define `foo(a, b)` and for subclasses to override it as `foo(x, y)`. Which argument names do you use when? -* Varargs. \ No newline at end of file +* Varargs. diff --git a/wiki/mysql/broken-xa.md b/wiki/mysql/broken-xa.md index ff7fa75..19afe22 100644 --- a/wiki/mysql/broken-xa.md +++ b/wiki/mysql/broken-xa.md @@ -15,8 +15,8 @@ manual](http://dev.mysql.com/doc/refman/5.5/en/xa-restrictions.html): If you're solving the kinds of problems where two-phase commit and XA transaction management look attractive, then you very likely have the kinds of -uptime requirements that make replication mandatory. "It works, but not with -replication" is effectively "it doesn't work". +uptime requirements that make replication mandatory. “It works, but not with +replication” is effectively “it doesn't work.” > It is possible that the server will roll back a pending XA transaction, even > one that has reached the PREPARED state. This happens if a client connection @@ -25,5 +25,5 @@ replication" is effectively "it doesn't work". XA transaction managers assume that if every resource successfully reaches the PREPARED state, then every resource will be able to commit the transaction -"eventually". Resources that unilaterally roll back PREPARED transactions +“eventually.” Resources that unilaterally roll back PREPARED transactions violate this assumption pretty badly. diff --git a/wiki/mysql/choose-something-else.md b/wiki/mysql/choose-something-else.md index 2851327..652ee84 100644 --- a/wiki/mysql/choose-something-else.md +++ b/wiki/mysql/choose-something-else.md @@ -30,17 +30,17 @@ Storage systems have four properties: 3. Provide stored data to applications on demand. 4. Give administrators effective management tools. -In a truly "pure" storage application, data-comprehension features +In a truly “pure” storage application, data-comprehension features (constraints and relationships, nontrivial functions and aggregates) would go -totally unused. There is a time and a place for this: the return of "NoSQL" +totally unused. There is a time and a place for this: the return of “NoSQL” storage systems attests to that. -Pure storage systems tend to be closely coupled to their "main" application: -consider most web/server app databases. "Secondary" clients tend to be +Pure storage systems tend to be closely coupled to their “main” application: +consider most web/server app databases. “Secondary” clients tend to be read-only (reporting applications, monitoring) or to be utilities in service of the main application (migration tools, documentation tools). If you believe constraints, validity checks, and other comprehension features can be -implemented in "the application", you are probably thinking of databases close +implemented in “the application,” you are probably thinking of databases close to this pole. ### Storing Data @@ -79,7 +79,7 @@ familiar with other SQL implementations). Swedish alphabetization rules, case-insensitively. * Since it's the default, lots of folks who don't know the manual inside-out and backwards observe MySQL's case-insensitive collation - behaviour (`'a' = 'A'`) and conclude that "MySQL is case-insensitive", + behaviour (`'a' = 'A'`) and conclude that “MySQL is case-insensitive,” complicating any effort to use a case-sensitive locale. * Both the encoding and the collation can vary, independently, by _column_. Do you keep your schema definition open when you write @@ -125,7 +125,7 @@ implicit string-to-integer conversions. ... against loss: hoo boy. MySQL, out of the box, gives you three approaches to [backups](http://dev.mysql.com/doc/refman/5.5/en/backup-methods.html): -* Take "blind" filesystem backups with `tar` or `rsync`. Unless you +* Take “blind” filesystem backups with `tar` or `rsync`. Unless you meticulously lock tables or make the database read-only for the duration, this produces a backup that requires crash recovery before it will be usable, and can produce an inconsistent database. @@ -152,13 +152,13 @@ the [behaviour](http://dev.mysql.com/doc/refman/5.5/en/replication-formats.html) is to log SQL statements, rather than logging their side effects. This has lead to numerous bugs over the years; MySQL (now) makes an effort to make -common "non-deterministic" cases such as `NOW()` and `RANDOM()` act +common “non-deterministic” cases such as `NOW()` and `RANDOM()` act deterministically but these have been addressed using ad-hoc solutions. Restoring binary-log-based backups can easily lead to data that differs from the original system, and by the time you've noticed the problem, it's too late to do anything about it. -(Seriously. The binary log entries for each statement contain the "current" +(Seriously. The binary log entries for each statement contain the “current” time on the master and the random seed at the start of the statement, just in case. If your non-deterministic query uses any other function, you're still [fucked by @@ -233,7 +233,7 @@ that implicitly transform stored data before returning it: You might think this is an unreasonable example: maybe you should always make sure your argument types exactly match the field types, and the query - should use `57` instead of `'banana'`. (This does actually "fix" the + should use `57` instead of `'banana'`. (This does actually “fix” the problem.) It's unrealistic to expect every single user to run `SHOW CREATE TABLE` before every single query, or to memorize the types of every column in your schema, though. This example derived from a technically-skilled @@ -358,7 +358,7 @@ fixed) type constraints: foreign key pointing into a MyISAM or NDB table, do not cause warnings or any other diagnostics. The foreign key is simply discarded. SURPRISE. (MySQL is riddled with these sorts of surprises, and apologists lean - very heavily on the "that's documented" excuse for its bad behaviour.) + very heavily on the “that's documented” excuse for its bad behaviour.) * The MySQL parser recognizes `CHECK` clauses, which allow schema developers to make complex declarative assertions about tuples in the database, but [discards them without @@ -370,7 +370,7 @@ fixed) type constraints: case](https://dev.mysql.com/doc/refman/5.5/en/timestamp-initialization.html) of at most one `TIMESTAMP` column per table and at most one sequence-derived column. Who designed this mess? - * Furthermore, there's no way to say "no default" and raise an error when + * Furthermore, there's no way to say “no default” and raise an error when an INSERT forgets to provide a value. The default `DEFAULT` is either `NULL` or a zero-like constant (`0`, `''`, and so on). Even for types with no meaningful zero-like values (`DATETIME`). @@ -385,7 +385,7 @@ because MySQL _cannot help you_ if you make a mistake. ### Summarizing and Deriving Data -SQL databases generally provide features for doing "interesting" things with +SQL databases generally provide features for doing “interesting” things with sets of tuples, and MySQL is no exception. However, MySQL's limitations mean that actually processing data in the database is fraught with wasted money, brains, and time: @@ -415,7 +415,7 @@ brains, and time: * MySQL's query planner can't fold constraints from outer queries into subqueries. * The generated in-memory table never has any indexes, ever, even when - appropriate indexes are "obvious" from the surrounding query; you cannot + appropriate indexes are “obvious” from the surrounding query; you cannot even specify them. * These limitations also affect views, which are evaluated as if they were subqueries. In combination with the lack of constraint folding in the @@ -452,19 +452,19 @@ brains, and time: using simple algebra, many useful cases (whitespace-insensitive comparison, hash-based comparisons, and so on) can't. * You can fake these by storing the computed value in the row alongside - the "real" value. This leaves your schema with some ugly data repetition + the “real” value. This leaves your schema with some ugly data repetition and a chance for the two to fall out of sync, and clients must use the - "computed" column explicitly. - * Oh, and they must maintain the "computed" version explicitly. + “computed” column explicitly. + * Oh, and they must maintain the “computed” version explicitly. * Or you can use triggers. Ha. See above. And now you know why MySQL advocates are such big fans of doing data -_processing_ in "the client" or "the app". +_processing_ in “the client” or “the app.” ### Alternate Representations and Derived Tables Many databases let schema designers and administrators abstract the underlying -"physical" table structure from the presentation given to clients, or to some +“physical” table structure from the presentation given to clients, or to some specific clients, for any of a number of reasons. MySQL tries to let you do this, too! And fumbles it quite badly. @@ -474,12 +474,12 @@ this, too! And fumbles it quite badly. partitioning arrangements or a permissions check in a view if you want any kind of performance. * The poor interactions between triggers and binary logging's default - configuration make it impractical to use triggers to maintain "materialized" - views to avoid the problems with "real" views. + configuration make it impractical to use triggers to maintain “materialized” + views to avoid the problems with “real” views. * It also effectively means triggers can't be used to emulate `CHECK` constraints and other consistency features. * Code to maintain materialized views is also finicky and hard to get - "right", especially if the view includes aggregates or interesting joins + “right,” especially if the view includes aggregates or interesting joins over its source data. I hope you enjoy debugging MySQL's procedural SQL… * For the relatively common case of wanting to abstract partitioned storage @@ -487,7 +487,7 @@ this, too! And fumbles it quite badly. tool](http://dev.mysql.com/doc/refman/5.5/en/partitioning.html) for it! But it comes with [enough caveats to strangle a horse](http://dev.mysql.com/doc/refman/5.5/en/partitioning-limitations.html): - * It's a separate table engine wrapping a "real" storage engine, which + * It's a separate table engine wrapping a “real” storage engine, which means it has its own, separate support for engine-specific features: transactions, foreign keys, and index types, `AUTO_INCREMENT`, and others. The syntax for configuring partitions makes selecting the wrong @@ -503,13 +503,13 @@ this, too! And fumbles it quite badly. together in the same file. Partitioning InnoDB tables is a waste of time for managing storage. * TL,DR: MySQL's partition support is so finicky and limited that - MySQL-based apps tend to opt for multiple MySQL servers ("sharding") + MySQL-based apps tend to opt for multiple MySQL servers (“sharding”) instead. ### Hosting Logic In The Database -Yeah, yeah, the usual reaction to stored procedures and in-DB code is "eww, -yuck!" for some not-terrible reasons, but hear me out on two points: +Yeah, yeah, the usual reaction to stored procedures and in-DB code is “eww, +yuck!” for some not-terrible reasons, but hear me out on two points: * Under the freestanding-database-server paradigm, there will usually be network latency between database clients and the database itself. There are @@ -572,7 +572,7 @@ choices: END LOOP; END; - The original "structured programming" revolution in the 1960s seems to + The original “structured programming” revolution in the 1960s seems to have passed the MySQL team by. * Okay, I lied. There are two looping constructs: there's also the `REPEAT ... @@ -581,7 +581,7 @@ choices: can't run zero iterations of the loop's main body this way. * There is nothing resembling a modern exception system with automatic scoping of handlers or declarative exception management. Error handling is entirely - via Visual Basic-style "on condition X, do Y" instructions, which remain in + via Visual Basic-style “on condition X, do Y” instructions, which remain in effect for the rest of the program's execution. * In the language shipped with MySQL 5.0, there wasn't a way to signal errors, either: programmers had to resort to stunts like [intentionally @@ -628,11 +628,11 @@ impact on the performance of various query plans, but the channels back to the query planner provide very little granularity for estimating cost and prevent the planner from making good use of the engine in unusual cases. Conversely, the table engine system is totally isolated from the actual query, and can't -make query-dependent performance choices "on its own". There's no third path; +make query-dependent performance choices “on its own.” There's no third path; the query planner itself is not pluggable. Similar consequences apply to type checking, support for new types, or even -something as "obvious" as multiple automatic `TIMESTAMP` columns in the same +something as “obvious” as multiple automatic `TIMESTAMP` columns in the same table. Table manipulation -- creation, structural modification, and so on -- runs @@ -652,7 +652,7 @@ constructs necessarily slow to implement and slow to test. ### Poor Priorities -Early on, the MySQL team focused on pure read performance and on "ease of use" +Early on, the MySQL team focused on pure read performance and on “ease of use” (for new users with simple needs, as far as I can tell) over correctness and completeness, violating Knuth's laws of optimization. Many of these decisions locked MySQL into behaviours very early in its life that it still displays @@ -712,7 +712,7 @@ following are much more common: database intelligently are very hard to notice in action. * **We already know how to use it.** MySQL development and administration causes brain damage, folks, the same way PHP does. Where PHP teaches - programmers that "array" is the only structure you need, MySQL teaches + programmers that “array” is the only structure you need, MySQL teaches people that databases are awkward, slow, hard-to-tune monsters that require constant attention. That doesn't have to be true; there are comfortable, fast, and easily-tuned systems out there that don't require daily care and @@ -736,7 +736,7 @@ following are much more common: embedded MySQL has even bigger problems than freestanding MySQL). * **It's getting better, so we might as well stay on it.** [It's true](http://dev.mysql.com/doc/refman/5.6/en/mysql-nutshell.html), if you go - by feature checklists and the manual, MySQL is improving "rapidly". 5.6 is + by feature checklists and the manual, MySQL is improving “rapidly.” 5.6 is due out soon and superficially looks to contain a number of good changes. I have two problems with this line of reasoning: 1. Why wait? Other databases are good _now_, not _eventually_. diff --git a/wiki/packaging-ideas.md b/wiki/packaging-ideas.md index b70520b..a881358 100644 --- a/wiki/packaging-ideas.md +++ b/wiki/packaging-ideas.md @@ -1,11 +1,11 @@ -# Why "Web 2.0" Matters +# Why “Web 2.0” Matters It's not about Web 2.0. It's about every stupid industry buzzword that's ever made programmers roll their eyes. ## Packaging ideas -"Web 2.0" gives people who don't live and breathe technology a handy hook to +“Web 2.0” gives people who don't live and breathe technology a handy hook to group ideas on. * New, unfamiliar ideas @@ -16,5 +16,5 @@ group ideas on. A well-packaged idea has to do two things: 1. Get the idea into someone's head. -2. Let someone "unpackage" the idea in their own context and think new things +2. Let someone “unpackage” the idea in their own context and think new things about it. diff --git a/wiki/people/rape-culture-and-men.md b/wiki/people/rape-culture-and-men.md index 0a02066..ca97504 100644 --- a/wiki/people/rape-culture-and-men.md +++ b/wiki/people/rape-culture-and-men.md @@ -2,20 +2,20 @@ In the last couple of years, I've been interacting with folks who take a more active hand in gender and social issues, and it's changed the way I see the -word "rape". It didn't entirely make sense to me how so many people could be +word “rape.” It didn't entirely make sense to me how so many people could be self-identified victims of rape culture while so few people are, even in a euphemistic way, identifiable as rapists, so I dug a bit at my assumptions. Growing up immersed in what I now recognize as the early stages of modern -"news" culture, rape was always reported as a violent act. Something so black +“news” culture, rape was always reported as a violent act. Something so black and white that if you committed rape, you would know yourself to be a rapist. Media descriptions of rape and of rapists focussed on acts of overt violence: -"she was in the wrong neighbourhood and got raped at knifepoint", "held down -and raped", and so on. +“she was in the wrong neighbourhood and got raped at knifepoint,” “held down +and raped,” and so on. -Reading more recent postings on the idea of "rape culture", however, paints a -very different picture of the same word. "Raped at a party", "too drunk to -consent", and other depictions of rape as an act of exploitation (or, +Reading more recent postings on the idea of “rape culture,” however, paints a +very different picture of the same word. “Raped at a party,” “too drunk to +consent,” and other depictions of rape as an act of exploitation (or, appallingly, convenience or indifference) rather than violence. Let me be perfectly clear here: without _active consent_, any sexual contact @@ -23,7 +23,7 @@ is rape or is on the road to it. In that sense, violence, exploitation, intoxication and other forms of coercion are interchangeable and equally vile. However, when the public idea of rape is limited to rapes with overt violence, -it's really easy to excuse non-violent coerced sex as "not really rape". After +it's really easy to excuse non-violent coerced sex as “not really rape.” After all, you didn't hit her, did you? She never said _no_ and _meant it_, right? I don't know what I'm going to do with this insight, yet, but I think it's an @@ -33,7 +33,7 @@ already have. Relevant reading: -* ["My friend group has a case of Creepy Dude", by Captain +* [“My friend group has a case of Creepy Dude,” by Captain Awkward](http://captainawkward.com/2012/08/07/322-323-my-friend-group-has-a-case-of-the-creepy-dude-how-do-we-clear-that-up/) (which also reminded me that it's possible to be a creep to your girlfriend) -* ["Meet the Predators", from the fantastic Yes Means Yes](http://yesmeansyesblog.wordpress.com/2009/11/12/meet-the-predators/), cited in the Captain Awkward article but worth a read on its own well-researched merits. +* [“Meet the Predators,” from the fantastic Yes Means Yes](http://yesmeansyesblog.wordpress.com/2009/11/12/meet-the-predators/), cited in the Captain Awkward article but worth a read on its own well-researched merits. diff --git a/wiki/people/rincewind.md b/wiki/people/rincewind.md index 23c7c25..7dbc202 100644 --- a/wiki/people/rincewind.md +++ b/wiki/people/rincewind.md @@ -11,7 +11,7 @@ capable of magic. Rincewind is a wizard: he is not well fed, having spent his life being thrust from one adventure to the next; his body is more attuned for running away from things than it is for meandering the halls or sitting by a fire; his -opinions largely revolve around "is this new thing going to eat me," rather +opinions largely revolve around “is this new thing going to eat me,” rather than more abstract matters; importantly, he is completely incapable of magic, in spite of years of study. @@ -26,7 +26,7 @@ back, while she was teaching herself to program. I don't recall exactly what prompted it, but at one point I told her to stop worrying about all the better programmers out there: from everyone else's point of view, she was already a wizard. There might be better wizards, and worse wizards, but she'd -already passed any sort of bright line delimiting "not a programmer" from -"programmer". +already passed any sort of bright line delimiting “not a programmer” from +“programmer.” I think self-identification is important, and overlooked. -- cgit v1.2.3