Git Product home page Git Product logo

articles's Introduction

Working on:

  • AutoDev - 🧙‍AutoDev: The AI-powered coding wizard with multilingual support 🌐, auto code generation 🏗️, and a helpful bug-slaying assistant 🐞! Customizable prompts 🎨 and a magic Auto Testing feature 🧪 included! 🚀
  • Chocolate Factory is a cutting-edge LLM application engine designed to empower you in creating your very own AI assistant.
  • ArchGuard is an architecture governance tool that can analysis architecture in container, component, code level, database, create architecture fitness functions, and test for architecture rules.
  • Fklang, 一个基于软件开发工业化思想设计的架构 DSL。 通过显式化的软件架构设计,以确保软件系统描述与实现的一致性,并探索结合 AI 代码生成。

Linkedin Wechat Twitter

articles's People

Contributors

phodal avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

articles's Issues

2017 年,你应该这样学习 Web 编程 —— 内置索引 + 外置搜索引擎

如果你不会使用 Google 去搜索,那么你是一个新手。而如果你只学会如何使用 Google,但是不知道搜索什么,那么你也仍是一个新手。

最初我对这个问题的思考,来自于一年前的一篇相关的文章《程序员的内置索引与外置的Google》。当时,文章的主要对比点是,门户网站与 Google。两者有一些明显的区别:

  • 门户网站更适合那些什么都不知道,从头开始探索互联网的人。
  • 搜索引擎更适合你知道相似的东西,但是忘记具体的细节。

也因此,学习应用型技术变成了一项相当简单的事。你只需要知道它有什么(索引),然后去了解怎么用(搜索)即可。

从怎么学到学什么

开始之前,先让我介绍一下,我的学习框架、语言的方式:

  • 买本中文书或者找个教程、官方的 Guide,花个十几分钟了解一下目录。
  • 直接找个官方的示例,运行一下 Demo。
  • 上手写写应用。
  • 查看官方文档,看看自己是不是漏掉了什么重要的东西。

首先,你有了一份入门资料了,并且也已经有官方的文档了。然后你只需要一步步去做就可以了,不会的地方你就可以搜索到。难怪,程序员被喻为新蓝领工人

蓝领工人

你拿上一份框架的说明书、一份需求文档、一个搜索引擎,就可以很容易地制造出一个产品。唯一的门槛是,你需要会读懂这些内容。这有点像新的知识阶级,只是门槛不再是识字与否,而在于是否能懂编程的知识。

将学习编程与门户网站、搜索引擎相比,就是:

  • 当你是一个新手程序员的时候,你需要一本书、一份指南、一个教程来作为索引,并学习上面的一个个内容。
  • 当你是一个有经验的程序员时,你只需要一个搜索引擎,因为你的脑子里已经有了整个世界。

当你不会使用 Google 时,你可能会这样去搜索资料(参见:英国老人坚持用敬语谷歌搜索 成网红被怒赞):please translate these roman numerals mcmxcviii, thank you。

这种感觉就好像是,你在使用机器人“娇娇”,背后有一个人一样:

Man Inside Computer

可惜,机器人都是晚期直男癌,喜欢单刀直入。

当你只会使用 Google 时,你只能去知乎、SegmentFault 或者 StackOverflow 提个问题:

HTML、CSS、JavaScript、PHP、 MySQL 的学习顺序是什么?

过去,我花了相当长的时间,在探索学习什么的问题。毕竟学习是相当简单的一件事,你只需要抽点时间、找个空间、研究个点就可以了。在这其中,最难的地方是研究一个点。因为你根本不知道,需要学习什么?并非所有的人,都能找到合适的路线。

索引与图谱

当你在某个领域拥有多年的经验时,你就可以将它整理为各式各样的图谱、技能树等等。如:

前端技能汇总

这样的图谱,就像门房网站一样,在上面列好了一个个的知识点。

门户网站

它按照不同的类别,一一的归类。稍有区别的是,这些类别都会相应的内容与之对应。而你在技能汇总上是看不到的,这也就是为什么像技能树这样的工具,也会相当的受欢迎。

Sherlock

人们需要的,不仅仅是一张简单的地图,还需要导航功能。技能图谱、技能汇总等等类似的图谱,它们都只是一些简单的工具。你还需要辅助相应的内容,如文章,视频、教程等等的资料。

在这个时候,或者你需要的是一个 Awesome-xx 的项目,上面不仅仅有目录,还有各式各样的资料。点击到相应的链接,你可以看到代码、应用。

初学的时候,你只需要找到一份合适的索引。学到一定程度的时候,你就可以和我一样创造相应的索引,还有各种资料,如 Growth(https://github.com/phodal/growth)。随后,你就可以对比不同的索引,来完善自己的知识休系。

不断的更新索引

小学的时候,你学会了基本的数学知识,如加法,除法,乘法。你开始在初中的时候,开始解决各种复杂的二次、三次方程、图形计算等等的问题。

从哇哇坠地在医院,到初高中毕业,学习的大部分知识都是别人觉得重要的。学习的时候,教育者们出于某种目的,已经为你规划好了一个个的路线。

工作的时候,领导们仍然会出于某种目的,为你规划好一个学习路线。你并不需要知道自己需要去什么,你像游戏中的国王一样,按别人的规划一步步地往前走。

如果别人为你规则学习的路线是合理的,那么学习起来就会很轻松。反之,你就会很痛苦,开始质疑合理性。

心流

知识本身具有连贯性——这就是《技术发展的本质》一书所阐述的。你把一个现代的智能手机,交给 20 年前的用户,他都不知道怎么用。

Phone

如果你是经历过手机 20 年的更新换代,那么你就很容易地就可以上手各种手机。与些同时,你并需要从 20 年前的大哥大开始用起。这也是大部分开发者的学习过程,但是并意味着你需要从头学起。你仍然可以忽略过很多东西,然后学习最新技术。

令人遗憾的是,知识本身不是静止的,而是一个不断发展的过程。就连吃饭,你都要学习使用不同的工具,如西餐。只有基础本身是静止(相对)的,一旦涉及到应用都是变化的——你学习的 A 技术,经过一段时间,都会被市场淘汰。

这时,你需要像爬虫一样,不断地去抓取新的网页,新的知识点。

Laraedit documents

docker pull laraedit/laraedit
docker run -d --name laravel -p 8082:80 -v c:\Users\ckwong\code\aypcalendar:/var/www/html/app/public laraedit/laraedit
docker start laravel
done

如何成为全栈增长工程师?

(文末有惊喜)

记得我们在《RePractise前端篇: 前端演进史》中提到技术在最近十几年的飞速发展,当然最主要的就是:技术的复杂度不断地从应用层抽象到了框架层。虽说:

技术的复杂度同力一样不会消失,也不会凭空产生,它总是从一个物体转移到另一个物体或一种形式转为另一种形式。

然而这也意味着成为一个全栈工程师,比以往的任何一个时间要容易得多。这也意味着一个全栈工程师也可以很快地成为一个Growth Hacking(中文:增长黑客)。所以,我们开始谈论如何成为一名全栈增长工程师

先成为全栈工程师

在电子书《全栈增长工程师指南》中,我们提到过成为全栈增长工程师的技术基础,但是没有并没有谈论到如何成为这样的全栈工程师——这是一个漫长的过程。

早期,当我们有一个想法的时候,我们会去搭建一个网站——如以WordPress作为CMS,以RoR、Django来开发应用等等。随后,我们将我们的网站推向市场,发现市场有点反应。

接着,我们不断地开发出一些新的功能——如CMS的留言、Sitemap等等。在这个过程中,我们会开发一些API来满足我们的需求。

在一个新的阶段里,我们开始推出移动应用。基于先前的API,我们不断地构建出了不同的API。或以单体应用的形式出现,或以微服务的形式产生出新的API。

然后,我们发现并不是所有的移动用户都愿意去下载我们的API。于是,我们推出了SPA(单页面应用),以此来迎接那些移动设备用户。

最后,我们的业务逐渐稳定了下来。我们开始了一些优化工作,或者如Facebook一样优化PHP,推出HHVM。或者如Netflix一样使用微服务解耦系统。又或者,我们使用新的架构对我们的系统进行重新的设计。

在整个过程中,我们将学习到如何去做网站后台、移动应用、API设计、前端单页面应用等等。从这种意义上来说,全栈工程师非常match初创企业所需要的技术要求。

再成为增长工程师

Growth整一个系列:APP、社区、电子书《全栈增长工程师指南》、电子书《全栈增长工程师实战》算是我对Growth Hacking的一个研究。不过,对于一个人来说这工作量还是蛮大的——在完成两本电子书后,我们将继续研究。在这一个过程中,我发现一些很有意思的东西——只有开发出用户想要的东西,这个过程才容易实践起来的。

增长可以分为两部分:一个是自身的增长,一个是用户的增长。两者实际上是一种相互促进的关系,当我们的能力增长到一定的程度,我们才能推进用户的增长。相用户增长到一定的程度,也会推进我们的技能增长。

只是要在技术、数据分析、用户分析、创新等等有所突破,看上去好像不是一件容易的事。只是对于大部分的全栈工程师来说,实现技术、数据抓取和分析是一件容易的事。要实现对数据的敏感是一种很难的事,但是可视化过后的数据就一样了。对于用户的行为分析也是类似的,只是因为我们缺乏一些有效的练习。

更让人惊讶的是创新也是可以练习的,每次我们遇到一个问题的时候,就是我们离创新最近的时候——难道不是吗?当你遇到一个难解的问题,就是你开拓一个新的能力的时候。

好好享受这个学习的过程吧!

全栈增长工程师实战

终于来到了我们的主题了——我们很高兴宣布《全栈增长工程师实战》已经可以阅读了,地址:http://growth-in-action.phodal.com

你将会看到:

  • 如何去开发一个Web应用(博客)
  • 如何编写单元测试、功能测试、自动化UI测试
  • 搭建并使用持续集成
  • 添加SEO支持——Sitemap、站长工具和Google Analytics
  • 使用API,制作AutoComplete
  • 开发相应的APP及其API——查看文章、用户登录、发表文章
  • 制作单页面应用
  • 可配置管理

在这本电子书里,我们将使用Django + Bootstrap,完成我们的桌面版:

desktop.png

以及移动版:

mobile.png

不仅仅如此,我们还提供前后端分享的实践——基于Riot.js的单页面移动版:

mobile-web.png

同时,我们还用基于混合应用框架Ionic提供了Android版

android.png

还有iOS版,当然也有WP版——只是当前我没有Windows 10的机器:

ios.png

ENJOY CREATE & SHARE

地址:https://github.com/phodal/growth-in-action

使用 adr 轻松创建 “程序员友好” 的架构决策记录

是的,我又写了一个 markdown 工具,它对我来说非常有用。

上下文

在一周里,我看到了一个名为 “轻量级架构决策记录” 的技术实践。在看到了一个简单的示例之后,并阅读了文章《架构决策记录》之后,我开始对于这种工具有了一个好的印象。这似乎就是我,以及敏捷团队、程序员所梦寐以求的工具。

作为一个程序员,我们并不喜欢阅读又长又臭的文档,它往往不如一个 hello, world 来得实在。更不用说自己去写一个又长又臭的的文档了。事实上,我们对于文档的痛恶的原因是:文档经常是落后的、老旧的。因此,一个更合适的方案是,创建一种轻量级的文档。

作为程序员,我们常说代码即文档。是的,代码本身是文档的一部分,但是代码往往告诉你的是结果代码不会告诉你原因。尽管从版本控制中,我们仍能通过 log 找到对应的 Author,可往往找到的这个人,可能已经没有人认识了(至少隔了一代开发人员)。

因此,如《架构决策记录》一文中所说:

项目在其生命周期中,最难追踪的事情之一就是:某些技术决策背后的动机

这时,我们往往需要一个工具来记录产生这些技术决策的原因。

随后通过 ThoughtWorks 技术雷达(在 2016.11 期上提到 ADR),我找到了一个相关的库:adr-tools,但是发现这个库有一些小的缺点:

  • 使用 shell 编写,不易读懂、只支持类 Unix;
  • 模板里使用的是英语,不支持中文及其他语言

决策

于是,我便决定自己写一个这样的工具。它应该采用 markdown,并使用《架构决策记录》一文中提到的格式:

标题,这些文件的名称是短名词短语。例如,“ADR 1: Deployment on Ruby on Rails 3.0.10” 或 “ADR 9: LDAP for Multitenant Integration

上下文,这一节描述了当前的技术、政治、社会和项目。这些力量可能处于紧张状态,应该这样说。本节中的语言是价值中立的,只用于描述事实

决策,这一节描述我们对这些力量的回应。这是充分的句子,以及积极的声音。 “我们会...”

状态,如果项目利益相关方尚未同意,或者一旦达成一致,则 “决定” 可能被 “提议”。如果以后的 ADR (架构决策记录)更改或撤消决定,则可能会将其标记为 “已弃用” 或 “已取代”,并参考其替换。

后果,这部分描述了应用决策后产生的上下文。所有的后果应该列在这里,而不仅仅是 “积极的”。一个特定的决策可能会产生积极的、消极的和中性的后果,但是它们都会影响未来的团队和项目。

并且,它应该可以轻松地实现:

  • 采用一种能用的语言环境,如 Node.js,以支持主流的操作系统
  • 多语言支持,我的意思是它至少可以支持 English 和 中文
  • 支持状态日志查询,即我应该可以看到一个决策在生命周期里的变化
  • 一个更好的列表展示,我应该可以查看到某条决策,以及对应的最后状态、修改时间等等
  • 使用 markdown 展示,以便在 GitHub 上显示
  • 拥有一个 ToC 页面,方便用户查看

状态

2017-11-22 提议
2017-11-22 通过
2017-11-22 完成第一个版本

后果

最后,我使用 TypeScript 与 Node.js 创建了一个 adr.js 的库。

它的安装很简单:

npm install -g adr

然后,你就可以创建你的 ADR 了:

adr new 'hello, world'

并结合提供的工具来查看这些技术决策:

$ adr list


╔══════════════════════════════════════╤══════════════╤═══════════════════╗
║ 决策                                  │ 上次修改时间   │ 最后状态           ║
╟──────────────────────────────────────┼──────────────┼───────────────────╢
║ 1.编写完整的单元测试                    │ 2017-11-27   │ 2017-11-26 完成 ║
╟──────────────────────────────────────┼──────────────┼───────────────────╢
║ 2.添加目录生成                         │ 2017-11-27   │ 2017-11-25 完成 ║
╟──────────────────────────────────────┼──────────────┼───────────────────╢
║ 3.图形生成功能                         │ 2017-11-27   │ 2017-11-24 完成 ║
╟──────────────────────────────────────┼──────────────┼───────────────────╢
║ 4.生成在线图形                         │ 2017-11-27   │ 2017-11-22 提议   ║
╟──────────────────────────────────────┼──────────────┼───────────────────╢
...
╟──────────────────────────────────────┼──────────────┼───────────────────╢
║ 15.考虑添加-export-功能来导出-adr       │ 2017-11-27   │ 2017-11-26 提议   ║
╟──────────────────────────────────────┼──────────────┼───────────────────╢
║ 16.使用不同色彩来标注不同的状态          │ 2017-11-27   │ 2017-11-27 提议   ║
╚══════════════════════════════════════╧══════════════╧═══════════════════╝

不过,在这里我犯了一个错误,就是把功能需求也放到里面了。

我们也可以查看某个决策在生命周期的变化:

$ git logs 9

╔════════════╤══════╗
║  -         │  -   ║
╟────────────┼──────╢
║ 2017-11-23 │ 提议  ║
╟────────────┼──────╢
║ 2017-11-23 │ 通过  ║
╚════════════╧══════╝

除了这些,还有额外的功能:

  • 内置 update 命令,方便同步决策到标题上
  • 生成决策的目录,方便快速定位
  • 支持导出 CSV 格式,以便在 Excel 中查看
  • 支持导出 JSON 格式,以便进行二次开发

欢迎 GitHub 围观:https://github.com/phodal/adr

Deep learning:From the primer to the mastery

You should master the basic knowledge of machine learning before learning.In the same way, basic mathematical knowledge is also essential,include:linear algebra, probability theory, etc.

《Growth In Action》草稿版——从网站到APP、再到前后端分离

作为Growth计划一部分的实战篇,比以往时候来得更晚一些。除了《Growth:全栈增长工程师指南》花费了更多的时间,还有一点则是在考虑新的技术栈。

后台

Growth In Action》在最初设计的时候,考虑了用三种风格的语言来完成服务端:

  • Python:简单易学的编程语言
  • JavaScript: 距今为止最流行的编程语言
  • Scala:函数式的面向对象语言,并且是编译型语言

后来考虑到一些时间成本花费以及易学的语言,只用Python语言的Django框架来完成服务端的编程。在五一前的时间里已经完成了大部分的后台代码,最近又补充了一些细节。

APP

作为计划的一部分的APP端,原计划是用:

  • React Native:最近比较火的APP框架。
  • Ionic: 易上手的混合应用框架。

随之发现时间不够用,并且发现Ionic已经推出了新的版本——没有理由继续使用旧的版本,于是就只用Ionic 2来完成。但是Ionic 2也带了一些新的变化:

  • 使用Angular 2作为基本框架
  • 使用TypeScript作为主要语言,但是也支持ES6
  • 带来了Ionic Native框架,替换原先的ngCordova
  • 等等

这些也带了一些些挑战,不过好在经过一周的开发,APP端已经完成了。

前端

前端的很多内容还没有开始,我真不知道用哪个框架好。。

其他

在编写的过程中还有一些难点,即要保持和《Growth:全栈增长工程师指南》中介绍的那些初中,并且要带入平时工作上的一些风格进去。总的内容大致如下:

  • 如何去开发一个Web应用(博客)
  • 如何编写单元测试
  • 如何编写功能测试、自动化UI测试
  • 搭建并使用持续集成
  • 添加SEO支持
  • 支持APP使用的API
  • 开发相应的APP——登录、注册、发现文章、查看文章
  • 添加单页面应用的前端
  • 自动化部署

在线阅读: https://github.com/phodal/growth-in-action-python

大神Linus说要写代码到71岁,你呢?

今天晚上我和往长一样在写《物联网周报》,然后我看到了一个新闻是:

Torvalds prepared to spend next 25 years helping Linux conquer the desktop

中文翻译就是: Torvalds准备花费下一个25年来帮助Linux占领桌面市场。

linus-torvalds.jpg

这让我联想起最近的《Microsoft将Linux带至桌面操作系统》

Windows Linux

这让我想到了这个:

ms_loves_linux.png

还有Linux桌面是不真的没救了?以前,我是一个Ubuntu粉——因为他们不断地从荷兰寄光盘给我。直至他们推出了Unity:

ubuntu-unity.png

我就在心里想:

wtf.jpg

然后我就跳到OpenSUSE阵营了!

opensuse-leap.jpg

看上去帅呆上,但是大部分的软件长的是这样的!!!

cde.jpg

让我静一静!

还有各个坑爹的显卡,以至于大神发话了!

nividia.jpg

吐槽完毕,回到正题

北回归线

再引下原文:

I would obviously love for Linux to take over that world too, but it turns out it's a really hard area to enter. I'm still working on it. It's been 25 years. I can do this for another 25. I'll wear them down.

我会非常乐意看到今后 Linux 作为桌面系统占满全球,但目前进入该领域依然还是充满着难度。我会全力以赴,已经 25 年过来了,未来的 25 年我依然会不屈不饶的为这目标而努力。

一看我发现不对劲了,Linus现在是46岁。

46+25 = ?
46+25 = ?
46+25 = ?

这让我想起了大叔RMS和他的“若为自由故”、还有龙芯:

rms.jpg

那么问题来了,你要写代码到几岁呢?

先说说我,我之前只打算写到40岁~~。

我的第四款编辑器:微信公众号上使用 Markdown 来显示代码

这已经是我第四次写编辑器了~~~

第一次是在三年前,当时我听说有一个工具叫 Node-Webkit,于是我就结合CodeMirror撸了一个编辑器,界面如下:

Lumia 编辑器

GitHub 地址:https://github.com/phodal/lumia

第二次是在一年多以前,当时在验证我玩的编辑-发布-分离模式,即一键 PUSH 到 GitHub 上去。

Fay 编辑器

技术栈:

  • Electron
  • React
  • Material UI
  • Alloy Editor

第三次是在去年,我们家 @花仲马 想要一个可以支持 QQ 音乐的微信编辑器,于是就撸了一个玩:

GitHub地址:https://github.com/phodal/congee

Congee 编辑器

技术栈:

  • Ractive (template-driven UI library)
  • Require.JS (AMD)
  • CKEditor
  • jQuery Nicescroll
  • jQuery Mixitup
  • Spectrum (ColorPicker)

之前的三个都没有下文了,好在这次的功能比较简单,我只需要一个可以支持代码高亮的转换工具——但是它看上去更像是一个转换工具,可以让我完美的在微信公众号上显示代码:

(function () {
  var input, output;
  var converter = new showdown.Converter({extensions: ['prettify']});

  function updateOutput() {
    output.innerHTML = converter.makeHtml(input.value);
    PR.prettyPrint();
  }

  document.addEventListener("DOMContentLoaded", function (event) {
    input = document.getElementById('input');
    output = document.getElementById('output');

    input.addEventListener('input', updateOutput, false);
    input.addEventListener('keydown', updateOutput, false);

    updateOutput();
  });
})();
$('document').ready(function () {
  new Clipboard('.btn');
});

上面这22行代码就是这个编辑器的核心代码,2333~~。里面的 HTML 是这样的:

<div class="row cf">
  <div class="col">
    <div class="header">
      <h2>Markdown</h2>
    </div>
    <textarea id="input" cols="100" rows="10"></textarea>
  </div>

  <div class="col">
    <div class="header">
      <button class="btn button" data-clipboard-action="cut" data-clipboard-target="#output">复制</button>
    </div>
    <div id="output"></div>
  </div>
</div>

然后用了这么这几个库:

  <link rel="stylesheet" href="css/custom-ui.css"/>
  <link rel="stylesheet" href="css/normalize.css"/>
  <link rel="stylesheet" href="css/style.css"/>
  <link rel="stylesheet" href="css/basic-ui.css"/>
  <link rel="stylesheet" href="css/highlight.min.css"/>
  <link rel="stylesheet" href="css/github-light.css"/>

  <script src="js/showdown.min.js"></script>
  <script src="js/showdown-plugins/showdown-prettify-for-wechat.js"></script>
  <script src="js/jquery-3.1.1.js"></script>
  <script src="js/clipboard.min.js"></script>

  <link rel="stylesheet" href="google-code-prettify/prettify.css"/>
  <script src="google-code-prettify/run_prettify.js"></script>
  <link rel="stylesheet" href="themes/tomorrow-night-eighties.css"/>

  <link rel="stylesheet" href="css/wechat-fix.css"/>

打完字,Showcase:

Markdown Pub

直接将你的代码复制到左侧,然后点复制。再 Ctrl + C 一下,就可以愉快地粘贴到你的公众号上了。

  • 采用 10 px 的字体、12 px的行高

GitHub 地址:https://github.com/phodal/mdpub

编程小牛成长记之练手项目

手绘板在两个月前来了深圳,今天又来了点灵感,所以就有了画风。。。

Story

好了,玩笑开到这,接下来是广告时间。

你是不是在为提高编程技术而发愁?

你是不是在为找不到合适的练手项目而烦恼?

你是不是在为有合适的项目,但是没有指南而烦恼?

所以,我整理了一些项目,变成了一本电子书,项目名为:

Title

中文名为:

Title

上面有各式各样的项目:

首当其冲(这个项目名为big-data,所以排第一)的就是分析一个2G的Nginx日志,生成用户访问地点图。

技术栈:Hadoop、Jython、AmMap、ElasticSearch

Map

还有一个简单的微信编辑器:

技术栈:Ractive、jQuery、CKEditor

Congee

全平台应用Growth:

技术栈:Electron、Ionic、Angular.js

Story

一个自动生成的技能树:

Skill Tree

还有一个直接写文章发布到GitHub的本地编辑器:

Story

除此,我们还有:

Echoesworks

O2O应用:

Story

项目首页:https://github.com/phodal/ideabook

程序员必知的七个图形工具

在上一篇《全栈工程师的百宝箱:黑魔法之文档篇》我们介绍了一些文档工具,今天让我来分享一下,我常用的一些图形工具,主要有两类:

  • 流程图
  • 数据可视化

流程图:Graphviz

说到流程图还是再次提及一下,我们之前说到的Graphviz

Graphviz (英文:Graph Visualization Software的缩写)是一个由AT&T实验室启动的开源工具包,用于绘制DOT语言脚本描述的图形。它也提供了供其它软件使用的库。

它的主要特点是代码生成图像,并且足够的简单。

在我的那个“Web Developer 成长路线图”(GitHub: https://github.com/phodal/developer)里,就是用这个工具生成下面这个复杂的图形。

tree.png

而其代码特别简单——和我们平时表达的手法是一样的,即:

"包管理" -> "包发布" -> "自动部署"
"CLI" -> "部署"
"脚本语言(Bash,Perl,Ruby,Python etc)" -> "部署"
"脚本语言(Bash,Perl,Ruby,Python etc)" -> "构建"
"*nix" -> "软件编译" -> "部署"
"构建" -> "软件编译"

Graphviz有一个大的优点和弱点是:自动生成,导致画线的时候很出现出问题。接着,我们就来看看手动画线的例子。

流程图: Visio vs Dia vs OmnIGraffle

在Windows世界里,在这一类的工具里面最常见的算是Visio:

MS-Visio-flowchart.png

遗憾的是,它并不支持在Mac OS上使用。而且,它并不在我购买的Office 365套装里。

在Mac世界里,最好的工具算是OmniGraffle,就是很贵——我们平时使用的是公司的Mac电脑,使用盗版软件是有法律风险的。

Omnigrafflescreen.jpg

在GNU/Linux世界里,我们使用Dia。

Dia 是开放源代码的流程图软件,是GNU计划的一部分,程序创立者是Alexander Larsson。Dia使用单一文件界面模式,类似于GIMP与Inkscape。 Dia将多种需求以模块化来设计,如流程图、网络图、电路图等。各模块之间的符号仍是可以通用的,并没有限制。

dia_screenshot.png

顺便安利一下,我最喜欢的操作系统OpenSuSE——简洁、尾长、绿色。

opensuse.jpg

OpenSuSE在KDE桌面下效果最赞了——因为KDE和OpenSuSE都是德国制造。总的来说,会比Debian系的Debian和Ubuntu,及RetHat系的CentOS及Fedora稳定、漂亮。

令人遗憾的是这三个工具,我都用不了。Mac对X Windows的支持不是一般的差,于是我就需要别的替代工具。

在线流程图:Processon

这个工具还是相当好用,至少是在GxFxW内比较快——我之前使用过Creately、draw.io、Gliffy等等的一些工具,只是随着版图的扩展,很多地区都已经“xx”了。

tlok.jpg

不过遗憾的是:他们没有给我广告费。

ProcessOn是一个在线协作绘图平台,为用户提供最强大、易用的作图工具!支持在线创作流程图、BPMN、UML图、UI界面原型设计、iOS界面原型设计等。

同样的,在我的那个“Developer进阶书单”(GitHub: https://github.com/phodal/booktree)中,就是用这个工具画出规规矩矩的线。

BookTree.png

并且,它还是跨平台的。

各种图: Word和Excel

由于翻译和写书的需要,我成了一个Office 365订阅用户。于是发现在Word等一系列的Office工具中,自带了一个SmartArt的工具:

smart-art.png

可以画出很多很有意思的图形,比如:

编程之路.png

又或者是:

growth-lob.png

分分钟就能画一个的节奏。

脑图: XMind

我想这个一般人都是知道的。

XMind思维导图软件被著名互联网媒体Lifehacker评选为“最佳头脑风暴和思维导图工具”及”最受欢迎的思维导图软件”。

它有一个很大的优点是使用了全球最先进的Eclipse RCP 软件架构,支持跨平台使用。它有一个很大的缺点是使用了全球最先进的Eclipse RCP 软件架构,导致了有点卡。

相比于流程图什么的,它只适合做脑图。

banner_index.png

如果你还在使用Eclipse,那么你应该试试Intellij IDEA了。

各种图:D3.js

D3.js(D3或Data-Driven Documents)是一个用动态图形显示数据的JavaScript库,一个数据可视化的工具。

与上面的工具相比,这个工具可能没有那么方便。但是,作为一个数据可视化工具,它不仅仅可以做出各种炫酷的图形。

还可以做出一个技能树:

sherlock.png

这个项目的GitHub见:https://github.com/phodal/sherlock

地图:Leaflet

Leaflet 是一个为建设移动设备友好的互动地图,而开发的现代的、开源的JavaScript 库。

虽然它与上面的图形没有啥关系,但是它带了一个图字啊。与Google Map原生的API,或者OpenStreet相比,它最大的优点是对移动设备支持好。

并且,它也是一个可以根据数据(GEOJSON,地理数据)生成图形的工具。

vmap.jpg

更多精彩内容欢迎关注我的微信公众号:Phodal

http://articles.phodal.com/qrcode.jpg

两年以来x两年以后

转眼间已经工作两年了,2014年07月07日我带着我的毕业证和学位证再次去到了ThoughtWorks西安,继续编写之前实习时的代码。两年以后的今天,在自己的Macbook下用Emacs下写下了这篇文章。

两年后的今天和两年前似乎没有太大的区别,我还是在为家里赚钱,还没到为自己赚钱的时候。我清理了一下所拥有的那些值钱的资产,无非就是:

  • 一个大学时买下的Kindle PaperWhite 1a
  • 一个三个月前才公司买下的三手电脑
  • 一个拿来当相机的Nokia Lumia 1020的手机,只是不支持4G
  • 一个本想拿来当电脑的Nokia N1平板,可惜是个Intel核心
  • 一个本以为可以刷Ubuntu的魅族MX5手机
  • 还有一堆书

要知道我在一个月之前连银行卡都丢了,还有值钱的身份证。因此,还是和大部分刚毕业不久的人一样,缺钱,甚至还远远不如一些刚毕业的学生,他们可以为自己赚钱。当和别人聊起待遇的时候,总会提到一句:我们不加班,所以工资比大部分的互联网公司都低。

为什么我就喜欢这种不加班的工作呢?我也说不清楚,大概是因为我想要更多的学习时间吧!

我的日常

在那篇《我的成长四步曲》里,我曾经提到过我的成长计划,要实践这样的计划也需要相当从的时间。而时间本来就是容易消耗的东西,一部电视剧、一部电影、一场游戏。累的时候,我们就无可避免地需要这样的休息。

但是如果每天你只上八个小时的班,还累的话,那么可能是因为你还没有渡过学习区,要么就是你真的太懒了。又或者是你没有想去做的事情,安逸地活着也是一种活法,只是那种活法还不到适合我的时候。我还想去看看这个世界,看看那些最美的地方。

每天早上我大概会七点起床,然后写会代码、再去洗簌,又或者先洗簌、再去继续代码,直到八点走人。这个习惯是在西安的时候养成的,即使是在没有暖气的冬天里也是如此。尽管我一直想把时间往前移移到六点,但是某人不同意。早上由于时间特别短,写起代码也特别有挑战性——一直有一个Deadline在提醒你,你要尽快去解决这个问题。要不这个问题就得留到晚上,又或者是明天了。你也可以试试每天这样挑战一下,会刺激你的肾上腺激素。不过,很快地你就又进入了休息状态了。要是幸运的话,还可以到公司再写点代码。

之前在西安的时候,中午都有一个小时的午休时间,拿出一小部分的时间休息。然后在那一年多里里,就拿中午的时间参与翻译了二本书,还写了一本书。也有些时间会写代码,但是比较少,因为吃完饭后,实在是困。

六点多开始踏上回家的旅途,七点多到家,多数时候都会睡上十几分钟到差不多八点的时候就起来码字、写代码。到了十点左右,会习惯性地看看书、又或者是写写代码。

一星期很容易就这样过去了,不过总有一些明显的规律,周一和周四写的代码都比较少。周一大家都知道为什么,但是周四就显得有些奇怪,大概是因为周五就要放假了吧。

周六、周日的早上习惯性的就会看电影,下午可能会玩玩游戏、看看书什么的,晚上才是写代码的状态——总觉得被自己平时的习惯坑了。周末总的来说,会比较轻松一点,但是也会和平时差不多一样的时间起床——除非不得已熬夜了。

所以,这就是下面这张图的由来:

GitHub

在这个过程中,有一篇篇的博客,一次次的代码提交记录了这些过程。

写作

写作本身就是整理自己知识体系的一个过程,我发觉我从中受益挺大的,便不断地再次重复这个过程。写书则会把自己所学的知识,以一起的框架整理出来。原本只是关于某方面的一些零散的知识,突然间知识点变成了一本本的书放图书馆里,整整齐齐地摆放着。在我们需要的时候,我们就可以极为方便地取出这些知识点。那些我们不熟悉的点,也会在我们写作的时候驱使自己去了解。我们会因此而对些更加了解,从输入到输出是一个很有趣的过程。

这两年里虽然也写了不少的博客,大概会有200篇左右,我的博客https://www.phodal.com/blog的文章数量也已经累积到了564篇了。除此,还有之前提到过的《六本电子书》,总结自己的经验,然后自己会学习到多,别人也学习到了更多,顺便再扩大一下影响力。哈哈,不过,我从小就一直想成为一个作家来着。《教你设计物联网系统》是由我的毕业设计而来的,《GitHub 漫游指南》是我的博客合集,以及Growth计划里的《全栈增长工程师指南》和《全栈增长工程师实战》。当然还有神来之篇的《Ideabook: 一个全栈增长工程师的练手项目集》,这绝对是一本好到爆的创意。以及还在编写的《RePractise》,这仿佛是一本没有终点的电子书籍。

如上所说,在这些年里,我还参与翻译了两本书籍,只是都还在出版中。一本是关于物联网的书籍,我也是这本书的英语版技术审阅,这意味着这本书会有两个地方都有我的介绍。还有一本是关于Arduino的书,不过这本书我只翻译了大概1/5的内容。可惜的是,翻译书真的是吃力不讨好的工作了。我从写作中获得收益最多的,怕是给InfoQ写《物联网周报》了,毕竟他们的稿费给得比较慷慨。然后我想我写的物联网方面的书籍也应该快出版了,算是第一个剧透。

我喜欢写电子书而不喜欢写纸质书籍的原因在于:写的纸质书籍过程中很容易将我的耐心消耗完。而电子书则是这样一个刚刚好的过程,我觉得我把自己的知识体系整理得差不多了,我也就可以停止写作了。我就可以很快地挪向下一本电子书籍,移向下一个感兴趣的点。

编程

这两年来,仿佛在编程上并没有多少提高,更多的是方法论和软件工程的实践。从原先对于软件工程的几乎一无所知,到敏捷软件开发是一系列有意思的过程,再到精益则是另外一个有趣的实践。

记得我们在学编程的时候,看到的书都是“xx语言程序设计”,而不是“Copy & Paste from StackOverflow”。程序中的设计又或者是从小到大,又或者是从大到小,都反应了不同的组织意识形态。有时候,并不是我们不能设计一个更好的架构,只是组织结构不允许。

从一个程序中,我们可以看到人的设计**,可以看出它的模式,也可以看到它的未来,这些都需要我们有一些了解、练习、实践。

编程的练习

有洁癖的工程师都在追求着更好的代码质量,为一个变量取一个好的名字、重构一段遗留代码、为旧有的代码添加测试、学习一些好的软件设计实践,我们都在追求更好的代码和设计。如果你也有时间,那么你也应该去做同样的练习:

  • 为自己的代码编写测试,乃至使用TDD来开发一些Side Project——顺手一推荐《测试驱动开发》。
  • 学会重构,以及依靠快捷键重构——你应该都听说过那本书《重构》,再试试Java的Intellij Idea、Python的Pycharm或者JavaScript的WebStorm的重构功能。
  • 学习、了解代码的设计模式——从普通代码到设计模式有一种方法就是“重构”,因此推荐一本书《重构与模式》。
  • 熟练使用键盘,熟练使用编辑器、IDE的快捷键。如果不行的话,你可以试着去寻找编辑器和IDE的cheatsheet,像VIM和Emacs这样的编辑器,你就可以买上相应的书。
  • 尽可能多地去探索提高效率的工具。这一点倒也可以参考我的Toolbox,建立自己的工具箱。
  • 有机会的时间尽可能去尝试新的技术。建议可以看看“ThoughtWorks 技术雷达”,你可以了解到一些技术趋势。
  • 当然还有预防颈椎病。你需要合适的椅子、桌子、键盘、鼠标,还有眼睛与屏幕的视角。

随后,你可以和我现在一样尝试在这方面的练习:

  • 适当地做一些架构方面的练习。

最好,你还能经常性的做出一些总结。

业务与技术

我们一直在技术和业务之前不断地周旋,很难好好地平衡两者间的关系,但是真的是如此吗?很多时候,我们只是为了实践一些新的技术而去责怪业务不给力。使用新的技术不一定使你开心,但是如果可以在繁琐的业务里创造新的技术、框架,则是更有激情的事!

作为刚入职场的人,我们都对业务有一些相似的看法。只是对于大部分领域来说,都是业务可以给技术带来生机。在那之上,有几种东西倒还是挺有意思的,一个是 DDD (领域驱动设计),还有一个是DSL(领域特定语言),都是我今年一直跃跃欲试地东西。他们真的是两个非常不错的看点——从技术与业务剥离的一些技术手段。我还是有点太年轻了,不是很了解这些东西。以领域的视角,去设计可以在业务专家与技术人员能理解的语言真的很赞。像我之前使用的BDD(行为驱动开发)就有这种趋势,只是它更多的用于编写业务场景。

设计

在这一方面的进展,又特别的小,但是我总想提一下。我是不是要把我的电脑密码改成de51gn@,这样我才会每天想它一次。不过,好在至少还有一个brand可以撑一下门面。

我开始使用以前设计的Logo来作为手机、电脑的背景,下一步呢?

半年x未来

Growth是今年年初计划做的东西,虽说并不是很理想,我特别有激情。

Growth

Growth本身是一个双重计划:提高自己、提高他人。从一篇文章引发的一系列作品,它就如蝴蝶一样,翻开了一个新的世界。他已经有了一个Android的APP,一个iOS的APP,还提供了桌面、Web版。这个故事里面也已经衍生出来了两本电子书,即上文中提到的指南和实战。其中还混合了一系列常用的工具、软件,我想以后的toolbox也会加到这个软件里面吧,笑~~。

Growth还有一部分的内容未解:解决方案。在重新思考了这个问题后,我想将之混合入架构的方面来实现这个功能。这也是我接下来想尝试写的电子书,脑子里已经零零散散地有了一些架构方面的知识,过去也没有想着好好清理。

解决方案 + 解决方案的架构,对于Growth来说,又是一个好的场景。

Build A Team

离开上一个Team,我就对这个问题思考了很久。工作上存在的Team,多数并没有共同的理想,都是因为种种原因而在一起的。这种比喻有点类似于,那些公司的创始人因为有着共同的理想走到了一起,公司也就有了共同的理想。当公司变大以后,每个人的理想就不一样了,公司的理想也就不一样了。有点习惯了年轻的团队带来得活跃感,怀念一个真正的产品带来的激情。

我想Build A Team去做一些技术方面的创新,推动国内的技术发展——毕竟我的博客和电子书都达到了这样的效果。不过,这是未来要开始做的事,而不是现在——路还长着呢。如果你想来参与,我希望你(排序是有先后顺序):

  1. 愿意去分享自己的知识
  2. 足够的技术热情
  3. 学习能力
  4. 当然还要有一定的技术水平和能力

你呢?你的这两年呢?

译书《物联网实战指南》出版 | 新成就:翻译自己的英文简介

这本书有一个很长的故事,到今天算是走到了一个意想中的结局。从审阅这本书开始、英文版出版、翻译成中文就这样走了两年的时间,这是一本值得纪念的书籍。

英文书名《Learning Internet of Things》,中文书名 《物联网实战指南》。

《物联网实战指南》简介

简单的先上个简介啦~:

本书从探讨流行的HTTP、UPnP、CoAP、MQTT和XMPP等物联网协议开始,并从实战角度介绍了现有的协议、通信模式、构架以及物联网安全的重要性。本书适合那些对物联网感兴趣的开发者和工程师阅读。那些对电子学、树莓派(RaspberryPi)或者卡片电脑有基本的了解(高中水平)以及有一些代码托管的编程经验的人,通过本书将会很快学到当前先进的物联网解决方案。

简单的一名话就是:

在Raspberry Pi上使用 C# 开发物联网应用。

我从这本书中,学到了相当多的东西——我写的《自己动手设计物联网》的一些知识点,如MQTT协议,也是从这本书上了解到的。还好我的书是用JavaScript写的,而且是以我的毕业设计为思路写的,中间加了个MQTT协议和CoAP协议。

这本书也介绍了其他的相关物联网协议,总得来说内容相关的不错,除了用 C#。

审阅者介绍

先让我装个逼~~~

当时在写Reviewer简介的时候,考虑到我刚毕业,又没有什么内容可以写。我只好写我在Web开发和硬件上有四年经验,不敢在上面写我从小开始写代码。

Phodal Huang has over 4 years of experience in hardware and web development. He graduated from Xi'an University of Arts and Science. He currently works at ThoughtWorks as a developer. He is the owner of the mini IoT project (https://github.com/phodal/iot) and the author of the eBook, Design IoT (http://designiot.phodal.com, in Chinese).
He loves designing, painting, writing, traveling, and hacking; you can nd out more about him on his personal website at http://www.phodal.com.

我在翻译的时候美化了一下:

黄峰达(Phodal Huang)目前是ThoughtWorks公司的一名软件工程师。其是最小物联网系统(https://github.com/phodal/iot)项目的创建者,同时也是电子书《一步步设计物联网》(http://designiot.phodal.com)的作者。其喜欢设计、画画、写作、旅行以及Hacking,在其个人网站(http://www.phodal.com)可看到更详细的信息。

在最近出版的《Smart Internet of Things Projects》我是这样写自己的简介的——把四年改成了六年。

Phodal Huang has over six years' experience in hardware development & web development
...

于是就占用大家宝贵的阅读时间,来让我介绍一下这本书的简史。

英文版流水帐

2014年7月28日 20:22 (星期一) 收到Packt出版社的邮件,他们在GitHub上发现了我(PS:当时我的GitHub并没有今天的这么拿得出手——只有我的毕业设计IoT项目。只是当时在GitHub上搜索IoT的时候,他们都在首页):

I came across your profile on github and I believe you’ll be best fit to review our current project on Internet of Things.

并表示,他们正在出版《Learning Internet of Things》,问我有没有意愿审阅这本书。

We're currently developing a book on Internet of Things titled ‘Learning Internet of Things’ with a page count of approximately 186 pages.
...
Would you be interested in reviewing this book?

于是,我回了这个邮件。说明了情况:当时我刚毕业,并表示我的英语不好。

Recently, I join the ThoughtWorks as a developer. I'm a Chinese and not very good at English except reading, so I practice lots of these days. As you known,I have some experience on IOT. If you think is OK,I would to do.

然后,然后我们就继续了。

2014年8月8日(星期五) 上午8:51 我收到这本书的第一章和第二章,并开始审阅这本书。

。。。 中间,我就不断地审阅不同的章节

2014年11月27日(星期四) 下午4:04 (UTC+05:00 伊斯兰堡、塔什干时间) 我收到最后一章的内容。

2015年1月28日(星期三) 下午3:37 (UTC+05:00 伊斯兰堡、塔什干时间) 这本书的电子版发布。

2015年2月10日(星期二) 中午1:15 这本书的纸质版发布。

中文版流水账

2015年2月9日 01:51 (星期一) 收到机械工业出版社的邮件:

我们计划引进Packt Publishing的《Learning Internet of Things》这本书,通过试读样张中得知你是这本书的技术审阅者。。。

2015年7月22日 14:32 (星期三) 这本书翻译完~~。

2016年9月19日 这本书的出版日期。

《物联网实战指南》与《自己动手设计物联网》

这里面又有好多的故事,不过正是因为《Learning Internet of Things》一书让我有了写书的想法——不过,最开始的时候是电子书。即是我GitHub上的《一步步搭建物联网系统》,已更名为《教你设计物联网系统》的项目。最开始的时候,是图灵教育出版社的编辑先联系我的,时间线上是 2014年11月21日 17:09 (星期五) 。

因为我刚毕业所以没这么大的能耐去写这样的书,就先拒绝了,继续以电子书的形式存在。

直到我翻译完《Learning Internet of Things》,电子工业出版社的编辑开始联系我写书,我便开始写《自己动手设计物联网》。

期间我还顺手审阅了 Manning 出版社的一本 IoT 相关的书的目录——因为我觉得目录不好,估计也有同样的审阅者也是这么觉得的。后来,这本书就没有机会出版了。

欢迎购买这两本书,并在各大网店上给个好评哈。

我们将在未来的两周末,赠送出几本的《物联网实战指南》和《自己动手设计物联网》

试一下功能

诗与美
Nature and laws lay hid in light; God said “Let Newton be” and all was light.这句赞美牛顿的()被译为:道法自然,旧藏玄冥。天生牛顿,万物生明。

读至此处,甚是惊艳,翻译之尊,信达雅三字可谓做到淋漓尽致,其中意味,颇有感慨。
私下试过使用有道词典进行翻译,其功能只不过是死板机械地生搬硬套罢了,直译出来的句子,毫无美感可言,再尝试更多古句译英,同样是毫无生气的字符相连。
美的存在是人类最引以为傲的一点,它不单单是视觉上的享受,更是从灵魂角度的契合。让人如沐春风,滋养在和煦春日暖阳的大草原里,恣意翻滚,不觉无趣。
机器在此方面终归是有所欠缺的,0和1组成的世界,或许是无法容忍下美好的错误的,没有了错误便很难发现美,多少令人赞叹的美,都是在一个个错误中被人记住,流芳千古。

我的前端之路:从切图到放弃

之前在那篇《我的编程之路》里,我讲述过我的编程之路。今天我们就来说说我的前端之路,相信以后还会有一篇《我的全栈之路》。

记得在一直有三个主要的发展方向:编程、写作、设计。依据这三个方向来说,前端就是编程和写作的结合体。

入门

故事要从大一说起:当时在入学前,我和楚非经常在“福(fu)建老乡群”讨论技术,于是到了大学就勾搭在一起了。他是学美术的,我是学电焊(电子信息工程)的。在后来的大学期间里我们常常搭档拉一些私活、做一些网站。

在我们有了远大的理想之后,我们就开始分前后端——就是谁做前端,谁做后端。这个问题的答案:难道不应该是学美术的用PS做前端,学电信的C写语言的做后端吗?反正答案大家都知道了:不是。在今天看来有两个原因:一、他是用Python的。二、我想学点设计。

于是,我就踏入前端这个坑,后来我就变成了萝卜。

keng.jpg

我一直都喜欢实战一个语言、框架、技术等等,所以在最初的时候我只能做出这样的页面——这是我的第一个网站的水平,求不取关

firstwebsite.png

并且很多写得比较好看的都不是我写的,就开始了长路漫漫的Cookbook学习了——这就是我为什么我对动物园(O'Reilly)的书好感比较深的原因了。

切图

大一暑假时,我就尝试向几家网络公司投了简历,第一个实习机会就是切图,当时这样的网络公司算是比较普遍的,不过我想今天大多数公司也是这样的:

cut

当时我只实习了半天就觉得混不下去了,主要是那个电脑太卡了——完全不适合用PS。那半天做的事情就是这样的:那家公司给了我个静态图片,让我把它切成一个个图层。类似于我们在写CSS + HTML的时候,划分DIV的感觉。

接着,很快地我就找到了第二家公司。这家公司要我做的事情:基于一张图片,做出一个静态页面。

不过,在今天我都是在做第二件事,除了这个网站不是这样的做的:

phodal-com.jpg

但是它真的不好看,求UX帮改进。

在那之后的很长一段时间里,我觉得前端就是HTML + CSS,外加JavaScript这个小三来操作HTML和CSS。当时我们面对客户的需求后,要做的第一件就是:找个jQuery插件。

后来,我就去学后端、还有“空手”焊电话:

phone.jpg

幸好,最后焊出来的这个电路是能用的。

前后端分离

某次在闲逛的时候,发现了一个基于jQuery Mobiel的单页面应用,发现原来Web也可以这样做。但是因为是基于jQuery就还觉得好奇了,到了后来都已经是实习的时候。当时项目上在用Backbone,今天已经是微服务 + React了。说是幸运也不好,不幸也好,经历过这么大的爆发。

APP和移动Web的出现改变了系统原先的MVC架构。

blog-with-fe-be.png

这时候出现了一些微妙的变化,于是我也经历了这些变化。

  • 逻辑代码不仅仅只在后台出现——同样的逻辑也会出现在前后端
  • 由于前端打交道的是API——人们不得不重新设计API,微服务开始流行
  • 信息安全变成了一个更重要的话题了
  • 混合应用带给了前端新的可能性
  • Node.js将前端人员引入了后端
  • 人们改进了JavaScript——ES6
  • 等等。。

越来越多的网站开始重构自己的系统,让自己的网站更轻量级,更快。当然,更有极端者走向了One JavaScript。

One JavaScript

如果说这个世界上有一个语言来解决绝大部分的技术问题,那么只有JavaScript。

因为只有JavaScript能在浏览器上运行,即使我们用了其他语言转换成JavaScript,那么它最终也是JavaScript。

在那篇《最流行的编程语言JavaScript能做什么?》,实际上就是我对JavaScript的一些尝试:

  • 数据可视化。我最喜欢的领域之一了,将难以读懂的数据,转换成美秒的图表。

  • 移动应用。无论是Growth还是我现在的项目,我都在尽可能去优化这种快捷地开发方式。

  • 服务端。我在我的物联网项目上,将Node.js用到其中,发现还是很不错的。

  • 桌面应用。Growth的桌面版就是这样的一个尝试,只是这个包太大了。

  • VR和AR。还记得之前提到过的火星漫游者吗?

  • 硬件。今天除了Tessel、还有Ruff可以做这样的事,未来还会有更多的硬件出现。

  • 物联网。既然前后端都统一了,那么它也将在物联网领域统一。

  • 全平台应用。

    依照现在的趋势,**未来人们只需要有一份代码,就可以运行在桌面、桌面Web、移动Web、移动应用上。**我想这个时间应该就在今年里就可以轻松做到了——已经有了,虽然还不怎么样。

但是这一切并没有让人太满意,技术并没有与业务有太好的隔离。

HTTP中GET与POST的区别

GET和POST是HTTP请求的两种基本方法,要说它们的区别,接触过WEB开发的人都能说出一二。

最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数。

你可能自己写过无数个GET和POST请求,或者已经看过很多权威网站总结出的他们的区别,你非常清楚知道什么时候该用什么。

当你在面试中被问到这个问题,你的内心充满了自信和喜悦。
你轻轻松松的给出了一个“标准答案”:

GET在浏览器回退时是无害的,而POST会再次提交请求。

GET产生的URL地址可以被Bookmark,而POST不可以。

GET请求会被浏览器主动cache,而POST不会,除非手动设置。

GET请求只能进行url编码,而POST支持多种编码方式。

GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。

GET请求在URL中传送的参数是有长度限制的,而POST么有。

对参数的数据类型,GET只接受ASCII字符,而POST没有限制。

GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。

GET参数通过URL传递,POST放在Request body中。
(本标准答案参考自w3schools)

“很遗憾,这不是我们要的回答!
请告诉我真相。。。

如果我告诉你GET和POST本质上没有区别你信吗?

让我们扒下GET和POST的外衣,坦诚相见吧!
GET和POST是什么?HTTP协议中的两种发送请求的方法。

HTTP是什么?HTTP是基于TCP/IP的关于数据如何在万维网中如何通信的协议。

HTTP的底层是TCP/IP。所以GET和POST的底层也是TCP/IP,也就是说,GET/POST都是TCP链接。GET和POST能做的事情是一样一样的。你要给GET加上request body,给POST带上url参数,技术上是完全行的通的。

那么,“标准答案”里的那些区别是怎么回事?
在我大万维网世界中,TCP就像汽车,我们用TCP来运输数据,它很可靠,从来不会发生丢件少件的现象。但是如果路上跑的全是看起来一模一样的汽车,那这个世界看起来是一团混乱,送急件的汽车可能被前面满载货物的汽车拦堵在路上,整个交通系统一定会瘫痪。为了避免这种情况发生,交通规则HTTP诞生了。HTTP给汽车运输设定了好几个服务类别,有GET, POST, PUT, DELETE等等,HTTP规定,当执行GET请求的时候,要给汽车贴上GET的标签(设置method为GET),而且要求把传送的数据放在车顶上(url中)以方便记录。如果是POST请求,就要在车上贴上POST的标签,并把货物放在车厢里。当然,你也可以在GET的时候往车厢内偷偷藏点货物,但是这是很不光彩;也可以在POST的时候在车顶上也放一些数据,让人觉得傻乎乎的。HTTP只是个行为准则,而TCP才是GET和POST怎么实现的基本。

但是,我们只看到HTTP对GET和POST参数的传送渠道(url还是requrest body)提出了要求。“标准答案”里关于参数大小的限制又是从哪来的呢?
在我大万维网世界中,还有另一个重要的角色:运输公司。不同的浏览器(发起http请求)和服务器(接受http请求)就是不同的运输公司。 虽然理论上,你可以在车顶上无限的堆货物(url中无限加参数)。但是运输公司可不傻,装货和卸货也是有很大成本的,他们会限制单次运输量来控制风险,数据量太大对浏览器和服务器都是很大负担。业界不成文的规定是,(大多数)浏览器通常都会限制url长度在2K个字节,而(大多数)服务器最多处理64K大小的url。超过的部分,恕不处理。如果你用GET服务,在request body偷偷藏了数据,不同服务器的处理方式也是不同的,有些服务器会帮你卸货,读出数据,有些服务器直接忽略,所以,虽然GET可以带request body,也不能保证一定能被接收到哦。

好了,现在你知道,GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。

你以为本文就这么结束了?

我们的大BOSS还等着出场呢。。。

这位BOSS有多神秘?当你试图在网上找“GET和POST的区别”的时候,那些你会看到的搜索结果里,从没有提到他。他究竟是什么呢。。。

GET和POST还有一个重大区别,简单的说:
GET产生一个TCP数据包;POST产生两个TCP数据包。

长的说:
对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);
而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

也就是说,GET只需要汽车跑一趟就把货送到了,而POST得跑两趟,第一趟,先去和服务器打个招呼“嗨,我等下要送一批货来,你们打开门迎接我”,然后再回头把货送过去。

因为POST需要两步,时间上消耗的要多一点,看起来GET比POST更有效。因此Yahoo团队有推荐用GET替换POST来优化网站性能。但这是一个坑!跳入需谨慎。为什么?

  1. GET与POST都有自己的语义,不能随便混用。
  2. 据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的TCP在验证数据包完整性上,有非常大的优点。
  3. 并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次。

现在,当面试官再问你“GET与POST的区别”的时候,你的内心是不是这样的?

(本文原创,转载请注明转自微信公众号WebTechGarden)
(如文中有纰漏,请不吝更正)

一次超帅的代码生成设计

需求

昨天,我看到这个Badge的时候,我就在想我也会创建一个自己的Badge。

Badge

然后,我就可以这样到处粘贴:

Phodal Works

看样子,我做的效果还是没有上面的好看,不过有些地方更炫。

需求分析

为了达到任意缩放的目的,我们就需要使用适量图片,即SVG。最开始的时候我从没想过用代码来生成,因为使用一些图形工具来创建是最简单的事情了。

原型设计

找了个工具先做了一个Demo:

Phodal Works

想了想居然还有三个要做……。

接着看了看SVG的代码,然后我惊呆了:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="1006px" height="150px" viewBox="0 0 1006 150" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <!-- Generator: Sketch 3.7 (28169) - http://www.bohemiancoding.com/sketch -->
    <title>phodal</title>
    <desc>Created with Sketch.</desc>
    <defs></defs>
    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <rect id="Rectangle-1" fill="#5E6772" style="mix-blend-mode: hue;" x="0" y="0" width="640" height="150"></rect>
        <rect id="Rectangle-1" fill="#2196F3" style="mix-blend-mode: hue;" x="640" y="0" width="366" height="150"></rect>
        <text id="PHODAL" font-family="Helvetica" font-size="120" font-weight="normal" fill="#FFFFFF">
            <tspan x="83" y="119">PHODAL</tspan>
        </text>
        <text id="idea" font-family="Helvetica" font-size="120" font-weight="normal" fill="#FFFFFF">
            <tspan x="704" y="122">idea</tspan>
        </text>
    </g>
</svg>

就这么简单的代码,为什么不自己写呢!!

Coding

SVG就是一个XML

可缩放矢量图形(Scalable Vector Graphics,SVG) ,是一种用来描述二维矢量图形的XML 标记语言。

要对这个XML进行修改也是一件很容易的事。只是,先找了PIL发现不支持,就找到了一个名为SVGWrite的工具。

A Python library to create SVG drawings.

示例代码如下:

import svgwrite

dwg = svgwrite.Drawing('test.svg', profile='tiny')
dwg.add(dwg.line((0, 0), (10, 0), stroke=svgwrite.rgb(10, 10, 16, '%')))
dwg.add(dwg.text('Test', insert=(0, 0.2)))
dwg.save()

然后我就照猫画虎地写了一个:

import svgwrite

dwg = svgwrite.Drawing('idea.svg', profile='full', size=(u'1006', u'150'))

shapes = dwg.add(dwg.g(id='shapes', fill='none'))
shapes.add(dwg.rect((0, 0), (640, 150), fill='#5E6772'))
shapes.add(dwg.rect((640, 0), (366, 150), fill='#2196F3'))
shapes.add(dwg.text('PHODAL', insert=(83, 119), fill='#FFFFFF',font_size=120, font_family='Helvetica'))
shapes.add(dwg.text('idea', insert=(704, 122), fill='#FFFFFF', font_size=120, font_family='Helvetica'))

dwg.save()

发现和上面的样式几乎是一样的,就顺手做了剩下的几个。然后想了想,我这样做都一样,一点都不好看。

我发现这样做起来太单调了,我就想加一点点趣味,比如: Idea风格应该是带蓝图的:

Phodal Idea

代码风格应该要是这样的:

Phodal Works

不断地变更需求之后,我就展开和SVG的大作战了。

示例代码

为了写上面的Idea的蓝图,我要画两种不同的矩形,他们有不同的粗细:

   def draw_for_bg_plus():
        for x in range(y_text_split + rect_length, width, rect_length):
            shapes.add(dwg.line((x, 0), (x, height), stroke='#EEEEEE', stroke_opacity=0.3))

        for y in range(rect_length, height, rect_length):
            shapes.add(dwg.line((y_text_split, y), (width, y), stroke='#EEEEEE', stroke_opacity=0.3))

        for x in range(y_text_split + max_rect_length, width, max_rect_length):
            for y in range(0, height, max_rect_length):
                shapes.add(dwg.line((x, y - 4), (x, y + 4), stroke='#EEEEEE', stroke_width='2', stroke_opacity=0.4))

        for y in range(0, height, max_rect_length):
            for x in range(y_text_split + max_rect_length, width, max_rect_length):
                shapes.add(dwg.line((x - 4, y), (x + 4, y), stroke='#EEEEEE', stroke_width='2', stroke_opacity=0.4))

生成对应的XML

        <line stroke="#EEEEEE" stroke-opacity="0.3" x1="529" x2="868" y1="60" y2="60"/>
        <line stroke="#EEEEEE" stroke-opacity="0.3" x1="529" x2="868" y1="70" y2="70"/>
        <line stroke="#EEEEEE" stroke-opacity="0.3" x1="529" x2="868" y1="80" y2="80"/>
        <line stroke="#EEEEEE" stroke-opacity="0.3" x1="529" x2="868" y1="90" y2="90"/>
        <line stroke="#EEEEEE" stroke-opacity="0.3" x1="529" x2="868" y1="100" y2="100"/>
        <line stroke="#EEEEEE" stroke-opacity="0.3" x1="529" x2="868" y1="110" y2="110"/>
        <line stroke="#EEEEEE" stroke-opacity="0.3" x1="529" x2="868" y1="120" y2="120"/>
        <line stroke="#EEEEEE" stroke-opacity="0.3" x1="529" x2="868" y1="130" y2="130"/>
        <line stroke="#EEEEEE" stroke-opacity="0.3" x1="529" x2="868" y1="140" y2="140"/>

同理于works,也可以生成对应的10,然后对其进行旋转

    for x in range(0, 300, 10):
        text = get_some_random10(100)
        shapes.add(
            dwg.text(text, insert=(phodal_width + 1, x), fill='#27ae60', font_size=12,
                     font_family='Inconsolata for Powerline',
                     opacity=0.3, transform="rotate(15 1000, 0)"))

生成

<text fill="#27ae60" font-family="Inconsolata for Powerline" font-size="12" opacity="0.3"
              transform="rotate(15 1000, 0)" x="529" y="220">
            100100011000111111111111110111111010011110110011001111011000111111101110100110110111111100101010110
        </text>

ShowCase

最后结果如下:

  1. 点亮Idea蓝图风格:

Phodal Idea

  1. 代码风格的works:

Phodal Works

  1. 没有设计好的Design:

Phodal Design

  1. 写作风格的article:

Phodal Article

合成图

Phodal's Idea
Phodal's Article
Phodal's Works
Phodal's Design

代码

代码放在GitHub上: https://github.com/phodal/brand
在线地址:http://brand.phodal.com/

欢迎关注我的微信公众号

Phodal Wechat

微信小程序「官方示例代码」剖析【下】:运行机制

在上一篇《微信小程序「官方示例代码」浅析【上】》中,我们只是简单的罗列了一下代码,这一篇,让我们来玩点刺激的——就是看看IDE的代码,了解它是怎么运行的。

还好微信的开发团队在软件工程的实践还有待提高,我们才有机会可以深入了解他们的代码——真想建议他们看看Growth的第二部分,构建系统

解压应用

首先你需要有下面的工具啦

  • Mac电脑
  • 微信web开发者工具.app
  • WebStorm / 其他编程器 或 IDE,最好可以支持重命名

首先,我们需要右键微信web开发者工具.app,然后显示包的内容,在 Contents/Resources/app.nw下面的内容即是我们的代码,拷贝出来啦:

drwxr-xr-x@   7 fdhuang  staff   238B Sep 22 19:43 app
drwxr-xr-x@   4 fdhuang  staff   136B Sep 21 13:12 modified_modules
drwxr-xr-x@ 194 fdhuang  staff   6.4K Sep 21 13:12 node_modules
-rw-r--r--    1 fdhuang  staff   900B Sep 22 21:09 package.json

简单的说明一下:

  • app/ 目录下放置了app的代码
  • modified_modules/ 即一些修改后的模块
  • node_modules/ 地球人都知道
  • package.json 呵呵,你一定是知道的,配置了NW相关的内容

modified_modules目录下有两个子模块:

  • anyproxy,从名字就可以看起来这是一个代理模块
  • weinre,远程调试工具

IDE运行顺序

我们已经知道了这是一个NodeWebkit封装的Web应用了。

在package.json中的"main": "app/html/index.html",,即定义了这个APP的入口是这个index.html,而不是别的文件。

很顺利的我们看到了他们调用的文件了:

<script src="../dist/app.js"></script>

这里面有一个init方法,看来他就是NodeWebkit相关的入口了。用WebStorm的shift + f6 RENAME 这些变量好十几次,终于看到了下面的代码了:

var React = require("../dist/lib/react.js");
var reactDom = require("../dist/lib/react-dom.js");
var init = require("../dist/common/loadInit/init.js");
var controller = require("../dist/components/ContainController.js");
var proxy = require("../dist/common/proxy/startProxy.js");
var windowActions = require("../dist/actions/windowActions.js");
var webViewAction = require("../dist/actions/webviewActions.js");
var webViewStore = require("../dist/stroes/webviewStores.js");
var log = require("../dist/common/log/log.js");
var shortCut = require("../dist/common/shortCut/shortCut.js");
var isDev = global.appConfig.isDev;

这是一个React应用,还好我一年多以前学得不错。扫视了一下代码,终于看到了这一句:

reactDom.render(React.createElement(controller, null), document.querySelector("#container")

直接跳转到ContainController.js,跳转到render方法,找到了这个:

React.createElement(Main, {
    project: this.state.project,
    appQuit: this.appQuit,
    appMax: this.appMax,
    appMin: this.appMin
})

果然Main里面就是大入口了

React.createElement("div", {className: "main"},
    React.createElement(menuBar, {
        appQuit: this.props.appQuit,
        appMin: this.props.appMin,
        appMax: this.props.appMax,
        showSetting: this.showSetting,
        project: this.props.project
    }),
    React.createElement(toolbar, {project: this.props.project}),
    React.createElement("div", {
            className: "body"
        },
        React.createElement(sidebar, {
            project: this.props.project,
            optProject: this.optProject
        }),
        React.createElement(develop, {
            show: this.state.show,
            optDebugger: this.optDebugger,
            project: this.props.project
        }),
        React.createElement(edit, {
            show: this.state.show,
            project: this.props.project
        }),
        React.createElement(detail, {
            project: this.props.project,
            show: this.state.show
        })),
    React.createElement(toast, null),
    React.createElement(setting, {
        show: this.state.showSetting,
        showSetting: this.showSetting
    }),
    React.createElement(dialog, null),
    React.createElement(popup, null),
    React.createElement(about, null))
}

对应的就是下面这个界面了:

editor-face.jpg

  • edit 就是编辑器及其相关的事项
  • detail就是项目的配置

WeApp是如何运行的

慢慢的就探索到了打包,其运行时的过程。由于我并没有拿到内测资格,所以我只好边看边猜测一下。

在之前的文章中,我们提到了两点很有意思的东西:wxmlwxss,这两个文件会被分别转换,即wxml -> html,wxss -> css。对应的有几个不同的transform:

  • transWxmlToJs

  • transWxssToCss

  • transConfigToPf

  • transWxmlToHtml

  • transManager

    这里的PF指代的是PageFrame的意思,pageFrame有一个对应的模板文件:

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
    <link href="https://res.wx.qq.com/mpres/htmledition/images/favicon218877.ico" rel="Shortcut Icon">
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
    <script>
      var __webviewId__;
    </script>
    <!-- percodes -->
    <!--{{WAWebview}}-->
    <!--{{reportSDK}}-->
    <!--{{webviewSDK}}-->
    <!--{{exparser}}-->
    <!--{{components_js}}-->
    <!--{{virtual_dom}}-->
    <!--{{components_css}}-->
    <!--{{allWXML}}-->
    <!--{{eruda}}-->
    <!--{{style}}-->
    <!--{{currentstyle}}-->
    <!--{{generateFunc}}-->
    </head>
    <body>
    <div></div>
    </body>
    </html>

这种风格一看就是生成字符串Replace的,然后他们写了一个名为wcc以及一个名为wcsc的工具。

  • wcc用于转转wxml中的自定义tag为virtual_dom
  • wcsc,我观察到的现象是它为转换wxss为css

这样的话,我们就可以理解为微信小应用有点类似于 Virtual Dom + WebView,毕竟上面有个WAWebView文件 ,还有一个webviewSDK文件 。

当然无论是React + WebView,或者Vue + WebView都不重要,现在有了 WA + WebView了,哈哈。

WeApp采用的是如下图所示的提交方式,所以:

commit.jpg

你在本地写的WeApp都会被提交到微信服务器,然后打包,上传到服务器,交给CDN——毕竟为了分发。

上传的过程大致如下:

好了,瞎扯完了,睡觉准备写继续写新书了。

这【五篇】文章将带你深入了解「微信小程序」

「微信小程序」剖析(一):运行机制

本文从‘微信web开发者工具’ IDE 中的代码下手,对「微信小程序」如何与 IDE 之前进行交互做了详细的介绍。并介绍了 IDE 如何将 WXML 代码和 WXSS 转换为对应的 HTML 和 CSS ,以及如何打包的一些基本情况:日期命名的wx文件、1M 大小的文件限制、APP 上传地址。

「微信小程序」剖析(二):框架原理

文章对 MINA 框架进行中的 APP 与函数间的关系进行了分析。从 WX 标签到 Virtual DOM 生成的方法,以及程序如何调用这个方法来生成 Virtual Dom 。并由其中的 exparser 部分来推理出,小程序由 WebView 和 Native 两部分组成的机制。以及在开发时、运行时,两种不同的 JavaScript 文件机制。

「微信小程序」剖析(三):让小程序运行在Chrome浏览器上

文章展示了如何在普通的浏览器上运行「微信小程序」应用。并使用 Gulp 结合‘微信web开发者工具’中的vendor文件 wcc 和 wcsc 来构建自动化的转化 WXML 和 WXSS 为 HTML 和 CSS,从而搭建独立于开发者工具的开发环境。

「微信小程序」剖析(四):原生的实时DOM转Virtual DOM

本文介绍了‘微信web开发者工具’中所使用的 WCC 文件的一些技术原理。即它可以将 WXML 文件转化为基于 JSON 的 Virtual DOM。以及 Virtual DOM如何去解析这个 JSON 文件,并在这个过程中进行数据绑定和函数绑定。

「微信小程序」剖析(五):创建一个兼容「微信小程序」的Web框架

本文介绍了如何创建一个可以兼容「微信小程序」的Web框架。这个框架可以将简单的 HTML 转为 Virtual DOM,并在 JSON 时将数据填充进去。还介绍了简单的函数绑定等等。

如何创建一个兼容「微信小程序」的Web框架:WINV

在「微信小程序」带领Web走向封闭之前,让我们创造一个Neo的种子。如果有可能的话,那么有一天,它终将成为Neo。

maxresdefault.jpg

从微信小程序开始内测时,很多人(也包括我)都在考虑这样的问题:「微信小程序」正在让Web走向封闭。我的第一反应是:创建一个兼容「微信小程序」的Web框架——它即可以在微信上运行,也可以在Web上,还有作为一个混合应用运行。

在微信web开发者工具里,它封装了足够多的细节。我们只需要写一些我们不知道它们是如何真正工作的代码,流量都这样被截胡了。虽然,我们无法改变这个即将发生的事实,但是我们可以向那些愿意走向开放的人一个更好的解决方案。

因为「微信小程序」的框架是叫MINA,所以让我们称呼这个框架为WINV。

设计构思

基本的设计点有:

  • 兼容微信小程序的语法——它并没有多少复杂的语法。只是简单的Virtual DOM操作,以及事件绑定
  • 尽可能兼容大部分的微信API,兼容所有的微信API几乎是不可能的。
  • 提供一个Virtual DOM转换的混合应用插件。

在之前的文章里,我们提到了MINA框架的基本原理,也差不多就是组件:

  • WXML转JSON Virtual DOM组件
  • Virtual DOM组件,并在这其中提供双向绑定
  • UI组件转换器,即将WXML转换为Web浏览器中的标签
  • UI组件,需要有一套UI组件,最好是和小程序保持一致,如WEUI
  • AMD组件,提供模块化需求
  • APP引擎,需要有Page模块和APP模块,来处理页面逻辑,还有Route。

一个WINV框架的Demo

计划了好几天的Demo,终于写完了,并且可以出来溜溜了~~。

这份代码在GitHub上,欢迎试玩:https://github.com/phodal/winv

并创建一个更好的出来,毕竟国庆要和我们家 ‘花仲巴’出去玩。

好了,看我们的代码,这还只是一个丑陋的原型,但是差不多可以解释了。

var App = winv.App;
var Page = winv.Page;

App({
    onLaunch: function() {
        console.log('On Launch');
    }
});
Page({
    data: {
        motto: 'hello, world'
    },
    onLoad: function() {
        console.log('On Load');
    }
});

winv.setTemplate('<view class="container"><text class="user-motto">{{motto}}</text></view>')
winv.appRun();

它在页面上的运行结果就是,输出一个 hello, world。顺便吐槽一句,微信小程序自带的hello world不是标准的hello world。Wiki上说:

但是需要注意的是,Hello World的标准程序是“hello, world”,没有感叹号,全部小写,逗号后面有空格,与现在流行的写法并不一致。

出于原型的原因考虑,没有像MINA一样,使用大量的事件来触发,只是简单的Run:

var domJson = this.stringToDomJSON(this.template)[0];
var dom = this.jsonToDom(domJson);
document.getElementById('app').appendChild(dom);
for (var event in window.eventPool) {
  window.eventPool[event]();
}

第一步,将上面的Template转化为JSON格式的Template,由DOMParser将其转换为DOM,并在这个时候添加一个Page标签。然后在转换的时候,顺便做一些更新的数据操作。
第二步,这个JSON DOM在转换成真实的DOM的时候,应该要添加事件绑定,只是还没有实现。
第三步,上面的DOM会被放到app ID里,结果就变成了

<winv-div class="page">
    <winv-div class="page__hd">
        <winv-view class="container">
            <winv-text class="user-motto">hello, world</winv-text>
        </winv-view>
    </winv-div> 
</winv-div>

一看就知道还有好多坑要填。

第四步,则是调用上面的on方法,写得比较简单、粗暴。

至于,对事件和数据的判断还是和MINA一致:

if('on' === option.slice(0, 2))

简单,而又粗暴。

那么问题来了,有一天小程序真的封闭了,你会考虑来开始一个兼容的Web框架吗?

如何解构单体前端应用——前端应用的微服务式拆分

刷新页面?路由拆分?No,动态加载组件。

本文分为以下四部分:

  • 前端微服务化**介绍
  • 微前端的设计理念
  • 实战微前端架构设计
  • 基于 Mooa 进行前端微服务化

前端微服化

对于前端微服化来说,有这么一些方案:

  • Web Component 显然可以一个很优秀的基础架构。然而,我们并不可能去大量地复写已有的应用。
  • iFrame。你是说真的吗?
  • 另外一个微前端框架 Single-SPA,显然是一个更好的方式。然而,它并非 Production Ready。
  • 通过路由来切分应用,而这个跳转会影响用户体验。
  • 等等。

因此,当我们考虑前端微服务化的时候,我们希望:

  • 独立部署
  • 独立开发
  • 技术无关
  • 不影响用户体验

独立开发

在过去的几星期里,我花费了大量的时间在学习 Single-SPA 的代码。但是,我发现它在开发和部署上真的太麻烦了,完全达不到独立部署地标准。按 Single-SPA 的设计,我需要在入口文件中声名我的应用,然后才能去构建:

declareChildApplication('inferno', () => import('src/inferno/inferno.app.js'), pathPrefix('/inferno'));

同时,在我的应用里,我还需要去指定我的生命周期。这就意味着,当我开发了一个新的应用时,必须更新两份代码:主工程和应用。这时我们还极可能在同一个源码里工作。

当出现多个团队的时候,在同一份源码里工作,显然变得相当的不可靠——比如说,对方团队使用的是 Tab,而我们使用的是 2 个空格,隔壁的老王用的是 4 个空格。

独立部署

一个单体的前端应用最大的问题是,构建出来的 js、css 文件相当的巨大。而微前端则意味着,这个文件被独立地拆分成多个文件,它们便可以独立去部署应用。

我们真的需要技术无关吗?

等等,我们是否真的需要技术无关?如果我们不需要技术无关的话,微前端问题就很容易解决了。

事实上,对于大部分的公司和团队来说,技术无关只是一个无关痛痒的话术。当一家公司的几个创始人使用了 Java,那么极有可能在未来的选型上继续使用 Java。除非,一些额外的服务来使用 Python 来实现人工智能。因此,在大部分的情况下,仍然是技术栈唯一。

对于前端项目来说,更是如此:一个部门里基本上只会选用一个框架。

于是,我们选择了 Angular。

不影响用户体验

使用路由跳转来进行前端微服务化,是一种很简单、高效的切分方式。然而,路由跳转地过程中,会有一个白屏的过程。在这个过程中,跳转前的应用和将要跳转的应用,都失去了对页面的控制权。如果这个应用出了问题,那么用户就会一脸懵逼。

理想的情况下,它应该可以被控制。

微前端的设计理念

设计理念一:中心化路由

互联网本质是去中心化的吗?不,DNS 决定了它不是。TAB,决定了它不是。

微服务从本质上来说,它应该是去中心化的。但是,它又不能是完全的去中心化。对于一个微服务来说,它需要一个服务注册中心

服务提供方要注册通告服务地址,服务的调用方要能发现目标服务。

对于一个前端应用来说,这个东西就是路由。

从页面上来说,只有我们在网页上添加一个菜单链接,用户才能知道某个页面是可以使用的。

而从代码上来说,那就是我们需要有一个地方来管理我们的应用:**发现存在哪些应用,哪个应用使用哪个路由。

管理好我们的路由,实际上就是管理好我们的应用

设计理念二:标识化应用

在设计一个微前端框架的时候,为每个项目取一个名字的问题纠结了我很久——怎么去规范化这个东西。直到,我再一次想到了康威定律:

系统设计(产品结构等同组织形式,每个设计系统的组织,其产生的设计等同于组织之间的沟通结构。

换句人话说,就是同一个组织下,不可能有两个项目的名称是一样的。

所以,这个问题很简单就解决了。

设计理念三:生命周期

Single-SPA 设计了一个基本的生命周期(虽然它没有统一管理),它包含了五种状态:

  • load,决定加载哪个应用,并绑定生命周期
  • bootstrap,获取静态资源
  • mount,安装应用,如创建 DOM 节点
  • unload,删除应用的生命周期
  • unmount,卸载应用,如删除 DOM 节点

于是,我在设计上基本上沿用了这个生命周期。显然,诸如 load 之类对于我的设计是多余的。

设计理念四:独立部署与配置自动化

从某种意义上来说,整个每系统是围绕着应用配置进行的。如果应用的配置能自动化,那么整个系统就自动化。

当我们只开发一个新的组件,那么我们只需要更新我们的组件,并更新配置即可。而这个配置本身也应该是能自动生成的。

实战微前端架构设计

基于以上的前提,系统的工作流程如下所示:

系统工作流

整体的工程流程如下所示:

  1. 主工程在运行的时候,会去服务器获取最新的应用配置。
  2. 主工程在获取到配置后,将一一创建应用,并为应用绑定生命周期。
  3. 当主工程监测到路由变化的时候,将寻找是否有对应的路由匹配到应用。
  4. 当匹配对对应应用时,则加载相应的应用。

故而,其对应的架构如下图所示:

Architecture

独立部署与配置自动化

我们做的部署策略如下:我们的应用使用的配置文件叫 apps.json,由主工程去获取这个配置。每次部署的时候,我们只需要将 apps.json 指向最新的配置文件即可。配置的文件类如下所示:

  1. 96a7907e5488b6bb.json
  2. 6ff3bfaaa2cd39ea.json
  3. dcd074685c97ab9b.json

一个应用的配置如下所示:

{
  "name": "help",
  "selector": "help-root",
  "baseScriptUrl": "/assets/help",
  "styles": [
    "styles.bundle.css"
  ],
  "prefix": "help",
  "scripts": [
    "inline.bundle.js",
    "polyfills.bundle.js",
    "main.bundle.js"
  ]
}

这里的 selector 对应于应用所需要的 DOM 节点,prefix 则是用于 URL 路由上。这些都是自动从 index.html 文件和 package.json 中获取生成的。

应用间路由——事件

由于现在的应用变成了两部分:主工程和应用部分。就会出现一个问题:只有一个工程能捕获路由变化。当由主工程去改变应用的二级路由时,就无法有效地传达到子应用。在这时,只能通过事件的方式去通知子应用,子应用也需要监测是否是当前应用的路由。

if (event.detail.app.name === appName) {
  let urlPrefix = 'app'
  if (urlPrefix) {
    urlPrefix = `/${window.mooa.option.urlPrefix}/`
  }
  router.navigate([event.detail.url.replace(urlPrefix + appName, '')])
}

相似的,当我们需要从应用 A 跳转到应用 B 时,我们也需要这样的一个机制:

window.addEventListener('mooa.routing.navigate', function(event: CustomEvent) {
  const opts = event.detail
  if (opts) {
    navigateAppByName(opts)
  }
})

剩下的诸如 Loading 动画也是类似的。

使用 Mooa 进行

So,我们就有了前端微服务框架 Mooa。它基于 single-spa && single-spa-angular-cli,并且符合以上的设计**。

GayHub 地址:https://github.com/phodal/mooa

对于主工程而言,只需要以下的几行代码就可以完成上面的功能:

http.get<any[]>('/assets/apps.json')
  .subscribe(data => {
    data.map((config) => {
      that.mooa.registerApplication(config.name, config, mooaRouter.matchRoute(config.prefix));
    });
    this.mooa.start();
  });

this.router.events.subscribe((event: any) => {
  if (event instanceof NavigationEnd) {
    that.mooa.reRouter(event);
  }
});

并添加一个对应的子应用路由:

{
  path: 'app/:appName/:route',
  component: HomeComponent
}

则如上所述的四个步骤。

对于子工程而言,则只需要一个对应的 Hook 操作:

mooaPlatform.mount('help').then((opts) => {
  platformBrowserDynamic().bootstrapModule(AppModule).then((module) => {
    opts['attachUnmount'](module);
  });
});

并设置好对应的 base_href:

providers: [
  {provide: APP_BASE_HREF, useValue: mooaPlatform.appBase()},
]

嗯,就是这么简单。DEMO 视频如下:

Demo 地址见:http://mooa.phodal.com/

GitHub 示例:https://github.com/phodal/mooa

我写的那六本开源计算机书

教你设计物联网系统

这是由我的毕业设计延伸出来的一本电子书、APP。

设计物联网系统是件有意思的事情,它需要考虑到软件、硬件、通讯等多个不同方面。通过探索不同的语言,不同的框架,从而形成不同的解决方案。

在这里,我们将对设计物联网系统有一个简单的介绍,并探讨如何设计一个最小的物联网系统。

目标读者:初入物联网领域,希望对物联网系统有一个大概的认识和把握,并学会掌握一个基础的物联网系统的设计。

GitHub: https://github.com/phodal/designiot
在线阅读: http://ebook.designiot.cn/

RePractise

原本这本电子书打算放在那本Growth之前,但是这本书的写作难度还是有点大,就暂时搁置了。

无论怎样的Coding,都是不断的Practise。想要有所成果,你需要RePractise——总结和diff change,再Practise。

对于工程而言,一个技术都是不断练习出来的。

不同的人对于练习会有不同的方法,有的练习是没有必要的,它并不会增长我们的技术点;有的练习则会将一万小时缩短为一半,或者更短。

目标读者:有一定的Web开发经验的开发者,并是没有一个好的方向。

GitHub: https://github.com/phodal/repractise
在线阅读: http://repractise.phodal.com/

GitHub 漫游指南

2015.3.9号,想着写个《GitHub漫游指南》,于是在最开始的地方写着:

我的GitHub主页上写着加入的时间——Joined on Nov 8, 2010,那时才大一,在那之后的那长日子里我都没有过到。也许是因为我学的不是计算机,到了今天——2015.3.9,我也发现这其实是程序员的社交网站。

但是过了很久都没有动静,今天是2015.10.24,我想是时候完成这个目标了。

目标读者:对GitHub探索有兴趣的读者。

GitHub: https://github.com/phodal/github-roam
在线阅读: http://github.phodal.com/

Ideabook: 一个全栈增长工程师的练手项目集

做为一个程序员哪能没有Idea呢,有了Idea就要做出来。

你是不是在为提高编程技术而发愁?

你是不是在为找不到合适的练手项目而烦恼?

你是不是在为有合适的项目,但是没有指南而烦恼?

拥有Ideabook,你就等于拥有一系列的练手项目。

我的Idea在不断地增长,有些Idea有Cool,而这些Idea都没有一个好的实战指南。这个电子书的目标就是为这些Idea提供实战指南,一步步搭建。

目标读者:有编程经验,但是苦于没有好的Idea的程序员

GitHub: https://github.com/phodal/ideabook
在线阅读: http://ideabook.phodal.com/

Growth: 全栈增长工程师指南

依据在《Repractise简介篇:Web开发的七天里》中所说的 Web 开发的七个步骤而展开的电子书。

这是一本指导性的书籍——不要指望从这本书中学到所有的知识点,但是他可以帮助你构建你的知识体系。

这也是其他技术书籍所欠缺的。它可以告诉你,你可以学习什么,然后看什么书。

对于有些人来说,成为全栈是因为:来自社会的各个不同的中小公司,只靠一个领域的知识难以生存 对于有些人来说,成为全栈是因为:这个世界有太多的乐趣,在一颗树上吊死太可惜了。 对于有些人来说,成为全栈是因为:他们想去创业。

而人们对于全栈有太多的误解——认为全栈应该什么都会,什么都精通。全栈只是因为我们对系统有整体性的认识,而不是精通整个系统。因为专家只精通某一个领域,总得有一个架构师来对系统把握。

目标读者:对于成为并超越全栈工程师有兴趣的有经验程序员

GitHub: https://github.com/phodal/growth-ebook
在线阅读: http://growth.phodal.com/

全栈增长工程师指南——Python语言实战

这本书是全栈增长工程师指南的Python(Django)实战版。

你将会学到:如何去开发一个Web应用(博客)、如何编写单元测试、如何编写功能测试,自动化UI测试、搭建持续集成、添加SEO支持、支持APP使用、开发相应的APP、添加单页面应用的前端、自动化部署、如何进行小步提交。

目标读者:对于成为并超越全栈工程师有兴趣的新手程序员

GitHub: https://github.com/phodal/growth-in-action-python
在线阅读: http://phodal.github.io/growth-in-action-python

我的GitHub PR故事,以及我向往的开源

最近在GitHub上发生了太多的事就不多说了,有好有坏。趁着Growth排在GitHub Trending上,我还是写一篇文章好了:

growth-trending.png

我向往的开源

我想我是一个理想主义者。在我工作一段时候后,我就开始在设想使用开源软件来度过未来的编程生涯。当然这样的公司已经有很多了,并且有很多是营利的。

os-tree.png

他们的营利方式有多种多样的,如:

  1. 多种产品线 。
  2. 技术服务型 。
  3. 附属品。
  4. Donate

这三个是我所想去探索的方向。第一个和第二个需要依赖于开源框架,在过去我试过做了这样的事。也差点有了一些收入,但是因为经验不够就没有去做这样的事。而第三个则是特别容易做的,对于我来说,就是将开源项目变成书籍。如之前的IoT项目变成了电子书,然后走到了出版流程里了。第四个是随着Growth的出现开始有了一些Donate。

说起来,我最大的感悟就是先提升影响力,后面做什么都容易了。

再回到标题里,我们再来说说和GitHub的那些故事。

我的那些PR

开源软件已经改变了这个世界的软件开发方式,软件从大教堂变成了集市。我们开发软件的时候越来越多的依赖于外部的开源软件库。因此,在实践的时候我们就会按照对方的README一步步往走。而如果README出错了,问题就很严重了。

在我刚工作的时候,我试图在写一个物联网的框架,使用到了一个名为node-coap的第三方库。这个库依赖于另外一个库,结果这个库的README出错了,然后我就来了一个PR。

first-pr-build-failur.png

虽然这是一个失败的PR,但是很快又有一个更新README了。。

first-pr.png

刚开始接触的时候,就觉得好有成就感。不久之后,我开始使用Google的Pagespeed来优化网站的性能。然后,我在编译的过程中出错了,但是错误提示我并没有找到这个文件。后来,我发现目录错了,于是我来了个PR,如:

google-pr.png

当然这次是最激动人心的,因为还要签署什么CLA——签署后才能merge代码。对于我这种没见过世面的毕业生来说,感觉好高端。

cla.png

后来发现很多大的公司都需要,如后来我尝试给Eclipse的PR,就是因为CLA不知何故签署失败就没有继续。

过了几天,又看到一个Repo,又来了个PR——这次是打广告去的~~~:

free-pb.png

接下来当然还有一些PR,不过大部分也是使用过程中出错才有的。现在因为README看少了,都只看测试用例了,PR也就少了。

说了那么多,大家看Growth的时候,多给点PR吧~~~。

第一次博客

不知道写些什么,感觉搭建博客就云里雾里的

最流行的编程语言JavaScript能做什么?

首先很遗憾的一点是,“PHP虽然是最好的语言”,但是它不是最流行的语言。

Sad

对不起的还有刚刚在4月TIOBE编程语言排行榜上榜的各个语言:

Tiobe四月

你们都很棒,但是你们都担当不了这个大任。

开始之前,我先说一下我常用的三个语言:Java、JavaScript、Python。

  • Java,让我学到了很多架构层级的知识,这一点可以参考我之前写的架构相关文档。虽然我一点儿也不喜欢这个语言,但是它真的很棒。
  • Python,它真的足够简单,以至于我喜欢拿它学习各种理论知识,如推荐系统、贝叶斯定理、自然语言处理等等。
  • JavaScript,看下文。

数据可视化

在过去我阅读的一些书籍里面,主要是以Processing作为可视化的语言——它起始于2001年,它最初是面向美术工作者和设计者创建的,后来变成了全面的设计和原型工具,可以用于创建复杂数据可视化领域。

Processing

Processing被带入了到Web领域产生了Processing.js,还出现了D3.js。

D3.js

当然还有Plotly、Leaflet、Sigma JS等等的工具。

移动端应用: Cordova

接着就是PhoneGap(今天的Cordova),将WebView带向了移动应用,也将JavaScript带向了移动应用。

Cordova

使用Cordova,可以让我们一次开发多平台发布。我们也顺便提一下Ionic,作为混合应用的翘楚:

Ionic

移动端应用: React Native

既然我们已经提到了Cordova,那么我们也应该说说React Native。也是一次开发多次运行:

React Native

虽然它的坑还有很多,但是还是值得期待的。

服务端:Node.js

正是V8的性能将JavaScript带到了一个新的高度,于是Node.js诞生了——前端、后台都可以用JavaScript,一个JavaScript的全栈时代。

Nodejs

Mongodb作为数据库,Express作为Server端MVC,他们可以提供一个RESTful服务,那么再加上MVVM框架的Angular.js,你就知道我在说什么!

mean.png

桌面应用: NW.js 和 Electron

NW.js 是基于 Chromium 和 Node.js 运行的, 它们可以让我们用HTML和JavaScript来制作桌面应用。除了NW.js还有最近比较火的Electron,Atom编辑器的

Electron

与Cordova的多平台构建多版本不同的是,Electron可以在一个平台上构建多个平台的应用。即我们可以在Mac OS上打包出Linux和Windows上的应用,而不需要在Windows再编译一次。

带向了桌面端,让桌面和Web保持了一致。最成功的案例就是估值达30亿美元的Slack:

Slack

So,如果你使用桌面端的Slack就会很卡~~。

全平台应用

还记得我写的那篇《一份代码构建移动、桌面、Web全平台应用》,在Eletcron上运行Ionic,就意味着无限的可能性。

一份代码构建移动、桌面、Web全平台应用

能用Web开发的事情就用Web来完成就好了。

游戏

自从WebGL被带入浏览器的那一刻,就决定了这又是一个新的天地。

HTML5 游戏

让我们忘记编译、启动更新、外挂等等的问题,并且我们还可以一次开发直接运行。

VR

如果你看到过之前的那篇《JavaScript在VR世界的应用》,那么你就会对这个内容有更多的印象。

主要**还是通过WebView来渲染VR视角:

Three.js Oculus

并且各浏览器产商各在推进WebVR 为虚拟现实设备显示提供支持。

AR

虽然大部分的AR应用可能离我们有点远,但是离我们最近的就是Leap Motion——它可以利用手掌和手指动作来进行输入,但无需手部接触或者触摸。

Leap Motion

同理于VR,读取传感器的数据,再将其手势交由浏览器端来处理。详细可以参考我之前写的:《Leap Motion JavaScript开发 手势控制基础篇

硬件

早先我看到了Arduino在编译的时候,以DSL的方式封装了API。而NodeMCU则内建了Lua语言的支持,可以让开始者使用Lua来开始。 而Tessel 原生就提供了JavaScript运行环境,我们写需要写好JavaScript就可以在上面运行。

Tessel 2

Tessel 2属于配置比较高的硬件,而低配的呢?

三星设计了JerryScript引擎,它能够运行在小于64KB内存上,且全部代码能够存储在不足200KB的只读存储(ROM)上。

IoT.js

想想就觉得未来是美好的。

物联网

等等,上面三星推出的是IoT.js,这就意味着它已经可以在物联网领域中应用了,为什么还会有这里的应用呢?我只是想稍微提一下这个:

IoT Node.js

上面说到的只是Node.js在Web中的应用,而物联网和Web的很大不同之处在于,物联网可以使用各种不同的协议,而这些协议都需要Node.js对其的支持。

因此,如果我们需要开始Web版、移动应用,那么我们自然更需要其作为后台。

操作系统界面

虽然更好的机器带来了更好的性能,但是显然人们对于原生应用的需求并没有那么强烈。Firefox OS已经在移动操作系统败下阵来,但是这个操作被带到了物联网领域:

Firefox OS

这就意味着,我们可以使用JavaScript来开发操作系统的界面了。

你觉得JavaScript还能做什么?

更多精彩内容欢迎关注我的微信公众号:Phodal
http://articles.phodal.com/qrcode.jpg

「微信小程序」剖析(二):框架原理 | 在浏览器上运行的猜想

本来想的是昨天晚上写这篇文章的,后来昨天在写一个Cordova上的iOS插件的时候各种不顺。对接的第三方SDK不给力,于是六点多回到家的时候,我就就开始娱乐了,哈哈哈~~

其实这篇文章应该算是一篇拾遗。

从map组件说起

在今天公布的开发文档里,我们知道使用一个地图组件的时候是这样子的:

<map longitude="23.099994" latitude="113.324520" markers="{{markers}}" covers="{{covers}}" style="width: 375px; height: 200px;"></map>

在之前的文件里,我们提到过这个文件是wxml文件,然后我们要用wxcc将其转换为virtual dom中的方法,如:

./wcc -d map.xml

它就会返回一个js的方法,如:

/*v0.7cc_20160919*/
var $gwxc
var $gaic={}
$gwx=function(path,global){
function _(a,b){b&&a.children.push(b);}
function _n(tag){$gwxc++;if($gwxc>=16000){throw 'enough, dom limit exceeded, you don\'t do stupid things, do you?'};return {tag:tag.substr(0,3)=='wx-'?tag:'wx-'+tag,attr:{},children:[]}}
function _s(scope,env,key){return typeof(scope[key])!='undefined'?scope[key]:env[key]}
...

插播一句:上面有一个count,很有意思$gwxc > 16000,这个就是dom数的count。超了就来个异常:enough, dom limit exceeded, you don't do stupid things, do you?,中文意思就是:你个愚蠢的人类,你是一个前端开发人员吗?

随后,在浏览器里调试一下:

JSON.stringify($gwx('map.wxml')('test'))

在小程序中是要这样调用的:

        document.dispatchEvent(new CustomEvent("generateFuncReady", {
            detail: {
                generateFunc: $gwx('map.wxml')
            }
        }))

就会返回下面的结果:

{
    "children": [
        {
            "attr": {
                "covers": "",
                "latitude": "113.324520",
                "longitude": "23.099994",
                "markers": "",
                "style": "width: 375px; height: 200px;"
            },
            "children": [],
            "tag": "wx-map"
        }
    ],
    "tag": "wx-page"
}

看来这个名为wx-map的标签就是微信下的map标签,它是wx-page的children。然后让我们在WAWebview中搜索一下,就会发现一个很有意思的代码:

{
    is: "wx-map",
    behaviors: ["wx-base", "wx-native"],
    template: '<div id="map" style="width: 100%; height: 100%;"></div>',
    properties: {
        latitude: {type: Number, reflectToAttribute: !0, observer: "latitudeChanged", value: 39.92},
        longitude: {type: Number, reflectToAttribute: !0, observer: "longitudeChanged", value: 116.46},
        scale: {type: Number, reflectToAttribute: !0, observer: "scaleChanged", scale: 16},
        markers: {type: Array, value: [], reflectToAttribute: !1, observer: "markersChanged"},
        covers: {type: Array, value: [], reflectToAttribute: !1, observer: "coversChanged"},
        _mapId: {type: Number}
  }

它的behaviors中有一句:wx-native,这莫非就是传说中的native组件:

WechatIMG1.jpeg

顺便再看一个video是不是也是一样的:

{
    is: "wx-video",
    behaviors: ["wx-base", "wx-player", "wx-native"],
    template: '<div class="container">\n    <video id="player" webkit-playsinline style="display: none;"></video>\n    <div id="default" class="bar" style="display: none;">\n      <div id="button" class$="button {{_buttonType}}"></div>\n      <div class="time currenttime" parse-text-content>{{_currentTime}}</div>\n      <div id="progress" class="progress">\n        <div id="ball" class="ball" style$="left: {{_progressLeft}}px;">\n          <div class="inner"></div>\n        </div>\n        <div class="inner" style$="width: {{_progressLength}}px;"></div>\n      </div>\n      <div class="time duration" parse-text-content>{{_duration}}</div>\n      <div id="fullscreen" class="fullscreen"></div>\n    </div>\n  </div>\n  <div id="fakebutton"></div>',
    properties: {
        _videoId: {type: Number},
        _progressLeft: {type: Number, value: -22},
        _progressLength: {type: Number, value: 0}
}

好了,你那么聪明,我就这么说一半好了,剩下你自己去猜。

可以肯定的是:

  • map标签在开发的时候会变成HTML + CSS
  • map标签在微信上可以使用类似于Cordova的形式调用 Native组件

再接着说,virtual dom的事,回到示例代码里的map.js:

Page({
  data: {
    markers: [{
      latitude: 23.099994,
      longitude: 113.324520,
      name: 'T.I.T 创意园',
      desc: '我现在的位置'
    }],
    covers: [{
      latitude: 23.099794,
      longitude: 113.324520,
      icaonPath: '../images/car.png',
      rotate: 10
    }, {
      latitude: 23.099298,
      longitude: 113.324129,
      iconPath: '../images/car.png',
      rotate: 90
    }]
  }
})

js里只放置了data,剩下的都是依据上面的值变动的observer,如:

  • _updatePosition
  • _hiddenChanged
  • latitudeChanged
  • longitudeChanged
  • scaleChanged
  • coversChanged
  • ...

这种代码的感觉比React更进了一步的节奏,本来你还需要编码来观察state,现在只需要state变动了就可以了。。。23333....,你们这些程序员都会被fire的。

好了,这里差不多就这样了~~。

重新审视WXWebview.js

于是,我重新逛逛WXWebview.js,发现这个文件里面不只有component的内容,还有:

  • reportSDK
  • webviewSDK ??
  • virtual_dom
  • exparser
  • wx-components.js
  • wx-components.css

等等,你是不是已经猜到我在说什么了,上一篇中我们说到了PageFrame:

  <!-- percodes -->
  <!--{{WAWebview}}-->
  <!--{{reportSDK}}-->
  <!--{{webviewSDK}}-->
  <!--{{exparser}}-->
  <!--{{components_js}}-->
  <!--{{virtual_dom}}-->
  <!--{{components_css}}-->
  <!--{{allWXML}}-->
  <!--{{eruda}}-->
  <!--{{style}}-->
  <!--{{currentstyle}}-->
  <!--{{generateFunc}}-->

在之前的想法里,我觉得我必须要集齐上面的SDK,才能招唤中神龙。后来,我看到了这句:

isDev ? {
        "<!--{{reportSDK}}-->": "reporter-sdk.js",
        "<!--{{webviewSDK}}-->": "webview-sdk.js",
        "<!--{{virtual_dom}}-->": "virtual_dom.js",
        "<!--{{exparser}}-->": "exparser.js",
        "<!--{{components_js}}-->": "wx-components.js",
        "<!--{{components_css}}-->": "wx-components.css"
    } : {"<!--{{WAWebview}}-->": "WAWebview.js"}

如果不是开发环境就使用WAWebview.js,在开发环境中使用使用xxSDK,那么生产环境是怎么回事?如果是在开发环境会去下载最新的SDK,好像不对~~,哈哈。。

我猜这部分,我需要一个内测id,才能猜出这个答案。

有意思的是,IDE会对比version.json,然后去获取最新的,用于预览?

{
  "WAService.js": 2016092000,
  "WAWebview.js": 2016092000,
  "wcc": 2016092000,
  "wcsc": 2016092000
}

上面已经解释清楚了WAWebview的功能了,那么WAService.js呢——就是封装那些API的,如downloadFile

uploadFile: function (e) {
    u("uploadFile", e, {url: "", filePath: "", name: ""}) && (0, s.invokeMethod)("uploadFile", e)
}, downloadFile: function (e) {
    u("downloadFile", e, {url: ""}) && (0, s.invokeMethod)("downloadFile", e)
}

这一点上仍然相当有趣,在我们开发的时候仍然是WAWebview做了相当多的事,而它和WAService的打包是分离的。

那么,我们从理论上来说,只需要有WAWebview就可以Render页面了。

好了,那么问题来了,如何在浏览器上运行呢?

实施微前端的六种方式

微前端架构是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用

由此带来的变化是,这些前端应用可以独立运行独立开发独立部署。以及,它们应该可以在共享组件的同时进行并行开发——这些组件可以通过 NPM 或者 Git Tag、Git Submodule 来管理。

注意:这里的前端应用指的是前后端分离的单应用页面,在这基础才谈论微前端才有意义。

结合我最近半年在微前端方面的实践和研究来看,微前端架构一般可以由以下几种方式进行:

  1. 使用 HTTP 服务器的路由来重定向多个应用
  2. 在不同的框架之上设计通讯、加载机制,诸如 MooaSingle-SPA
  3. 通过组合多个独立应用、组件来构建一个单体应用
  4. iFrame。使用 iFrame 及自定义消息传递机制
  5. 使用纯 Web Components 构建应用
  6. 结合 Web Components 构建

不同的方式适用于不同的使用场景,当然也可以组合一起使用。那么,就让我们来一一了解一下,为以后的架构演进做一些技术铺垫。

基础铺垫:应用分发路由 -> 路由分发应用

在一个单体前端、单体后端应用中,有一个典型的特征,即路由是由框架来分发的,框架将路由指定到对应的组件或者内部服务中。微服务在这个过程中做的事情是,将调用由函数调用变成了远程调用,诸如远程 HTTP 调用。而微前端呢,也是类似的,它是将应用内的组件调用变成了更细粒度的应用间组件调用,即原先我们只是将路由分发到应用的组件执行,现在则需要根据路由来找到对应的应用,再由应用分发到对应的组件上。

后端:函数调用 -> 远程调用

在大多数的 CRUD 类型的 Web 应用中,也都存在一些极为相似的模式,即:首页 -> 列表 -> 详情:

  • 首页,用于面向用户展示特定的数据或页面。这些数据通常是有限个数的,并且是多种模型的。
  • 列表,即数据模型的聚合,其典型特点是某一类数据的集合,可以看到尽可能多的数据概要(如 Google 只返回 100 页),典型见 Google、淘宝、京东的搜索结果页。
  • 详情,展示一个数据的尽可能多的内容。

如下是一个 Spring 框架,用于返回首页的示例:

@RequestMapping(value="/")
public ModelAndView homePage(){
   return new ModelAndView("/WEB-INF/jsp/index.jsp");
}

对于某个详情页面来说,它可能是这样的:

@RequestMapping(value="/detail/{detailId}")
public ModelAndView detail(HttpServletRequest request, ModelMap model){
   ....
   return new ModelAndView("/WEB-INF/jsp/detail.jsp", "detail", detail);
}

那么,在微服务的情况下,它则会变成这样子:

@RequestMapping("/name")
public String name(){
    String name = restTemplate.getForObject("http://account/name", String.class);
    return Name" + name;
}

而后端在这个过程中,多了一个服务发现的服务,来管理不同微服务的关系。

前端:组件调用 -> 应用调用

在形式上来说,单体前端框架的路由和单体后端应用,并没有太大的区别:依据不同的路由,来返回不同页面的模板。

const appRoutes: Routes = [
  { path: 'index', component: IndexComponent },
  { path: 'detail/:id', component: DetailComponent },
];

而当我们将之微服务化后,则可能变成应用 A 的路由:

const appRoutes: Routes = [
  { path: 'index', component: IndexComponent },
];

外加之应用 B 的路由:

const appRoutes: Routes = [
  { path: 'detail/:id', component: DetailComponent },
];

而问题的关键就在于:怎么将路由分发到这些不同的应用中去。与此同时,还要负责管理不同的前端应用。

路由分发式微前端

路由分发式微前端,即通过路由将不同的业务分发到不同的、独立前端应用上。其通常可以通过 HTTP 服务器的反向代理来实现,又或者是应用框架自带的路由来解决。

就当前而言,通过路由分发式的微前端架构应该是采用最多、最易采用的 “微前端” 方案。但是这种方式看上去更像是多个前端应用的聚合,即我们只是将这些不同的前端应用拼凑到一起,使他们看起来像是一个完整的整体。但是它们并不是,每次用户从 A 应用到 B 应用的时候,往往需要刷新一下页面。

在几年前的一个项目里,我们当时正在进行遗留系统重写。我们制定了一个迁移计划:

  1. 首先,使用静态网站生成动态生成首页
  2. 其次,使用 React 计划栈重构详情页
  3. 最后,替换搜索结果页

整个系统并不是一次性迁移过去,而是一步步往下进行。因此在完成不同的步骤时,我们就需要上线这个功能,于是就需要使用 Nginx 来进行路由分发。

如下是一个基于路由分发的 Nginx 配置示例:

http {
  server {
    listen       80;
    server_name  www.phodal.com;
    location /api/ {
      proxy_pass http://http://172.31.25.15:8000/api;
    }
    location /web/admin {
      proxy_pass http://172.31.25.29/web/admin;
    }
    location /web/notifications {
      proxy_pass http://172.31.25.27/web/notifications;
    }
    location / {
      proxy_pass /;
    }
  }
}

在这个示例里,不同的页面的请求被分发到不同的服务器上。

随后,我们在别的项目上也使用了类似的方式,其主要原因是:跨团队的协作。当团队达到一定规模的时候,我们不得不面对这个问题。除此,还有 Angluar 跳崖式升级的问题。于是,在这种情况下,用户前台使用 Angular 重写,后台继续使用 Angular.js 等保持再有的技术栈。在不同的场景下,都有一些相似的技术决策。

因此在这种情况下,它适用于以下场景:

  • 不同技术栈之间差异比较大,难以兼容、迁移、改造
  • 项目不想花费大量的时间在这个系统的改造上
  • 现有的系统在未来将会被取代
  • 系统功能已经很完善,基本不会有新需求

而在满足上面场景的情况下,如果为了更好的用户体验,还可以采用 iframe 的方式来解决。

使用 iFrame 创建容器

iFrame 作为一个非常古老的,人人都觉得普通的技术,却一直很管用。

HTML 内联框架元素 <iframe> 表示嵌套的正在浏览的上下文,能有效地将另一个 HTML 页面嵌入到当前页面中。

iframe 可以创建一个全新的独立的宿主环境,这意味着我们的前端应用之间可以相互独立运行。采用 iframe 有几个重要的前提:

  • 网站不需要 SEO 支持
  • 拥有相应的应用管理机制

如果我们做的是一个应用平台,会在我们的系统中集成第三方系统,或者多个不同部门团队下的系统,显然这是一个不错的方案。一些典型的场景,如传统的 Desktop 应用迁移到 Web 应用:

Angular Tabs 示例

如果这一类应用过于复杂,那么它必然是要进行微服务化的拆分。因此,在采用 iframe 的时候,我们需要做这么两件事:

  • 设计管理应用机制
  • 设计应用通讯机制

加载机制。在什么情况下,我们会去加载、卸载这些应用;在这个过程中,采用怎样的动画过渡,让用户看起来更加自然。

通讯机制。直接在每个应用中创建 postMessage 事件并监听,并不是一个友好的事情。其本身对于应用的侵入性太强,因此通过 iframeEl.contentWindow 去获取 iFrame 元素的 Window 对象是一个更简化的做法。随后,就需要定义一套通讯规范:事件名采用什么格式、什么时候开始监听事件等等。

有兴趣的读者,可以看看笔者之前写的微前端框架:Mooa

不管怎样,iframe 对于我们今年的 KPI 怕是带不来一丝的好处,那么我们就去造个轮子吧。

自制框架兼容应用

不论是基于 Web Components 的 Angular,或者是 VirtualDOM 的 React 等,现有的前端框架都离不开基本的 HTML 元素 DOM。

那么,我们只需要:

  1. 在页面合适的地方引入或者创建 DOM
  2. 用户操作时,加载对应的应用(触发应用的启动),并能卸载应用。

第一个问题,创建 DOM 是一个容易解决的问题。而第二个问题,则一点儿不容易,特别是移除 DOM 和相应应用的监听。当我们拥有一个不同的技术栈时,我们就需要有针对性设计出一套这样的逻辑。

尽管 Single-SPA 已经拥有了大部分框架(如 React、Angular、Vue 等框架)的启动和卸载处理,但是它仍然不是适合于生产用途。当我基于 Single-SPA 为 Angular 框架设计一个微前端架构的应用时,我最后选择重写一个自己的框架,即 Mooa

虽然,这种方式的上手难度相对比较高,但是后期订制及可维护性比较方便。在不考虑每次加载应用带来的用户体验问题,其唯一存在的风险可能是:第三方库不兼容

但是,不论怎样,与 iFrame 相比,其在技术上更具有可吹牛逼性,更有看点。同样的,与 iframe 类似,我们仍然面对着一系列的不大不小的问题:

  • 需要设计一套管理应用的机制。
  • 对于流量大的 toC 应用来说,会在首次加载的时候,会多出大量的请求

而我们即又要拆分应用,又想 blabla……,我们还能怎么做?

组合式集成:将应用微件化

组合式集成,即通过软件工程的方式在构建前、构建时、构建后等步骤中,对应用进行一步的拆分,并重新组合。

从这种定义上来看,它可能算不上并不是一种微前端——它可以满足了微前端的三个要素,即:独立运行独立开发独立部署。但是,配合上前端框架的组件 Lazyload 功能——即在需要的时候,才加载对应的业务组件或应用,它看上去就是一个微前端应用。

与此同时,由于所有的依赖、Pollyfill 已经尽可能地在首次加载了,CSS 样式也不需要重复加载。

常见的方式有:

  • 独立构建组件和应用,生成 chunk 文件,构建后再归类生成的 chunk 文件。(这种方式更类似于微服务,但是成本更高)
  • 开发时独立开发组件或应用,集成时合并组件和应用,最后生成单体的应用。
  • 在运行时,加载应用的 Runtime,随后加载对应的应用代码和模板。

应用间的关系如下图所示(其忽略图中的 “前端微服务化”):

组合式集成对比

这种方式看上去相当的理想,即能满足多个团队并行开发,又能构建出适合的交付物。

但是,首先它有一个严重的限制:必须使用同一个框架。对于多数团队来说,这并不是问题。采用微服务的团队里,也不会因为微服务这一个前端,来使用不同的语言和技术来开发。当然了,如果要使用别的框架,也不是问题,我们只需要结合上一步中的自制框架兼容应用就可以满足我们的需求。

其次,采用这种方式还有一个限制,那就是:规范!****规范!****规范!。在采用这种方案时,我们需要:

  • 统一依赖。统一这些依赖的版本,引入新的依赖时都需要一一加入。
  • 规范应用的组件及路由。避免不同的应用之间,因为这些组件名称发生冲突。
  • 构建复杂。在有些方案里,我们需要修改构建系统,有些方案里则需要复杂的架构脚本。
  • 共享通用代码。这显然是一个要经常面对的问题。
  • 制定代码规范。

因此,这种方式看起来更像是一个软件工程问题。

现在,我们已经有了四种方案,每个方案都有自己的利弊。显然,结合起来会是一种更理想的做法。

考虑到现有及常用的技术的局限性问题,让我们再次将目光放得长远一些。

纯 Web Components 技术构建

在学习 Web Components 开发微前端架构的过程中,我尝试去写了我自己的 Web Components 框架:oan。在添加了一些基本的 Web 前端框架的功能之后,我发现这项技术特别适合于作为微前端的基石

Web Components 是一套不同的技术,允许您创建可重用的定制元素(它们的功能封装在您的代码之外)并且在您的 Web 应用中使用它们。

它主要由四项技术组件:

  • Custom elements,允许开发者创建自定义的元素,诸如 。
  • Shadow DOM,即影子 DOM,通常是将 Shadow DOM 附加到主文档 DOM 中,并可以控制其关联的功能。而这个 Shadow DOM 则是不能直接用其它主文档 DOM 来控制的。
  • HTML templates,即 <template><slot> 元素,用于编写不在页面中显示的标记模板。
  • HTML Imports,用于引入自定义组件。

每个组件由 link 标签引入:

<link rel="import" href="components/di-li.html">
<link rel="import" href="components/d-header.html">

随后,在各自的 HTML 文件里,创建相应的组件元素,编写相应的组件逻辑。一个典型的 Web Components 应用架构如下图所示:

Web Components 架构

可以看到这边方式与我们上面使用 iframe 的方式很相似,组件拥有自己独立的 ScriptsStyles,以及对应的用于单独部署组件的域名。然而它并没有想象中的那么美好,要直接使用 Web Components 来构建前端应用的难度有:

  • 重写现有的前端应用。是的,现在我们需要完成使用 Web Components 来完成整个系统的功能。
  • 上下游生态系统不完善。缺乏相应的一些第三方控件支持,这也是为什么 jQuery 相当流行的原因。
  • 系统架构复杂。当应用被拆分为一个又一个的组件时,组件间的通讯就成了一个特别大的麻烦。

Web Components 中的 ShadowDOM 更像是新一代的前端 DOM 容器。而遗憾的是并不是所有的浏览器,都可以完全支持 Web Components。

结合 Web Components 构建

Web Components 离现在的我们太远,可是结合 Web Components 来构建前端应用,则更是一种面向未来演进的架构。或者说在未来的时候,我们可以开始采用这种方式来构建我们的应用。好在,已经有框架在打造这种可能性。

就当前而言,有两种方式可以结合 Web Components 来构建微前端应用:

  • 使用 Web Components 构建独立于框架的组件,随后在对应的框架中引入这些组件
  • 在 Web Components 中引入现有的框架,类似于 iframe 的形式

前者是一种组件式的方式,或者则像是在迁移未来的 “遗留系统” 到未来的架构上。

在 Web Components 中集成现有框架

现有的 Web 框架已经有一些可以支持 Web Components 的形式,诸如 Angular 支持的 createCustomElement,就可以实现一个 Web Components 形式的组件:

platformBrowser()
	.bootstrapModuleFactory(MyPopupModuleNgFactory)
		.then(({injector}) => {
			const MyPopupElement = createCustomElement(MyPopup, {injector});
			customElements.define(‘my-popup’, MyPopupElement);
});

在未来,将有更多的框架可以使用类似这样的形式,集成到 Web Components 应用中。

集成在现有框架中的 Web Components

另外一种方式,则是类似于 Stencil 的形式,将组件直接构建成 Web Components 形式的组件,随后在对应的诸如,如 React 或者 Angular 中直接引用。

如下是一个在 React 中引用 Stencil 生成的 Web Components 的例子:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

import 'test-components/testcomponents';

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

在这种情况之下,我们就可以构建出独立于框架的组件。

同样的 Stencil 仍然也只是支持最近的一些浏览器,比如:Chrome、Safari、Firefox、Edge 和 IE11

复合型

复合型,对就是上面的几个类别中,随便挑几种组合到一起。

我就不废话了~~。

结论

那么,我们应该用哪种微前端方案呢?答案见下一篇《微前端快速选型指南》

相关资料:

为什么我们需要一个兼容「微信小程序」的Web框架

在这几天的代码探索里,我写了几篇文章:

  1. 「微信小程序」官方示例代码浅析
  2. 「微信小程序」剖析(一):运行机制
  3. 「微信小程序」剖析(二):框架原理

我的目的其实比较简单:

我们需要想一个办法,来让让微信小程序运行在普通浏览器。

对于产品经理、CEO等等的人来说,这并不重要,但是对于开发者来说这相当的重要。

从微信web开发者工具说起

微信web开发者工具带来了内置了完整的web开发工具集:

  • IDE
  • 构建系统
  • 自动化脚本
  • 。。。

我们所要做的事情就只是编写我们的代码,这个开发者工具就会帮我们照顾其他工作。想想就觉得很美好,但是最后我们发布出去的是一个wx包——微信wx包。尽管从上一篇文章里,我们可以猜测到它在开发时是WebView,运行时是WebView + Native。

而在这个wx包里压缩的则是我们编写的wxml + wxss + js,这也意味着我们在微信客户端上安装这个APP的时候,下载下来极有可能就是这个wx包,然后解压运行。当时如果它是纯WebView的话,那么它就可以在服务器上运行一些预编译的工作了。

这并不重要,重要的是我们写的web应用已经无法在Web上运行了。而这个工具称之为 web 开发者工具。

Cordova与ATM平台Web框架

以前,我们为iOS平台、Android平台写代码;
现在,我们为微信平台写代码;
以后,我们还会有支付宝等等的平台写代码。

这就变成一个很有趣的循环。

故事最开始的时候:

有了iOS平台,人们开始为自己的应用写Objective-C代码;
有了Android平台,人们开始自己的应用写Android代码;

有一天,人们开始受不了不同平台的问题,于是写了Cordova,现在我们只需要写一份代码即可。

现在就更有意思了,毕竟小程序这种东西,巨头们都是不会放过的。。。

有了微信小程序,人们开始用WXML + WXSS写微信web小程序。
有了支付宝小程序,人们开始有ALIML + ALISS写支付宝小程序。

有一天,人们又受不了不同平台的问题,于是写了Avodroc,现在我们仍只需要写一份代码即可。

乐观地一想,我们可以顺手用Cordova + Avodroc 做一个微信小程序的平台,在上面运行的程序就不会受到数量限制了。除去安装量的限制,我们就不会受各大应用商店的限制——当然我说的是Android平台。

为什么我偏爱用GitHub来写书?

为什么我偏爱用GitHub来写书?

GayHub作为一个全球著名的社交网站,它的用途可不仅仅只有约基那么简单。

github-social.png

今天,让我们来说说为什么我越来越喜欢用Git来写书——只是电子书,并且将它发布到GitHub上。

GitHub上的第一本书

我在GitHub上写的第一本书是《一步步搭建物联网系统》,它是我的毕业论文与博客的合集。

designiot.png

在这本电子书里,我和我的同学小兵一起协作来编写内容。在今天看来,这仍是一本不错的物联网指南。只是物联网这个领域一直都不温不火,并且在GitHub上比较流行的都是Web开发的项目。

随后只是因为这个项目,一个PACKT出版社的编辑在GitHub上找到了我,帮他们审阅《Learning Internet of Things》这本书——英文版的。

learning-iot.png

从这个过程中,我学到了两件事:

  • 协作写作是可能的
  • 在GitHub上写作意味着机会

接着,我就开始尝试去写一本物联网的书,并且我使用Git来管理。

使用Git管理内容

在开始之前,希望你对于Pandoc这个软件及LaTeX有一点点概念:

  • Pandoc是由John MacFarlane开发的标记语言转换工具,可实现不同标记语言间的格式转换,堪称该领域中的“瑞士军刀”。如我们可以将Markdown转化为Word,然后统计字数——这是我最常用的功能。

    latex.png

    LaTeX 是 Leslie Lamport 在 TeX 基础上按内容/格式分离和模块化等**建立的一集 TeX 上的格式。TeX是诞生于20世纪70年代末到80年代初的一款计算机排版软件,用来排版高质量的书籍论文,特别是包含有数学公式的文章书籍。

结合上面的两种工具,我们可以用Pandoc结合LaTex来将md文件转化成PDF格式,又或者用Pandoc结合kindlegen将其转化为Kindle能阅读的mobi格式。

(PS: 我的毕业论文的初稿就是拿Pandoc + LaTeX完成的。)

版本控制

关于使用Git来作为数据库已经不是一个新的概念了。在那篇《编辑-发布-开发分离》中我们还提到了,拿Git作为一个NoSQL数据库。它是一个很好的数据存储器,我们可以将其PUSH到我们所能创建的私有仓库里。并且这个过程中是持续递增的,你不再需要不断地复制你的文件了——以免丢失造成的影响。

但是这: 少了一个脱稿的理由了

Diff Change

Git让人最爽的莫过于可以Diff修改了。如果你遇到下面的一些情况:

  • 需要对比两个不同的JSON文件的字段差异
  • 查看一个文件的修改历史

请拥抱Git,并添加一次提交来完成这个工作。

如果我们的写作项目与不同的人一起完成的话,那么这可能会变成一场恶梦。在我之前的翻译项目里,我们使用Git来完成这个工作。通过Git,我们可以发现:谁做了一些修改,如添加内容、删除某些内容。并且我们都很熟悉Git的话,那么我们只会在一次提交里修改尽量少的文件,并提交代码。这样做会避免我们破坏其他人正在修改的文件。

GitHub上的第二本书

我在GitHub上写的第二本电子书是《GitHub漫游指南》,这本电子书完全没有任何写作计划——它就是一个博客全集(PS: 谁让我写过的博客多呢!)。

github-roam.png

而这本书里,我最大的感受是增量性添加——我可以不断地往这个Repo里添加内容,而不需要担心影响人们的阅读。这也是纸质书不能比拟的,当一本书出版后,只能等下一次修订。只是修订只是少数书的命运,而另外一个明显的感受是,我们只需要写一点内容就可以判断是不是用户想要的内容:

mvp.png

在早期做出一个最小化可行产品,然后投向市场,来观察用户的反馈。而在这本书里,很好的验证了我的想法是对的,因此就被添加到Growth中去了。

GitHub协作

使用GitHub来写书的最大理由就是协作。对于熟悉GitHub的用户来说,他们看到错误就很乐意帮你提一下,或者是帮你来一个Pull Request来帮你修复错误。这样做也可以增加自己的Contributions,同时也可以帮助到别人。

  • 持续部署。GitHub有一个很大的优势,即GitHub Page,使用GitHub Page可以让我们实现持续性部署。即我们只能一PUSH我们的修改,我们就可以将我们的最新版本呈现给用户。
  • 支持CNAME。这样我们就可以使用一个简单的域名就可以完成一个高逼格的整合。
  • 支持评论功能。如果你在某个修改里说了,JavaScript是这个世界最流行的语言,那么有人就会在评论里说了吧。

GitHub上的第三本书

在那本《一步步搭建物联网系统》有一个很大的问题是,内容并不是受到GitHub上的用户欢迎的,受众在网上也比较少——需要依赖于线下渠道。

而《GitHub漫游指南》有一个天生的不足是:在一开始的时候并没有好好策划,虽然主题很受欢迎。

因此Growth就结合了上述两者的优势,即在一开始的时候做了一个MVP,发现还不错。然后还好好地编写了内容。

github-ebook.png

单单只有努力看上去是不够的,还要有一点点小技巧。

最后一个偏爱的理由是:人们并不缺乏学习的意愿,只是不知道学习什么。

在GitHub上一个流行的库可以帮助你完成工作,但是仍然需要有有文章来帮助你成长,帮助你变得更好。

更多精彩内容欢迎关注我的微信公众号:Phodal
http://articles.phodal.com/qrcode.jpg

单页面应用后台渲染的三次实践

我已经想不到一个好的关于前端分享的主题了,于是联想到最近想要做的一件事,就想到了这个标题。或许这是一个好的主题,又或许这不是一个好的主题。但是至少我可以Share一下我的经验:

  • 基于Mustache模板引擎的前后台渲染。
  • 基于PreRender方式的Angular.js应用的后台渲染
  • 服务端渲染的React

开始之前,我希望即使你们需要后台渲染,你们也应该前后端分离!由后台来提供API数据,前端用自己的后台来渲染页面。听上去有点绕,简单的来说就是不要把大量的业务逻辑放前台来,只把显示逻辑放在前台上。这样一来,即使有一天我们换了新的前端,如移动应用,那么我们的后台也是可用的。。

为什么需要前后端分离?

这是一个很古老的话题,对于大公司来说就是部门大了,需要拆分。因此开始之前,先提一下“康威定律”:

Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations.

换成中文,即:设计系统的组织,其产生的设计和架构等价于组织间的沟通结构。上图

Conway

这张图可以解释相当多的软件开发过程中的问题,而我们知道软件开发的主要问题是沟通问题。组织结构影响了我们的沟通结构,进而影响了我们的软件系统结构。好吧,我承认可能离题有点远。不过,我想说的是组织结构可能不允许我们做出一些好的系统架构。

如我们在《RePractise前端篇: 前端演进史》中提到的那样:我们已经有了一个桌面版网页,然后我们打造了一个APP。然而,总有些客户想在手机上浏览但是又不想下APP,我们就需要一个移动版。为什么会这样?因为用户已经被养成了这样的习惯,大部分的网站提到了桌面版、移动版、APP。要维护这样的三个不同的系统,对于大部分的业务公司来说成本太高了。

于是,大部分公司来说解决方案就是 后台 + 大前端 (桌面前端、移动Web、手机APP)。Angular和React就是为了解决这样的问题,而出现了不同的解决方案——基于Angular.js的混合应用框架Ionic、以及React Native。不过在当前,我对React Native的共用UI还是持观望态度。有人可能会提到Vue和Weex,但是我觉得并没有那么好用。或许是因为我接触React比较早,我觉得Vue的语法四不像。

在这样的情形下,我们只需要几个后台开发人员和几个前端开发人员就可以完成系统的设计了。这种前端开发人员就是最近几年人们“最想要”的。

前后台渲染同一模板

我接触的第一个SPA应用是一个基于Spring MVC和Backbone的移动网站,但是它比一般的SPA应该要复杂——由于SEO的缘故,它需要支持后台渲染。

当搜索引擎通过URL访问我们的网站的时候,我们就需要返回相应的HTML。这意味着我们需要在后台有对应的模板引擎来支持,而由于SPA的性质又决定了,这需要使用一个纯前端的模板引擎。因此,我们并不能使用两个模板引擎来做这件事,维护两套模板注定会是一件痛苦的事,并且当时还没有React这种模板引擎在。不过,后来我们发现维护两种不同的渲染方式也是一件痛苦的事。因此,我们就会有了类似于下图的架构:

Spring MVC Backbone

我们在后台使用Spring MVC作为基础架构、Mustache作为模板引擎,和使用JSP作为模板引擎相比没有多大的区别——由Controller去获取对应的Model,再渲染给用户。多数时候搜索引擎都是依据Sitemap来进行索引的,所以我们的后台很容易就可以处理这些请求。同样的当用户访问相应的页面的时候,也返回同样的页面内容。当完成页面渲染的时候,就交由Backbone来处理相应的逻辑了。换句话来说,从这时候它就变成了一个单页面应用。

尽管这是一个三年年前开始的项目,但是在今天看来,这种做法仍然相应地有趣: 大部分的单页面应用只有一个首页,并由HTTP服务器(如Nginx)、Web框架(如Express、Koa)对路由做一些处理,可以让用户通过特定地URL访问特定地页面。而我们需要保证所有的用户访问地都是真实的页面,既然JavaScript没有加载完,用户也能看到完整的页面。

在这个项目里,最大的挑战就是如何保证后台渲染和前台渲染的业务逻辑是一样的。如当我们想要针对不同的产品显示不同的内容时,我们就需要在JavaScript中赋予一些逻辑,我们还需要在Java在有同样的逻辑。相比于在同一个代码里有桌面版、移动版来说,逻辑有更加复杂的趋势——因为在这种情况下,我们只需要维护两个不同的模板即可。而在SPA的情况下,我们要维护两套逻辑。后来,这个框架交由下文中的React与响应式设计重写。

在今天你仍然可以使用这样的方式来渲染,JDK 1.8自带了嵌入式JavaScript引擎Nashorn,完成支持ECMAScript 5.1规范以及一些扩展。

PreRender方式

在我们重新设计系统的时候,曾经考虑过类似的做法。将我们的所有页面渲染成静态的HTML,然后用爬虫抓取我们的所有页面,再上传到AWS即可。当时我们咨询了其他小组的做法,其中有一个小组正是采用了这种PreRender的方式——在本地运行起一个Server,由PhantomJS来渲染页面,再保存为对应的HTML。

PreRender就是预先渲染好HTML,并针对于爬虫返回特定的HTML。(PS:不过作为一个很有经验的SEO开发人员,我一点不喜欢这种作法。要知道Google有时候会模拟成真实的用户,不带有爬虫的那些参数和标志,去访问页面。如果你返回给Google的两个页面差异太大——可能是你忘记更新了频率,那么Google可能就会认为你在作弊。)

PreRender

对于一般用户来说就不会返回后台渲染的结果了:

Angular PreRender

和上面的第一种情况相比,这种作法可以大大减少服务器地负担,并且可以直接交由CDN就可以了。这时我们只需要考虑要渲染哪些页面即可,对于数据量比较少的网站来说这是一个不错的做法,但是多了就不一样了。

对于我们来说,有两个问题:一个是速度的问题,他们有上万条数据就需要近一天左右的时间来生成(渲染时间长),而我们有上百万条数据。二是数据的实时问题,我们的产品数据每天都会更新一次。

React

对于使用React的开发人员来说,要处理后台渲染就是一种更简单的事,毕竟React中提供了一个方法叫 renderToString()。我们所要做的就是用Express或者Koa对路由进行处理,然后返回对应的内容即可:

React Server Side Render

然后,剩下的事都可以交由React来解决,就是这么简单。

因为在这个时候我们在前后台使用的都是JavaScript,我们可以在这个地方直接实现对数据库的操作,就会出现我们在开头说到的前后台分离的问题。这样做并不合理,后台只应该返回我们所需要的数据,并且它可以随时被其他语言替换掉。

在GitHub连击的365*2-7天里 && See you Again

刚毕业的时候,有一段时间我一直困惑于如何去提高编码能力——因为项目上做的东西多数时候和自己想要的是不一样的,我便想着自己去找一些有意思的东西做着玩,在这个过程中边练习技能。

如果你知道自己代码能力不够,为什么不花两年时间去提高这方面的能力呢?

编码的练习

编码是一件值得练习的事,你从书中、互联网上看到的那一个个的编程大牛无一不是从一点点的小技能积累起来的。从小接触可以让你有一个好的开始,一段好好的练习也会帮助你更好的前进。

记得我在最开始练习的时候,我分几个不同的阶段去练习:

  • 按照《重构:改善即有代码的设计》一书边寻找一些 bad smell 的代码,一边想方设法去让代码变得优雅。
  • 按照《设计模式》以及《重构与模式》来将代码重构成某种设计模式。
  • 按照《面向模式的软件架构》去设计一些软件架构。

而这些并不是一种容易的事,很多时候有一些模式,我们都很难有一个好的实践。只是这些东西都不是一些可以生搬硬套的,我们更需要的是知道有这些东西的存在,以便于在某一天,我们可以从我们的仓库里将这些知识取出来。

2014.png

我们的刻意练习加上我们的持之以恒总是会取得长足的进步。不过在我们练习之前,你需要有一个目标。这个目标可以是一个 Idea、一个设计模式、一个模仿等等,这些内容都可以以 Issue 的好好管理着。

在最开始我们下定目标的几天里,我们可以很容易做到这样的事。同样的,我们也可以很容易达到 21 天。只是,我们很容易在 21 天后失去一些目标。所以在练习开始之前,你需要创建一个帮助你提高技术的列表,然后一点点加以提高。比如说:

  1. 尝试使用 React + Redux + Koa 2、或者Angular 2 + TypeScript,这样我们就能凭此来学习新的技术。
  2. 尝试使用 CQRS 架构来设计 CMS,这样我们就可以练习在架构方面的能力。

在我们想到一点我们可以练习的技术的时候,这就是一个可以变成 Issue 管理的内容,我们就可以针对性的提高。

通常在这种情况下,我们知道自己不知道什么东西,当我们处于不知道自己不知道、不知道自己知道时,那我们就需要网上的各种技能图谱——如StuQ的技能图谱。

2014.png

然后了解图谱上的一个个的内容,尽可能依照此构建自己的体系——以让自己走向知道自己不知道的地步,然后我们才依此来展开练习。

建议试试我们家的Growth哈,地址:http://growth.ren。

文章的剩下部分就让我分享一下:在这723天里,我创造出了哪些有意思的东西(ps:让我装逼一下)——其实我不仅仅只是 Markdown 写得好

2014年

时间:2014.10.08-2014.12.30

2014.png

在这一段时间里,我创建的项目大部分都是一些物联网项目:

  • iot-coap 一个基于CoAP协议的物联网
  • designiot 即电子书《教你设计物联网系统》
  • iot-document 收集一些物联网相关的资料,和Awesome不是一个性质
  • iot 基于PHP框架Laravel的物联网
  • iot-android 一个与iot项目相配套的Android程序
  • 等等

正是这几个IoT项目,让Packt出版社找到了我,才有了后来和国内外出版社打交道的故事。也开始了技术审阅、翻译、写书的各种故事,想想就觉得这个开头真的很好。

期间还创建了一个很有意思的Chrome插件,叫onebuttonapp——没错,就是模仿Amazon的一键下单写的。这个插件的目的就是难证当时在项目上用的Backbone、Require.js的这一套可以在插件上好好玩。

OnMap项目是为了让我用Nokia Lumia 920拍照的照片,可以在地图上显示而创建的项目。

当然还有其他的一些小项目啦。

2015年

2015.png

整个区间就是刷各种前端的技术栈,创建了各种有意思的项目:

  • Lettuce框架,一个基于简单的SPA框架
  • echoesworks,一个支持字幕、Markdown、动画的Slide框架
  • diaonan,一个支持CoAP、MQTT、HTTP的物联网项目
  • developer,收集各种 Web Developer 成长路线,以及读书图谱

期间还创建了几个混合应用项目:

更多内容可以见我的Idea列表:https://github.com/phodal/ideas,我实在是不想写了。

2016年

2016.png

我们有了Growth系列的电子书、APP,还有Mole,几个极具代表性的项目就够了。

  • Growth,一款专注于Web开发者成长的应用,涵盖Web开发的流程及技术栈,Web开发的学习路线、成长衡量等各方面。
  • Growth: 全栈增长工程师指南,一本关于如何成为全栈增长工程师的指南
  • Growth: 全栈增长工程师实战,在Growth中我们介绍的只是一系列的实践,而Growth实战则会带领读者去履行这些实践

See you Again

停止这次连击,只是为了有一个更好的开始。

如果你也想提高自己,不妨从创建你的 ideas 项目开始,如我的Ideas项目一样,上面已经有了大量的 Idea。然后,我们还可以依据这一个个的项目,创建出一本电子书,即 ideabook

我要想的生活: 做有趣的事,然后赚钱。你呢?

本周里,我终于迎来了我人生“赚”的第一个电脑。依据我们公司的规定,就是两年可以换一个新的电脑。于是新旧两个电脑出现了,我想你已经猜到哪个是旧电脑了。 :)

这里就不晒Command键了~~~,今天把自己书架上的书打包了寄到下一站——深圳。书架上的书,很快地就变成了九个西瓜箱——虽然,我不是很喜欢吃西瓜,但是我喜欢这个整齐的样子:

xigua.jpg

之前送走了近百本书,现在留下的是200kg的重量,还带走了600RMB的物流费。

生活就是充满折腾带来的乐趣。失意的时候,总会想起这句话:

title-1.png

为什么会有这么多的书?

到目前为止在ThoughtWorks的两年多的时光里,我还没有加过班。所以我有足够的时候去看书、写代码、玩游戏,说到游戏不得不多说一两句:

game.jpg

没钱就不要玩网游了——花钱买经验是很实用的一个招数。没钱的话,你还是和我一样玩单机游戏《文明》吧:

civ.png

花钱买经验对于软件开发来说也是如此,所以有事没事的时候多买买书——只要星多和评价多,都值得一买。

花钱买经验对于软件开发来说也是如此,所以有事没事的时候多买买书——只要星多和评价多,都值得一买。

花钱买经验对于软件开发来说也是如此,所以有事没事的时候多买买书——只要星多和评价多,都值得一买。

books.png

没钱?

**为什么你会没钱?因为你在加班,所以你没钱~~~。**因为没钱,所以你还在加班~~~。

扯多了,让我们回到正题,写剩下一半的内容。

无暇思考的一生

我们已经吐槽了那么多的点,归根到底就是那句NOT FAIR,但是根本就不会存在FAIR。所以,不要去抱怨,多多思考生活的可能性。

**什么叫思考?**看完这篇文章根本就不会让你拥有思考的能力,睡觉前想一想也不会让你有思考的能力。从小到大,大部分人都是按照别人的想法来生活的:

growth.jpg

  • 小学
  • 初中
  • 高中
  • 大学
  • 结婚
  • 生子
  • 孩子上学
  • 。。。

总结:无暇思考自己的一生

当你从大学毕业的时候,你有没有想过你要怎样的生活?我想多数的人并没有多少时间去想象,就开始按照父母的意志生活着。

对于多数的人来说,你所掌握的知识比你父母还多。而你父母对于你的计划,多数只是源于假想:

compare.jpeg

你痛恨的那个旧社会,以某种形式印象在你的身上,就好比是加班的程序员是新的进城务工人员——社会还是掌握在资本家手中。

Create & Share

寻找你觉得有趣的事,投入时间练习,然后将之变为你营生的方法。简单地来说,就是你可以忘记时间的事物。即:

flow.png

  • 小时,看动画片、玩游戏到忘记时间。
  • 小学,看漫画、故事到忘记时间。
  • 初中,看小说到忘记时间。
  • 高中,运动到没有概念。

如果你是学物理的话,那么应该是这样的:

如果你在一个漂亮的姑娘旁边坐了两个小时,就会觉得只过了1分钟;而你若在一个火炉旁边坐着,即使只坐1分钟,也会感 觉到已过了两个小时。

前者就是心流~~,后者就是你所讨厌的工作。

对于我来说可以达到流的领域有:

  • 编程
  • 写作
  • 设计

对于编程来说,我并不想成为一个大牛或者大神,我只想有足够的能力来创造。
对于写作来说,虽然我也希望可以靠写作为生,但是我发现它可以影响更多的人。
对于设计来说,虽然我还只是一个超级新手,但是我很容易投入进去。

而且,我也很容易不同的领域的知识来创造一些有意思的东西。如编程与写作的技术文章,编程与设计的UI设计。

你呢?你找到你的心流了么?

我并不聪明,只是多练习&思考

五一后刚来到一个新的项目,所以写作的时候就没有那么充足了。从一个舒适的环境走到了学习的环境:

32.png

从一个舒服的环境走到一个不舒服的环境需要一个过程。当然这种不舒服的学习区不仅仅局限于工作,还有生活上,还需要去适应深圳的生活——不过,我想应该很快就能适应了。

这篇文章的起源会比较复杂,一个是来自对知乎上相关问题的思考,一个是最近工作上的一些思考。

挂科x四百本书

有一天在知乎上逛的时候看到了一个问题《请教我该如何取舍课程,然后如何学习成为一个程序员?》。因为题主的专业和我是一样的——电子信息工程,也是对计算机感兴趣,然后我就很无耻地把我的成绩单贴了上去,还说了我看了大学期间看了四百本书

score

上面一共挂了两挂,其中有两科是体育——游泳,还有四科分别是:

  • 高等数学
  • 线性代数
  • 复变函数与积分变换
  • 通信原理

以上都是数学课,因此我就被喷了~~:

score-60-400-book.png

score-60-2.png

然后我就开始思考了这个问题了,我在大学期间到底做了些什么?反正,以上的两个事实是已经有了:

  • 挂了四门数学
  • 看了四百书——这只是一个估计数字,应该也在400以上,当时在大二、大三时的平均速率是 7080/学期。

以上的结论加上GitHub的连击只能说明——我不够聪明,但是很勤奋,哈哈哈 。

专家x通才

受最近项目的影响,昨天我在翻阅《咨询的奥秘》、《麦肯锡方法》,发现在后者的最前面写了一句话:

麦肯锡顾问大多数是通才,他们博学却涉猎不深,随着经验的积累和职位的提升,他们对涉猎行业的了解逐步加深。

在之前那篇《为什么说全栈工程师是未来?》中,我们已经阐述了足够多的专家与全栈工程师的对比。

通才从某种意义上来说就是又大又薄的山东煎饼:

jianbing.jpg

而专家就是月饼,那么很厚就像月饼一样:

yuebing.jpg

好了,掩饰完毕。


综上所述,**如果把我们的饼变厚,那么我们就可以取得一个好成绩了。**而这也意味着,我们就不能涉猎更多的领域。那样,我们就不能成为一个Consultant——咨询师、顾问。

放弃xFocus

问题1:如何去看四本百书?

在那篇《程序员的内置索引与外置的Google》中,我们提到过:学习的过程中我们只需要不断地去构建我们的索引即可

所以作为一个侦探顾问,福尔摩斯需要不断地汲取各个领域的一些知识:

holmes

并且只在少数领域成为专家——必须要腾出空间给其他知识点,所以作者 Arhur Conan Doyle的那句话那经典:

quote-i-consider-that-a-man-s-brain-originally-is-like-a-little-empty-attic-and-you-have-to-arthur-conan-doyle-8-13-64.jpg

即:

人的大脑如同一间空空的小阁楼,对放置进去的家具要有选择。

下半句是:

只有傻瓜才会把他碰到的各种各样的破烂不加选择地装进去。不然,无用的东西会挤占太多的空间,或者许多东西相互杂处,条理不清。

即:

Attic

在今天这句话就变成:

构建你自己的索引目录,同时使用搜索引擎来完成构建。

看多了书之后,大部分的计算机书看目录就够了。

放弃xFocus

我只是走了一条,我认为是正确的道路:成为全栈工程师&咨询师。或者如justjavac所说的全栈工程师咨询师,如Sherlock Holmes的侦探顾问。但是这并不意味着,适用于每一个人。

  • 有的人想成为专家,进入大公司。
  • 有的人想在某个领域有所建树。
  • 。。。

面对太多的需求,我们总得做出些择则。并非每个人都是天才,天才只是少数——还没见到天生下来就会写代码的。

好了,我又解(掩)释(饰)了挂科的问题了——把这些时间都花在看书上了。。

作息

新买的钟很漂亮,上面写的是“Give Me 5”:

WP_20160508_10_35_28_Raw.jpg

不是“凌晨五点的深圳”的意思:

20150302155212964.jpg

我也是每天12点前睡,然后七点多起床的——三遍

足够的睡眠,才能更好的前进。

足够的睡眠,才能更好的前进。

足够的睡眠,才能更好的前进。

先定一个小目标,比如写一本英文技术书

从Growth 2.0 Release到现在的近一个月时间里,我一直在思考未来的半年里——即到春节前,我应该做点什么。在GitHub上刷代码来增长经验值已经越来越难了,是时候停止这样的练习。但是在停止之前,我应该明确我的下一步打算。

一个月的思考

在一天天的思考过后,慢慢的有了一个清晰的答案了。虽然是花了一个月去思考未来半年、一年、两年需要做什么,但是它是值得的,这总比我们盲目的去做一件事强多了。

尽管之前我正在努力计划提高软技术的能力,如咨询、教练、营销、询问等等。由于我将参与技术活动、会议的时间放在工作三年以后,所以只能推到明年去做这些事。现在只是工作的第二年,出去丢脸之前,先把技术活做好。

人生就像是坐地铁,在去一个遥远的地点之前,我们要想好下一个中转点是什么。

在去桂林的路上,我看了一本名为《理性动物》的书,这本书中提到了一个慢对策的观点。这个观点和《思考,快与慢》有点类似,只是慢对策更像制作一个长期计划。

先定一个小目标,比如Growth纸质版

半年多以前,在完成Growth 1.0的时候,发现这个APP还蛮受欢迎。在完成了2.0后,发现还是不错,而在这时已经产生了两本相关的电子书:

  • 《全栈增长工程师指南》
  • 《全栈增长工程师实战》

这两本书算是奠定了Growth纸质版的一些基础,但是仍然会有相当多的变化。它变成了三部分,一共十二章的内容,这些当然还是暂定咯。

  • Part 1. Inception,继承部分我司Agile的基础,介绍一些基础设施的搭建、技术选型、抽象等等。
  • Part 2. Continuous,即Growth的核心内容,讲述Web开发的过程、并实践之。
  • Part 3. RePractise,相信大家都对《RePractise》电子书的内容有些印象,计划在这一部分教大家思考哈!

目录的初稿应该会在这周完成,然后写章样章,再找个合适的出版社。实际上,这本书是在很早很早以前我想的“实习记”,所以这本书会以故事的展示。然后,有一天我就变成了写故事的人了,哈哈。

先定一个小目标,组建开源软件团队

以前我也想做一个框架,然后扬名立万!

后来,我找到了一些更有意思的事情做了。人们并不缺乏好的框架,好的框架又是容易使用的。人们更多的是缺少一些好的实践,缺少一些**。

Growth在某种程度上可以弥补这部分的功能,我就想着在这方面上是不是可以走得更远。之前的Mole项目就是一个好的尝试,但是我想做得更多,如帮程序员找对象。

现在,我们已经有了一个程序员,还有一堆想法,还差你的加入了。如果有一天我们可以集合一些程序员,那么我们就会有一个伟大的产品。

当然,我想要构建的是一个开源团队,只为程序员服务。以前我也想着在组织内部做这样的事,但是公司都是以盈利为目的的。

先定一个小目标,写本英文技术书

有一天,我在回想起我第一本书(《自己动手设计物联网》)的事件时间线:

  • 2014年07月28日,收到英国Packt出版社的一封邮件,大意是作为技术审阅Review《Learning Internet of Things》。
  • 2014年08月10日,将我的毕业设计的内容放置GitHub上,随后创建了电子书《一步步搭建物联网系统》。
  • 2015年02月09日,收到“机械工业出版社”的邮件,翻译《Learning Internet of Things》。
  • 2015年07月01日,收到“电子工业出版社”的邮件,开始商谈写作《自己动手设计物联网》事宜。
    从决定出一本物联网相关的电子书,即2014年08月10日,到现在完成出版已经两年了。

这是一个很长的旅途,于是我便想着我现在写一本英语的电子书,两年后我是不是就会有一本纸质的英文技术书。

考虑到了我之前的英语水平,还是用两年来完成吧:

只是随着这两年来在为Packt出版社Review计算书经验的加深,我发现用英语写技术书籍也不是很难。

现在,我现在Review一本Angular 2的书籍,说不定半年后我就会翻译这本书了,哈哈~~。

现在,先让我从简单的开始,翻译我的Ideabook。

如何以“正确的姿势”阅读开源软件代码

所有让你直接看最新源码的文章都是在扯淡,你应该从“某个版本”开始阅读代码。

之前想过写这篇文章,但是没有想到一个好的内容、好的突破点。在《GitHub 漫游指南》指南里,我们提到过《如何在GitHub“寻找灵感(fork)”》,但是并不是关于阅读源码的好文章。

我们并不建议所有的读者都直接看最新的代码,正确的姿势应该是:

  • clone某个项目的代码到本地
  • 查看这个项目的release列表
  • 找到一个看得懂的release版本,如1.0或者更早的版本
  • 读懂上一个版本的代码
  • 向后阅读大版本的源码
  • 读最新的源码

最好的在这个过程中,可以自己造轮子来实现一遍

阅读过程

在我阅读的前端库、Python后台库的过程中,我们都是以造轮子为目的展开的。所以在最开始的时候,我需要一个可以工作,并且拥有我想要的功能的版本。

it-works-cms.png

紧接着,我就可以开始去实践这个版本中的一些功能,并理解他们是怎么工作的。再用git大法展开之前修改的内容,可以使用IDE自带的Diff工具:

pycharm-diff.jpg

或者类似于SourceTree这样的工具,来查看修改的内容。

在我们理解了基本的核心功能后,我们就可以向后查看大、中版本的更新内容了。

开始之前,我们希望大家对版本号管理有一些基本的认识。

版本号管理

我最早阅读的开始软件是Linux,而下面则是Linux的Release过程:

linux-history.png

表格源自一本书叫《Linux内核0.11(0.95)完全注释》,简单地再介绍一下:

  • 版本0.00是一个hello,world程序
  • 版本0.01包含了可以工作的代码
  • 版本0.11是基本可以正常的版本

这里就要扯到《GNU 风格的版本号管理策略》:

1.项目初版本时,版本号可以为 0.1 或 0.1.0, 也可以为 1.0 或 1.0.0,如果你为人很低调,我想你会选择那个主版本号为 0 的方式;
2.当项目在进行了局部修改或 bug 修正时,主版本号和子版本号都不变,修正版本号加 1;
3. 当项目在原有的基础上增加了部分功能时,主版本号不变,子版本号加 1,修正版本号复位为 0,因而可以被忽略掉;
4.当项目在进行了重大修改或局部修正累积较多,而导致项目整体发生全局变化时,主版本号加 1;
5.另外,编译版本号一般是编译器在编译过程中自动生成的,我们只定义其格式,并不进行人为控制。

因此,我们可以得到几个简单的结论:

  • 我们需要阅读最早的有核心代码的版本
  • 我们需要阅读1.0版本的Release
  • 往后每一次大的Release我们都需要了解一下

示例

以Flask为例:

一、先Clone它。

clone-flask.png

二、从Release页面找到它的早期版本:

flask.png

三、 从上面拿到它的提交号8605cc3,然后checkout到这次提交,查看功能。在这个版本里,一共有六百多行代码

flask-0.1.png

还是有点长

四、我们可以找到它的最早版本:

flask-init.png

然后查看它的flask.py文件,只有简单的三百多行,并且还包含一系列注释:

flask-init.png

五、接着,再回过头去阅读

  • 0.1版本
  • 。。。
  • 最新的0.10.1版本

那些年我总结的Web开发者成长路线

从实习后的那些年里,我就开始经常总结一下自己的学习路线,成长路线等等。今天,就重新把这些资料再放出来啦啦。

当然,这些资料也都是在我的GitHub上有的啦。

Developer成长路线图

最开始的时间,我并没有想到这张大图可以如此的受欢迎。在最开始的时候,我只想整理一下,我学习了什么东西、觉得什么东西不错。。

Tree

GitHub: https://github.com/phodal/developer

Sherlock 技能树

最开始的时候这是一个Fork的项目,后来它用D3.js动态生成了技能树·~。

除了Developer上的一些路线,它还有推荐书籍。

Sherlock

GitHub: https://github.com/phodal/sherlock

Developer进阶书单

同样的,Sherlock的主要问题是,没有提供一个好的学习路线,就变成了这个项目。这是基本的模式:

Book Tree

还推荐了不同的学习路线图,如前端、DDD、架构等等。

Code

GitHub: https://github.com/phodal/booktree

Growth

遗憾的是,上面的内容都是分散的,于是我们就有了Growth。它是一款专注于Web开发者成长的应用,涵盖Web开发的流程及技术栈,Web开发的学习路线、成长衡量等各方面。在这里,你将通过不断检验自己的学习成效,形成属于你自己的独一无二的个性技能图谱。

Growth

GitHub: https://github.com/phodal/growth

Growth: 全栈工程师增长指南

当我整理出APP的时候,发现这个APP太重了,于是我又整理出了一本电子书。依据在《Repractise简介篇:Web开发的七天里》中所说的 Web 开发的七个步骤而展开的电子书。当然它也是一个 APP,它是一本关于如何成为全栈增长工程师的指南。

GitHub: https://github.com/phodal/growth-ebook

Growth:全栈增长工程师实践

我总以为这时候就结束了,后来发现并没有,人们还想要一个实战手册。于是,我们就有了这样的一个实战手册。

在Growth中我们介绍的只是一系列的实践,而Growth实战则会带领读者去履行这些实践。你将会看到:如何开发一个Web应用(博客)、如何编写测试——单元测试、功能测试、自动化UI测试、搭建并使用持续集成、添加SEO支持——Sitemap、站长工具和Google Analytics、创建API,制作AutoComplete

开发相应的APP及其API——查看文章、用户登录、发表文章等等。

GitHub: https://github.com/phodal/growth-in-action

Ideabook: 一个全栈增长工程师的练手项目集

后来的后来,人们想要更多的实践项目,于是就有了这本电子书。

你是不是在为提高编程技术而发愁?

你是不是在为找不到合适的练手项目而烦恼?

你是不是在为有合适的项目,但是没有指南而烦恼?

GitHub: https://github.com/phodal/ideabook

Growth 2.0

事情还没有结束,Growth 2.0将推出更棒的解决方案。

GitHub: https://github.com/phodal/growth2

敬请期待!

技术不局限于赚钱,还应当保护我们的家人、看到社会的公正

有一天,我们也会有孩子;有一天,我们也会成为低端人口。

昨天在电影院看了《正义联盟》,可以容纳上百人的电影院里,只有不到十个人。

唯一的观感是:贫穷限制了我们的想象力

这个世界没有超级英雄,没有人为他们站出来。

不是智慧,而是权力制定了法律。 ——托马斯 霍布斯

我们大可能理解为:屁股决定脑袋。

我原以为携程事件,已经够可怕了,没想到我还是 too young。

然而,这些只是我们见到的冰山一角,因为我们看不到『我们看不到』的东西。

我们所能见到的都是:规模级的事情——量变引起了质变。真正的穷人是连网络是什么都不知道的。正如,孩子对于望远镜的功能理解是一样的。

我们永远不可能真相,因为我们的互联网是中心化的。哪怕只是一点点的相关内容,在微博上,在知乎上,在微信里,会立即消失。毕竟:我们写了一个程序,它消灭了我们。

这个『吃人』的世界,仍然是这样的。

可无论结果是如何,我们都不知道真相。我们不是福尔摩斯,我们不能从:一滴水推测出大西洋或尼亚加拉大瀑布的存在。

只是,我们仍然知道,药是真的、针眼是真的,被虐待是真的。因为那个 22 岁的幼儿园教师已被依法刑事拘留,只是没有『人』去解释那些神秘的叔叔、爷爷。

我们缺少一个去中心化的消息平台。就算有了这样的消息平台,我们也没有办法判定事情的真伪。可,到少我们可以拥有发言权。

当纳粹逮捕共产党的时候,我没有站出来;

当纳粹逮捕工会主席的时候,我没有站出来;

当纳粹围堵基督教徒的时候,我也没有站出来;

到最后他们终于找到我了,已经没人为我站出来

那天,在朋友圈发不了携程xx 的时候,我就在想:我是不是一直在自言自语。

这又是一个跨越不了的沟:

A:您找到事了吗,搬了吗 ?

B:您孩子还好吗 ?

C:最近纪委找你了吗?

而高低都是相对的,因为这是一个『吃人』的世界。

我翻开历史一查,这历史没有年代,歪歪斜斜的每页上都写着“仁义道德”几个字。我横竖睡不着,仔细看了半夜,才从字缝里看出字来,满本都写着两个字是“吃人”!

让你的「微信小程序」运行在Chrome浏览器上,让我们使用WebStorm

「微信小程序」的开发框架体验起来,还不错——自带了UI框架。但是问题是他的IDE,表现起来相当的糟糕——其实主要是因为,我当时买WebStorm License买了好多年。所以,我觉得他的IDE真不如我这个付费好用。

webstorm.png

而且,作为一个拥护自由和开源的 「GitHub **区首席Markdown程序员」。微信在「微信小程序」引导着Web开向封闭,我们再也不能愉快地分享我们的代码了。

如果我们放任下去,未来的Web世界令人堪忧。

好了,废话说完了:

文章太长不想看,可以直接看Demo哈哈:

GitHub: https://github.com/phodal/weapp-webdemo
预览:http://weapp.phodal.com/

真实世界下的MINA三基本元素

「微信小程序」的背后运行的是一个名为MINA框架。在之前的几篇文章里,我们介绍得差不多了。现在让我们来作介绍pipeline:

Transform wxml和wxss

当我们修改完WXML、WXSS的时候,我们需要重新编译项目才能在浏览器上看到效果。这时候后台就会执行一些transform动作:

  1. wcc来转换wxml为一个genrateFun,执行这个方法将会得到一个virtual dom
  2. wxss就会转换wxss为css——这一点有待商榷。

wcc和wxss,可以从vendor目录下获取到,在“微信web开发者工具”下敲入help,你就会得到下面的东东:

help.png

运行openVendor(),你就会得到上面的wcss、wxss、WAService.js、WAWebview.js四个文件了。

Transform js文件

对于js文件来说,则是一个拼装的过程,如下是我们的app.js文件:

App({
onLaunch: function () { }
})

它在转换后会变成:

define("app.js", function(require, module){var window={Math:Math}/*兼容babel*/,location,document,navigator,self,localStorage,history,Caches;
        App({
            onLaunch: function () {

            }
        })
});
require("app.js");

我假装你已经知道这是什么了,反正我也不想、也不会解释了~~。同理于:

define("pages/index/index.js", function(require, module){var window={Math:Math}/*兼容babel*/,location,document,navigator,self,localStorage,history,Caches;
        Page({
            data: {
                text: initData
            }
        });
    require("pages/index/index.js");

至于它是如何replace或者apend到html中,我就不作解释了。

MINA如何运行?

为了运行一个Page,我们需要有一个virtual dom,即用wcc转换后的函数,如:

 /*v0.7cc_20160919*/
        var $gwxc
        var $gaic={}
        $gwx=function(path,global){
            function _(a,b){b&&a.children.push(b);}
            function _n(tag){$gwxc++;if($gwxc>=16000){throw 'enough, dom limit exceeded, you don\'t do stupid things, do you?'};return {tag:tag.substr(0,3)=='wx-'?tag:'wx-'+tag,attr:{},children:[]}}
            function _s(scope,env,key){return typeof(scope[key])!='undefined'?scope[key]:env[key]}
            function _wl(tname){console.warn('template `' + tname + '` is being call recursively, will be stop.')}
            function _ai(i,p,e,me){var x=_grp(p,e,me);if(x)i.push(x);else{console.warn('path `'+p+'` not found from `'+me+'`')}}
            function _grp(p,e,me){if(p[0]!='/'){var mepart=me.split('/');mepart.pop();var ppart=p.split('/');for(var i=0;i<ppart.length;i++){if( ppart[i]=='..')mepart.pop();else if(!ppart[i])continue;else mepart.push(ppart[i]);}p=mepart.join('/');}if(me[0]=='.'&&p[0]=='/')p='.'+p;if(e[p])return p;if(e[p+'.wxml'])return p+'.wxml';}
//以下省略好多字。

然后在我们的html中加一个script,如

document.dispatchEvent(new CustomEvent("generateFuncReady", {
        detail: {
            generateFunc: $gwx('index.wxml')
        }
    }))

就会凑发这个事件了。我简单的拆分了WXWebview.js得到了几个功能组件:

  • define.js,这里就是定义AMD模块化的地方
  • exparser.js,用于转换WXML标签到HTML标签
  • exparser-behvaior.js,定义不同标签的一些行为
  • mobile.js,应该是一个事件库,好像我并不关心。
  • page.js,核心代码,即Page、App的定义所在。
  • report.js,你所说的一切都能够用作为你的呈堂证供
  • virtual_dom.js,一个virtual dom实现结合wcc使用,里面应该还有component.css,也可能是叫weui
  • wa-wx.js,定义微信各种API以及WebView和Native的地方,和下面的WX有冲突。
  • wx.js,同上,但是略有不同。
  • wxJSBridge.js,Weixin JS Bridge

于是,我就用上面的组件来定义不同的位置好了。当我们触发自定义的generateFuncReady事件时,将由virtual_dom.js来接管这次Render:

document.addEventListener("generateFuncReady", function (e) {
    var generateFunc = e.detail.generateFunc;
    wx.onAppDataChange && generateFunc && wx.onAppDataChange(function (e) {
        var i = generateFunc((0, d.getData)());
        if (i.tag = "body", e.options && e.options.firstRender){
            e.ext && ("undefined" != typeof e.ext.webviewId && (window.__webviewId__ = e.ext.webviewId), "undefined" != typeof e.ext.downloadDomain && (window.__downloadDomain__ = e.ext.downloadDomain)), v = f(i, !0), b = v.render(), b.replaceDocumentElement(document.body), setTimeout(function () {
                wx.publishPageEvent(p, {}), r("firstRenderTime", n, Date.now()), wx.initReady && wx.initReady()
            }, 0);
        } else {
            var o = f(i, !1), a = v.diff(o);
            a.apply(b), v = o, document.dispatchEvent(new CustomEvent("pageReRender", {}));
        }
    })
})

因此,这里就是负责DOM初始化的地方了,这里得到的Dom结果是这样的:

<wx-view class="btn-area">
    <wx-view class="body-view">
        <wx-text><span style="display:none;"></span><span></span></wx-text>
        <wx-button>add line</wx-button>
        <wx-button>remove line</wx-button>
    </wx-view>
</wx-view>

而我们写的wxml是这样的:

<view class="btn-area">
  <view class="body-view">
    <text>{{text}}</text>
    <button bindtap="add">add line</button>
    <button bindtap="remove">remove line</button>
  </view>
</view>

很明显view会被转换为wx-view,text会被转换为wx-text等等,以此类推。这个转换是在virtual dom.js中调用的,调用的方法就是exparser。

遗憾的是我现在困在 data初始化上面了~~,这里面有两套不同的事件系统,有一些困扰。其中有一个是:WeixinJSBridge、还有一个是app engine中的事件系统,两个好像不能互调。。。

使用WebStorm开发

在浏览器上运行之前,我们需要简单的mock一些方法,如:

  • window.webkit.messageHandlers.invokeHandler.postMessage
  • window.webkit.messageHandlers.publishHandler.postMessage
  • WeixinJSCore.publishHandler
  • WeixinJSCore..invokeHandler

然后把 config.json中的一些内容变成__wxConfig,如:

__wxConfig = {
    "debug": true,
    "pages": ["index"],
    "window": {
        "backgroundTextStyle": "light",
        "navigationBarBackgroundColor": "#fff",
        "navigationBarTitleText": "WeChat",
        "navigationBarTextStyle": "black"
    },
    "projectConfig": {

    },
    "appserviceConfig": {

    },
    "appname": "fdfafafafafafafa",
    "appid": "touristappid",
    "apphash": 2107567080,
    "isTourist": true,
    "userInfo": {}
}

如这里我们的appname是哈哈哈哈哈哈哈——我家在福建。

然后在我们的html中引入各个js文件,啦啦。

我们还需要一个自动化的glup脚本来watch wxml和wxss的修改,然后编译,如:

exec('./vendor/wcc -d ' + inputPath + ' > ' + outputFileName, function(err, stdout, stderr) {
            console.log(stdout);
            console.log(stderr);
});

说了这么多,你还不如去看代码好了:

GitHub: https://github.com/phodal/weapp-webdemo
预览:http://weapp.phodal.com/

从Growth看“内容APP”与“技术社群”结合的可能性

了解过Growth起源的人都知道在最开始的时候,它只是一篇文章《Web开发的七天里》——是我在2015年底对2015年的一个小结。它只是我对Web开发过程的一个吐槽,结果它变成了2016年一个精彩的开始。

从文章到APP

在我总结的时候,我发现了我在15年写的两个以内容为主的APP:《极客爱情》、《教你设计物联网系统》都有一定的下载。便想着整理一下我的博客的内容,也可以变成一个APP。于是在元旦的那几本里,我就写了这样的一个APP,即做了个MVP

mvp.png

看样子,似乎很受欢迎:

new-year.png

在随后的日子里,它也稳定在每天一百个用户左右:

ga-traffic.png

在FIR.IM上统计到的Android下载量有4440次:

firim.png

ITunes Connect统计到的iOS下载量有2151次:

itunes-connect.png

还有32个Windows Phone下的下载:

wp.png

总觉得棒棒的,不过出于某些原因,并没有统计到桌面版的使用次数。而在这个过程中,一个很严重的问题是内容质量的问题。

于是在3月份开始的日子里,我便开始尽量去编写这个APP的内容——即变成电子书。

从APP到电子书

写书的过程很无聊,但是也很刺激,我们总得写一些精彩的章节在书中。而这些精彩的章节又可以是一篇篇文章,这些文章即可以扩大现有的影响力,又可以提高内容的质量。并且有相当部分的文章都相当受欢迎:

如在微信公众号上的文章《为什么说全栈工程师是未来》:

wechat.png

以及发在今日头条上的《程序员必知的隔离技术》:

toutiao.png

就这样过去了七七四十九天,这本书写完了。开始试着去营销的工作,从知乎引导去的流量是最多的

referring-sites.png

终于,它在GitHub上也超过了一个Page View:

growth-github-traffic.png

技术社区到技术社群

在Growth的开发过程中,为了方便讨论,引入了Flarum论坛——由于其自带API、JWT,适合用做APP的后台。

于是,花了两三天的时候把这个功能做了进去:

growth-social.png

然而,真正使用的人还是很少~~。联想到最近火热的技术社群,我便开始在思索是不是我也可以创建一个这样的技术社群。

社群是一个很老的概念了,最主玩这个的莫过于“特百惠”了。

当然,我扯远了~~,让我再摸索一下~~。

fans.jpg

我更希望可以推进Growth做得更好,好的产品 + 好的推广 才会有好的未来。

  • 如果你也对改进这个APP有想法~
  • 如果你想提高你的技术~~
  • 如果你想探索这一些

试试APP,然后加入开发团队(当前只有我一个啦~~)或者加入我们的社区。

关于IT书籍,你应该知道的五件事

虽然在我的书架上有很多的技术书籍,但是这并不代表我对每本书都很了解——但是至少每本书我都过了一下目录,大部分的书都翻了一遍。在开始瞎扯之前,先让我们过一下目录:

  • 在什么情况下,我们会买技术书籍?
  • 我们应该买怎样的书?
  • 拿到书后,我们会怎么做?
  • 书看完之后呢?
  • 技术书籍,不就是花钱买时间吗?

在什么情况下,我们会买技术书籍?

买技术书籍的情形应该是下面的几种情况:

  • 工作上使用到一些“新的技术”。对于自己来说是新技术,不代表在行业上是新技术。
  • 业余生活中想尝试某个新的技术。
  • xxx推荐的某本书。虽然和应用无关,但是到底是xxx推荐的。这个xxx可以是某些大牛,这可以是亚马逊——我看到亚马逊的书有好多的star,我就会买。因为在亚马逊能给书评的都是真爱。
  • 探索一个新的领域。在上大学的时候,这是我最喜欢干的事,动动就去看一个无关的领域。

上面的第一、二点都是因为我们需要,所以我们才去看——这也是我们日常买书的常见原因。

我们应该买怎样的书?

从出版行业来说,我最喜欢的就是动物园(O'Reilly出版社)的书,然后就是其他书籍了。但是O'Reilly出版社出的书都比较慢、慢,除此,与进到国内还需要经过翻译等等。说到翻译,不得不说图灵教育出版的翻译书籍挺不错的。

而这个行业里,最敏捷的就数Manning出版社的Manning Early Access Program,这是一个非常敏捷的出版流程。

In MEAP, you read a book chapter-by-chapter while it's being written and get the final eBook as soon as it's finished. If you pre-order the pBook, you'll get it long before it's available in stores.

简单地说,就是当作者完成一章的内容时,你就可以阅读这一章的内容。作者在不断写作的过程中,你就可以不停地收到相关的书籍。当作者写完这本书的时候,你就读完这本书了。

可惜如果你要等中文版的书籍,差不多要等一年。并且英文版的书籍,动不动就是几百的。

因此从流程上来说,国内的出版的书籍从流程上来说会更快一些。而国内的出版现状是,写书都是为了赚名气。对比于工作时间来说,写书基本上是亏钱的买卖。更不用说,我写的六书开源电子书,就是更亏钱的买卖了。因此,很多技术大牛都不愿意写书。他们本身就是大牛了,不差名气、也不差钱。

因此,如果我们需要某一个领域的技术书籍。从理论上来说,最看到的是 国内的 -> Manning > Packt > O'Reilly。

因此:

  • 如果要买实战类的书籍,可以直接稍微考虑一下买国内的书,然后是Manning的In Action系列、Packt的Learning系列。
  • 如果要买理论系列的书籍,优先考虑国外的——国内的绝大部分大牛都不愿意写。最常见的就是机械工业出版社引进的经典系列,以及那些Prentice Hall、Apress、Addison Wesley、Pearson等等的厚书了。
  • O'Reilly的大部分书籍都值得一买,以及图灵教育翻译的O'Reilly系列。

对了,如果你看的是盗版书籍,即电子版等等,你没有资格说这本书写得烂、翻译得烂。

拿到书后,我们会怎么做?

开始之前,我们需要简单地知道几点内容:

  • 普通的书籍都是连续的、不可跳跃的,但是技术书籍都是可跳跃的。
  • 技术书籍的内容都写在目录上,一眼看上去就知道发生什么了,如:第一回 宴桃园豪杰三结义,斩黄巾英雄首立功、第二回 张翼德怒鞭督邮,何国舅谋诛宦竖。
  • 在以介绍某个框架、语言的书籍中,作者会不断地强调这个框架、语言的特点。

现在,我们是不是应该:

沐,濯发也。 浴,洒身也。 洗,洒足也。 澡,洒手也。

翻译过来就是:

古人读书,庄重之极,读书之前要沐浴焚香,清新敛欲,泡上一杯清茶,在茶香袅袅中,把情绪酝酿的极其饱满,然后端坐书室。

完了,我们就可以开始看书了。一般来说,书的主要内容要么写在前言里,要么写在第一章里,但是它一定是在目录里的,所以可以按照这个顺序:

  • 先阅读前言和第一章
  • 然后看目录,找感兴趣的章节
  • 最后放书籍上,装逼。
  • 时不时地可以拿下来——放瓜子壳。

其实这个过程中,有一点很重要——对书的内容进行索引。换句来说,就是我们应该大概记得这本书在讲什么时候,相当于是,我们记住了这个框架、语言的一些基本属性。而正是这些构建了这些属性,我们就可以记住那些关键点,然后Google it。

如在那篇 索引 中所说:

人的大脑如同一间空空的小阁楼,对放置进去的家具要有选择。

书看完之后呢?

“当然是要放在书籍上装逼了。”

最好的效果莫过于:

  • 讨论
  • 实践
  • 教授给他人——如写作

技术书籍,不就是花钱买时间吗?

一般来说,我们都会推荐给别人去看官方文档,毕竟官方文档比较新什么的。然而有一点值得商榷的是,时间成本。阅读一本英语的原著书籍,至少能让可以读英语书籍的人读3~5本翻译书籍。

当你工作之后,你会发现这一点更不值:大部分情况下,我们需要花费几天的时间自己去探索一项新的技术,但是如果是一本书籍的话,可能就是一两个小时的事。

我要去吃外卖了——沙县小吃,谁让我钱包丢了。

「微信小程序」剖析(四):原生的实时DOM转Virtual DOM

在之前的几篇文章里,我们讨论了MINA的一些原理。晚上在想着怎么结合Vux + Virtual Dom实现一个名为WINV框架的时候,在探索WCC功能才发现:自己又忽略掉了一个很重要的性能优化细节。这个WCC如果内置在浏览器里,就是可以实时的将DOM转换为以JSON表示的DOM。

先将DOM转换为Virtual Dom,再转换回去的优点是可以分离数据和样式。这也就是为什么React的学习成本高的原因之一了。

Virtual Dom的表现形式

为了将真实的DOM转换为Virtual DOM,我们需要将DOM以一定的形式保存下来,如MINA的:

<map longitude="23.099994" latitude="113.324520" markers="{{markers}}" covers="{{covers}}" style="width: 375px; height: 200px;"></map>

如:

{
    "attr": {
        "covers": "",
        "latitude": "113.324520",
        "longitude": "23.099994",
        "markers": "",
        "style": "width: 375px; height: 200px;"
    },
    "children": [],
    "tag": "wx-map"
}

又或者是React中的:

{"type":"ul","key":null,"ref":null,"props":{"className":"my-list","children":{"type":"li","key":null,"ref":null,"props":{"children":"Text Content"},"_owner":null,"_store":{}}},"_owner":null,"_store":{}}

当然我们也可以自己实现一个比较简单的DOM转为Virtual DOM,如将

  var newDiv = document.createElement("div"); 
  var newContent = document.createTextNode("Hi there and greetings!"); 
  newDiv.appendChild(newContent); //add the text node to the newly created div. 

转换为接近原生的:

{"nodeType":1,"tagName":"div","attributes":[],"childNodes":[{"nodeType":3,"nodeName":"#text","nodeValue":"Hi there and greetings!","childNodes":[]}]}

原生的Parser与JS Parser

我会假装你已经知道了浏览器相关的很多细节,我也假装我已经对这些细节很清晰。下图一份Webkit浏览器的早期架构图:

如果我们使用JS实现一个将WXML将换为DOM JSON,我们就需要间接通过JavaScript Engine(即JSCore )来转换这个JSON文件。当有大量的DOM的时候,这就不是一件轻松的事了。所以,在WCC的生成代码里对DOM的数量限制为16000

我们可以用原生的接口来将WX DOM转换为JSON,但是我们没有办法用原生的接口来将DOM JSON转换DOM——毕竟我们还有大量的数据和绑定函数。

而这一点对于混合应用来说,就特别有帮助:

如果这个插件可以用在Cordova上,那么它将改善混合应用的性能。

数据绑定

当我们触发了generateFunc方法的时候:

document.dispatchEvent(new CustomEvent("generateFuncReady", {
    detail: {
        generateFunc: $gwx('src/index.wxml')
    }
})

我们调用下面的方法去初始化我们的DOM,并把数据传输进去:

var node = generateFunc((0, DataClass.getData)());

函数绑定

MINA的函数绑定机制是由函数名来决定的,如:

"bind" === propKey.slice(0, 4) ? createEventHandle(domElement, propKey.slice(4), propValue);
"catch" === propKey.slice(0, 5) ? createEventHandle(domElement, propKey.slice(5), propValue, !0);
"on" === propKey.slice(0, 2) ? createEventHandle(domElement, propKey.slice(2), propValue);

对于其他类型的绑定则是:

"style" === propKey ? domElement.setAttribute(propKey, (0, r.transformRpx)(propValue)) : domElement.setAttribute(propKey, propValue)
  - "animation" === propKey && "object" === ("undefined" == typeof propValue ? "undefined" : i(propValue)) && propValue.actions && propValue.actions.length > 0 && !function() {})

PS:我突然就不想看这个if else经过minify以后的代码了,太恶心了。。。

如,我们的wxml:

<view  bindtap="bindViewTap" class="userinfo"></view>

我们的propKey是bindtap,我们的propValue是bindViewTap,随后我们就会根据当前的函数名去创建相应的事件。

微信小程序」剖析系列

2016年最值得新手程序员阅读的书:《增长工程师指南》

这本书的来源于依据我在《Repractise简介篇:Web开发的七天里》中所说的 Web 开发的七个步骤而展开的电子书。当然它也是一个 APP、它一本关于如何成为增长工程师的指南。

编写过程

昨天,我算是把这本电子书(可在GitHub上阅读、下载)的初稿写完了,已经有75,505个字了。

count.png

在8星期49天里,一共提交了477次,修改了212个文件。

git-summary.png

收到了1.4k+的star:

star.png

在最开始的时候,我对这本书的定位是整理自己所学的知识——让自己Growth。因为输入是最好的输出,如图所示:

learn-ta.png

整理自己所学的知识并不是一件容易的事,但是却是一件特别有意思的事。在这过程中,我发现自己还需要补补一系列的基础知识。我倒是重新阅读了几十本书 。到了今天,由于工作的原因,很多技能、技术、知识点已经丢失了。

而这些实现上应该是需要去补充的基础知识。如:

  • 我对算法和数据结构已经忘却到一定的程度了。这些知识都是我在多年前学习的,后来的日子里就没有好好用过。
  • 我甚至已经忘记很多熟知的概念,大抵是因为用得不多,然后没记住。

知道自己不知道,倒是一件特别好的事情。喜欢这种感觉,反正我暂时也不想去学习那些不知道的,暂时保持一些紧迫感。

所以什么是Growth Enginnering?

全栈工程师

我们在前言里,对比了两种不同的工程师——全栈和专家。全栈可以依赖于学习能力扩展知识体系,而专家则是深入某个领域。问题来了,什么是全栈工程师?,即:

他们能够自己构建和部署一个完整的、可以工作的应用程序,而不需要其他任何人的帮助。

而大部分人认识里的全栈工程师,则是全栈专家,即对下面的所有知识点都精通。

stack.png

由于软件开发成本的极速下降低,这个行业正在迎来后发者优势的时代,即年纪越小的开发者会使用越先进的技术。我看到的那些所谓的专家理论者,也不得不走向全栈。

expert-vs-fullstack.png

那些不喜欢接触自己不熟悉的领域、停滞不前的专家,喜欢鼓吹全栈无用
那些不喜欢接触自己不熟悉的领域、停滞不前的专家,喜欢鼓吹全栈无用
那些不喜欢接触自己不熟悉的领域、停滞不前的专家,喜欢鼓吹全栈无用

人本身就存在不同的差异:内向的人可以深入某个领域,外向的人可以成长全栈。只是人们走向全栈的方式过程不一样罢了!

编程只是全栈的一部分技能,全栈也只是一部分技能。

增长工程师

增长工程师的定义很简单,即持续学习。

既然我们都会完整的开发一个应用,那么我们也掌握足够的技术去成为一个Growth Hacker:

growth-hacking.jpg

既然我们都会完整的开发一个应用,我们也可以成为大数据领域的一个英雄:

d3js.jpg

既然我们都会完整的开发一个应用,我们就能开发全平台应用:

slack.jpg

全栈增长工程师指南

我们都会学习,但是有时候我们只是不知道应该学习什么而已

因此,这是一本指导性的书籍。不要指望从这本书中学到所有的知识点,但是他可以帮助你构建知识体系——这是其他技术书籍所欠缺的。它可以告诉你,你可以学习什么,然后看什么书。

开源编程学习应用 Growth 发布 3.0,在碎片时间里练习

Growth 1.0~2.0 已经有 2101 次提交,而 Growth 3.0 则已经拥有了 900+ 提交。这意味着 Growth 整个项目有多达 3000 次提交,感谢每一个为 Growth 项目作为贡献的开源先锋。

特别感谢:@travelgeezer 为 Growth 3.0 编写了大量的功能。

现在,让我来开启装逼模式。

使用 React Native 重写,性能提升了 N + 1 倍

在 Growth 1.x 里,我们使用了 Ionic 1.x + Angular 1.x 来开发,而当时 Angular 1.x 已经过时了。

在 Growth 2.x 里,我们使用了 Ionic 2.x + Angular 2.x~4.x 重写了一遍,而我们发现性能不能让人满意。

因此在 Growth 3.x 里,我们使用了 React Native 重写了整个应用,再一次。

使用 React Native,从开发速度上来说,真心没有 WebView 来得快,但是性能上的提升是有目共睹的。至少,打开速度比原来快了好多倍。如我们所料,RN 的坑很多,过些日子,我再写一篇文章吧。

现在,让我们再看看 Growth 这个应用里,有什么新功能。

LeetCode 试题,适合于地铁思考模式

记得很多新手程序员问过我,他们每天要在地铁上花很多的时间,有什么东西可以在这段时间学习的。看书吧,不是很合适,如我这样的人就容易因引此而晕车——所以我一般不喜欢在公交车上玩手机。我给的答案是:这个时候适合思考问题

那么,在这个时候可以来一个 LeetCode 题,每天在路上成长一点点。LeetCode 据说是,一些经典的公司用来面试应聘者的面试题。

LeetCode

目前相应的题目是在 GitHub 上的,下载速度有点慢,希望有产商可以提供个服务器,哈哈哈~~。

如果你每天要在地铁上站一小时,那么请带上一个 LeetCode 问题练习。

算法动画学习工具

基于 AlgorithmVisualizer

既然,我们已经有了那么多算法题,那么我们也应该在手机上学习。于是,Growth 的用户 @ ivanberry 便提出了可以参考:https://visualgo.net/en,可是这个是不开源的。

找了一二个星期,看到了 Algorithm Visualizer 项目,它可以用动画展示算法、展示每一步的执行过程、拥有相应的示例代码。便花了两星期的时间,做成了下面的模样。

Algorithm

上半部分的动画内容是 WebView,下面则是 React Native。

如果你每天要等上半个小时的公交,那么不妨学一个算法知识。

正则表达式练习

基于 Regexper

同样的这个功能,也是由 Growth 用户 @allmelgr 提出来的,他对于 regexer.com 的评价是:用过的人都说简单易懂。是的,一看就懂的样子:

Regex

而为了更方便的学习,便结合 RegexHub 提供一些正则表达式示例,只需要选择对应的正则表达式,就可以展示 相应的正则关系。

如果你每天要在公交车上坐一小时,那么不妨练习一人小时的正则。

设计模式简介

基于 Design Patterns for Humans

既然我们都已经有算法和数据结构、正则表达式,我便将 GitHub 上的 Design Patterns for Humans 也集成了到 APP 里。

Design Pattern

如果你已经能完成工作,但是迷茫,那么试试设计模式

内置 VS Code 的编辑器

基于 Monaco Editor

既然都已经有了 LeetCode,那么我们应该还有一个编辑器。找了几天,终于找到将 VisualStudio Code 的同款编辑器 Monaco Editor 集成进去了。

Code

而显然它不仅仅是一个编辑器,它还可以运行 JavaScript 代码,一个『伟大的手机 IDE』就此诞生了。输入完代码,点击运行,即可运行代码。console.log 会以 Toast 的形式展示出来。

这绝逼是我在 Growth 做的最吊的,但是没有什么卵用的功能。

如果你想试试某行代码,那么试试新的编辑器。

成长路线与技能树

依旧的,仍然可以在上面看到技能树,并且速度更快了:

SkillTree

如果你对某一个领域迷茫,那么来看看对应的技能树。

与此同时,我们更新了一下成长路线:

Roadmap

如果你对某一个领域迷茫,那么来看看对应的学习路线。

未来,我们将结合网上的资源,整合学习路线和技能树——如果有更多的人来参与的话。

Awesome 列表

基于 Awesome

某一天,我在对着 Awesome React Native 发呆的时候,便顺手集成了 Awesome Awesomes 项目——写了个脚本,解析 awesome 项目生成对应的 JSON 文件。

Extends

不过就是这个列表有点太长太长太长太长太长,即使使用了 RN 的 FlatList 也不能很好地解决问题。

如果你找不到合适的灵感,那么不妨看看 Awesome 列表吧。

开源电子书

基于免费的编程中文书籍索引

有一天,我在想虽然我号称是最伟大的『md程序员』,但是一个我,肯定比不上一百个我的写作速度快。于是,我们便想将那些在 GitHub、GitBook 上的书,制作成方便在手机上阅读的内容。便有了:

Extends

实际上,这个功能实现得是最早的。但是在当前并没有什么用,当前只是链接。未来,将制作对应的 API 来获取不同书的内容,就是工作量有点巨大巨大巨大巨大巨大。

如果你找不到免费的电子书,那么试试开源的编程中文书籍。

Growth

在 Growth 3.0,Growth 原先的内容仍然还在,只是还有一些 Bug,啊哈哈

Growth

对于支持 Growth 指南对应的纸质书籍《全栈应用开发:精益实》,觉得好的就给个好评,差的就算了吧~~。

如果你想成长顶尖开发者,那么试试 Growth 吧~。

Discover

在探索栏目里,我们依旧准备了丰富的阅读、练习资源。

Discover

如果你觉得无聊,那么可以在探索和社区里,了解更广泛的世界。

So

这就是 Growth 3.0,让你练习更多。

这就是 Growth 3.0,让你练习更多。

这就是 Growth 3.0,让你练习更多。

PS:应用已在 App Store、Google Play、应用宝、小米应用商店、360应用商店上架,其它用户可以从应用宝 直接下载 APK。

欢迎到 GitHub 来支持我们的开发:https://github.com/phodal/growth

JavaScript在物联网中的应用

凡是能用JavaScript写出来的,最终都会用JavaScript写出来。

—— Atwood定律

在那篇《最流行的编程语言JavaScript能做什么?》里,我们列举了JavaScript在不同领域的使用情况,今天让我们来详解一下JavaScript在物联网中的应用。

基础:物联网的三个层级

开始之前, 先让我们简单地介绍点物联网的基础知识。如果你有点Web开发经验的话,都知道下图是CS架构:

Client-Server架构

相比于一个物联网系统,无非就是多了一层硬件层以及可选的协调层。

源自《自己动手设计物联网》

这个硬件层决定了物联网应用比Web应用更加复杂。对于大部分的Web应用来说 ,客户端都是手机、电脑、平板这些设备,都有着强大的处理能力,不需要考虑一些额外的因素。

对于物联网应用来说,我们需要考虑设备上的MCU的处理能力,根据其处理能力和使用环境使用不同的通信协议,如我们在一些设备上需要使用CoAP协议。在一些设备上不具备网络功能,需要考虑借助于可以联网的协助层,并且还需要使用一些短距离的无线传输协议,如低功耗蓝牙、红外、Zigbee等等。

一个物联网系统:六种语言

两年半以前,大四,电子信息工程,我选定的毕业论文是一篇关于物联网的论文——《基于REST服务的最小物联网系统设计》。这是一篇入门级的物联网论文,如果大部分学习CS的人有一点硬件基础,都能写出这样的论文。

这篇论文是之前参加比赛的作品论文的“最小化”,里面使用到的主要就是创建RESTful服务,而它甚至称不上是一种技术。在这个作品里:

  • 我们使用Python语言里的Django框架作为Web服务框架,使用Django REST Framework来创建RESTful服务。
  • 为了使用手机当控制器,我们还要用Java写一个Android应用。
  • 我们使用Raspberry Pi作为硬件端的协调层,用于连接网络,并传输控制信号给硬件。
  • 我们在硬件端使用Arduino作为控制器,写起代码特别简单,可以让我们关注于业务。
  • 最后,我们还需要在网页上做一个图表来显示实时数据。

所有的这些,我们需要使用Python、Java、JavaScript、C、Arduino五种语言。而如果我们要写相应的iOS应用,我们还需要Objective-C。

你是在逗我吗?

JavaScript在物联网领域的发展

同样的,两年多以前,刚实习,在我们的项目里,我们的新项目里我们使用Backbone作为单页面应用框架的核心来打造Web应用。这时,我开始关注Node.js实现物联网应用的可能性。

Node.js Express Mongodb

当时,已经有了物联网协议MQTT和CoAP协议的库,于是我照猫画虎地写了一个支持HTTP、CoAP、WebSocket和MQTT的物联网。由于,当时缺乏一些大型应用的开发经典,所以做得并不是很好,但是已经可以看到JavaScript在这方面的远景。

Ionic Cordova

一年多以前,Ionic还没推出正式版的时候,我发现到了这个框架真的很棒——它自带了一系列的UI,还用NgCordova集成了Cordova的一系列插件。我便开始使用Ionic写了一些移动应用,发现还挺顺手的。接着,我就开始拿这个框架尝试写物联网应用,这需要一些原生的插件,如BLE、MQTT。后来,我也写了一个简单的CoAP插件。

Iot

后来我们不再需要编译Node.js,就可以在ARM处理器上运行Node.js。并且我们已经有Tessel、Espruino、Kinoma Create、Ruff这些可以直接运行JavaScript的开发板。三星还推出iot.js,可以让更多的嵌入式设备可以使用JavaScript语言作为开发语言。

Node.js Future

人们开始在硬件上使用JavaScript的原因有很多,如Web的开发人员是最多的、JavaScript很容易上手。

现在,这次我们在这三个层级上都可以使用JavaScript,只需要一种语言。

使用一种语言开发物联网应用:JavaScript

在我写的那本《自己动手设计物联网》中,我就试图去展示JavaScript在这方面的威力。使用Node.js + Node-CoAP + MQTT.js + MongoDB + Express搭建了一个支持多协议的物联网:

Lan IoT

不过,上图是完善版的物联网,代码自然是在GitHub上啦:Lan。作为服务端来说,Node.js的能力已经是经过验证的。而在混合应用上,仍然也可以经受住考验,混合应用在手机上做个图表是轻轻松松的事(只需要获取数据,然后显示):

混合应用图表

作一个控制端也是轻轻松松的事(我们只需要发个POST请求,更具逻辑一点的就是先获取状态):

Led控制

而在硬件端,我并没有在书中以JavaScript作为例子来展示JavaScript的用法,因为这会局限了用户的硬件设备。

不过,我们仍然可以使用类似于Johnny-Five这样的库来做硬件方面的编程,只是它没有那么好玩~~。

既然我们可以JavaScript来实现,为什么我们还要喝杯咖啡等它用C编译完呢?

你想知道的答案都在这本书里,已在亚马逊、京东、当当上架:

自己动手设计物联网

亚马逊:https://www.amazon.cn/dp/B01IBZWTWW

京东:http://item.jd.com/11946585.html

毕竟:

凡是能用JavaScript写出来的,最终都会用JavaScript写出来。

令人可憎的信息不对称

好不容易在雨夜里来到了深圳,休整了一晚上,一大早就看到各种在说《青年魏则西之死》。写这篇文章的原因是,我希望大家可以深入地去思考问题,即问题的本质。

背景

昨天我在飞机上看了一本书叫《增长的本质:秩序的进化、从原子到经济》中提到了一个租房子的问题,因此对于上面的事件来说,这又是一个“信息不对称”带来的悲剧。先让我们从租房子这个问题说起——我也是付着昂贵的房租,住在一个小房子里。

在网上很难租到好房子

这是之前一直困扰着我的一个问题:我从西安搬到深圳的时候,想去租个房子。但是找了很久都是又贵又小的房子,又或者是一些问题小区,很难找到合适的房子。

而我的第一个渠道就是来自各个房地产家居网络平台,如下是58同城返回的结果:

58同城

我们都知道,排在搜索结果的前几个肯定会有很好的点击量。那么问题来了,我会让怎样的房地产排到前面呢? **自然是你给我的钱多,那么我就让你排在前面。**如58同城会有一个置顶的标志在那里,我们看到首先看到的也就是这些置顶的房子。

这就导致我们很难在首页看到适合的个人房源,掏这个钱并不值得。并且中介有中介费,即使排在首页某个房子已经被出租了,那么他可以出租合适的房源。

对于房地产来说,这并不是什么问题,我们会自己识别房子的好坏。只是对于某些行业,如医疗来说,就很难识别。

百度是这一些排名网站里的极端,收了太多的不义之财。那么问题来了,Google能解决这一类的问题么?

不要指望Google

答案很明显Google不能帮你选出好坏,之所以这么说是因为我对SEO有一定的了解。我们都知道Google的搜索结果页上的排名,可以简单的分成两个指标:链接和点击率。

PageRank通过网络浩瀚的超链接关系来确定一个页面的等级。Google把从A页面到B页面的链接解释为A页面给B页面投票,Google根据投票来源(甚至来源的来源,即链接到A页面的页面)和投票目标的等级来决定新的等级。简单的说,一个高等级的页面可以使其他低等级页面的等级提升。

最形象的比喻可能就是微博一些大V的成长了:

dav.jpg

下图是PageRank的示例:

pagerank.png

在早期,如果我们手上有B和C两个网站,我们要提高E的Rank值是一件容易的事,添加一定的链接即可。在那之后我们只需要有一定的点击即可:

Google搜索物联网

从某种意义上来说,Google PageRank只会导致马太效应——即强者越强。

医院这个问题只所以没在Google上出现是因为:大部分的**人都用不了Google。既然大部分的**人都用不了Google,那么医院也不会把这些钱先给那些专营SEO的公司。对于这样的公司来说,他们只需要做到两点:

  • 将自己大量的PR较高的网站指向医院
  • 雇佣水军切换IP,从搜索结果页点击相应的医院

就可以拥有丰厚的收入。

并且Google曾在2011做了一件事:

Google的广告部门为了利润,主动帮助卖假药者规避其公司的合规审查,使得大量假药、走私处方药、非法药物(如类固醇)广告网页长时间充斥其搜索结果。

弱弱地说一句:** Google也解决不了这样的问题,但是美国政府可以。**

既然竞价和PageRank都解决不了这样的问题,靠人为评价可以吗?

人为与水军

既然我们也跨不了GFW的大墙,那么我们来看看淘宝是怎样做的。

上淘宝的搜索结果页:

taobao.png

难道排名前几的商店真的是靠销量上去的?生活中你是不是也曾经帮助过别人刷过单?淘宝的信用说实话和PageRank并没有多大区别,并且刷单是一个无法禁止的黑色产业——这一点和人为地去点击Google的搜索结果来提高Rank没有太大的区别。

并且淘宝还有之前的淘小二丑闻,这一点和Google看上去差不多。

(PS: 不要和我说腾讯不作恶)

LOL小学生

对于其他互联网公司更是如此,水军是很便宜的,但是这些水军也造就了自己的悲剧。

谁才是信息不对称的受害者?

上面的这些例子里都是因为卖家比买家拥有更多关于交易物品的信息。而这些都是信息不对称:

参与交易各方所拥有、可影响交易的信息不同。一般而言,卖家比买家拥有更多关于交易物品的信息,但相反的情况也可能存在。

遗憾的是我们很难解决这个问题——公司都是以赢利为目的的。

要我来说,最有可能成为信息不对称的受害者就是你的父母。

对于大部分能看到这篇文章的人来说,他们都受着良好的教育,至少是相比于他们的父母来说。并且我所能触及的领域绝大多数人都是IT从业者,对于他们来说他们可以远离百度。但是对于我们来说,让我们的父母远离百度不是一件容易的事。

不过,如果你的父母和我一样没有接受过良好的教育,那么他们面对的就不是百度之苦,而是其他形式的犯罪,如电信诈骗。

So,不烦教教你的父母少受信息不对称之苦。

程序员如何写好简历 && 一份优秀的程序员简历是什么样的?

最近收到了很多要来面试的简历,发现你们的简历怎么都是这样的呢?要是我是面试官,你们肯定进入不了下一轮。

马上就要到一年一度,最适合找工作的时间段:金三银四。另外一个时间段是:金九银十。金三银四的大意是:最好的时间是三月,其次是四月。同理于金九银十,最好的时间是九月,其次是十月。反正我也是在几年前,道听途说过来的。一过完年,一交流总会多些想法,就有了金三银四。金九银十则是,一些公司在年中的时候,发去年的年终奖。

今年的行情虽然没有去年火热,但是你仍应该拾掇拾掇一下你的简历,万一机会来了呢?

跳槽的 N 个原因

作为一个技术人员,如果你满足以下条件中的任意一个,你应该去看看更多的机会:

  • 钱少了
  • 技术空间增长太少
  • 没有发展空间
  • 心里委屈了

以及

  • 老板招你的时候,和你谈理想。现在,老板问你说:理想能赚钱吗?
  • 加班太多——都没有时间约会或者女朋友和别人跑了
  • 你的女朋友在北京,而你在上海
  • 这个技术公司已经没有大牛了

这不是马上就要到,传说中一年一度的狗粮节了么。回到正题,一份优秀的前端开发工程师简历是怎么样的?

一份优秀的前端开发工程师简历是怎么样的?

这个嘛,我觉得应该是这样的:

Phodal

然后呢,HR 只需要打开这个 PDF 中的 GitHub 链接即可:

Phodal's GitHub

这才叫优秀嘛,你说是不是?

好了,写完段子了,让我们来看正文。

简历的 N 种错误姿势

这些年来,我也多多少少了,看了一些简历。也稍微有一些经验,让我先罗列一下问题,再说说原因:

打开姿势

简历造假。任何造假的行为都是不能容忍的,这个问题容易出现在不自信的面试者身上。还容易出现在培训机构的学生上——我并没有任何歧视培训机构培训的学生,我只歧视培训机构及其行为。即使你能幸运的通过面试,在工作的时候,你也有可能被觉察出来。

不适当的文件名。当我收到一份简历,你可以是 xxx.pdf,可以是 xx公司_xx.pdf,但是不能是 all.pdf、resume.pdf 这样的文件名。我还需要帮你重新命名一下,然后存档么?在简历的文件名上,你要突出重点,谁,需要什么岗位,如:李小明_Android工程师_简历.pdf

使用 PDF 以外的格式,如PPT、DOCX、HTML。PDF 是我目前看到兼容性最好的格式,要知道 Windows 上写的 TXT 在 Mac OS 上打开都会有编码问题。DOCX 就更不用说了,我司标配的 Office 是 LibreOffice,打开的文件 100% 出问题。PPT 我就不说了,虽然很帅,但是我很累——要面试的人是你,不是我

PPT Resume

呵呵~

Be Professional

语法问题。在平时的时候,你可以将一些技术栈的单词拼错。但是在简历上,请认真一点~,最好可以找基友帮你过一遍。该大写的时候就应该大写,如 HTML 不应该写成 html 或者 Html,Java 8 不应该写在 JAVA 8 或者 java 8, 乃至 J8。

排版问题。像审美风格这样就算是其次的,该换行的时候就要换行,该对齐的时候就应该对齐。好在大家都是用模板来完成的,这个问题不大。

没有项目经验或者无用的项目经验。只是罗列技术栈,没有写你做了什么。这种感觉就好像,我在 BAT 里都干过,只不过是我是在里面扫地的。作为一个美团外卖员工,天天进百度外卖大楼去送外卖——除了没被打死,你还有什么可以自豪的?。
**
写了一些无关紧要的废话。谁 TM 想知道你和你家大伯的女儿关系,以及你在中小学的时候去哪玩了。除此,你在大学的时候做的家教、兼职也不重要。你要来面试的是一份
技术工作**、技术工作技术工作,不是销售,也不是大家老师。如果你是党员,你也不用突出你是有多爱党。毕竟,作为一个普通人,我们都拥互党的领导的。

不作死

罗列技术栈。不要在简历上,写上太多的无关技术栈。写到简历上的东西,都会成为你的呈堂证供。如我毕业的时候,准备了三种不同类型的简历,嵌入式工程师的、Web 工程师的、包含两者的。然后在专业技能上,我列举了我玩过的各个东西。在现在看来,简直是。。。

罗列技术栈

简直是作死。当年,我写在简历上的每一个内容,都被一一过问了一遍

程序员该如何去写自己的简历

简历就是简单的介绍一下你自己有多 NB。所以,你需要介绍以下的内容:

  1. 我是谁
  2. 我会什么
  3. 做过什么
  4. 结果如何

然后把这些内容放到一个模子里,就可以了。

选择一套模板

如果你并非设计师,或者想要相关的求职岗位,那么请不要在简历的样式上花时间。你应该将更多的时间花费在简历的内容上吧。作为一个技术岗位,面试官想看的是你能干什么,而不是漂亮不漂亮。你又不是要面试 鼓励师程序员 = 鼓励师 + 程序员。

然后推荐下我用的模板,LaTex 里的 modercv 模板。就是这样的效果:

LaTex简历模板

这个模板最大的优点是,写废话的地方很少。最大的缺点是:你需要学习 LaTex。你可以轻松地写上你的各种经历,并且排版出来的效果很不错。

首屏加载:在第一页尽可能突出自己

这里有一个突出自己的,最好例子:

本人学识渊博、经验丰富,代码风*、效率恐怖,c/c++、java、php无不精通,熟练掌握各种框架,深山苦练20余年,一天只睡4小时,千里之外定位问题,瞬息之间修复上线。身体强壮、健步如飞,可连续编程100小时不休息,讨论技术方案5小时不喝水,上至带项目、出方案,下至盗账号、威胁pm,啥都能干。泡面矿泉水已备好,学校不支持编程已辍学,家人不支持编程已断绝关系,老婆不支持编程已离婚,小孩不支持编程已送孤儿院,备用电源万兆光纤永不断电断网,门口已埋雷无人打扰

因此,你要保证 HR 可以轻松地打开你的简历,并且可以看到他们想要看的内容。如果你使用 GitHub Pages 和网页的时候,就要注意这个问题。并不是所有的 HR 都会翻墙的,并不是所有公司访问外网都会很轻松的。

你刚毕业不久的时候,你应该突出你在学校的成果:

在校情况

工作的时候,便是突出你的公司,和 NB 的项目。

毕业到工作:从看学校到看公司

校招的时候,你可以把你在学校玩过的各种东西都写在上面,如下:

学校简历

就是要把你玩过的、觉得很 High 的东西都往上写。毕竟大部分人都是玩游戏过来的,然后你还玩过这么多东西,面试官对你的印象一定特定好。不过,还是那一点,不要造假——写到简历上的东西,都会成为你的呈堂证供。作为一个 Play for Fun 的程序员,谁的大家不是这么玩过来的。

除了这种玩可以为你加分之后,还有:

  1. 211 985高校加分
  2. 硕士学历加分
  3. 大公司实习经验加分
  4. GitHub、博客加分
  5. ACM 等比赛加分
  6. 项目经验加分
  7. 等等

而,等你工作多年后,教育经历就变成无关经历了。这时候加分的内容就变成:

  1. BAT 等大公司加分
  2. NB 的开源项目加分
  3. 与本公司相关的项目经验加分
  4. 行业大牛,自带光环
  5. 技术栈完全匹配加分
  6. GitHub、博客加分
  7. 认识 Phodal 加分 (笑~~)
  8. 等等

这个世界就会从看学校到看公司。所以,如果你毕业的时候遇到这样一个选择:大公司还是创业公司。请考虑上这一点因素,如果这家创业公司倒了,那么你的下家就不好找了。反之,你从大公司要进入小公司,则是轻轻松松地一件事。

(PS:我的干货就到这里结束了,以下是广告时间。)

小结

当然了,简历再漂亮,能力不行的话,你也是进不了进一轮的。这时候,你一定需要新版的 Growth 2.5.0,我们将带你成为顶尖开发者:全新的技术树、全新的学习体验。下载链接(http://a.app.qq.com/o/simple.jsp?pkgname=ren.growth)。

学好编程,你还需要这个开源APP | Growth 2.0现已发布

终于等来了Growth 2.0从APP Store审核通过了,想想觉得这个过程也蛮不容易的——从最早的一篇文章开始,然后变成了一个APP,它还衍生出了两本电子书。今天它仍然再前进着,也希望它能带领大家一起前进。

Web应用开发过程与Growth

在那篇RePractise文章里,我们提到过Web的开发过程是这样的七个步骤:

  • 前期准备
  • 编码
  • 上线
  • 数据分析
  • 持续交付
  • 遗留系统
  • 回顾与新架构

再加上一个初学者在最开始的时候需要一些基础知识,就构成了Growth的基本内容了。

main-view.png

经历了一个又一个的项目,我们就会得到这样的经验。大部分的项目也是这样的开发过程,那么这就是很理想的学习资料了——这相当于是我们的业务,既然我们的业务已经稳定了。那么我们就可以在这之外一点点补充我们的技术即可,而这些技术并不局限于任何特有的框架和技术。

换句话来说,这只是一系列的理由知识。所以在第一个版本之后,人们就希望上面可以有实战的内容,还希望有一些实战项目。因此就有了两本电子书《Growth:增长工程师实战》和《Ideabook:练手项目集》,在2.0里这两本电子书也放到了里面:

ebooks.png

最开始的时候,在写实战这本电子书的时候我是拒绝的——不想受限于技术栈。在里面我们使用了Python语言,并使用了Django作为Web开发框架,使用Ionic作为移动应用的框架。也因此我们的开发速度相当的快,我想这也会让大家有更快的学习速度。

在编程世界里探索

在学习的过程中,人们需要有一些测验、有一些练手项目、还有一些发展路线,这就变成了我们的探索栏目。对于测验功能来说,要做起来倒也是容易——无非就是收集一些面试题,然后提问呗。

quiz.png

对于学习路线来说,可能就不是那么容易了。需要尽可能地去收集某一个领域的技术栈,然后一一分类,再做出一些合适的判断。

roadmaps.png

然后,我们还需要一些练手项目,但是现在有太多的新技术。我们还需要尽可能多地将他们一一地罗列出来:

practises.png

某个瞬间想到了自己整理的自己的工具箱也可以变成大家的工具箱,就有了这样的一个新栏目:

toolbox.png

当人们学习到一定的程度就想着去寻找一些解决方案了,想了想这似乎也是我擅长的内容,就有了:

solutions.png

这个APP很快地就变成了一个Awesome Lists了。收集用户反馈在很多时候都不是一件容易的事,而在这个时候我们只能一点点的去判断。有时候,难免会做出一些错误的判断。

累!

很多琐事做多了也就觉得有点累,而这时候你的APP突然又有可能遭遇这样的场景!

1stars.png

还是会觉得心里有点不爽。所以,如果你觉得这个APP好,那么你就给个好评呗:

ratings.png

它开源并且免费,而且数以万计的人正在使用它。

下载地址:http://growth.ren/

或者在APP Store以及相应的Android应用商店搜索:Growth,或者搜索Fengda。

从2016年11月期ThoughtWorks《技术雷达》看前端的未来

本文仅代表 Phodal 的个人观点,来听听一个前端程序员的 YY。

新一期的技术雷达有点出乎意料,使用new标签的框架、工具、技术、语言等等超过了一半——Vue.js、ES2017上榜,Three.js凭着VR的火又上榜了,还有熟悉的Electron,以及微前端的概念。

让我们先看看一些技术亮点~~。

前端在可见的未来


在那篇《最流行的编程语言JavaScript能做什么?》的文章里,我们看到了JavaScript在各个领域的应用。在这一期里,仍然有很多亮点(new):

Vue.js

Vue.js,如果你在使用Vue.js,那么你更应该找到相当的自信了,现在它已经被列入了评估期了。Vue.js是一个简单易上手的框架,并且相当的轻量,在最近的这段时间里,它发挥得相当的出色。

可惜,宝宝现在在用Angular.js 和 Angular 2,毕竟我现在是开发混合应用的。不过相信在半年后,Angular 2 和 Ionic 2是会上榜的。

Ember.js,尽管没有证据表明这个框架在国内将火起来的趋势,我现在还对这个框架缺乏深入的了解。

ECMAScript 2017,尽管我现在已经倾向于使用TypeScript,不过 ES2017 还是会用到的,只是我觉得 Babel 对我来说就是个坑啊

PWA

Electron,如果你是一个老读者,那么你已经知道我在很多场合里使用了这个框架,从NodeWebkit开始写编辑器,再到用Electron完成Growth 1.0的桌面版。

Physical Web,现在我们可以在浏览器上来控制真实世界,通过蓝牙低功耗技术。

不过与此相比,我更看好 Progressive Web App,毕竟他可以让Web应用接触到更多的底层API,而不是局限于蓝牙,还可以是Push Notification等等。

VR

Three.js,它上榜的原因是因为 WebVR 的流行。这一点可以从我去年写的那篇《Oculus + Node.js + Three.js 打造VR世界》,就可以看到一些趋势。这些就和现在的单页面应用一样,虽然运行起来不是那么流畅,但是还是行得通。因而在可见的未来使用 Web 技术来开发 VR 也有一点苗头,未来浏览器上应该是可以运行编译过后的代码,而不是在运行时。

WebRTC,它可以让我们在浏览器端实现实时视频聊天。第一次接触到这个视频流技术是在两年多以前,上一次接触则是在半年多以前使用 WebRTC + Oculus,你可以在我博客的那篇《JavaScript在VR世界的应用》中了解到更多的详细信息。当然如雷达所说,WebRTC将会形成未来在Web上进行AR/VR 协作的基础。

接着再让我们看看一些架构上的变化吧。

前端引起的架构变化


在过去的两三年里,前端火得一塌糊涂——对于后端程序员来说,这有点 winter is coming 的感觉。我在那篇《前端演进史》对前端的演进做了相当多的介绍,并在《后台即服务演进史》里对后台即服务开了个头,在这篇文章里让我们根据《技术雷达》来继续补几刀。

前后端分离

我们可以看到在中大型团队里,已经分解为前端和后台两个小组,沟通可以通过接口、契约等等的方式来进行。但是这一点儿也不精益,沟通在这时仍然是一个问题,让我有点怀念起之前前后端都做的项目了——自己可以创建自己想要的接口。

不过,这意味着前端和后台在技术选型上更加独立了。

臃肿的前端——微前端

前端单体应用

在上一个项目里,我们一步步地将一个有近10年系统的系统替换掉。起初这是一个传统的Spring + JSP网站,然后我们用JSP创建了JSON API,后来创建了一个新的 API 来服务移动应用和单页面应用,再后来这个 API 被拆分成了几个 API。我们的后台已经成一个单体应用变成了一个微服务架构的应用,但是这一点并没有在前端上应用——前端应用正在变得难以维护。

因此在这一期的雷达里,你可以看到微前端的概念(micro frontends)。这也是在上一个项目里,我们尝试做的一部分,遗憾的是并没有成功完全实施。这是一个搜索类型的网站,网站的首页承担着大部分的访问量,而详情页的主要流量来源则是搜索引擎。我们在首页上使用jQuery + Require.js技术栈,而在其他页面(搜索结果页 + 详情页)使用 React.js,我们在最初的时候考虑过将详情页静态化——因为需要 SEO 的缘故,这样可以让我们降低 SEO 带来的复杂度。

MicroServices

后来,我也在我的博客上解耦了两部分,为了更快的访问首页的速度——将首页独立出来,不使用JS,直接使用Pure.css来担重任;在其他页面里使用Material Design Lite作为 UI 部分。

有一点值得考虑的是:对于微服务架构来说,在一个系统的不同的部分使用不同的技术栈是一种不错的体验;而对于一个前端团队来说,在同一个系统的使用不同的技术栈就不是一种不错的体验。

API 设计——应该变得简单

Backend

如我们所见的Spring Boot已经变成推荐采用的程度了,按雷达上的习惯用语:“我们已经在多个项目上使用这个框架”——反正我最近的项目都是用这个框架。如果你考虑使用 Java,那么你一定不要错过这个框架,以及使用这个框架来实施前后端分享。

对于大部分不需要考虑 SEO 的应用来说,将后台变成一系列 RESTful 的 API 并不是一件复杂的事,但是在后台 API 上的设计就变成一件麻烦的事。因此尽管在实见的过程中,有契约来作为保证,但是不一定是可靠的。作为一个前端程序来说,我们在调用后台 API 的过程中,总会遇到这样、那样的问题。除此,还有接口不好用的问题——“要是你可以在这里使用超媒体 API,那么我的代码就会更加简单了”。

因此在 API 设计上,雷达上给出了两个不错的案例:

强化后台查询

GraphQL

代表的例子就是 Facebook 的 GraphQL,它是在 Facebook 内部应用多年的一套数据查询语言和 runtime。原本为了请求一个用户及其好友信息的请求,需要发起多个 API 请求。现在,我们只需要在客户端拼装好对应的 Query语句,在这个语句里将大部分需要查询的东西写好,即 JSON 格式的数据,然后发给服务端来处理。而在我们客户端上,我们所获取到的结果都是我们所需要的,不需要再做特殊处理了。

这一切,看上去很美好——除了,在客户端上拼查询语句。

过去,我们使用搜索引擎来搜索数据,就需要在前端拼好对应的 Query,再传给后台 API,由后台 API 返回我们需要的结果。在这个过程里,我们在Query做一些对应的数据处理。

反正,他们都是使用查询语言来搜索结果。如果你考虑使用 QL 的话,不妨做一层 Wrapper,以后好做迁移。

前后端同时优化

Falcor

Netflix对于这样复杂的API请求下,创建了 自己的库Falcor——它可以从多个数据源获取数据,并在服务端上汇总成一个 JSON model;在客户端上,请求的时候我们只需要在请求的时候加上对应的参数即可——可以将多个请求合并到一起,也可以只针对某一个部分发出请求。这样可以减少发出多个请求,所带来的复杂度。

我想,一种最实用的做法:就是将一些更新频率较低的API合并成一个大的 API 了——大部分人都会这样做吧。

简化的后台——无服务器架构

ServerLess

除了上面的这些内容,后台还有一些东西还蛮好玩的,其中一个就是 Serverless 架构,即无服务器架构。不过,这种架构目前在国内运行起来还是有点难度的,缺少一系列的配套措施。如在这期的雷达上的Auth0可以为我们提供一个授权服务,以及AWS Lambda可以直接使用 AWS系列云服务来对数据进行处理。

我就不多说了~~,读者可以自己去看。

那么未来,你看想玩哪种技术。

访问 https://www.thoughtworks.com/cn/radar 获取最新一期ThoughtWorks技术雷达

(PS:如果你访问不了原文链接,可以修改DNS为 8.8.8.8,或者放在我的GitHub Page上的备份:http://radar.phodal.com/2016.pdf

关于编程,你的练习是不是有效的?

最近由于工作及Solution项目的影响,我在重新学习DDD和领域建模的一些知识。然后,我突然就相到了这个问题,以及我是怎么做的?

对于我来说,提升技能的项目会有四种:

  • 纯兴趣驱动的项目。即我的Idea列表上的一个个酷炫的项目,先满足自己再说。
  • 理论驱动的项目。这一类的项目会比较少,因为我们需要牵强地驱动出这样的项目,然后以理论的方式驱动它。
  • 兴趣结合理论型。有一个长长的Idea列表,难免有些时间会和将要学习的理论有很大的交集。这种的练习效果是最好的。
  • 整合成文章、电子书。这一步主要是为了分享、巩固知识点、讨论。

简单地来说,就是:

  • 刻意的理论练习
  • 兴趣实践

两种不同的走向,上面的第三点和第四点,算是获得一些更好的效果。开始之前,让我们再次讨论一下情绪周期的问题。

编程与情绪周期

如果你每天都有很多可支配的自由时间时,你也会观察出情绪周期这件事。

所谓“情绪周期”,是指一个人的情绪高潮和低潮的交替过程所经历的时间。

这种周期看上去就好像是一图所示,但是总体上好像会长一点。

情绪周期

这一点在我的GitHub上看起来就有点明显了,至少它是一年的一个周期:

GitHub与编程的情绪周期

对于我来说,我会交替写代码和写博客、电子书。因为它以一定的规律在迭代着:

  • 适合写大量代码的日子
  • 适合学习理论的日子
  • 适合玩游戏《文明》、看电影、睡觉的日子。一般来说,这种事件的出现天数比较少。

主要还是集中在前两点上,代码练习与理论学习。

练习与计划

持续性

对于练习来说,需要保持相当高的持续性。很明显的一点是,参考我的GitHub的连击。对于我的连击来说,主要有下面的两个意图

  • 装逼
  • 驱使不断自己练习

如果有一个很好的动机来驱动自己去练习编程,那么GitHub的连击就是一个很好的入口。当然,GitHub已经不再显示连击多少天了。

在我们达到所谓的10000小时之前,我们还需要这么久:

10000.png

这只算上了工作上的时间,如果我们还有一半的时间也在练习上面,那么就会缩短为2.4年?

答案是:不可能!

怀孕需要10 个月,但是显然即使10 个人同时努力,也不能在一个月内生下孩子。

为了保证更好的练习效果,我们需要在每次短暂的时候之后,休息一段时间。为了实现这个我们可以用两种方式:

  • 多喝水。无论是学习还是工作,喝水总是有利于大脑思考,还有利于你多上厕所。多走动,可以防止你有各种职业病。
  • 采用所谓的番茄工作法——可以找个借口让自己休息。

番茄工作法

不断地休息,才能让下一个练习走得更往,这样才能保证好的练习效果。

练习之前,你需要知道三件事

  1. 练习要有计划才会有效果的!
  2. 练习要有计划才会有效果的!
  3. 练习要有计划才会有效果的!

对于不同的类型来说,你需要不同的练习计划。

编程:使用新技术、新**

在练习编码的过程中,使用一些新的技术和新的编程**可以帮助我们走出舒适区。当然如果你要在项目上用上新技术的时候,你也会采取相似的练习来做这样的事。而这也是大部分人尝试新技术的开始,如在每个新的编程语言的入门手册上,他们都会来一个经典的:

helloworld.png

然后我们就会做一些类似的项目来快速上手这个语言,如以前我们用Java实现了一个Blog系统,我们就可以用Node.js实现一个Blog系统。同样的,我们也很容易将其应用到不同的语言环境中。

假定,你在A项目上使用了Java语言,而你们的新项目使用了是类似于A的业务,那么你就可以采用新技术或者**来实现。

理论:练习和总结

理论本身有可能很难理解,从而很难应用。因此,在学习理论的最好方式还是应用,而要构建一个好的场景并不是一件容易的事。

我们需要不断地探索过别人实践过的一些例子,模仿一些相似的用法,然后创建自己的类似的项目。同样的,我们还是可以基于我们以前实践过的项目,在那之上做一些改进来学习理论知识。

理论还有一点比较麻烦的是,记住它。在我们练习了很多之后,我们可能很快地就忘记它了。因此,你需要笔记或者博客来做这样的事。

不过,我还是觉得博客比私有化的笔记会有一点,好的东西应该分享出来。既然你都已经保存了,那说明它很重要。既然它对你很重要,那么它也对别人很重要,要不你怎么会保存呢?

最好是能写一些文章来发现自己了解了多少,如果是一系列的理论,那么就可以整理成电子书了。

一个前端程序员的一个月原生 Android 开发体

一个前端程序员的一个月原生 Android 开发体验。自从我写了 Android 应用后,上知乎的时间变得更长了。

自从我写了 Android 应用后,上知乎的时间变得更长了。哦,不对,你理解错了,我的意思是:编译代码、打包 APK、运行在设备上需要时间。可不像前端,一保存代码,就自动刷新页面。

是的,从上上周一开始,因为项目缺人的原因,作为一个有 Java 开发经验的大前端,我又又双叕进入了原生 Android 开发的世界。

这一个月下来,也算是有一些写 XML 的心得吧——不对,写 Java 代码,看 Kotlin 代码的心得。总的来说,Android 与前端的差异并不是非常大,在某些东西上,他们还是蛮相似的。怪不得像我这样的程序员,会将 Android 开发也归类到大前端上去。

如果你是一个前端程序员,想学习移动开发;又或者是一个移动开发,想接触前端开发;那么,本文可能就很适合你去了解两者间的差异。

本文包含了以下的内容:

  • 编码效率 vs 可维护度
  • MVP vs MV*:后天的 MV*
  • 静态语言 vs 动态语言
  • View 与 DOM
  • 代码调试
  • 兼容性

(PS:受限于我只有短暂的经验,所以有些用词可能没有那么准确。)

:这里的前端应用特指单页面应用

编码效率 vs 可维护度

因为从运行效率上来说,原生应用必须远远大于 WebView——毕竟 WebView 的背后还是原生应用,直接等于中间多了一个层级。所以,在这里直接讨论编码效率。

Web

从编码效率上来说,还是前端快,快得不止一点点。

  • 更快的预览速度。
  • 成熟的生态系统。
  • 大量可用的 UI 框架及组件。
  • 参考别家的实现。Web 前端是开放的世界,在今天来看,要实现的效果基本上已经被实现过了,所以我们可以直接参考
  • 富文本支持好

而考虑到 Android 和 iOS 是各自实现的,那么一个混合应用的开发效率可能是远远大于 2 倍,而跨平台应用(如 React Native、Weex、NativeScript) 的开发效率会接近他们的 2 倍(原因是:集成某些功能时,需要原生代码来实现,这时工作量直接翻倍等同)。

Android

从目前的维护程度上来说,还是 Java 的代码相对维护。主要是前端领域的变化太快了,并且在软件工程上的实践不像 Java 是必需要求的,因此容易出现大量的遗留代码。只是考虑到,Java 代码的臃肿,还是改用 Kotlin 吧。

Android Studio 转 Kotlin

只需要按下: Command + Alt + Shift + K,轻松当爸爸。

MVP vs MV*:后天的 MV*

MVP,即 Model-View-Presenter,对应于视图层-数据层-展示层。

在 MVP 上来看,前端应用与 Android 都并非天生的 MVP 架构的。不过,两者在对业务逻辑上的处理,但是没有多少差异。唯一能体验差异的,可能就是 JavaScript 的异步,以及 Java 的同步带来的一些差别。

V*

采用了框架的前端应用,则会因此而带上 MV* 的加成。一旦选用上了某个框架,那么你只能按照其特有的模式,如 Vue 提供的核心是 MVVM 中的 VM,React 则只是 MVC 中的 View 层,则 Angular 则可能是 MVW(Model-View-Whatever)。在这种情况下,要在框架的基本之上变更,那么灵活性上可能没有那么大。

而 Android 方面则是 MVP 架构,其主要依赖于约定俗成,其中一个参考的规范就是 Google 官方的 android-architecture,又或者是社区上推荐的 Clean Architecture。而无论是 Clean Architecture,还是 MVP,其都依赖于约定。一旦我们谈及参考的时候,便意味着灵活性——可遵循,可不遵循。

在这种时候,Android 的 MVP 需要我们自己去创建 MVPView,创建 Presenter。

public class MainActivity extends AppCompatActivity implements MainView {
	...
}

而整个 MainActivity 只是一个 View 层,真正的业务逻辑要交给 Presenter 来处理。简单来说,就是你需要手动地创建四五个类,才能完成一个 Activity 的 Hello, world。

Model

与此同时,Android 默认是要对 Model 进行校验和转换的。因为取出 JSON 中的某个值,需要将 JSON 转换为对象——可以直接使用 Retrofit 库来转换数据,又或者用 GJSON 转换成某种对象。算是与前端的一个大的区别,在前端世界里,这种事情是轻而易举的,有万能的 JSON.parse

在使用 JavaScript 编写的时候,可以不对 Model 进行校验。不过,在 React 里会有 proptypes,在 Angular 里可以用 TypeScript 来做相似的事。

与没有对象校验的前端相比,一旦出错,根本不容易察觉。这一点,或者也是一个优势所在——当你上架了新版本的 API 时,旧的应用不会 NullPointerException。与此同时,在开发的时候,后台 API 发生变化的时候,也会导致后续的一系列 bug。

静态语言 vs 动态语言

自从我写了 Android 应用后,上知乎的时间变得更长了。

编译与动态运行

当我们编写 Web 应用的时候,只要一保存代码,网页就可以由 LiveReload 这样的工具来帮我们自动刷新。于是,在诸如 React Native 这样的跨平台框架里,也有 Live Reload 这样的特性。

而当我开发 Android 应用的时候,每次我想试着在手机上查看效果的时候,得构建、编译代码、安装,大概得等上个两三钟才能运行在虚拟机或者真机上。

Android Studio Process

可事件往往不会这么顺利,动不动会遇上个 NullPointerException,然后应用就 Crash 了。这个时候,就要去修复代码中的问题,加个 blabla!=null,然后编译,继续 Crash。

怪不得 Android 的程序员喜欢上了 Kotlin,只要一个 view? 就能判断是不是有值的事:

override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    val view = inflater?.inflate(R.layout.fragment_home, container, false)
    val button: Button = view!!.findViewById(R.id.open_rn_button)
    button.setOnClickListener(this)
    return view
}

可由于没有经验,我经常把 val 写成了 var。这就和那些习惯写 alloc init 的 iOS 程序员,一夜间突然喜欢上了写 ES6 一样:

let className = NSStringFromClass(MyClass)
 let classType = NSClassFromString(className) as? MyClass.Type
 if let type = classType {
   let my = type.init()
 }

哦,不对他们写的是 Swift。

并且作为一个面向对象的语言,Java 天生就意味着,大量的臃肿代码。

public int getId() {  
    return id;  
}  
public void setId(int id) {  
    this.id = id;  
}  
public String getName() {  
    return name;  
}  
public void setName(String name) {  
    this.name = name;  
}

大量的代码,就意味着大量的 bug,一定量的重复代码,一下子又回到设计模式的天下。

IDE 支持

好在,由于 Android Studio 有强大的、良好的 Intellij 支持。在 IDE 上对语言的支持,要比 JavaScript 的第三方库支持友好得多:

静态语言

要知道 WebStorm 或者 Intellj IDEA 专业版,它们在 JavaScript 第三方类的支持上就是坑。

View 与 DOM

过去,前端在 DOM 操作上存在天然的问题,即在我们使用 $("*") 的时候,全局。当然现今的框架,在这个问题上比较少,但是考虑到仍然可能会被误用,或者注入。而 Android 则是局部页面的。

样式复用

前端使用 HTML + CSS 来编写样式,而安装则只使用 XML 来切图,这并不是一件容易的事。不像 CSS 可以通过 “继承”
和 “覆写” 的形式来实现样式复用。Android 中也有类似于 JavaScript 生成 HTML 的方式,自定义模板。

当我们使用 React 编写组件的时候,可以传递对应的属性到组件中,这个属性可以是函数、值、组件等等。

MyComponent.propTypes = {
  optionalArray: PropTypes.array,
  optionalBool: PropTypes.bool,
  optionalFunc: PropTypes.func,
  optionalElement: PropTypes.element
}

而在 Android 的布局上,这就不是一样容易的事。为了复用样式,需要抽取成 UI 组件,还只能是 UI 上的组件。只能实现 HTML + CSS 上的复用。

HTML + CSS 在编写 UI 的时候,有各种奇技淫巧,比如说样式的优先级,或者 important

双向绑定

从原生的角度来看,前端的 document.getElementById() 与 Android 的 findViewById 并没有多大的区别。而当前端有了前端框架之后,就不一样了。好在 Android 有 ButterKnife 这样的 View 注入框架。

与此同时,Android 还自带了双向的 DataBinding,而原生的前端是没有的。

只是前端有前端框架,在这一点也完全问题也不多。

布局调试

还好,已经有写 React Native 布局的一些经验,在写起 Android 的布局,倒也还好——没有那么坑。

在布局调试上,还是前端用浏览器调式方便——还可以在浏览器实时修改 DOM 结构。Android 也有这样的工具,叫Layout Inspector

Layout Inspector

除此,还可以通过 Facebook 家的 stetho 做与 Web 相关的调试工作:

Stetho 调试示例

总的来说,还算是不错的。就是这个结构,看上去和 React Native 怎么那么样呢?

代码调试

在代码调试上来说,Java 底子厚,总的来说会比 JavaScript 好一些。

Android 调试

除此,记得我们在 Chrome 浏览器里可以打断点,随后在 Console 中做出一些计算。而得益于 Android Studio 背后的 JetBrain 的 Evaluating Expressions,可以实时计算表达式的值,Android 上的代码调试也是很容易的。

Evaluating Expressions

而以我有限的 Objective-C 编程经验来说,XCode 也是可以做到的。

网络调试

在 Chrome 浏览器里,自带的 NetWorks 几乎是万能的。Android 方面也可以借助于 Stetho 来使用:

Stetho 网络调试

但是依赖上比较大,需要在页面上注入,并且调试不了插件化的应用。要调试网络吧,还是 Charles 好用一些。

可是,万一开发环境 HTTPS 了呢,不就更麻烦了。

兼容性

前端面临的是调试不同的浏览器,又或者是兼容 IE。总的来说,问题都不大——不会面临闪退的问题。即使出了点小问题,用户可以先换个浏览器试试。而当你的 Androdi 应用在用户的手机上闪退了,那么用户只能换个 APP 了。

除此,Android 则是面临碎片化的系统,不同的版本,及不同的屏幕大小,总的来说,要对前端复杂得多。

结论

Android 在软件工程上做得相当优秀,而前端则是在开发效率上占优势。

Web 开发大法好。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.