├── .eleventy.js
├── .eleventyignore
├── .forestry
└── settings.yml
├── .gitattributes
├── .gitignore
├── .nvmrc
├── 404.md
├── LICENSE
├── LICENSE.txt
├── README.md
├── _data
└── site.json
├── _includes
├── assets
│ ├── css
│ │ ├── 404.css
│ │ └── inline.css
│ ├── images
│ │ └── github.svg
│ ├── js
│ │ ├── 404.js
│ │ ├── inline.js
│ │ └── search.js
│ └── utils
│ │ ├── image.txt
│ │ └── imagesize.txt
├── components
│ ├── contact.njk
│ ├── footer.njk
│ ├── head.njk
│ ├── header.njk
│ └── nav.njk
├── experimental
│ └── blog
│ │ ├── author.njk
│ │ ├── authors.njk
│ │ ├── components
│ │ ├── pageslist.njk
│ │ └── postslist.njk
│ │ ├── content
│ │ └── posts
│ │ │ ├── firstpost.md
│ │ │ ├── fourthpost.md
│ │ │ ├── posts.json
│ │ │ ├── secondpost.md
│ │ │ ├── the-fifth-and-hopefully-final-example-post.md
│ │ │ └── thirdpost.md
│ │ ├── layouts
│ │ ├── blog.njk
│ │ └── post.njk
│ │ ├── pages
│ │ └── blog.md
│ │ └── tags.njk
└── layouts
│ ├── 404.njk
│ ├── base.njk
│ ├── contact.njk
│ ├── page.njk
│ └── robots.njk
├── admin
├── config.yml
├── index.html
└── preview-templates
│ ├── index.js
│ ├── page.js
│ └── post.js
├── content
├── buy.md
├── images
│ └── hello.jpg
└── pages
│ ├── contact.md
│ ├── home.md
│ └── pages.json
├── filters
└── searchFilter.js
├── loader.js
├── manuscript
├── Book.txt
├── manuscript.json
├── process.json
├── process.md
├── rules.json
├── rules.md
├── why.json
└── why.md
├── netlify.toml
├── outline.md
├── package.json
├── password_template.html
├── postcss.config.js
├── robots.md
├── search-index.json.njk
├── styles
├── tailwind.config.js
└── tailwind.css
└── uploads
└── uws2.png
/.eleventy.js:
--------------------------------------------------------------------------------
1 | const { DateTime } = require("luxon");
2 | const CleanCSS = require("clean-css");
3 | const UglifyJS = require("uglify-es");
4 | const htmlmin = require("html-minifier");
5 | const svgContents = require("eleventy-plugin-svg-contents");
6 | const mdIterator = require('markdown-it-for-inline')
7 | const embedEverything = require("eleventy-plugin-embed-everything");
8 | const pluginTOC = require('eleventy-plugin-nesting-toc');
9 | const eleventyNavigationPlugin = require("@11ty/eleventy-navigation");
10 | const Image = require("@11ty/eleventy-img");
11 | const fs = require('fs');
12 | module.exports = function(eleventyConfig) {
13 | // eleventyConfig.addPlugin(pluginTOC);
14 | eleventyConfig.addPlugin(svgContents);
15 | eleventyConfig.addPlugin(embedEverything);
16 | eleventyConfig.addShortcode("version", function () {
17 | return String(Date.now());
18 | });
19 |
20 | // Responsive image shortcode
21 | eleventyConfig.addLiquidShortcode("image", async function(src, alt, sizes = "100vw") {
22 | if(alt === undefined) {
23 | // You bet we throw an error on missing alt (alt="" works okay)
24 | throw new Error(`Missing \`alt\` on responsiveimage from: ${src}`);
25 | }
26 | src = './content/images/'+src
27 | let metadata = await Image(src, {
28 | widths: [400, 600, 800, 1000, 1200, 1400, 1600, 1900],
29 | formats: ['webp', 'jpeg', 'png'],
30 | urlPath: "/content/images/",
31 | outputDir: "./_site/content/images/"
32 | });
33 |
34 | let lowsrc = metadata.jpeg[0];
35 |
36 | let picture = `
37 | ${Object.values(metadata).map(imageFormat => {
38 | return ` `;
39 | }).join("\n")}
40 |
45 | `;
46 |
47 | return `${picture}`;
48 |
49 | });
50 |
51 | eleventyConfig.addLiquidShortcode("icon", function(title,url) {
52 | return '';
53 | });
54 |
55 | // Button shortcode -- experimental
56 | // eleventyConfig.addLiquidShortcode("button", function(title,url) {
57 | // return ''+title+'';
58 | // });
59 |
60 |
61 | // Tailwind pass through and watch target
62 | eleventyConfig.addWatchTarget("./_tmp/style.css");
63 | eleventyConfig.addPassthroughCopy({ "./_tmp/style.css": "./style.css" });
64 |
65 | // Alpine.js pass through
66 | eleventyConfig.addPassthroughCopy({
67 | "./node_modules/alpinejs/dist/alpine.js": "./js/alpine.js",
68 | });
69 |
70 | // Eleventy Navigation https://www.11ty.dev/docs/plugins/navigation/
71 | eleventyConfig.addPlugin(eleventyNavigationPlugin);
72 |
73 | // Configuration API: use eleventyConfig.addLayoutAlias(from, to) to add
74 | // layout aliases! Say you have a bunch of existing content using
75 | // layout: post. If you don’t want to rewrite all of those values, just map
76 | // post to a new file like this:
77 | // eleventyConfig.addLayoutAlias("post", "layouts/my_new_post_layout.njk");
78 |
79 | // Merge data instead of overriding
80 | // https://www.11ty.dev/docs/data-deep-merge/
81 | eleventyConfig.setDataDeepMerge(true);
82 |
83 | // Add support for maintenance-free post authors
84 | // Adds an authors collection using the author key in our post frontmatter
85 | // Thanks to @pdehaan: https://github.com/pdehaan
86 | // eleventyConfig.addCollection("authors", collection => {
87 | // const blogs = collection.getFilteredByGlob("posts/*.md");
88 | // return blogs.reduce((coll, post) => {
89 | // const author = post.data.author;
90 | // if (!author) {
91 | // return coll;
92 | // }
93 | // if (!coll.hasOwnProperty(author)) {
94 | // coll[author] = [];
95 | // }
96 | // coll[author].push(post.data);
97 | // return coll;
98 | // }, {});
99 | // });
100 |
101 | // Creates custom collection "pages"
102 | eleventyConfig.addCollection("pages", function(collection) {
103 | return collection.getFilteredByGlob("pages/*.md");
104 | });
105 |
106 | // Creates custom collection "posts"
107 | // eleventyConfig.addCollection("posts", function(collection) {
108 | // const coll = collection.getFilteredByGlob("posts/*.md");
109 |
110 | // for(let i = 0; i < coll.length ; i++) {
111 | // const prevPost = coll[i-1];
112 | // const nextPost = coll[i + 1];
113 |
114 | // coll[i].data["prevPost"] = prevPost;
115 | // coll[i].data["nextPost"] = nextPost;
116 | // }
117 |
118 | // return coll;
119 | // });
120 |
121 |
122 | // Creates custom collection "results" for search
123 | const searchFilter = require("./filters/searchFilter");
124 | eleventyConfig.addFilter("search", searchFilter);
125 | eleventyConfig.addCollection("results", collection => {
126 | return [...collection.getFilteredByGlob("**/*.md")];
127 | });
128 |
129 | // Creates custom collection "menuItems"
130 | eleventyConfig.addCollection("menuItems", collection => {
131 | const coll = collection
132 | .getFilteredByGlob("manuscript/*.md")
133 | .sort((a, b) => {
134 | return (a.data.eleventyNavigation.order || 0) - (b.data.eleventyNavigation.order || 0);
135 | })
136 | return coll;
137 | });
138 |
139 | // Date formatting (human readable)
140 | eleventyConfig.addFilter("readableDate", dateObj => {
141 | return DateTime.fromJSDate(dateObj).toFormat("LLL dd, yyyy");
142 | });
143 |
144 | // Date formatting (machine readable)
145 | eleventyConfig.addFilter("machineDate", dateObj => {
146 |
147 | return DateTime.fromJSDate(dateObj).toFormat("yyyy-MM-dd");
148 | });
149 |
150 | // Minify CSS
151 | eleventyConfig.addFilter("cssmin", function(code) {
152 | return new CleanCSS({}).minify(code).styles;
153 | });
154 |
155 | // Minify JS
156 | eleventyConfig.addFilter("jsmin", function(code) {
157 | let minified = UglifyJS.minify(code);
158 | if (minified.error) {
159 | console.log("UglifyJS error: ", minified.error);
160 | return code;
161 | }
162 | return minified.code;
163 | });
164 |
165 | // Minify HTML output
166 | eleventyConfig.addTransform("htmlmin", function(content, outputPath) {
167 | if (outputPath.indexOf?.(".html") > -1) {
168 | let minified = htmlmin.minify(content, {
169 | useShortDoctype: true,
170 | removeComments: true,
171 | collapseWhitespace: true
172 | });
173 | return minified;
174 | }
175 | return content;
176 | });
177 |
178 | // Don't process folders with static assets e.g. images
179 | eleventyConfig.addPassthroughCopy("favicon.ico");
180 | eleventyConfig.addPassthroughCopy("images/")
181 | eleventyConfig.addPassthroughCopy("content/images/")
182 | eleventyConfig.addPassthroughCopy("admin");
183 | eleventyConfig.addPassthroughCopy("_includes/assets/");
184 | eleventyConfig.addPassthroughCopy("_includes/experimental/");
185 |
186 | /* Markdown Plugins */
187 | let markdownIt = require("markdown-it");
188 | let markdownItAnchor = require("markdown-it-anchor");
189 | let markdownItEmoji = require("markdown-it-emoji");
190 | let markdownItFootnote = require("markdown-it-footnote");
191 | let markdownItContainer = require("markdown-it-container");
192 | let markdownLinkifyImages = require('markdown-it-linkify-images')
193 | let markdownToc = require('markdown-it-table-of-contents')
194 | let markdownItTasks = require('markdown-it-task-lists')
195 | let markdownItAttrs = require("markdown-it-attrs")
196 | let markdownItCenterText = require("markdown-it-center-text")
197 | let options = {
198 | html: true,
199 | breaks: false,
200 | linkify: true,
201 | typographer: true
202 | };
203 | let opts = {
204 | // permalink: true,
205 | // permalinkClass: "direct-link",
206 | // permalinkSymbol: "#"
207 | };
208 |
209 | eleventyConfig.setLibrary("md", markdownIt(options)
210 | .use(mdIterator, 'url_new_win', 'link_open', function (tokens, idx) {
211 | const [attrName, href] = tokens[idx].attrs.find(attr => attr[0] === 'href')
212 | if (href && (!href.includes('franknoirot.co') && !href.startsWith('/') && !href.startsWith('#'))) {
213 | tokens[idx].attrPush([ 'target', '_blank' ])
214 | tokens[idx].attrPush([ 'rel', 'noopener noreferrer' ])
215 | }
216 | })
217 | .use(markdownItAnchor, opts)
218 | .use(markdownItEmoji)
219 | .use(markdownItFootnote)
220 | .use(markdownItContainer, 'callout')
221 | .use(markdownItContainer, 'callout-blue')
222 | .use(markdownItContainer, 'callout-pink')
223 | .use(markdownItContainer, 'callout-green')
224 | .use(markdownItContainer, 'warning')
225 | .use(markdownItTasks)
226 | .use(markdownItCenterText)
227 | .use(markdownLinkifyImages, {
228 | imgClass: "p-4",
229 | })
230 | .use(markdownItAttrs, {
231 | includeLevel: [2,3],
232 | listType: "ol"
233 | })
234 | );
235 |
236 | return {
237 | templateFormats: ["md", "njk", "html", "liquid"],
238 |
239 | // If your site lives in a different subdirectory, change this.
240 | // Leading or trailing slashes are all normalized away, so don’t worry about it.
241 | // If you don’t have a subdirectory, use "" or "/" (they do the same thing)
242 | // This is only used for URLs (it does not affect your file structure)
243 | pathPrefix: "/",
244 | markdownTemplateEngine: "liquid",
245 | htmlTemplateEngine: "njk",
246 | dataTemplateEngine: "njk",
247 | dir: {
248 | input: ".",
249 | includes: "_includes",
250 | data: "_data",
251 | output: "_site"
252 | }
253 | };
254 | };
--------------------------------------------------------------------------------
/.eleventyignore:
--------------------------------------------------------------------------------
1 | README.md
2 | .github/
3 | functions/*
4 | functions/
5 |
--------------------------------------------------------------------------------
/.forestry/settings.yml:
--------------------------------------------------------------------------------
1 | ---
2 | new_page_extension: md
3 | auto_deploy: false
4 | admin_path: ''
5 | webhook_url:
6 | sections:
7 | - type: directory
8 | path: ''
9 | label: Test
10 | create: all
11 | match: "**/*"
12 | upload_dir: uploads
13 | public_path: "/uploads"
14 | front_matter_path: ''
15 | use_front_matter_path: true
16 | file_template: ":filename:"
17 | build:
18 | preview_env:
19 | - ELEVENTY_ENV=dev
20 | preview_output_directory: _site
21 | install_dependencies_command: npm install
22 | preview_docker_image: forestryio/node:12
23 | mount_path: "/srv"
24 | working_dir: "/srv"
25 | instant_preview_command: npx @11ty/eleventy --serve
26 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
19 |
20 | _site/
21 | node_modules/
22 | package-lock.json
23 | .idea
24 | .vscode
25 | *~
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | _site/
2 | node_modules/
3 | package-lock.json
4 | .idea
5 | .vscode
6 | *~
7 | .cache
8 | _tmp
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | v14
2 |
--------------------------------------------------------------------------------
/404.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 404
3 | permalink: /404.html
4 | layout: layouts/404.njk
5 | ---
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Tim Broeker
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Creative Commons
2 | Attribution-NonCommercial-NoDerivs 3.0 Unported
3 |
4 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE.
5 |
6 | License
7 |
8 | THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
9 |
10 | BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
11 |
12 | 1. Definitions
13 |
14 | "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License.
15 | "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License.
16 | "Distribute" means to make available to the public the original and copies of the Work through sale or other transfer of ownership.
17 | "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License.
18 | "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast.
19 | "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work.
20 | "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
21 | "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images.
22 | "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium.
23 |
24 | 2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws.
25 |
26 | 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:
27 |
28 | to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; and,
29 | to Distribute and Publicly Perform the Work including as incorporated in Collections.
30 |
31 | The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats, but otherwise you have no rights to make Adaptations. Subject to 8(f), all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights set forth in Section 4(d).
32 |
33 | 4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:
34 |
35 | You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested.
36 | You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in connection with the exchange of copyrighted works.
37 | If You Distribute, or Publicly Perform the Work or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work. The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Collection, at a minimum such credit will appear, if a credit for all contributing authors of Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties.
38 |
39 | For the avoidance of doubt:
40 | Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License;
41 | Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b) and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and,
42 | Voluntary License Schemes. The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b).
43 | Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation.
44 |
45 | 5. Representations, Warranties and Disclaimer
46 |
47 | UNLESS OTHERWISE MUTUALLY AGREED BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
48 |
49 | 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
50 |
51 | 7. Termination
52 |
53 | This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
54 | Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.
55 |
56 | 8. Miscellaneous
57 |
58 | Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
59 | If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
60 | No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
61 | This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.
62 | The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law.
63 |
64 | Creative Commons Notice
65 |
66 | Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor.
67 |
68 | Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of this License.
69 |
70 | Creative Commons may be contacted at https://creativecommons.org/.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Prose for Programmers
2 |
3 | This is a book for programmers.
4 | It is a guide to mastering the most difficult programming language of all: human language.
5 |
6 | Just as with programming,
7 | we write with particular goals in mind.
8 | That goal might be as simple as reminding someone about a requirement
9 | or as complex as justifying an entirely new architecture for a product.
10 | But in every case we write in order to achieve something.
11 |
12 | This book will teach you how to achieve those goals more effectively with clearer, more persuasive writing.
13 |
14 | ## It is a work in progress
15 |
16 | The first three chapters are content complete.
17 |
18 | * [Why should developers study writing?](manuscript/why.md)
19 | * [General Rules](manuscript/rules.md)
20 | * [The Writing Process](manuscript/process.md)
21 |
22 | And there are four chapters to come.
23 |
24 | * Writing Structures
25 | * Audience
26 | * Genres
27 | * Other Resources
28 |
29 | For more detail, take a look at [the outline](outline.md).
30 |
31 | ## Can I get it in EPUB/MOBI/PDF?
32 |
33 | [Yes, you can.](https://leanpub.com/proseforprogrammers)
34 |
35 | ## Contributing
36 |
37 | * For general questions and suggestions, please [open an issue][issues].
38 | * To correct typos or suggest specific changes in the way something is written, please [open a pull request][prs].
39 |
40 | Note: By contributing content to this repository, you grant the book author (Joshua Clanton) a non-exclusive license to use that content in the book as he deems appropriate.
41 |
42 | ## License
43 |
44 | Prose for Programmers by Joshua Clanton is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.
45 |
46 | [issues]:https://github.com/joshuacc/prose-for-programmers/issues
47 | [prs]:https://github.com/joshuacc/prose-for-programmers/pulls
--------------------------------------------------------------------------------
/_data/site.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Prose for Programmers",
3 | "subtitle": "Learn to write for people, not just computers",
4 | "description": "Learn to write for people, not just computers",
5 | "footer": "Prose for Programmers by Joshua Clanton is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.",
6 | "url": "https://spacebook.app",
7 | "githubUrl": "https://github.com/joshuacc/prose-for-programmers",
8 | "githubBranch": "master",
9 | "navigationStyle": "vertical",
10 | "emoji": "✍🏻",
11 | "enableSearch": false,
12 | "enableDarkMode": true,
13 | "enableEditButton": true,
14 | "enableDatestamp": true,
15 | "enableGithubLink": true,
16 | "enableContact": false,
17 | "enableNetlifyCMS": false,
18 | "enableComments": false,
19 | "enableEncryption": false,
20 | "enablePageNavigation": true
21 | }
22 |
--------------------------------------------------------------------------------
/_includes/assets/css/404.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | width: 100%;
5 | margin: 0px;
6 | background: linear-gradient(90deg, #2f3640 23%, #181b20 100%);
7 | }
8 |
9 | .moon {
10 | background: linear-gradient(90deg, #d0d0d0 48%, #919191 100%);
11 | position: absolute;
12 | top: -100px;
13 | left: -300px;
14 | width: 900px;
15 | height: 900px;
16 | content: '';
17 | border-radius: 100%;
18 | box-shadow: 0px 0px 30px -4px rgba(0, 0, 0, 0.5);
19 | }
20 |
21 | .moon__crater {
22 | position: absolute;
23 | content: '';
24 | border-radius: 100%;
25 | background: linear-gradient(90deg, #7a7a7a 38%, #c3c3c3 100%);
26 | opacity: 0.6;
27 | }
28 |
29 | .moon__crater1 {
30 | top: 250px;
31 | left: 500px;
32 | width: 60px;
33 | height: 180px;
34 | }
35 |
36 | .moon__crater2 {
37 | top: 650px;
38 | left: 340px;
39 | width: 40px;
40 | height: 80px;
41 | transform: rotate(55deg);
42 | }
43 |
44 | .moon__crater3 {
45 | top: -20px;
46 | left: 40px;
47 | width: 65px;
48 | height: 120px;
49 | transform: rotate(250deg);
50 | }
51 |
52 | .star {
53 | background: grey;
54 | position: absolute;
55 | width: 5px;
56 | height: 5px;
57 | content: '';
58 | border-radius: 100%;
59 | transform: rotate(250deg);
60 | opacity: 0.4;
61 | animation-name: shimmer;
62 | animation-duration: 1.5s;
63 | animation-iteration-count: infinite;
64 | animation-direction: alternate;
65 | }
66 |
67 | @keyframes shimmer {
68 | from {
69 | opacity: 0;
70 | }
71 | to {
72 | opacity: 0.7;
73 | }
74 | }
75 |
76 | .star1 {
77 | top: 40%;
78 | left: 50%;
79 | animation-delay: 1s;
80 | }
81 |
82 | .star2 {
83 | top: 60%;
84 | left: 90%;
85 | animation-delay: 3s;
86 | }
87 |
88 | .star3 {
89 | top: 10%;
90 | left: 70%;
91 | animation-delay: 2s;
92 | }
93 |
94 | .star4 {
95 | top: 90%;
96 | left: 40%;
97 | }
98 |
99 | .star5 {
100 | top: 20%;
101 | left: 30%;
102 | animation-delay: 0.5s;
103 | }
104 |
105 | .error {
106 | position: absolute;
107 | left: 100px;
108 | top: 400px;
109 | transform: translateY(-60%);
110 | font-family: 'Righteous', cursive, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
111 | color: #363e49;
112 | }
113 |
114 | .error__title {
115 | font-size: 10em;
116 | }
117 |
118 | .error__subtitle {
119 | font-size: 2em;
120 | }
121 |
122 | .error__description {
123 | opacity: 0.5;
124 | }
125 |
126 | .error__button {
127 | min-width: 7em;
128 | margin-top: 3em;
129 | margin-right: 0.5em;
130 | padding: 0.5em 2em;
131 | outline: none;
132 | border: 2px solid #2f3640;
133 | background-color: transparent;
134 | border-radius: 8em;
135 | color: #576375;
136 | cursor: pointer;
137 | transition-duration: 0.2s;
138 | font-size: 0.75em;
139 | font-family: 'Righteous', cursive,ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";;
140 | }
141 |
142 | .error__button:hover {
143 | color: #21252c;
144 | }
145 |
146 | .error__button--active {
147 | background-color: #e67e22;
148 | border: 2px solid #e67e22;
149 | color: white;
150 | }
151 |
152 | .error__button--active:hover {
153 | box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.5);
154 | color: white;
155 | }
156 |
157 | .astronaut {
158 | position: absolute;
159 | width: 185px;
160 | height: 300px;
161 | left: 70%;
162 | top: 50%;
163 | transform: translate(-50%, -50%) rotate(20deg) scale(1.2);
164 | }
165 |
166 | .astronaut__head {
167 | background-color: white;
168 | position: absolute;
169 | top: 60px;
170 | left: 60px;
171 | width: 60px;
172 | height: 60px;
173 | content: '';
174 | border-radius: 2em;
175 | }
176 |
177 | .astronaut__head-visor-flare1 {
178 | background-color: #7f8fa6;
179 | position: absolute;
180 | top: 28px;
181 | left: 40px;
182 | width: 10px;
183 | height: 10px;
184 | content: '';
185 | border-radius: 2em;
186 | opacity: 0.5;
187 | }
188 |
189 | .astronaut__head-visor-flare2 {
190 | background-color: #718093;
191 | position: absolute;
192 | top: 40px;
193 | left: 38px;
194 | width: 5px;
195 | height: 5px;
196 | content: '';
197 | border-radius: 2em;
198 | opacity: 0.3;
199 | }
200 |
201 | .astronaut__backpack {
202 | background-color: #bfbfbf;
203 | position: absolute;
204 | top: 90px;
205 | left: 47px;
206 | width: 86px;
207 | height: 90px;
208 | content: '';
209 | border-radius: 8px;
210 | }
211 |
212 | .astronaut__body {
213 | background-color: #e6e6e6;
214 | position: absolute;
215 | top: 115px;
216 | left: 55px;
217 | width: 70px;
218 | height: 80px;
219 | content: '';
220 | border-radius: 8px;
221 | }
222 |
223 | .astronaut__body__chest {
224 | background-color: #d9d9d9;
225 | position: absolute;
226 | top: 140px;
227 | left: 68px;
228 | width: 45px;
229 | height: 25px;
230 | content: '';
231 | border-radius: 6px;
232 | }
233 |
234 | .astronaut__arm-left1 {
235 | background-color: #e6e6e6;
236 | position: absolute;
237 | top: 127px;
238 | left: 9px;
239 | width: 65px;
240 | height: 20px;
241 | content: '';
242 | border-radius: 8px;
243 | transform: rotate(-30deg);
244 | }
245 |
246 | .astronaut__arm-left2 {
247 | background-color: #e6e6e6;
248 | position: absolute;
249 | top: 102px;
250 | left: 7px;
251 | width: 20px;
252 | height: 45px;
253 | content: '';
254 | border-radius: 8px;
255 | transform: rotate(-12deg);
256 | border-top-left-radius: 8em;
257 | border-top-right-radius: 8em;
258 | }
259 |
260 | .astronaut__arm-right1 {
261 | background-color: #e6e6e6;
262 | position: absolute;
263 | top: 113px;
264 | left: 100px;
265 | width: 65px;
266 | height: 20px;
267 | content: '';
268 | border-radius: 8px;
269 | transform: rotate(-10deg);
270 | }
271 |
272 | .astronaut__arm-right2 {
273 | background-color: #e6e6e6;
274 | position: absolute;
275 | top: 78px;
276 | left: 141px;
277 | width: 20px;
278 | height: 45px;
279 | content: '';
280 | border-radius: 8px;
281 | transform: rotate(-10deg);
282 | border-top-left-radius: 8em;
283 | border-top-right-radius: 8em;
284 | }
285 |
286 | .astronaut__arm-thumb-left {
287 | background-color: #e6e6e6;
288 | position: absolute;
289 | top: 110px;
290 | left: 21px;
291 | width: 10px;
292 | height: 6px;
293 | content: '';
294 | border-radius: 8em;
295 | transform: rotate(-35deg);
296 | }
297 |
298 | .astronaut__arm-thumb-right {
299 | background-color: #e6e6e6;
300 | position: absolute;
301 | top: 90px;
302 | left: 133px;
303 | width: 10px;
304 | height: 6px;
305 | content: '';
306 | border-radius: 8em;
307 | transform: rotate(20deg);
308 | }
309 |
310 | .astronaut__wrist-left {
311 | background-color: #e67e22;
312 | position: absolute;
313 | top: 122px;
314 | left: 6.5px;
315 | width: 21px;
316 | height: 4px;
317 | content: '';
318 | border-radius: 8em;
319 | transform: rotate(-15deg);
320 | }
321 |
322 | .astronaut__wrist-right {
323 | background-color: #e67e22;
324 | position: absolute;
325 | top: 98px;
326 | left: 141px;
327 | width: 21px;
328 | height: 4px;
329 | content: '';
330 | border-radius: 8em;
331 | transform: rotate(-10deg);
332 | }
333 |
334 | .astronaut__leg-left {
335 | background-color: #e6e6e6;
336 | position: absolute;
337 | top: 188px;
338 | left: 50px;
339 | width: 23px;
340 | height: 75px;
341 | content: '';
342 | transform: rotate(10deg);
343 | }
344 |
345 | .astronaut__leg-right {
346 | background-color: #e6e6e6;
347 | position: absolute;
348 | top: 188px;
349 | left: 108px;
350 | width: 23px;
351 | height: 75px;
352 | content: '';
353 | transform: rotate(-10deg);
354 | }
355 |
356 | .astronaut__foot-left {
357 | background-color: white;
358 | position: absolute;
359 | top: 240px;
360 | left: 43px;
361 | width: 28px;
362 | height: 20px;
363 | content: '';
364 | transform: rotate(10deg);
365 | border-radius: 3px;
366 | border-top-left-radius: 8em;
367 | border-top-right-radius: 8em;
368 | border-bottom: 4px solid #e67e22;
369 | }
370 |
371 | .astronaut__foot-right {
372 | background-color: white;
373 | position: absolute;
374 | top: 240px;
375 | left: 111px;
376 | width: 28px;
377 | height: 20px;
378 | content: '';
379 | transform: rotate(-10deg);
380 | border-radius: 3px;
381 | border-top-left-radius: 8em;
382 | border-top-right-radius: 8em;
383 | border-bottom: 4px solid #e67e22;
384 | }
--------------------------------------------------------------------------------
/_includes/assets/css/inline.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joshuacc/prose-for-programmers/fc0c8a4a093f406d380768aa626615307fabf707/_includes/assets/css/inline.css
--------------------------------------------------------------------------------
/_includes/assets/images/github.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/_includes/assets/js/404.js:
--------------------------------------------------------------------------------
1 | (function (window, document) {
2 | "use strict";
3 | window.addEventListener('load', function () {
4 | const cordCanvas = document.getElementById('cord');
5 | const ctx = cordCanvas.getContext('2d');
6 |
7 | let y1 = 160;
8 | let y2 = 100;
9 | let y3 = 100;
10 |
11 | let y1Forward = true;
12 | let y2Forward = false;
13 | let y3Forward = true;
14 | drawVisor()
15 | //animate()
16 | });
17 | })(window, document);
18 |
19 | function drawVisor() {
20 | const canvas = document.getElementById('visor');
21 | const ctx = canvas.getContext('2d');
22 |
23 | ctx.beginPath();
24 | ctx.moveTo(5, 45);
25 | ctx.bezierCurveTo(15, 64, 45, 64, 55, 45);
26 |
27 | ctx.lineTo(55, 20);
28 | ctx.bezierCurveTo(55, 15, 50, 10, 45, 10);
29 |
30 | ctx.lineTo(15, 10);
31 |
32 | ctx.bezierCurveTo(15, 10, 5, 10, 5, 20);
33 | ctx.lineTo(5, 45);
34 |
35 | ctx.fillStyle = '#2f3640';
36 | ctx.strokeStyle = '#f5f6fa';
37 | ctx.fill();
38 | ctx.stroke();
39 | }
40 |
41 |
42 |
43 | function animate() {
44 | requestAnimationFrame(animate);
45 | ctx.clearRect(0, 0, innerWidth, innerHeight);
46 |
47 | ctx.beginPath();
48 | ctx.moveTo(130, 170);
49 | ctx.bezierCurveTo(250, y1, 345, y2, 400, y3);
50 |
51 | ctx.strokeStyle = 'white';
52 | ctx.lineWidth = 8;
53 | ctx.stroke();
54 |
55 |
56 | if (y1 === 100) {
57 | y1Forward = true;
58 | }
59 |
60 | if (y1 === 300) {
61 | y1Forward = false;
62 | }
63 |
64 | if (y2 === 100) {
65 | y2Forward = true;
66 | }
67 |
68 | if (y2 === 310) {
69 | y2Forward = false;
70 | }
71 |
72 | if (y3 === 100) {
73 | y3Forward = true;
74 | }
75 |
76 | if (y3 === 317) {
77 | y3Forward = false;
78 | }
79 |
80 | y1Forward ? y1 += 1 : y1 -= 1;
81 | y2Forward ? y2 += 1 : y2 -= 1;
82 | y3Forward ? y3 += 1 : y3 -= 1;
83 | }
84 |
--------------------------------------------------------------------------------
/_includes/assets/js/inline.js:
--------------------------------------------------------------------------------
1 | if (window.netlifyIdentity) {
2 | window.netlifyIdentity.on("init", user => {
3 | if (!user) {
4 | window.netlifyIdentity.on("login", () => {
5 | document.location.href = "/admin/";
6 | });
7 | }
8 | });
9 | }
10 |
11 | document.addEventListener("DOMContentLoaded", function() {
12 |
13 | const el = document.getElementById("main");
14 | el.addEventListener("click", closeNavigation, false)
15 |
16 | if (localStorage.getItem('darkmode') === 'true') {
17 | document.body.classList.add("dark");
18 | } else {
19 | document.body.classList.remove("dark");
20 | }
21 | });
22 |
23 | function logout() {
24 | localStorage.removeItem("passphrase")
25 | window.location.href = "/";
26 | }
27 |
28 | function showNavigation() {
29 | const navigation = document.getElementById("navigation");
30 | navigation.classList.remove("hidden", "sticky","pt-32");
31 | navigation.classList.add("absolute","right-0", "top-0", "-mt-0", "z-50", "pt-0", "bg-white","border-l", "border-gray-200");
32 | }
33 |
34 | function closeNavigation() {
35 | const navigation = document.getElementById("navigation");
36 | navigation.classList.add("hidden");
37 | navigation.classList.remove("absolute","right-0","z-50", "bg-gray-100", "border-r", "border-gray-800" );
38 | }
39 |
40 | function activateDarkMode() {
41 | if (localStorage.getItem('darkmode') === 'true') {
42 | localStorage.setItem('darkmode', 'false')
43 | document.body.classList.remove("dark");
44 | } else {
45 | localStorage.setItem('darkmode', 'true')
46 | document.body.classList.add("dark");
47 | }
48 | }
49 |
50 | function toggleLayout(state) {
51 | if (localStorage.getItem('layout') === "horizontal") {
52 | localStorage.setItem('layout', 'vertical')
53 | } else if (localStorage.getItem('layout') === "vertical") {
54 | localStorage.setItem('layout', "horizontal")
55 | } else if (!localStorage.getItem('layout')) {
56 | if (state === "horizontal") {
57 | localStorage.setItem('layout', 'vertical')
58 | } else {
59 | localStorage.setItem('layout', 'horizontal')
60 | }
61 | }
62 |
63 |
64 | console.log(localStorage.getItem('layout'))
65 | }
--------------------------------------------------------------------------------
/_includes/assets/js/search.js:
--------------------------------------------------------------------------------
1 | (function (window, document) {
2 | "use strict";
3 | const search = (e) => {
4 | const results = window.searchIndex.search(e.target.value, {
5 | bool: "OR",
6 | expand: true,
7 | });
8 | const searchBox = document.getElementById("searchField");
9 | const resEl = document.getElementById("searchResults");
10 | const noResultsEl = document.getElementById("noResultsFound");
11 | const navigation = document.getElementById("navigation");
12 |
13 | searchBox.addEventListener('focus', (event) => {
14 | event.target.classList.remove("hidden");
15 | resEl.classList.remove("hidden");
16 | });
17 |
18 | document.addEventListener('click', function(event) {
19 | var isClickInside = searchBox.contains(event.target);
20 | if (!isClickInside) {
21 | console.log('hidden')
22 | resEl.classList.add("hidden"),noResultsEl.classList.add("hidden")
23 | noResultsEl.classList.add("hidden")
24 | }
25 | });
26 |
27 | resEl.innerHTML = "";
28 | if (e.target.value != "") {
29 | if (results != "") {
30 | noResultsEl.classList.add("hidden")
31 | resEl.classList.add("p-4")
32 | results.map((r) => {
33 | const { id, title, description } = r.doc;
34 | const el = document.createElement("li", { tabindex: '-1' });
35 | resEl.appendChild(el);
36 |
37 | const h3 = document.createElement("h3");
38 | el.appendChild(h3);
39 |
40 | const a = document.createElement("a");
41 | a.setAttribute("href", id);
42 | a.textContent = title;
43 | h3.appendChild(a);
44 |
45 | const p = document.createElement("p");
46 | p.textContent = description;
47 | el.appendChild(p);
48 | });
49 | } else {
50 | noResultsEl.classList.remove("hidden")
51 | }
52 | } else {
53 | noResultsEl.classList.add("hidden")
54 | }
55 | };
56 | fetch("/search-index.json").then((response) =>
57 | response.json().then((rawIndex) => {
58 | window.searchIndex = elasticlunr.Index.load(rawIndex);
59 | document.getElementById("searchField").addEventListener("input", search);
60 | })
61 | );
62 | })(window, document);
--------------------------------------------------------------------------------
/_includes/assets/utils/image.txt:
--------------------------------------------------------------------------------
1 | {% image "sagan.jpg" "Carl Sagan, 1987" %}
--------------------------------------------------------------------------------
/_includes/assets/utils/imagesize.txt:
--------------------------------------------------------------------------------
1 | {% image "sagan.jpg" "Carl Sagan, 1987" "200px" %}
--------------------------------------------------------------------------------
/_includes/components/contact.njk:
--------------------------------------------------------------------------------
1 |
27 | {% for tag in post.data.tags %}
28 | {%- if tag != "post" -%}
29 | {% set tagUrl %}/tags/{{ tag }}/{% endset %}
30 | {{ tag }}
31 | {%- endif -%}
32 | {% endfor %}
33 |
34 | {% endif %}
35 |
36 |
37 | {#
38 |
Foo
39 | {% set latest_posts = collections.posts %}
40 | {% for post in latest_posts.slice(0,2) | reverse %}
41 | {{ post.data.title}}
42 | {% endfor %} #}
43 |
--------------------------------------------------------------------------------
/_includes/experimental/blog/content/posts/firstpost.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: This is the first example post
3 | metaDescription: This is a sample meta description. If one is not present in your page/post's front matter, the default metadata.desciption will be used instead.
4 | date: 2019-01-01T00:00:00.000Z
5 | author: John Appleseed
6 | summary: Why contemplating our mortality can be a powerful catalyst for change
7 | tags:
8 | - tech
9 | - environment
10 | - politics
11 | - sport
12 | ---
13 | Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.
14 |
15 | Bring to the table win-win survival strategies to ensure proactive domination. At the end of the day, going forward, a new normal that has evolved from generation X is on the runway heading towards a streamlined cloud solution. User generated content in real-time will have multiple touchpoints for offshoring.
16 |
17 | ## Section Header
18 |
19 | Capitalize on low hanging fruit to identify a ballpark value added activity to beta test. Override the digital divide with additional clickthroughs from DevOps. Nanotechnology immersion along the information highway will close the loop on focusing solely on the bottom line.
20 |
21 | ``` text/2-3
22 | // this is a command
23 | function myCommand() {
24 | let counter = 0;
25 | counter++;
26 | }
27 | ```
28 | Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.
29 |
--------------------------------------------------------------------------------
/_includes/experimental/blog/content/posts/fourthpost.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: This is the fourth example post
3 | date: 2020-02-03
4 | author: John Doe
5 | summary: Why contemplating our mortality can be a powerful catalyst for change
6 | tags:
7 | - environment
8 | - politics
9 | ---
10 | Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.
11 |
12 | 
13 |
14 | Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.
15 |
--------------------------------------------------------------------------------
/_includes/experimental/blog/content/posts/posts.json:
--------------------------------------------------------------------------------
1 | {
2 | "layout": "layouts/post.njk",
3 | "permalink": "posts/{{ title | slug }}/index.html",
4 | "author": "Anonymous",
5 | "tags": [
6 | "post"
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/_includes/experimental/blog/content/posts/secondpost.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: This is the second example post
3 | summary: Why contemplating our mortality can be a powerful catalyst for change
4 | date: 2020-01-01
5 | author: John Appleseed
6 | tags:
7 | - sport
8 | ---
9 | Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.
10 |
11 | ## Section Header
12 |
13 | Bring to the table win-win survival strategies to ensure proactive domination. At the end of the day, going forward, a new normal that has evolved from generation X is on the runway heading towards a streamlined cloud solution. User generated content in real-time will have multiple touchpoints for offshoring.
14 |
15 | Capitalize on low hanging fruit to identify a ballpark value added activity to beta test. Override the digital divide with additional clickthroughs from DevOps. Nanotechnology immersion along the information highway will close the loop on focusing solely on the bottom line.
16 |
--------------------------------------------------------------------------------
/_includes/experimental/blog/content/posts/the-fifth-and-hopefully-final-example-post.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: The fifth and hopefully final example post yo yo
3 | date: 2020-10-15T12:23:39.598Z
4 | author: Jane Doe
5 | summary: Why contemplating our mortality can be a powerful catalyst for change
6 | tags:
7 | - environment
8 | - sport
9 | eleventyComputed:
10 | key: Spacelog
11 | ---
12 | Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.
13 |
14 | 
15 |
16 | Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.
--------------------------------------------------------------------------------
/_includes/experimental/blog/content/posts/thirdpost.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: This is the third example post which has a slightly longer title than the others
3 | date: 2020-01-01
4 | author: Jane Doe
5 | summary: Why contemplating our mortality can be a powerful catalyst for change
6 | tags:
7 | - tech
8 | - politics
9 | ---
10 | Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.
11 |
12 | ```
13 | pre,
14 | code {
15 | line-height: 1.5;
16 | }
17 | ```
18 |
19 | Bring to the table win-win survival strategies to ensure proactive domination. At the end of the day, going forward, a new normal that has evolved from generation X is on the runway heading towards a streamlined cloud solution. User generated content in real-time will have multiple touchpoints for offshoring.
20 |
21 | ## Section Header
22 |
23 | Capitalize on low hanging fruit to identify a ballpark value added activity to beta test. Override the digital divide with additional clickthroughs from DevOps. Nanotechnology immersion along the information highway will close the loop on focusing solely on the bottom line.
24 |
--------------------------------------------------------------------------------
/_includes/experimental/blog/layouts/blog.njk:
--------------------------------------------------------------------------------
1 | ---
2 | layout: layouts/base.njk
3 | section: blog
4 | permalink: /blog/index.html
5 | ---
6 |
30 |
31 |
32 | `;
33 | }
34 | });
35 |
36 | export default Post;
37 |
--------------------------------------------------------------------------------
/content/buy.md:
--------------------------------------------------------------------------------
1 | ---
2 | permalink: false
3 | eleventyNavigation:
4 | key: Get the eBook edition
5 | order: 10
6 | url: https://leanpub.com/proseforprogrammers
7 | ---
--------------------------------------------------------------------------------
/content/images/hello.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joshuacc/prose-for-programmers/fc0c8a4a093f406d380768aa626615307fabf707/content/images/hello.jpg
--------------------------------------------------------------------------------
/content/pages/contact.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: layouts/contact.njk
3 | title: Send a message
4 | section: contact
5 | date: Last Modified
6 | permalink: /contact/index.html
7 | ---
8 | You can use [Netlify Forms](https://www.netlify.com/docs/form-handling/) to create contact forms like this one, or any other custom forms you may wish to create. All submissions are sent directly to your Netlify dashboard (with optional notifications.) All forms utilize Netlify's native spam filter will display a CAPTCHA for any flagged submissions.
9 |
--------------------------------------------------------------------------------
/content/pages/home.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: About this book
3 | permalink: /
4 | eleventyNavigation:
5 | key: About this book
6 | order: 0
7 | ---
8 |
9 | _Prose for Programmers_ is a book for programmers.
10 | It is a guide to mastering the most difficult programming language of all: human language.
11 |
12 | Just as with programming,
13 | we write with particular goals in mind.
14 | That goal might be as simple as reminding someone about a requirement
15 | or as complex as justifying an entirely new architecture for a product.
16 | But in every case we write in order to achieve something.
17 |
18 | This book will teach you how to achieve those goals more effectively with clearer, more persuasive writing.
19 |
20 | ## It is a work in progress
21 |
22 | The first three chapters are content complete.
23 |
24 | * [Why should developers study writing?](/manuscript/why)
25 | * [General Rules](/manuscript/rules)
26 | * [The Writing Process](/manuscript/process)
27 |
28 | And there are four chapters to come.
29 |
30 | * Writing Structures
31 | * Audience
32 | * Genres
33 | * Other Resources
34 |
35 | ## It is editable on GitHub
36 |
37 | The manuscript of _Prose for Programmers_,
38 | as well as the code for the website is hosted on [GitHub](https://github.com/joshuacc/prose-for-programmers).
39 | Each chapter has a convenient edit link at the top of the page.
40 | If you see any mistakes, typos, or other issues,
41 | feel free to edit and open a pull request.
42 |
43 | ## It is available in eBook form for your Kindle or other e-reader
44 |
45 | You can get the EPUB/MOBI/PDF version of _Prose for Programmers_ [via Leanpub](https://leanpub.com/proseforprogrammers).
--------------------------------------------------------------------------------
/content/pages/pages.json:
--------------------------------------------------------------------------------
1 | {
2 | "layout": "layouts/page.njk"
3 | }
4 |
--------------------------------------------------------------------------------
/filters/searchFilter.js:
--------------------------------------------------------------------------------
1 | const elasticlunr = require("elasticlunr");
2 | const emojiRegex = require('emoji-regex/RGI_Emoji.js')
3 |
4 | module.exports = function (collection) {
5 | // what fields we'd like our index to consist of
6 | var index = elasticlunr(function () {
7 | this.addField("title");
8 | this.addField("content");
9 | this.setRef("id");
10 | });
11 |
12 | // loop through each page and add it to the index
13 | collection.forEach((page) => {
14 | index.addDoc({
15 | id: page.url,
16 | title: page.template.frontMatter.data.title,
17 | content: squash(page.templateContent),
18 | });
19 | });
20 |
21 | function squash(text) {
22 | const regex = emojiRegex();
23 | var content = new String(text);
24 |
25 | // all lower case, please
26 | var content = content.toLowerCase();
27 |
28 | // remove all html elements and new lines
29 | var re = /(.*?<.*?>)/gi;
30 | var plain = unescape(content.replace(re, ''));
31 |
32 | // remove duplicated words
33 | var words = plain.split(' ');
34 | var deduped = [...(new Set(words))];
35 | var dedupedStr = deduped.join(' ')
36 |
37 | // remove short and less meaningful words
38 | var result = dedupedStr.replace(/\b(\.|\,|\<;|the|a|an|and|am|you|I|to|if|of|off|me|my|on|in|it|is|at|as|we|do|be|has|but|was|so|no|not|or|up|for)\b/gi, '');
39 | //remove newlines, and punctuation
40 | result = result.replace(/\.|\,|\?|
|-|—|\n/g, '');
41 | //remove repeated spaces
42 | result = result.replace(/[ ]{2,}/g, ' ');
43 | // remove most emoji
44 | result = result.replace(/([#0-9]\u20E3)|[\xA9\xAE\u203C\u2047-\u2049\u2122\u2139\u3030\u303D\u3297\u3299][\uFE00-\uFEFF]?|[\u2190-\u21FF][\uFE00-\uFEFF]?|[\u2300-\u23FF][\uFE00-\uFEFF]?|[\u2460-\u24FF][\uFE00-\uFEFF]?|[\u25A0-\u25FF][\uFE00-\uFEFF]?|[\u2600-\u27BF][\uFE00-\uFEFF]?|[\u2900-\u297F][\uFE00-\uFEFF]?|[\u2B00-\u2BF0][\uFE00-\uFEFF]?|(?:\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDEFF])[\uFE00-\uFEFF]?/g, '');
45 |
46 | let match;
47 | while (match = regex.exec(result)) {
48 | const emoji = match[0];
49 | result = result.replace(emoji,' ')
50 | }
51 |
52 | return result;
53 | }
54 |
55 | return index.toJSON();
56 | };
--------------------------------------------------------------------------------
/loader.js:
--------------------------------------------------------------------------------
1 | if (localStorage.getItem('password')) {
2 | insertPlainHTML(atob(localStorage.getItem('password')))
3 | } else {
4 | document.getElementById('staticrypt-form').addEventListener('submit', function(e) {
5 | e.preventDefault();
6 | insertPlainHTML(document.getElementById('staticrypt-password').value);
7 | });
8 | }
--------------------------------------------------------------------------------
/manuscript/Book.txt:
--------------------------------------------------------------------------------
1 | why.md
2 | rules.md
3 | process.md
--------------------------------------------------------------------------------
/manuscript/manuscript.json:
--------------------------------------------------------------------------------
1 | {
2 | "layout": "layouts/page.njk"
3 | }
4 |
--------------------------------------------------------------------------------
/manuscript/process.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "The Writing Process",
3 | "eleventyNavigation": {
4 | "key": "The Writing Process",
5 | "order": 3
6 | }
7 | }
--------------------------------------------------------------------------------
/manuscript/process.md:
--------------------------------------------------------------------------------
1 | # The Writing Process
2 |
3 | Many people are under the impression that writing is a mystical
4 | -- or at least mysterious --
5 | activity, governed entirely by inspiration.
6 | While it is true that some authors work this way,
7 | waiting for inspiration to strike isn't a common strategy among professional writers,
8 | even novelists.
9 |
10 | For programmers and others writing non-fiction in a business context,
11 | there is a simple process that yields quality results.
12 |
13 | 1. Determine the goal
14 | 2. Determine the audience
15 | 3. Choose a suitable structure
16 | 4. Build an outline
17 | 5. Turn the outline into prose
18 | 6. Revise obvious weaknesses
19 | 7. Obtain feedback
20 | 8. Revise based on feedback
21 | 9. Publish
22 |
23 | In this chapter, we will walk through what each of these steps entail.
24 |
25 | ## 1. Determine the Goal
26 |
27 | ### Why am I writing this, anyway?
28 |
29 | Every time you start writing something,
30 | ask yourself, "Why?"
31 | Sometimes the answer is obvious,
32 | but often it's not.
33 | And even on those occasions when it is obvious,
34 | asking the question helps keep you focused on the goal.
35 |
36 | It's important to remember that we're trying to find the purpose of the document,
37 | not your personal motivation for writing it.
38 | If your answer to "Why am I writing this?" includes the words "I" or "me,"
39 | it is worth evaluating whether you're really thinking of the document's goal.
40 |
41 | For instance, if the answer to why you are writing a tutorial is,
42 | "So that I can get a raise,"
43 | you're thinking of the wrong thing.
44 | It's not that the motivation is _wrong_.
45 | It's just _irrelevant_ to producing a good tutorial.
46 | A better answer is,
47 | "To help others improve their game's performance."
48 |
49 | Because this answer is focused on what the audience receives,
50 | it is actually useful for guiding your writing efforts.
51 |
52 | ### Keep asking why.
53 |
54 | Often, the first goal we come up with will be superficial.
55 | "Teaching others how to use object pools,"
56 | may be accurate,
57 | and even somewhat useful,
58 | but a bit more context can be even more useful.
59 |
60 | There is a technique for root cause analysis called [5 Whys][],
61 | the premise of which is that you need to ask "Why?" multiple times to find the root cause of a problem.
62 | This technique also works well for determining a useful goal for writing.
63 |
64 | Suppose the first goal that occurs to you is
65 | "Teach developers how to use object pools."
66 | That is a perfectly clear and useful goal.
67 | But if you write only to that narrow goal,
68 | your readers won't know why the technique is useful.
69 | So ask yourself, "Why object pools?"
70 |
71 | Perhaps the answer is "To improve performance."
72 | But again we can ask "Why?"
73 | And our answer is something like, "To keep gameplay smooth."
74 |
75 | At this point we can state the goal as:
76 | "Teach game developers how to keep their games running smoothly by using object pools."
77 |
78 | With this more robust goal in mind we're more likely to communicate,
79 | not just the technique,
80 | but also its importance and trade-offs.
81 |
82 | ## 2. Determine the Audience
83 |
84 | Once we understand the goal of the document,
85 | we have enough information to start considering our audience.
86 | Our first question, though, takes a step back from the goal.
87 |
88 | ### Who will be reading this?
89 |
90 | Often the readership of documents is wider than we would initially expect.
91 | A framework's website will be read by developers, of course,
92 | but perhaps also:
93 |
94 | * Architects evaluating technology choices
95 | * Managers trying to keep abreast of what their team is using
96 | * Technical recruiters trying to understand the skillset they are hiring for
97 | * Designers trying to understand technical constraints on their designs
98 | * Sysadmins figuring out the framework's deployment features
99 |
100 | Take time to list the different types of potential readers.
101 | Doing so will help draw out whether additional supporting material is needed.
102 |
103 | ### Which readers are primary?
104 |
105 | Once you have the list of potential readers,
106 | refer back to the goal to decide which readers are most important.
107 | In most cases there will be a single group of readers who constitute your primary audience.
108 |
109 | Continuing the previous example:
110 | the primary audience of a framework website is developers.
111 | Others are important, but secondary to that audience.
112 |
113 | ### What is their relation to the subject?
114 |
115 | At this point we have our primary audience,
116 | but haven't given much detail about them.
117 | So it's time to consider their relation to the subject.
118 |
119 | One important axis to consider is their current level of expertise.
120 | Are they absolute beginners,
121 | world class experts,
122 | or somewhere in between?
123 | The answer to this question drives
124 | which sorts of things can be assumed
125 | and which need to be explained in great detail.
126 |
127 | Another axis is the readers emotional relationship with the subject.
128 | Are they intimidated, enthusiastic, or something else?
129 | A developer who fled Java for Ruby will have a very different attitude toward Haskell than a brand new developer.
130 | They may both be fearful,
131 | but about different things.
132 | Those emotional concerns also need to be addressed.
133 |
134 | ### What is their relation to you?
135 |
136 | In addition to the subject,
137 | we must also consider how the audience is related to you,
138 | the author.
139 | Are they coworkers?
140 | Then you can make certain assumptions about their familiarity with the business.
141 |
142 | Are you on friendly terms or is some of the audience hostile?
143 | You may need to focus more on your logical case for the latter.
144 |
145 | Are you part of the same culture/subculture?
146 | "Corporate suits" probably won't find image macros as amusing as your 22-year-old developer buddy.
147 |
148 | [5 Whys]: http://en.wikipedia.org/wiki/5_Whys
149 |
150 | ## 3. Choose a Suitable Structure
151 |
152 | Now that we know the goal and the audience
153 | we can consider how to structure the document to serve them.
154 |
155 | ### Choosing a structure based on the goal
156 |
157 | Goals can generally be placed on a spectrum between purely informational and purely persuasive.
158 | On one end of the spectrum,
159 | topical hierarchies are great at communicating lots of information efficiently.
160 | The hierarchy conveys the big picture while also supporting scanning through subtopics.
161 |
162 | At the other end of the spectrum,
163 | narrative is particularly effective at persuading people by engaging our natural sense of empathy.
164 | Telling a child that "Lying is a bad idea," is less likely to change their behavior than hearing _The Boy Who Cried Wolf_.
165 | For an example closer to our industry, consider _The Phoenix Project_:
166 | it vividly illustrates the problems of bureacratic IT departments
167 | as well as the benefits of embracing the DevOps movement.
168 |
169 | ### Choosing a structure based on the audience
170 |
171 | Your structure also needs to be suited to your audience.
172 |
173 | If your primary audience is developers with deep experience in your topic,
174 | then you may want to address them with an equally deep and detailed hierarchy of topics.
175 | A beginner, however, would likely benefit from a shallower step by step "recipe" guide.
176 |
177 | The reader's level of interest factors into which structure is best suited.
178 | A highly motivated reader may want to get right to the heart of the matter.
179 | But a distinterested reader
180 | --who is only looking at your document because his boss made him--
181 | may need to be enticed with a joke or anecdote explaining what is in it for him.
182 | That sort of reader will probably also need frequent positive reinforcement.
183 |
184 | The audience's relationship with you also makes a difference.
185 | If they are familiar with you and trust your judgment,
186 | they are more likely to be patient waiting for a payoff.
187 | But if they don't know anything about you,
188 | the internet is only a click away.
189 |
190 | ### Mixing and matching
191 |
192 | Most writing structures are relatively flexible
193 | and can be combined with other structures as warranted by the goal and the audience.
194 | **Don't be afraid to mix and match them.**
195 |
196 | For example, suppose that you need to convince business leaders that
197 | it is worthwhile to break your large monolithic application into several separate services.
198 | You'd probably start with a Problem-Solution structure like this:
199 |
200 | * Problems with the current architecture
201 | * Proposed solution
202 |
203 | In order to help the businesspeople make a decision, you'd probably extend it with a Pro-Con analysis as well.
204 |
205 | * Problems with the current architecture
206 | * Proposed solution
207 | * Costs and risks of change
208 | * Costs and risks of not changing
209 |
210 | A simple factual elaboration on that outline may win intellectual assent,
211 | but is unlikely to elicit wholehearted support from non-technical leaders.
212 | Why?
213 | Because they lack experiential knowledge of the problems, solutions, and risks.
214 |
215 | But parables and other metaphorical narratives can impart a degree of experiential knowledge without requiring actual experience.
216 | What sort of narrative would work in this case?
217 |
218 | Perhaps a story of a military building a single gigantic ship.
219 | It is powerful,
220 | but difficult to maneuver,
221 | and if it somehow fails then its entire arsenal is useless.
222 | (Business books are fond of military metaphors for some reason.)
223 | Then contrast this with building a fleet of small independently maneuverable ships.
224 |
225 | Revising the outline to incorporate this narrative gives us:
226 |
227 | * Problems with the current architecture
228 | * Parable of the dreadnought
229 | * Supporting factual details
230 | * Proposed solution
231 | * Parable of the fleet
232 | * Supporting factual details
233 | * Costs and risks of change
234 | * Refer to parable
235 | * Supporting factual details
236 | * Costs and risks of not changing
237 | * Refer to parable
238 | * Supporting factual details
239 |
240 | Combining these three structures creates a much more powerful and persuasive account than any of them alone.
241 |
242 | ## 4. Build an Outline
243 |
244 | With a structure
245 | (or set of structures)
246 | chosen for your project,
247 | it is time to build an outline.
248 | Some structures,
249 | like API documentation,
250 | may come with an outline template to follow.
251 | But many others,
252 | like the inverted pyramid,
253 | do not.
254 |
255 | This phase is all about taking your chosen structures
256 | and combining them with the details of your subject
257 | to produce the skeleton of your document.
258 |
259 | The outline itself is a simple hierarchical list of
260 | the things you want to communicate
261 | and the approach you want to take at each step.
262 | Particularly for smaller projects,
263 | the line between choosing a structure and outlining can be rather blurry.
264 | (Evidenced by the the section on choosing structures ending with an outline!)
265 | But an outline should show in detail **how** you intend to implement your chosen structure.
266 |
267 | ### How detailed should an outline be?
268 |
269 | This will likely vary from person to person,
270 | but I prefer to outline in enough detail that
271 | each low level bullet point corresponds to one or two paragraphs in the final text.
272 | This gives me sufficient guidance that I don't get lost,
273 | but also gives me enough flexibility to expand on some points without deviating from the outline.
274 |
275 | ### How do you actually create the outline?
276 |
277 | There are two basic approaches:
278 | depth-first
279 | and breadth-first.
280 | A depth-first approach starts at the top
281 | and explores all the way down to the details one point at a time.
282 | A breadth-first approach starts at the highest level
283 | and only becomes more detailed after all the higher level points have been filled in.
284 |
285 | **Partially completed depth-first outline**
286 |
287 | * Point 1
288 | * Point 1.1
289 | * Point 1.1.1
290 | * Point 1.1.2
291 | * Point 1.1.3
292 |
293 | **Partially completed breadth-first outline**
294 |
295 | * Point 1
296 | * Point 2
297 | * Point 3
298 | * Point 4
299 | * Point 5
300 |
301 | Breadth-first generally produces better results,
302 | because it provides more overall context each time we step down a level of detail.
303 | That extra context makes it much less likely that we will get stuck on trivia.
304 |
305 | ### Evaluate and revise
306 |
307 | Once you've drafted your outline,
308 | be sure to evaluate it with your goals and audience in mind.
309 | It is much easier to move or edit a few bullet points
310 | than to revise entire sections of your document.
311 |
312 | ## 5. Turn the outline into prose
313 |
314 | Everything we've talked about so far has been aimed at preparing you for this part of the process.
315 | You should know your goal, audience and structure.
316 | And your outline gives you a game plan.
317 | Now it's time to turn all that into something for others to read.
318 |
319 | ### Putting flesh on the bones
320 |
321 | Right now what you've got is a skeleton.
322 | It's vaguely in the shape you want,
323 | but if it tried to walk around it would quickly fall apart.
324 | There are two principle things that it is lacking:
325 | muscle to give it strength,
326 | and ligaments to hold things together.
327 | Let's start with the muscle.
328 |
329 | Bare statements of fact rarely carry much weight with readers,
330 | regardless of how important those facts might be.
331 | They have to be elaborated on
332 | and placed into their proper context.
333 | And usually the most important context for a reader is the answer to
334 | "Why do I care about this?"
335 | A reason to care gives your prose strength.
336 |
337 | Consider this example:
338 |
339 | > Continuous integration improves the development process.
340 |
341 | > Continuous integration improves the development process by helping us detect defects sooner.
342 | > That means fewer late night calls to debug production.
343 |
344 | The latter includes more supporting detail about _how_ it helps,
345 | as well as a reason for developers to care about it.
346 |
347 | In addition to muscle we need ligaments.
348 | The ligaments are what actually connects one bone to another.
349 | The prose equivalent is a transition.
350 |
351 | Sudden jumps from one topic to another
352 | (even closely related)
353 | are jarring.
354 | Transitions serve to smooth that over by
355 | clearly signaling the close of one topic,
356 | the introduction of the next,
357 | and possibly how they are related.
358 |
359 | A transition can be a simple phrase.
360 | It can be an entire sentence.
361 | It can be a paragraph.
362 | Or multiple paragraphs.
363 | It all depends on the size of the pieces you're transitioning between.
364 |
365 | For an example, take a look at the paragraph that started this section (#5) above.
366 |
367 | ### It's not necessarily exposition
368 |
369 | When working from your outline,
370 | beware of always choosing the most direct expansion of your points.
371 | Simple exposition is the most common way of describing things,
372 | but it isn't always the best.
373 | Using other forms of expansion will give your prose variety and help maintain reader interest.
374 |
375 | Especially in a longer text,
376 | including the occasional story, joke, or anecdote
377 | can make the difference between a pleasant read or an unbearably boring one.
378 |
379 | Whatever you choose to use,
380 | it should be integrally related to the points you're trying to make.
381 |
382 | There is a story about a high school student who had to give a book report.
383 | When he stood up in front of the class he yelled,
384 | "Sex! Sex! Sex!"
385 | then continued,
386 | "Now that I have your attention,
387 | I'd like to talk to you about The Complete History of World War II."
388 |
389 | Don't be like the high school student.
390 |
391 | ## 6. Revise
392 |
393 | At this point you have a fleshed out draft,
394 | so now it is time to fix the gaps and rough edges.
395 |
396 | ### Evaluate
397 |
398 | Starting at the beginnning, read each unit of your work.
399 | Depending on the length of your document, that unit might be a paragraph, section, or chapter.
400 | As you read, ask yourself the following questions:
401 |
402 | * Does this advance the goal?
403 | * Is it clear?
404 | * Is it concise?
405 | * Is it well organized?
406 | * Is it scannable?
407 |
408 | You'll likely want to read the unit multiple times to answer these questions.
409 | For a longer unit, one read per question -- or even more -- may be appropriate.
410 |
411 | > #### Tip: Try different contexts
412 | >
413 | > Reading in a different context than you usually write in can help you to see things differently and spot problems more easily.
414 | > For example, if you usually write at a computer,
415 | > try printing your document out on paper,
416 | > or even reading it out loud.
417 |
418 | ### Plan your corrections
419 |
420 | Take notes on each thing that needs to be improved,
421 | but don't make corrections right away.
422 | Introducing a slight delay between identifying the problem and attempting to fix it
423 | will give your mind a chance to work on the problem,
424 | and often arrive at a better solution than the first one you thought of.
425 |
426 | Your notes can take many forms:
427 | a separate text file,
428 | using Track Changes in Microsoft Word,
429 | and so on.
430 | I tend to prefer annnotating a physical paper with pen or pencil,
431 | but you should experiement and find what works best for you.
432 |
433 | After you have a list of all the corrections you plan to make,
434 | you may be able to spot common patterns for future improvement.
435 | But the immediate task is to begin making corrections.
436 |
437 | ### Make your corrections
438 |
439 | Proceed through your notes from beginning to end,
440 | correcting each problem.
441 | If you get stuck on something,
442 | leave it to the side for now.
443 | You'll come back to it later.
444 |
445 | Once you've completed all the corrections you were able to make,
446 | take another look at any you left behind.
447 | You may know how to fix them now.
448 | If so, go ahead.
449 | If not, we'll leave them for the next stage of the writing process: feedback.
450 |
451 | ## 7. Get feedback
452 |
453 | Up to this point everything has come from you,
454 | even thinking about the audience.
455 | But this is where you actually engage with other people for the first time.
456 | Brace yourself,
457 | because feedback from real people is almost certain to suprise you,
458 | regardless of whether it's positive or negative.
459 |
460 | ### Sources of feedback
461 |
462 | Generally you will be getting feedback from one of three types of readers:
463 | members of the target aurdience,
464 | experts on the subject,
465 | and friends/coworkers.
466 | Each of these groups has strengths and weaknesses.
467 | Getting feedback from all three is ideal,
468 | and occasionally the groups overlap,
469 | but feedback from any of them is useful for checking your assumptions.
470 |
471 | #### Target audience
472 |
473 | Members of the target audience are extremely valuable
474 | because they can tell you whether your writing is achieving the intended goal.
475 | Unfortunately, they often can't tell you why.
476 | And even if they do offer a reason,
477 | it shouldn't always be taken at face value.
478 |
479 | To help overcome this issue,
480 | it can help to supply a list of specific questions for them to answer.
481 | For example:
482 |
483 | * By the end did you think that it is worth investigating the new technology I described?
484 | * If not, was there a specific point where I lost you?
485 | * Did any of my supporting evidence seem questionable?
486 |
487 | Unfortunately, it can be difficult or impossible to get feedback from the audience.
488 | After all, when drafting an email to your boss's boss,
489 | you can't very well ask them to proofread it.
490 |
491 | #### Experts
492 |
493 | Expert feedback can also be very useful,
494 | particularly for identifying inaccuracies and mistakes.
495 | One issue to watch out for, though,
496 | is that experts may not remember what it was like to be a beginner.
497 | So if beginners and non-experts are in your target audience,
498 | be careful of suggestions to includes lots of additional details which they won't have the context to understand.
499 |
500 | #### Friends and coworkers
501 |
502 | Friends and coworkers are often the easiest reviewers to obtain.
503 | Unfortunately, they are often the least reliable in providing needed correction.
504 | No one wants to hurt the feelings of someone they like.
505 | But they are often excellent at providing encouragement,
506 | and when working on a large writing project,
507 | that can be invaluable.
508 |
509 | ### Evaluating feedback
510 |
511 | When evaluating the feedback there are a few principles to keep in mind.
512 |
513 | First, _readers are always right about their reactions_.
514 | If a reader says that they were confused by a certain point,
515 | then they were,
516 | no matter how clear it may appear to you.
517 |
518 | Second, _a reader's negative reaction does not automatically lead to revision_.
519 | It is your responsibility to evaluate
520 | whether issues raised are actually problems for your target audience
521 | and serious enough to require addressing.
522 |
523 | Third, _a reader's proposed solution may not be correct_.
524 | Sometimes readers will suggest solutions without explaining the problem they identified.
525 | For example, "I think you need a fancy graphic right here."
526 | This suggestion might be a good one,
527 | but you should work to understand the underlying problem.
528 | Perhaps the text became boring,
529 | or perhaps a diagram would help with clarity.
530 | Whatever the case may be,
531 | don't just take the suggestion at face value.
532 |
533 | Finally, _a reader's feedback should be weighted differently based on who they are and what area their feedback is in._
534 | An expert's feedback regarding correctness should be prioritized over a beginner's,
535 | and an audience member's feedback regarding readability should be prioritized over the expert's.
536 |
537 | ### Compile the feedback into revision notes
538 |
539 | After taking all of this in,
540 | you should have a list of changes to make.
541 | And you may also have a list of positive points which you should try to retain.
542 | Despite the focus on improving problems,
543 | you also don't want to edit away something that is working.
544 |
545 | ## 8. Revise based on feedback
546 |
547 | Just like with your first revision notes,
548 | you will go back through and make your changes one at a time,
549 | evaluating the criteria of clarity, concision, organization, scannability and goal focus.
550 | By the time you are done,
551 | you should have a pretty solid draft.
552 |
553 | As you revise, make changes one at a time,
554 | assessing clarity, concision, organization, scannability, and goal focus.
555 | Pay attention to common themes in the feedback you receive.
556 | Those are the ones most likely to require revision.
557 |
558 | Remember to prioritize the most significant changes first.
559 | Tackle issues like organization or persuasiveness before minor details like grammar.
560 | Getting something grammatically correct is a waste of time
561 | if that entire section will be reworked or removed.
562 | Throughout revision, continuously review your goals and audience,
563 | and be prepared for multiple rounds of changes.
564 |
565 | After you've revised, seek additional feedback,
566 | both to verify initial concerns are addressed
567 | and to ensure no new problems have been introduced.
568 | Consult with both original and new readers to get different perspectives.
569 | Remember, continuous revision is crucial for producing a polished and effective piece of writing.
570 |
571 | ## 9. Publish
572 |
573 | Publishing your work is usually the most critical part of the writing process,
574 | but remember, it can happen at any point, depending on the project.
575 | In some cases, publishing might be part of an ongoing process,
576 | with updates and revisions made after the first release.
577 | This is especially true for things like wiki-based technical documentation
578 | or presentations that are given multiple times and need tweaks based on audience feedback.
579 |
580 | Before you publish, think about the context and the level of polish your writing needs.
581 | Not every situation calls for super polished writing.
582 | A quick email to a coworker won't need the same level of refinement as a formal report for the big boss.
583 | Adapt the level of polish to the context so you strike the right balance between quality and getting things done.
584 |
585 | Before hitting that publish button,
586 | give your work a once-over for any errors or inconsistencies,
587 | and make sure your formatting looks good,
588 | based on what's required in your situation.
589 | This final check is crucial for presenting your writing in the best light.
590 |
591 | After publishing, don't forget to spread the word.
592 | Share your work with the people who need to see it,
593 | whether that's passing a report to colleagues,
594 | posting a blog on social media,
595 | or presenting your findings at a conference.
596 | Keep in mind that publishing doesn't mean you're done with revisions.
597 | Be open to feedback even after your work is out there,
598 | and be ready to make updates or corrections as needed.
599 | Embracing this back-and-forth will help you keep improving your writing skills
600 | and adapt to the needs of your audience in all kinds of situations.
601 |
602 | ## Summing it up
603 |
604 | The writing process is all about striking the right balance between the formal process and the needs of the situation.
605 |
606 | From setting goals and figuring out who you're writing for,
607 | to making an outline,
608 | revising,
609 | and hitting that publish button,
610 | each step is important.
611 | But not equally important.
612 |
613 | Keep an eye on your context and switch things up as needed,
614 | whether it's the level of polish or the amount of feedback and revision you're going for.
615 | Don't forget, the process can and should be trimmed down when it makes sense for the situation,
616 | helping you focus on what's most important in each specific context.
617 | The more you work at it, the better you'll get at writing and connecting with your audience.
618 |
619 | Writing takes time, practice, and being open to learning from both the things you nail and the things you, well, don't.
620 | As you gain experience as a writer,
621 | you'll find that this whole process starts to feel more natural,
622 | and your ability to get your point across will only get better.
623 | Just keep writing, learning, and tweaking your process to fit each unique writing situation you find yourself in.
--------------------------------------------------------------------------------
/manuscript/rules.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "General Rules",
3 | "eleventyNavigation": {
4 | "key": "General Rules",
5 | "order": 2
6 | }
7 | }
--------------------------------------------------------------------------------
/manuscript/rules.md:
--------------------------------------------------------------------------------
1 | # General Rules
2 |
3 | Rules.
4 | The very word can trigger skepticism.
5 | And understandably so.
6 | We are often confronted with seemingly arbitrary rules
7 | which make our lives harder for no apparent reason.
8 |
9 | In this chapter I will give you rules to follow,
10 | but I will also explain each rule's rationale.
11 | So if you find yourself in a situation beyond the scope of the rule,
12 | you'll be equipped to make intelligent decisions about how or if to apply it.
13 |
14 | It is also important to acknowledge the limits of these rules.
15 | They are targeted principally at writing within a professional business context.
16 | If you are writing a novel,
17 | these rules will be of limited use.
18 | And if you are writing poetry,
19 | they will probably be entirely useless.
20 | But if you need to communicate ideas to your coworkers,
21 | then these rules will serve you well.
22 |
23 | Now that we've set the appropriate context, let's look at those rules.
24 |
25 | ## 1. Be goal oriented.
26 |
27 | > "In my end is my beginning."
28 | >
29 | > -- T.S. Eliot
30 |
31 | ### Everything you write has a goal
32 |
33 | Suppose a boss or client came to you and said they needed you to build a web application.
34 | Your first question would probably be,
35 | "What is the application for?"
36 | The very idea of writing an application without knowing its purpose is ridiculous.
37 | Yet when it comes to writing prose,
38 | we too often fail to ask the obvious question.
39 |
40 | Everything you write has a goal,
41 | whether explicit or implicit.
42 | Those API docs?
43 | The stated goal is to inform other developers how to use your library.
44 | That weekly status report you email your client?
45 | The unstated goal is reassuring them that their money is being well spent.
46 |
47 | The goal of a document isn't always obvious,
48 | but in the next chapter, we'll look at some tools to figure it out.
49 |
50 | ### Knowing the goal equips you to fulfill it.
51 |
52 | Let's go back to our hypothetical web application above.
53 | Suppose you did try to build it without actually knowing its purpose?
54 | You are just given a list of features and told to start building.
55 | What would happen?
56 |
57 | You'd have no way to evaluate how well or poorly the application was doing.
58 | And that's not just a problem at the end.
59 | All along you'd have questions about how best to build each feature.
60 | But without knowing the application's purpose,
61 | you'd have no way of choosing between the alternatives.
62 | That kind of uncertainty is crippling.
63 | And I suspect that is why many people avoid writing.
64 |
65 | But when you do know the goal you are writing toward,
66 | decisions are easier,
67 | and it is simpler to tell whether your writing succeeds in achieving its end.
68 |
69 | ### The structure of goals
70 |
71 | We've talked about goals a lot,
72 | but so far we haven't really clarified what kind of goals we're talking about.
73 | It's all about the document.
74 |
75 | In this book,
76 | when I talk about goals,
77 | I mean the purpose intrinsic to the document[^telos],
78 | not the author's personal motivations.
79 | For instance,
80 | your goal in writing API docs may be to keep your tech lead from bugging you about it yet again.
81 | But the purpose of the docs themselves is to assist users of the API.
82 |
83 | A document's goals will generally fall into one of two categories:
84 | to inform or to persuade.
85 | Most documents will include a bit of both,
86 | but one will be primary.
87 | To go back to the API docs example,
88 | it may help persuade people to use your library,
89 | but the primary purpose is just to inform them about how to do so.
90 |
91 | [^telos]: If you're familiar with ancient Greek philosophy,
92 | this is what Aristotle would call the document's _telos_.
93 |
94 | ## 2. Be concise.
95 |
96 | In a professional context,
97 | everyone is pressed for time.
98 | Being concise is about respecting your readers' time.
99 | Don't force them to read a page when a paragraph will do.
100 |
101 | Conciseness also helps you achieve your goal.
102 | The more time investment your text requires,
103 | the more reluctant readers will be to give it to you.
104 | So we should do our best to keep the required investment to a minimum.
105 |
106 | At the same time, conciseness does not mean being excessively terse.
107 | Conciseness means saying the exact amount necessary to achieve the goal:
108 | no more and no less.
109 |
110 | ## 3. Be Clear
111 |
112 | ### Avoid ambiguity
113 |
114 | Human language is rife with ambiguity.
115 | Take as an example my first title idea for this book:
116 | "Writing for Developers."
117 | Only three words,
118 | yet it could be read in two totally different ways.
119 | That title could have meant
120 | -- as I intended --
121 | "A book for developers on the subject of writing."
122 | But another equally reasonable interpretation was,
123 | "A book on writing for an audience of developers."
124 |
125 | Ambiguous language is useful in art and poetry,
126 | but not when we are trying to communicate as efficiently as possible.
127 |
128 | ### Avoid jargon
129 |
130 | It is also wise to avoid unfamiliar terms and jargon.
131 | Of course, this is dependent on your audience.
132 | To a developer, this sentence makes perfect sense:
133 |
134 | > "Hoth is a lightweight MVVM framework
135 | > which leverages dirty checking
136 | > and immutable data structures for performance."
137 |
138 | To a non-developer,
139 | it sounds more like this:
140 |
141 | > Hoth is a lightweight magic framework
142 | > which leverages scary magic
143 | > and scarier magic for performance.
144 |
145 | For readers unfamiliar with the terminology it communicates next to nothing.
146 |
147 | ### Narrow the scope of your words
148 |
149 | We love to speak in generalities.
150 | Perhaps because it is difficult to definitely prove a generality wrong.
151 | The problem is that the more general a statement is,
152 | the more difficult it is to understand and apply.
153 | Consider this example:
154 |
155 | > Object-oriented programming is terrible.
156 |
157 | It's not completely meaningless,
158 | but it is extremely broad,
159 | and the implications are unclear.
160 | Should readers avoid all object oriented languages?
161 | It's hard to tell what the author is thinking.
162 |
163 | Contrast with this:
164 |
165 | > Class-based inheritance tends to make code unnecessarily complex.
166 |
167 | This version has narrowed the scope in two ways.
168 | It has narrowed from all object-oriented programming to class-based inheritance.
169 | And it has narrowed from "terrible" to "tends toward unnecessary complexity."
170 | As a result,
171 | this sentence is much easier to understand and evaluate.
172 |
173 | Given the choice between the specific and the general, choose the specific.
174 |
175 | ## 4. Be organized.
176 |
177 | For many people this is the most difficult part.
178 | They know the goal.
179 | They can write clear, concise sentences.
180 | But they have a hard time putting those pieces together into a coherent whole.
181 |
182 | In the next chapter we'll look at how to do it.
183 | For now let's explore why.
184 |
185 | ### Structure aids comprehension
186 |
187 | The human mind is built for pattern matching.
188 | And it is pretty good at its job,
189 | otherwise we'd have all been eaten by tigers long ago.
190 |
191 | Consider two different lists:
192 |
193 | * Apple pie
194 | * Blueberry pie
195 | * Cranberry pie
196 |
197 | * Wrench
198 | * Justice
199 | * Puppy
200 |
201 | The first list is much more memorable and comprehensible.
202 | Why?
203 | Because it is organized into a structure that our minds can easily extract.
204 | Each item in the list was a pie.
205 | Each of the pies was fruit-based.
206 | And the pies were alphabetically ordered.
207 | But the second list had no unifying organizational structure.
208 |
209 | ### Structure is fractal
210 |
211 | Writing structures are simultaneously high level and low level.
212 | They encompass everything
213 | from your three main points
214 | to that sub-sub-sub-point in paragraph 45.
215 | And if you've chosen your structure well,
216 | the micro and macro levels will tend to mirror each other.
217 | For example, consider this outline for an article on the Hoth Framework.
218 |
219 | > * Intro to Hoth
220 | > * Immutable data structures
221 | > * Intro
222 | > * Benefits
223 | > * Examples
224 | > * Dirty checking
225 | > * Intro
226 | > * Benefits
227 | > * Examples
228 | > * Example application
229 | > * Conclusion
230 |
231 | Both of the main sub-points follow the same structure as the outline as a whole.
232 | The mirroring isn't always this obvious,
233 | but it is generally present.
234 |
235 | ### Projects may come with built-in structure
236 |
237 | Certain kinds of projects come with ready-made,
238 | very detailed structures,
239 | simply because of how common that type of project is.
240 | API docs,
241 | for example,
242 | may vary a bit by language,
243 | but will generally look pretty close to this.
244 |
245 | * Modules
246 | * Name
247 | * Description
248 | * Classes
249 | * Name
250 | * Description
251 | * Methods
252 | * Name
253 | * Arguments
254 | * Return value
255 | * Description
256 |
257 | Not every predetermined structure is that specific, though.
258 | Library websites have several things they need to include,
259 | like language,
260 | purpose of the library,
261 | and how to install it,
262 | but they also have more flexibility.
263 |
264 | ### General purpose structures
265 |
266 | In addition to these very specific structures,
267 | there are also many general purpose structures.
268 | These are things like the inverted pyramid, objection-response, etc.
269 |
270 | Typically you will pick two or three of these general purpose structures
271 | and use them as the organizing principle of the project.
272 |
273 | ## 5. Be scannable.
274 |
275 | While the previous rule was about the conceptual structure of a text,
276 | this rule is about the visual typographic structure.
277 | The point of scannability is to allow readers to locate important information at a glance,
278 | rather than reading every word on the page.
279 | Even for readers that do read every word,
280 | scannable typography makes it easier to refer back to key ideas in the text.
281 |
282 | ### Break text into bite-sized pieces
283 |
284 | Have you ever read a paragraph that took up an entire printed page?
285 | They are no fun to read.
286 | With no visual breaks,
287 | it is difficult to keep track of where you are,
288 | much less follow the flow of ideas.
289 |
290 | To maximize scannability,
291 | text should be broken into bite-sized units of thought.
292 | Paragraphs, for example, should generally be 2-5 sentences long.
293 | Much longer and it becomes difficult to read.
294 | Shorter and you may want to use a heading instead.
295 |
296 | ### Divide and conquer with headings
297 |
298 | The primary purpose of headings is to make your text's conceptual structure explicit.
299 | However, they also have two important scannability implications.
300 |
301 | First, headings provide a visual anchor allowing readers to locate where a concept is discussed.
302 |
303 | Second, headings breaks the text into units of progress which help the reader stay motivated to continue.
304 | This is part of the reason list posts are such a popular article format.
305 | Each time the reader reaches the next heading,
306 | they get to cross something off their mental checklist.
307 |
308 | ### Use lists for your lists
309 |
310 | While not as common as paragraphs,
311 | the humble list is one of the author's most helpful tools.
312 | It provides:
313 |
314 | * Visual attraction for the list
315 | * Visual attraction for each item in the list
316 | * A break from the monotony of paragraphs
317 | * A sense of progress
318 |
319 | You can, of course, embed lists directly into your sentences and paragraphs.
320 |
321 | > While not as common as paragraphs,
322 | > the humble list is one of the author's most helpful tools.
323 | > It provides:
324 | > visual attraction for the list,
325 | > visual attraction for each item in the list,
326 | > a break from the monotony of paragraphs,
327 | > and a sense of progress.
328 |
329 | However, doing so relegates the list contents to a secondary status.
330 | In general,
331 | using typographic lists
332 | (bulleted, numbered, etc.)
333 | for your conceptual lists makes sense if the exact contents are worth emphasizing.
334 |
335 | ### Emphasize key ideas with bold or italics
336 |
337 | Ordinary paragraphs are the parts of a text most likely to be skipped over.
338 | But sometimes important ideas only make sense as part of a paragraph.
339 | That's where typographic emphasis comes in.
340 |
341 | Highlighting important ideas with bold or italics allows readers to see key ideas at a glance.
342 |
343 | However, there are some rules of thumb to keep in mind.
344 |
345 | * Only highlight one phrase or sentence per paragraph.
346 | * Don't highlight something in _every_ paragraph.
347 | * **Never** highlight something with both bold and italics.
348 |
349 | Go beyond these limits and readers are likely to feel that you are shouting at them.
--------------------------------------------------------------------------------
/manuscript/why.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Why should developers study writing?",
3 | "eleventyNavigation": {
4 | "key": "Why should developers study writing?",
5 | "order": 1
6 | }
7 | }
--------------------------------------------------------------------------------
/manuscript/why.md:
--------------------------------------------------------------------------------
1 | # Why should developers study writing?
2 |
3 | If you've picked up this book, then you're probably a software developer.
4 | Furthermore, you're someone who cares about your career.
5 | You've probably spent countless hours
6 | studying manuals,
7 | reading library docs,
8 | learning how to write clean code,
9 | and otherwise mastering your craft.
10 |
11 | But you may be skeptical.
12 | There are a thousand other things you could learn.
13 | Why spend the time studying writing?
14 | Let's walk through some of the things you might be thinking.
15 |
16 | ## I'm paid to code, not to write.
17 |
18 | In most cases, developers aren't paid to code.
19 | We are paid to produce working software that solves a business problem.
20 | In order to do that we may need to:
21 |
22 | * Email a product manager to clarify a requirement
23 | * Instant message a designer to verify the color and placement of a call-to-action button
24 | * Document the details of an internal REST API
25 | * Submit a patch to an open-source project you use
26 | * File a bug report about a part of the software developed by another team
27 | * Provide explanatory notes about that spike in server errors on the 14th
28 | * Tweak the wording of some UI text that is confusing users,
29 | since the designer is unavailable
30 |
31 | All of these things are run of the mill tasks for a software developer.
32 | And every single one of them is a form of writing.
33 |
34 | ## I already know how to write. I did well in school.
35 |
36 | Unfortunately, literacy,
37 | even at college or university level,
38 | doesn't guarantee the ability to write effectively.
39 | Many degree programs place little emphasis on writing.
40 | And those that do emphasize it often encourage an academic style which doesn't mesh well with most developer's jobs.
41 |
42 | Academic writing tends to value a kind of distant objectivity which can manifest as:
43 |
44 | * Unnecessary jargon
45 | * Verbose and indirect prose
46 | * Extreme formality
47 |
48 | In contrast, most developers would benefit from making their prose clear, direct, and concise.
49 |
50 | ## But I could be studying the Hoth framework instead. It's so cool!
51 |
52 | Yes, no matter which topic you decide to study,
53 | you will be passing up something else.
54 | But writing deserves special consideration.
55 | Why?
56 | **Because writing is a durable skill.**
57 |
58 | Technology changes quickly.
59 | If you're not careful,
60 | you can easily invest a lot of time and energy into a technological one hit wonder.
61 | Writing, though, will never be rendered obsolete by the fickle winds of technology or fashion.
62 |
63 | **Writing is also a transferable skill.**
64 | If you decide to change careers and become a
65 | realtor,
66 | landscape artist,
67 | or -- God forbid! -- a manager,
68 | your expertise in the Hoth MVVM framework will be of limited use.
69 | But writing will remain.
70 |
71 | ## But what will I get out of studying writing?
72 |
73 | ### Less back and forth
74 |
75 | We've all experienced out of control email threads.
76 | It starts with a vague question,
77 | is usually followed by an ambiguous answer,
78 | and before you know it,
79 | someone in another department is freaking out about a non-existent problem.
80 |
81 | What if you could step in and make people understand?
82 | Even better, what if you could prevent the issue from escalating in the first place?
83 | That's the power of clear and effective writing.
84 |
85 | ### Fewer bugs and less rework
86 |
87 | Sometimes we run across frustratingly mysterious bits of code.
88 | Perhaps we've even written some ourselves.
89 | But what's even more frustrating
90 | is when the code is accompanied by an equally mysterious comment like,
91 | "fixes IE bug."
92 |
93 | What IE bug? And which version of IE?
94 |
95 | A developer working on this code, now needs to:
96 |
97 | * Talk to the original programmer,
98 | who won't remember anything.
99 | * Manually test to see if there are obvious bugs related to that line,
100 | which he probably won't catch.
101 | * And perhaps make changes anyway,
102 | without knowing what he broke.
103 |
104 | A clearly written comment would have prevented all of that.
105 |
106 | ### Protect your development flow
107 |
108 | Talking face to face is a valuable and necessary part of our jobs.
109 | But not every face to face conversation is valuable.
110 |
111 | If you find yourself explaining certain things over and over again
112 | (perhaps because you're an expert in a particular subsystem)
113 | then you should write it down in a public location like a team wiki.
114 | If your explanations are clear and easy to understand,
115 | you'll have fewer interruptions messing with your development flow.
116 |
117 | ### Recognition of your expertise
118 |
119 | Perhaps you have a different problem.
120 | You have a deep knowledge of some tool, library, or system,
121 | but no one realizes it.
122 | Writing guides, tutorials, and presentations
123 | can help you achieve greater recognition,
124 | both inside and outside your company.
125 |
126 | ### Greater trust from managers
127 |
128 | Watching a software development project from the outside can be a frustrating experience.
129 | This is doubly true if you are on the hook when something goes wrong.
130 |
131 | A developer who can clearly articulate the state of the project,
132 | without getting bogged down in technical details,
133 | is invaluable.
134 |
135 | If you are that developer,
136 | you will quickly earn the trust of your manager and non-technical colleagues.
137 |
138 | ### Improve your own understanding
139 |
140 | > "How can I tell you what I think till I see what I say?"
141 | >
142 | > -- E.M. Forster, _Aspects of the Novel_
143 |
144 | The process of writing takes our often fuzzy and unformed ideas,
145 | and shapes them into something clear enough to communicate to others.
146 | This makes writing an excellent way to deepen our own understanding of a subject.
147 | Sometimes the improvement comes from research,
148 | but often it comes simply due to organizing our own thoughts.
149 |
150 | ## What now?
151 |
152 | Hopefully by this point you can see why studying writing is worthwhile.
153 | In the next chapter,
154 | we'll launch into some general rules you can use to improve your writing.
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | publish = "_site"
3 | command = "npm run build"
4 | #command = "npm run build && set -e && find ./_site -type f -name '*.html' -exec staticrypt -f password_template.html {} $PASSWORD -o {} \\;"
5 | functions = "functions"
6 |
7 | # REDIRECT and HEADERS examples
8 |
9 | # Redirect rule example
10 | # For more information see:- https://www.netlify.com/docs/netlify-toml-reference/
11 |
12 | #[[redirects]]
13 | # from = "/*"
14 | # to = "/blog/:splat"
15 |
16 | # The default HTTP status code is 301, but you can define a different one e.g.
17 | # status = 302
18 |
19 | # Headers rule example
20 | # For more information see:- https://www.netlify.com/docs/netlify-toml-reference/
21 |
22 | #[[headers]]
23 | # Define which paths this specific [[headers]] block will cover.
24 | # for = "/*"
25 |
26 | #[headers.values]
27 | # X-Frame-Options = "DENY"
28 | # X-XSS-Protection = "1; mode=block"
29 | # Content-Security-Policy = "frame-ancestors https://www.facebook.com"
30 |
31 | # Redirects and headers are GLOBAL for all builds – they do not get scoped to
32 | # contexts no matter where you define them in the file.
33 | # For context-specific rules, use _headers or _redirects files, which are
34 | # applied on a PER-DEPLOY basis.
35 |
--------------------------------------------------------------------------------
/outline.md:
--------------------------------------------------------------------------------
1 | # Prose for Programmers Outline
2 |
3 | Checked boxes indicate that the initial draft of a section is complete.
4 |
5 | ## [Why should developers learn to write?](manuscript/why.md)
6 |
7 | - [x] Objections
8 | - [x] Paid to code, not write
9 | - [x] Laundry list of writing developers have to do
10 | - [x] Coding is writing
11 | - [x] I already know how to write. I did well in school.
12 | - [x] Literacy, even college level, doesn’t mean your writing is good
13 | - [x] Academics can even foster bad writing habits
14 | - [x] But I could be learning technology X instead
15 | - [x] Writing is a durable skill
16 | - [x] Writing is a transferable skill
17 | - [x] Benefits
18 | - [x] fewer back and forth emails/chats
19 | - [x] Fewer bugs due to misunderstood code/docs
20 | - [x] Fewer interruptions from coworkers with questions (keep flow)
21 | - [x] More understanding/empathy from managers
22 | - [x] Recognition of your knowledge
23 | - [x] Increase your own understanding
24 |
25 | ## [General Rules](manuscript/rules.md)
26 |
27 | - [x] Be goal oriented
28 | - [x] Everything you write has a goal or purpose
29 | - [x] may be implicit or explicit
30 | - [x] Understanding the goal promotes better writing
31 | - [x] Structure of goals
32 | - [x] 2 types
33 | - [x] inform
34 | - [x] persuade
35 | - [x] Most writing serves both to one degree or other
36 | - [x] But most writing has a primary goal, with others as secondary
37 | - [x] Be concise
38 | - [x] Not short or terse
39 | - [x] Everything contributes to the goal
40 | - [x] Avoids wordiness for the sake of the goal
41 | - [x] Be clear
42 | - [x] Avoid unfamiliar or unnecessary jargon
43 | - [x] Avoid ambiguity
44 | - [x] Be precise
45 | - [x] Be organized
46 | - [x] Human mind uses patterns to extract meaning
47 | - [x] Structure is fractal: macro and micro mirror each other
48 | - [x] Projects may come with built-in structure (API docs)
49 | - [x] Several general purpose structures available
50 | - [x] Be scannable
51 | - [x] Typographic structure to direct attention to ideas
52 | - [x] Break up text into digestible chunks
53 | - [x] use headlines
54 | - [x] use lists
55 | - [x] Make use of bold and italic to highlight points
56 |
57 | ## [The Writing Process](manuscript/process.md)
58 |
59 | - [x] Determine the goal
60 | - [x] Why am I writing this?
61 | - [x] Purpose of doc
62 | - [x] Not personal motivations
63 | - [x] Keep asking why
64 | - [x] Determine audience
65 | - [x] Who will be reading this?
66 | - [x] Given the goals, which readers are the primary audience?
67 | - [x] What is their relation to the subject?
68 | - [x] What is their relation to you?
69 | - [x] Examples of how audience affects writing
70 | - [x] Choose a suitable structure
71 | - [x] Different structures are suitable for different goals
72 | - [x] Hierarchical structures are often good for informational
73 | - [x] Narrative is good for persuasive
74 | - [x] Different structures for different audiences
75 | - [x] Expertise in topic
76 | - [x] Shallow bullet points
77 | - [x] Deep information hierarchy
78 | - [x] Level of interest
79 | - [x] Relationship
80 | - [x] Can mix and match
81 | - [x] Examples
82 | - [x] Build an outline
83 | - [x] Structure may come with an outline template (API docs)
84 | - [x] List of the ideas you want to communicate
85 | - [x] Evaluate outline based on goal and audience
86 | - [x] Revise outline
87 | - [x] Revising earlier is cheaper
88 | - [x] Turn outline into prose
89 | - [x] Put flesh on the bones
90 | - [x] Muscles: human connection/emotion for strength
91 | - [x] Connective tissue: transitions between ideas
92 | - [x] Not necessarily exposition
93 | - [x] Stories
94 | - [x] Jokes
95 | - [x] Revise
96 | - [x] Evaluate
97 | - [x] Does this unit advance the goal?
98 | - [x] Is it concise?
99 | - [x] Is it clear?
100 | - [x] Is it organized?
101 | - [x] Is it scannable?
102 | - [x] Plan a correction
103 | - [x] Make corrections
104 | - [x] Get feedback
105 | - [x] Types of readers
106 | - [x] Target audience
107 | - [x] Experts
108 | - [x] Friends
109 | - [x] Evaluating feedback
110 | - [x] Readers are always right about their reactions
111 | - [x] Readers may be wrong about the problems and solutions they identify
112 | - [x] Bear in mind what kind of reader this is
113 | - [x] Produce a list of problems to address and good points to keep
114 | - [x] Revise based on feedback
115 | - [x] See previous
116 | - [x] Publish
117 | - [x] May be done at any point (depending on project)
118 | - [x] Can be part of an iterative process
119 | - [x] Tell people about it
120 | - [x] Not the end of revision
121 | - [x] Conclusion
122 | - [x] Abbreviate process as appropriate
123 |
124 | ## Writing Structures
125 |
126 | - [ ] General Structures
127 | - [ ] Inverted Pyramid
128 | - [ ] what it is
129 | - [ ] why it is useful (time saving)
130 | - [ ] high level
131 | - [ ] low level (topic sentences)
132 | - [ ] List
133 | - [ ] Sequence
134 | - [ ] Q & A ?
135 | - [ ] Informational Structures
136 | - [ ] Hierarchy
137 | - [ ] Examples
138 | - [ ] Textbooks
139 | - [ ] API Docs
140 | - [ ] Persuasive structures
141 | - [ ] Objection - response
142 | - [ ] Persuasive version of Q&A
143 | - [ ] Problem - solution
144 | - [ ] Story
145 | - [ ] Syllogism
146 | - [ ] Juxtaposition (attention grabbers)
147 | - [ ] Combine as appropriate
148 | - [ ] Examples
149 |
150 | ## Audience
151 |
152 | - [ ] Aspects of audience
153 | - [ ] Expertise in subject
154 | - [ ] Relationship to you
155 | - [ ] Motivation for reading
156 | - [ ] Emotional state
157 | - [ ] Level of caution/skepticism
158 | - [ ] Common audiences for developers
159 | - [ ] Other developers
160 | - [ ] Somewhat similar outlook on the world
161 | - [ ] Not necessarily the same as you
162 | - [ ] Experience
163 | - [ ] Different technologies
164 | - [ ] Corporate vs startup
165 | - [ ] QA & testers
166 | - [ ] Designers
167 | - [ ] Teammates
168 | - [ ] Non-technical peers
169 | - [ ] Your boss
170 | - [ ] Management
171 | - [ ] Ops/SysAdmin
172 | - [ ] Users
173 | - [ ] Clients
174 | - [ ] Customers
175 |
176 | ## Genres
177 |
178 | - [ ] Genres
179 | - [ ] Email
180 | - [ ] Docs
181 | - [ ] Code Comments
182 | - [ ] Blog posts
183 | - [ ] Chat?
184 | - [ ] Project site
185 | - [ ] Case for new technology
186 | - [ ] Requirements
187 | - [ ] Bug reports
188 | - [ ] Error messages
189 | - [ ] Help articles
190 | - [ ] UI text
191 | - [ ] Commit messages
192 | - [ ] Code review
193 | - [ ] Code?
194 | - [ ] Talks/presentations?
195 |
196 | ## Other Resources
197 |
198 | - [ ] Books
199 | - [ ] The Elements of Style by Strunk & White
200 | - [ ] The Economist Style Guide
201 | - [ ] Steering the Craft by Ursula K. Le Guin
202 | - [ ] On Writing Well by William Zinsser
203 | - [ ] Writing That Works by Ogilvy?
204 | - [ ] Team Geek?
205 | - [ ] Applications & Tools
206 | - [ ] Workflowy
207 | - [ ] Writeroom
208 | - [ ] Writemonkey
209 | - [ ] IA Writer
210 | - [ ] Hemingway?
211 | - [ ] write-good npm library?
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "spacebook",
3 | "version": "1.0.0",
4 | "description": "A simple site generator based on Eleventy, Tailwind 2.0, and Alpine.js",
5 | "scripts": {
6 | "start": "eleventy --serve & postcss styles/tailwind.css --o _tmp/style.css --watch",
7 | "build": "ELEVENTY_PRODUCTION=true eleventy && NODE_ENV=production postcss styles/tailwind.css --o _site/style.css && ./node_modules/.bin/cleancss -o _site/style.css _site/style.css",
8 | "watch": "npx eleventy --watch",
9 | "debug": "DEBUG=* npx eleventy"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/broeker/spacebook.git"
14 | },
15 | "author": "Tim Broeker (https://www.electriccitizen.com/)",
16 | "license": "MIT",
17 | "bugs": {
18 | "url": "https://github.com/broeker/spacebook/issues"
19 | },
20 | "homepage": "https://github.com/broeker/spacebook",
21 | "devDependencies": {
22 | "@11ty/eleventy": "^0.11.1",
23 | "alpinejs": "^2.7.3",
24 | "eleventy-plugin-lazyimages": "^2.1.0",
25 | "eslint": "^7.9.0",
26 | "lazysizes": "^5.2.2",
27 | "luxon": "^1.25.0",
28 | "markdown-it": "^10.0.0",
29 | "markdown-it-anchor": "^5.3.0",
30 | "markdown-it-image-lazysizes": "^1.0.0",
31 | "postcss-cli": "^8.3.0",
32 | "prettier": "^2.1.2",
33 | "tailwindcss": "^2.0.2"
34 | },
35 | "dependencies": {
36 | "@11ty/eleventy-img": "^0.5.0",
37 | "@11ty/eleventy-navigation": "^0.1.6",
38 | "@tailwindcss/forms": "^0.2.1",
39 | "@tailwindcss/typography": "^0.3.1",
40 | "autoprefixer": "^10.1.0",
41 | "clean-css": "^4.2.1",
42 | "clean-css-cli": "^4.3.0",
43 | "elasticlunr": "^0.9.5",
44 | "eleventy-plugin-embed-everything": "^1.9.4",
45 | "eleventy-plugin-nesting-toc": "^1.2.0",
46 | "eleventy-plugin-svg-contents": "^0.7.0",
47 | "eleventy-plugin-toc": "^1.1.0",
48 | "emoji-regex": "^9.2.0",
49 | "html-minifier": "^4.0.0",
50 | "markdown-it-attrs": "^3.0.3",
51 | "markdown-it-center-text": "^1.0.4",
52 | "markdown-it-container": "^3.0.0",
53 | "markdown-it-emoji": "^2.0.0",
54 | "markdown-it-footnote": "^3.0.2",
55 | "markdown-it-for-inline": "^0.1.1",
56 | "markdown-it-linkify-images": "^2.0.0",
57 | "markdown-it-table-of-contents": "^0.5.0",
58 | "markdown-it-task-lists": "^2.1.1",
59 | "postcss": "^8.2.2",
60 | "qs": "^6.9.4",
61 | "remove": "^0.1.5",
62 | "staticrypt": "^1.3.2",
63 | "uglify-es": "^3.3.9",
64 | "url-pattern": "^1.0.3"
65 | },
66 | "main": ".eleventy.js"
67 | }
68 |
--------------------------------------------------------------------------------
/password_template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Private Page
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
136 |
142 |
143 |
144 |
145 |
146 |
147 | {crypto_tag}
148 |
149 |
227 |
228 |