我最近做了一些令我惊讶的事情。 我最终写了一本书,甚至没有意识到。
![](https://i-blog.csdnimg.cn/blog_migrate/bf975293347e5ced978bd037205b3f6e.gif)
在这篇文章中,我将讨论我的书/交互课程“视觉学习者的编码”的发展历程,以及从技术角度来看作为程序员的书本写法。 我还将谈论创建在线课程,因为这是我写作旅程的起点。 如果时间有限,您可以跳到本文的第三部分,在那儿我讨论我最终用来编写和出版书籍的工具是什么,或者查看下面的tl; dr。 但是请记住,有时候旅途比目的地更有意义。
![](https://i-blog.csdnimg.cn/blog_migrate/d484e535c1f471fe644ea30fc8644116.gif)
tl; dr:
- 从您最熟悉的工具开始。 刚开始时,保持低摩擦很重要。
- 您不断出现的需求将为您制定具体的刀具决策提供依据,因此您只需开始创建而不是陷入计划中。
- 我尝试了Workflowy和Notion.so进行写作。 因其Markdown支持,云同步和脱机编辑功能而落在StackEdit.io上 。 这是一个很好的选择,但在收集您对材料的反馈时可能会失败。
- 充分利用YAML的前 题,在文本和Nunjucks模板语言中包含元数据,以便能够使用条件和变量。
- 创建了node.js脚本以根据所需的输出格式(脱机还是在线)来移动文档并对其进行预处理。
- 我的过程是自动化的,但没有过度设计。 请记住, 不要做无法扩展的事情 。
- 我在Fiverr上与校对人员一起工作
- 使用Leanpub进行自我发布并生成多种格式的无品牌电子书,然后在Amazon Kindle商店中出售。
- 如果您打算进行自我发布,则必须阅读Zapier的这篇链接文章。
- 使用Educative.io从我现有的材料中创建了一个交互式的动画课程。
第1部分:我如何在没有意识到的情况下写书?
让我们从适当的介绍开始。 我叫Engin ,我是软件开发人员,教育家,现在是作家。 两年多来,我一直在大学里教授Python入门课程,几个月前,我也开始在网上创建在线课程/视频教程。 我通常会发现自己在录制之前先对整个课程进行脚本编写,以使结果更加可预测和可重复。 换句话说,我并不擅长即兴创作。 我最终写的这些脚本通常非常全面,几乎包含了我计划在录制过程中说的每个单词。 去年,我在Pluralsight上发布了我的第一本在线课程, 即使用PhantomJS和CasperJS自动化网络 。 如果尚未进行检查,则应进行检查。 没关系,我会等你回来。
这次我想创建另一个在线课程,但是我想自己做所有事情,以在课程创建方面获得更多的端到端体验。 我一生都在为别人工作,从未真正独自完成任何交易。 我认为创建课程可能是对事物的业务方面进行试验的好练习,因为它也需要我处理诸如营销或分销之类的事情。 在我的初步研究中,我发现了在视觉上学习编码的方式方面的市场空白,并选择使用出色的JavaScript库p5.js向初学者教授编程。 作为一名自学成才的程序员,我清楚地记得新程序员所面临的斗争。 我着手创建一种可以对我起步有帮助的课程。
为了编写在录制过程中要阅读的脚本,我一直在使用名为Workflowy的服务。 从本质上讲,它是一个列表创建器,您可以在其中创建深层嵌套的可折叠列表 。 我发现这种界面很好地映射了我的思维方式。 它允许我为每对句子创建一个新的列表项。 这使得通过拖放就可以非常轻松地重新组织文本。 折叠列表有助于隐藏和管理复杂性。
![](https://i-blog.csdnimg.cn/blog_migrate/a33620e70dd929f60a9c96a73166f55d.png)
Workflowy很好地映射了我如何进行初始录制。 我一次只录制几个句子,因为感觉连续录制很长时间会增加语音中出现错误的机会。 #ESL
学习一 :后来我发现这不是录音的最好方法。 这种粒度级别大大增加了您的编辑和记录时间。 一位音频工程师向我建议,我应该尝试批量录制(例如甚至尝试一次性完成全部操作),并在以后尝试对其进行编辑/打补丁。
Workflowy是一个很棒的工具,我已经将其用于其他许多与生产力相关的目的了多年。 它使书写和记笔记变得容易且顺畅,但是在显示代码段,图像或纯文本之外的其他内容方面效果不佳。 几个月前,我遇到了Notion,并且对它的功能印象深刻。 基本上就像Workflowy一样,它还可以创建无限嵌套的列表,但就组织/生产力工具而言,它还可以创建其他任何内容(清单,格式化的代码片段,Markdown文档等)。 我决定将我的工作迁移到Notion并继续在那里写作。 它优美的界面使我为自己的工作感到更加自豪,并萌生了这样的想法,即我正在开发的这段文字可能超出了预期的范围。 具有代码高亮显示,图像导入等功能。概念让我看到了如果将其放在纸上(即数字纸),我的工作会是什么样子。 美学很重要。
在这一点上,我注意到我已经写了150多页。 使用列表项使我的方法变得非常迭代,并且它们容易折叠的本质使我无法了解自己的进步。 我注意到我写的书甚至没有意识到。 这就是你写书的方式。 我的朋友,一次一句话。 一次一句话。
![](https://i-blog.csdnimg.cn/blog_migrate/b188416df4dd425eac18ea734be86b4d.gif)
学习二:小事加起来。 我每天只写几个谈话要点,但是随着时间的流逝,它们给了我足够的素材,可以用它们来写书。 拥有可以让我以一致的方式工作的系统,确实有助于取得非凡的最终结果。 介质的选择也有帮助。 列表使事物保持原子性,而可折叠的列表使我看不到越来越多的工作,从而因引发焦虑而阻止了我的自我破坏。
因为我手头有问题,所以这里开始变得有点技术性。 一本书需要连续的文本,而我所拥有的是一堆巨大的句子列表。 由于各种原因,我需要保留两种格式。 当时有一个列表帮助我记录在线课程,但是如果我要从此文档中创建一段文本,那将是一个问题。 输入编码。
第二部分:选择写作平台
我从来没有真正理解过为什么为什么要自行出版一本书需要编程。 但这开始在我身上拂晓。
概念可以选择将我的脚本导出为Markdown文件。 我需要将这个Markdown文件(实际上是一个巨大的嵌套列表)转换为扁平文本。 为此,我使用了一个node.js Markdown库 。 效果很好,但剩下的问题是它现在是一个HTML文档,具有巨大的未排序列表。 可使用性还有很长的路要走。
在这一点上,我开始使用另一个名为Cheerio的 node.js库,以便能够将生成的HTML转换为所需的形式。 Cheerio是一个在服务器端提供类似JQuery语法的库,用于处理超文本数据。 尽管Cheerio在一定程度上有所帮助,但仍然无法一路吸引我。
结果,我决定在文本中添加类型提示。 基本上,提供一组标签来指导Cheerio进行正确的操作。 我将添加一个{{h1}}来指示列表标题必须是h1标题,或者在某些句子的前面添加一个{{+}}符号来表明一个项目需要与前一个合并一个创建一个段落。
大约在这个时候,发生了一件可怕的事。 “想法”决定发布一系列沟通不畅的更新,这些更新使我连续几天#firstworld问题都无法处理我的文本。 当时,Notion是一项相对较新的服务,因此其桌面应用程序在缓存在线数据方面也不是很好。 我发现自己无法在工作时间上工作,因为云服务不可用。 在不对云服务抱有太多信念的情况下,这是一个艰难的教训。 连续几天失败了几次,使我意识到自己需要为写作找到新的家。
现在,这并不是说Notion是一项糟糕的服务。 它实际上是一个了不起的产品。 但是我犯了一个错误,那就是在他们的产品开发的早期阶段就太依赖它了,因为事情仍在不断变化,他们的脱机应用程序与在线平台的同步并不是很好。
学习之三:如果事情变得不可访问,您需要有一种离线工作的方法。 您不能假设云将永远存在。
我开始寻找替代我的工作流程的替代方法,并迅速使用StackEdit.io解决。 它允许您使用本地缓存在浏览器中编写Markdown。 它也可以轻松地与Google云端硬盘同步。 大约是在这个时候,我还发现我以前的录音方式并不是很低效。 一次只记录(和编写)一个脚本只需要几个句子,这有点过于精细,在进行编辑时会减慢您的速度。 这促使我将所有写作内容作为纯净的markdown文本转移到StackEdit.io中,完全摆脱了列表结构。
学习四:刚开始时没有对或错的工具。 对 , 错 , 错的概念最好存在于互联网的点击标题范围内。 如果我一开始就沉迷于我的工具,那么我将无法做任何有意义的工作。 您会弄错事情,没关系。 这是旅程和学习过程的一部分。
第三部分:发布编码
在这一点上,我所有的工作都在StackEdit中进行,我也摆脱了以前添加的所有样式提示,因为我可以继续使用Markdown语法。 StackEdit可以自动与Google云端硬盘同步,因此我也可以提取正在处理的文件以进行脱机处理。 我终于有了可靠的方法来围绕事物构建管道。 这就是编码发挥作用的地方。
我希望能够从Markdown源文件创建多个输出。 我已经在写书中更深入的部分,我开始考虑将其作为高级产品。 我想用这些材料创建一本电子书,但是我也希望能够在我的Jekyll网站上显示相同的材料。 这已经隐含了源文本的四个不同变体,例如免费 在线 , 在线付费 , 免费 离线 , 离线付费 。 在线和离线输出之间的另一个区别是,我可以在在线版本中使用视频(gif)文件,但是这些相同的视觉效果在离线版本中需要是静态图像。
现在,我开始了解编程如何为我的过程提供帮助。 我只有一个权威来源,需要管理多种输出格式,这开始越来越像一个自动化问题。
我开始构建node.js脚本来建立我的工作流程。 我已经在将Google云端硬盘同步到磁盘上的文件夹。 因此,我编写了一个脚本,该脚本将从Google云端硬盘中获取所需文件到我的工作文件夹中,并将其放置在暂存区中。
'use strict';
const fs = require('fs');
const SOURCE_DIR = '/Users/username/Google Drive'; const TARGET_DIR = './staging';
// remove the target content synchroniously let targetContent = fs.readdirSync(TARGET_DIR); targetContent.forEach((file, index) => { let targetFile = `${TARGET_DIR}/${file}` let isFile = fs.lstatSync(targetFile).isFile(); if (isFile) { fs.unlinkSync(targetFile); } });
fs.readdir(SOURCE_DIR, (err, files) => { files.forEach((file) => { if (file.startsWith('p5js-') && !file.endsWith('.gdoc')) { fs.createReadStream(`${SOURCE_DIR}/${file}`) .pipe(fs.createWriteStream(`${TARGET_DIR}/${file}.md`)); } }); });
我托管了在imgur的Markdown文件中引用的图像。 我构建了另一个脚本,这些脚本会将这些图像下载到暂存文件夹中。 我需要将图像保存在本地以编译电子书。
然后,我创建了另一个脚本,该脚本将对暂存区域中的文件进行预处理,然后将其移动到根据目标位置确定的相应文件夹中。 为了能够在联机和脱机版本以及付费和免费版本之间呈现不同的内容,我决定使用Nunjucks模板语言。 这为我解决了两个主要用例:
使用Nunjucks,我能够根据目标输出格式有条件地呈现内容。 例如,我的文档中的gif可能是这样表示的:
{% if online %} ![01–01](http://i.imgur.com/<id>) {% else %} ![01–01](images/01–01.jpg) {% endif %}
有了if-else语句,我可以在预处理脚本中设置一个变量来决定要执行的条件,并使用此数据来呈现Nunjucks模板。
const data = {online: true}; let renderedContent = nj.renderString(content, data);
Nunjucks还允许我创建变量。 我可以在Markdown文本中使用诸如“ {{item}}”之类的变量,根据我要定位的目标,该变量可以呈现为“ book”或“ course”的值。 (我最终使用书的材料创建了一个交互式课程,在那里我需要将该材料称为“课程”,稍后再介绍)。
![](https://i-blog.csdnimg.cn/blog_migrate/a9ab9daa03666ca1a83fc4bab3a49d93.png)
使用预处理脚本,我还可以使用名为front-matter的节点库来处理我在原始Markdown文件中拥有的前端问题 。 之所以需要这样做,是因为我的目标输出格式之一是Jekyll的.md文件,而我想自动为Jekyll添加一些额外的前端物属性以进行解析。
这一切听起来像是过度设计和不必要的。 而且很有可能会这样。 但是我对此过程感到满意的一件事是,即使我面对微小的问题就顺应了开发人员的意愿,但对于构建通用的,可扩展的解决方案我并没有太着迷。 实际上,我编写的所有代码都很丑陋且令人尴尬,但我的意思是要快速行动并以不会浪费时间的方式构建自动化解决方案。 主要目标不是构建可交付内容的系统,而是可交付内容。 您应该做的事情无法扩展 。
学习五:一定要读保罗·格雷厄姆(Paul Graham)关于做不成比例的事情的文章。 效率低下的事情可能会在短期内为您带来巨大的影响力。 但是,如果您刚入门时就对可扩展性的关注感到困惑,那么您可能会错过增长的机会和动力来源,例如,可能会阻碍甚至破坏您的进步的价值传递给人们。
我后悔的一项技术决定是将Promises用于文件系统操作。 我想我想证明自己对使用它们很满意,但是由于我没有任何性能方面的考虑,因此对于我的情况来说,它们完全是一个过大的选择。 对Promises的过度使用开始造成精神上的损失,我只是想快速行动,因为它们不像同步操作那样简单。 游戏开发人员乔纳森·布洛(Jonathan Blow)在开发个人项目时就优化认知负荷进行了精彩演讲 。 当然,这并不是他所从事的任何工作的规模,而是如果您只是在从事需要工作的工作,而不管您如何确保它尽可能地可用。 不要试图变得聪明,因为大多数时候你会比最聪明的自己更笨。
我还创建了将用于某些特定目的的后处理文件。 例如,将文档发送到副本编辑器(我在Fiverr上与自由职业者合作 ),我不需要那里的代码片段,因为它们增加了我的字数,因此影响了定价。 拥有自动化的工作流程使我可以轻松删除它们。 在某些情况下,我遇到了一个相反的问题,即我只需要代码片段。 通过使用后处理文件从文件中有选择地删除目标元素(不是代码片段的任何内容),可以再次快速解决此问题。
![](https://i-blog.csdnimg.cn/blog_migrate/9bb597d03c16d8fd0e75bdb69f791050.png)
我最终在三个不同的平台上发布了我的作品。 我首先在Leanpub上出版了这本书。 已经建立了管道,将我的工作与Leanpub集成并使用他们的Github集成非常容易。 在Leanpub上推动我的工作之后,我使用他们的工具导出了该书的非品牌版本,并将其放置在Amazon Kindle Store中。 Zapier在自发布平台上有一篇很棒的博客文章。 对于对此空间感兴趣的任何人,这都是必读的。
对我而言,最令人惊奇的发现是通过Hacker News上的一篇文章发现了Educative.io 。 Educative.io是一个在线课程创建网站,您可以在其中使用块来构建交互式课程,这些块使您可以轻松地在文档内添加可执行代码段(以及许多其他功能)。 这使您可以创建类似于Jupyter笔记本的文档。 将源文本传输到他们的平台很容易,因为它也使用Markdown格式。
我并不是说我的工作流程是完美的。 一个很大的缺点是,很难从其他人那里收集关于我的文字的在线反馈。 对于这种用例,在Google文档中进行工作会更加有用。 但是不幸的是,Google Docs没有提供一种处理Markdown文件的好方法。
同样,在源文本中使用Nunjucks模板会带来一些开销,因为您不能只复制粘贴文本,而是需要先处理-编译-。 但是考虑到所获得的效率,我认为这是一个合理的权衡。
这总结了我的旅程。 如果要在这里得出最后的教训,我认为不要从一开始就过于迷恋工具和最佳实践,而只是从创建事物开始。 真正重要的是内容和产品,而所有其他问题至少在最初都是次要的。 不要让自己因选择而放慢脚步,一开始可能对您的决策知之甚少,所以根据您的新兴需求开始并反复进行调整很重要。
![](https://i-blog.csdnimg.cn/blog_migrate/3fe8ac608e1e7e311f7b97d422f0a8fa.gif)
谢谢您的成功! 随时查看面向视觉学习者的编码,并随时通过Twitter或通过我的网站与我联系 ,提出您的意见,建议和问题。
同时还要感谢 Myplanet的 Hoi-En和Leigh阅读了此草稿。
From: https://hackernoon.com/writing-a-book-as-a-developer-f02b887880f5