Hao
Hi, I am Hao (👋): a coder, a woodworker, a blogger, and a father.
工作四年感受

没有任何提醒的情况下注意到了公司个人页面的年限那一栏变成“四年”。对于之前几份工作平均在职一年即跳的我来说,可以称得上里程碑事件。里程碑最大的作用在于反思和总结。于是想记录一些基于个人视角的感受。由于之前工作经历繁杂、样本数有限,且公司规模和文化完全不同,很难把在Google工作的四年与其他经历相比较,反而是疫情把四年时光撕扯成两半,被新环境格式化后的大脑产生了另类的新鲜感,所以感受大多停留在Google本身上。 相关人士 级别越高,合作的人就越多。初级程序员只需在TL的领导下,埋头苦干,快速把想法变成代码。待到资历加深,负责的内容愈来愈多,打交道的人变成了PM,UX,Infra,以及项目所涉及的其他部门的工程师…… 合作的人变多了,输入和输出的信息也成倍增加。如何进行有效的沟通管理,如何当一个好的合作者,都大有难度。 此前我对大厂的偏见是:分工过细,每个人都是螺丝钉,日复一日...

04/2022
使用树莓派、Alexa和Siri打造智能家居系统

引言 需求、目标 硬件购买清单 基础设施设置 树莓派 使用 Homebridge 连接 Siri Amazon Echo Dot ESP8266 NodeMCU 模块 灯 整合到语音控制 空调/风扇 门锁 引言 我目前的住址是唯一硅谷圣塔克拉拉某条街道的一间公寓。公寓不大,但是有很多墙壁开关和墙壁插头。其中某些开关可以控制某些插头是否通电。美国的公寓一般在客厅没有屋顶灯,一般情况下美国人把落地灯连接到墙壁插座上,然后通过能控制它的开关来开关灯。 听起来好像很方便,但实际上造成了巨大麻烦。插座的位置固定,所以落地灯的位置也必须靠近插座,否则就得使用难看的复杂的延长线。第二,由于开关在门口,所以想关灯只能走到门口去。 另外一个生活上亟须解决的...

07/2017
Leetcode Q10 正则匹配动态规划解法

这道题首先要把题目读懂,不然会因为想当然而制造了很多错误的解法。在isMatch()这个方法里,要求前者s与p模式匹配,而不是s是p的子集或者相反。另外,关于星号的定义也与真正的正则不太相同。这里的星号”*“是要匹配星号前面的字符,有零个或者多个。因此,根据题目可以假设模式中如果出现星号,则星号之前必然有字符,而不会出现诸如”**“这样的字符。 因此,我们可以稍微改变一下匹配字符p的形状。在没有星号的字符后面认为添加一个不存在的字符(比如”#”号),使得这个匹配字符工整,方便后续操作。 这样的转换下,如下字符则会变成下列的样子,把新生成的字符叫做pp: a -> a# aa -> a#a# a*a -> a*a# 因此制作如下两个辅助私有方法: // 判断当前字符是否是多重匹配 private boolean isMultiple(int i, Stri...

06/2017
使用Hammerspoon自动化工作流

引言 我的一些配置:~/.hammerspoon/init.lua 使用alt + 字母组合键快速启动应用 使用alt + 字母快速打开某个Chrome标签页 快速修改窗口为屏幕尺寸的30%, 50%或者70% 快速切换Chrome用户,打开隐身模式窗口 休眠Mac 连接到工作网络WIFI后,自动静音电脑 快速添加提醒事项 Mac上录制键盘宏 引言 作为程序员,我一直致力于避免来回从鼠标/触摸板和键盘之间切换。因为程序员花大量的时间在黑漆漆的屏幕上,而鼠标相比键盘来说效率要逊色太多,这一点随着屏幕尺寸的增大越发明显。最近我发现了一个叫做Hammerspoon的强大工具。下面我会分享一些我自己的使用技巧和心得。有些技巧非常有用,能够极大提升电脑的日...

06/2017
在iPhone上同时登录两个微信的方法

在iPhone上登录多个微信早年有一些类似“微信分身版”这样的奇淫技巧,但是随着腾讯和苹果以封闭为目标的不断耕耘这些方法已经纷纷失效。本文介绍另外一种办法,通过在服务器端架设破解了微信通讯协议的机器人,从而达到在手机端登录浏览器即可访问多个微信的方法。 这个方法主要使用了https://github.com/Urinx/WeixinBot 这是一个基于python的微信API。因此,思路主要是在云服务器上运行架设一个机器人,用手机微信扫码登录开始一个微信instance,该instance提供收取消息和发送消息的接口,同时在网页端架设简单聊天UI,每次手机只需要访问这个网页即可登录该微信账号。 服务器 使用最简单的Flask来作为web服务器。考虑是个人使用,因此只需要运行一个微信实例: # app.py if __name__ == '__main__': web...

01/2017
使用Javascript的KMP算法

KMP算法中比较麻烦的是生成匹配数组的部分。《算法4》里Sedgewick使用一个非常难懂的DFA概念,再加上charAt()方法字符和整数的混乱转换,让这个部分变得非常难懂。网络上也有对KMP算法的解释,但是对如何生成匹配数组的部分却含糊不清。经过一个小时的认真研究画图,终于算是弄懂了生成匹配函数的原理。对于KMP的原理和匹配数组的使用,多有文章介绍,此不赘述,这篇文章主要介绍匹配数组生成的原理。 // pattern ABCDABD // @param String pattern // @return Array var fail = function(pattern) { var mode = []; for (let i = 0; i < pattern.length; i++) { mode[i] = 0; } ...

09/2016
两个有序数组找中位数的Javascript解法

There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)). 此为LeetCode的第四题,却花了我五个小时时间才做出来,题干格外精简,不愧为“Hard”模式的难题一道,因此要好好记录一下解题过程: 计算中位数需要考虑数字总数为奇数或偶数,计算中位数的方法也不一样。为了方便思考,首先只考虑总数为奇数的情况,即 (m + n) % 2 !== 0; 中位数不只是一串数字的中间数,它还有一个明显但却很重要的性质:大于和小于中位数的数字数目为总数 N / 2. 比如在如下一列数字中,排列在中位数后面...

07/2016
一些前端技巧

以下是前端开发来的一些有用的小技巧。 网页顶部100%高度 任何一个有节操的网页设计师都不会创造出一个带有100%可视区域高度的顶部的网页来,因为这样会造成很多问题。如果网页高度太窄,则100%顶部区域内的很多部件会错乱(显示不全、导航条位置错误等等)。 然而好马虽多,良驹尤少。面临一份带有100%高度顶部的设计图时,妄图使用100vh或者Javascript来即时调整文档结构的办法都是不切实际而且注定失败的。对于第一种方法来说,首先有兼容性问题,其次在移动Safari浏览器下有bug。第二种方法来说,使用Javascript来调整结构无异于杀鸡取卵,高射炮打飞机的行为,不仅会让网页变慢性能降低,还会让人产生脱裤子放屁的错觉。 正确的办法是使用如下代码。优点:无兼容性问题,原生态速度快,可拓展性极强。 <div class="container"> <...

04/2016
记录一个优雅的React框架解决方案

从14年开始接触React,已经一年有余,不仅在公司的大大小小项目上全面采用基于React的前端架构,也在自己的私人项目上大量采用。React不仅搭网站上效率感人,结合Electron后写全平台桌面应用也是十分方便,实乃居家旅行必备工具。但当年jQuery的地位似乎也是如此,在前端这个技术爆炸的行业,React未必会坚持很久。很快就会有更新的技术理念诞生。因此,一个小巧、可靠、可扩展的简单架构是应用开发的王道。开发者不必受限于大型架构的种种限制,而可根据实际情况灵活变化。React中的Flux架构已有多重实现,除了官方的Flux外,还有Fluxxor,Redux,Reflux等,无一不要引入大量概念和模块,使简单的模型也变得愈发笨重。我认为React本来并不是为了大型Web应用而准备,但却具备其潜力,并且以模块化的思想使开发过程变得异常简单。 我所使用的最后一个React架构,严格...

04/2016
React搭建大型应用的载入优化和SEO优化

最近发现公司的基于React全面架构的网站面临两个严重问题。 一是载入速度:网站所有的部分都被分成模块,以页面为单位交织在一起,形成了一个巨大的Javascript文件,体积大概有600+KB,尽管使用gzip压缩到200+KB,但是在网络缓慢的情况下用户还是在开始的阶段看到一片空白。 二是SEO问题。这个问题期初并不严重,但是由于网站内容增多而无法被搜索引擎收录而变得严重起来。 其实对于两个问题有一个通用的解决方案:使用React.renderToString()在后台快速渲染页面。这个方法有一个非常严重的问题,首先是代码中有很多基于jQuery和velocity的DOM操作,这都需要window对象,然而在服务器渲染中,是没有这个对象的。第二,webpack打包后,尽管设置了target: "node",却始终无法在服务器中require。这就导致一些网站的UI部分(Les...

11/2015
把Electron应用发布到Mac App Store

2016年9月17日更新 本文已经过时。按照最新版本的指南即可顺利发布。需注意的是,目前Electron不支持bookmark entitlement,导致某些应用需要存储本地文件的功能将在重启后失效。 2016年4月21日更新 根据这个Issue,似乎0.37的签名问题得到了解决。 2016年4月10日更新 由于Electron最近一次0.37升级中Chrome版本升级导致签名后的应用异常(issue),在此情况下使用0.36.12版本。 原文 把做好的Electron应用发布到Mac App Store上需要一定的难度。首先,很多人使用electron-packager来简化发布流程,但是实际上,在他们正式推出mas(Mac App Store)平台的发布包之前,我并不建议使用它。因为目前(2015年11月10日前)electron-packager只支持darwi...

11/2015
React基于Pub/Sub的简单架构

在上篇文章中,我在比较了Flux和Redux两个架构中提出一种基于Pub/Sub观察者模式的架构,但在实际使用中发现效果十分不理想。虽然有了PubSub,但是由于动作发出者和接受者经常是同一个对象,导致当程序体积扩大后,代码十分混乱,并且会伴有未知的bug。 在事态进一步扩大之前,我及时收手,必须对此架构进行改进。整个架构虽说参考了Redux中的一些思想,但主要还是停留在Flux的思维层面,实际上并没有牵扯到Redux的一个精髓——即全场只有一个state。 经过两天的调整,一个承上启下的全新架构出炉了。这个架构的最大优点在于结构简单,除了PubSubJS之外没有任何依赖。下面是以一个简单的markdown编辑器为例的架构介绍: 目录 项目文件结构如下。 Project |-- components |-- Editor |-- Preview |--...

11/2015
React Native中基于Pub/Sub的数据架构

在完成我的第一个项目子阅阅读器时,由于当时想象大部分的数据交换都利用ajax和服务器通信,也没有用户系统这些复杂的东西,因此没有使用看起来非常复杂的Flux架构。 在另外一个项目寻味中,虽然牵扯到大量的本地存储,但我还是没有使用Flux架构。主要原因在于不同component的层级不多,比较扁平,因此一个中央的HomePage就足够处理各种事件。但此时数据的交换是非常混乱的,比如说,在HomePage下管辖着两个平行的组件,一个是List,另一个是Map。希望达到的目的是,点击List上的一个项目,会在旁边的Map里有所反应,同时点击Map里的某个点,List组件也会相应更新。这样数据既从子组件传回父组件,又要从父组件传给子组件,完全是Flux架构的相反含义。当组件多了之后,项目(尤其是HomePage这个中央处理器)会变得混乱不堪。 但是,为了维持这个混乱的架构,我不得不做另外...

10/2015
Python后台伺服中文字体

中文字体在网页的使用严重受挫,原因主要在于中文并不是字母形文字,而像英文,仅需要26个字母就可以组成所需文字。这一原因导致中文字体文件动辄几MB大小,对于一般网页的载入尺寸严重过大。 有字库提供了一个解决方案:通过给需要加载字体的文字添加类名的方式,用Javascript向服务器发起请求,服务器再根据所需文字导出所需字体文件返回。对于免费版来说,有一个请求次数限制,因此对于高访问量的网站并不合适。 方正字库提供了一个云服务,提供多种不同字体的载入。对于方正字库来说,这倒是一个很好的利用互联网思维的例子。 本文提供了另一种解决思路,利用sfntly这个库自行搭建字体处理中心。 Google提供了一个类库sfntly,能够很容易地把所需要字体从字体文件中提取出来。具体方法如下: 把sfntly克隆到本地后,进入java文件夹。运行build命令: $ ant build好...

09/2015
React自定义滚动条模块

01/29/2016 Update 我基于本文种种,造了一个React插件轮子可以直接使用 React component。 背景 前端开发中很少有人折腾滚动条,一是兼容性问题:Firefox暂时不支持任何形式的滚动条的样式修改;二是必要性:大部分浏览器使用系统默认的滚动条样式,似乎没有必要修改滚动条。但是我最近的一个项目的页面中用了大量的列表(三列),而Mac系统中使用鼠标的情况下,滚动条会默认保持出现,会造成18px左右的空间,跟整体风格非常不搭,因此非常有必要修改下。(下图为三列图,是一个标准的列表形app,滚动条会占用相当大的空间) 思考 Mac系统下使用鼠标和触摸板的滚动条完全不同。使用触摸板时滚动条绝对定位,不使用的时候会自动隐藏,设计非常好。使用鼠标的时候为了方便点击,滚动条始终保持在上,会给使用滚动条的div块占用相当大的一个空间。 一般对于滚动条的修...

09/2015
React开发有感

最近要做一个浏览器端的支付页面,选用了React来进行项目搭建。之所以选择React,很大程度上是想尝试新鲜事物(虽然React 2013年就已经出现了,但是对我来说是个新鲜事物)。这个支付页面并非复杂——一个登录表单,一些Pricing的内容,一个支付表单和产品介绍。虽然不复杂,但如果只是用最简单的HTML和CSS来做,势必也会随着项目内容的增加或者修改而导致很难管理。一直以来我对于前端开发的看法是:很容易入门,但是也很难精益求精。很多人仅仅是懂基本的HTML标签,了解一些CSS的属性,再加上懂得怎样使用jQuery的第三方插件就可以正儿八经做一些前端项目了,但随着项目的复杂度的提升加上更多需求的引入,这种原始的方式会变得非常痛苦。 对于我个人来说,写CSS是必须要用LESS或者Sass的。离开了它们我会变得食欲不振,精神萎靡,一天不想写三行代码。这只是组件化(或者模块化)的第一...

07/2015
体验Material Design Lite of Google

前几天Google推出新的前端UI框架Material Design Lite (MDL),让人眼前一亮。Bootstrap作为大而全的老牌前端UI框架,其泛滥的使用早就让人审美疲劳,偶尔换换口味也不错。我一直以来都比较喜欢的Google的设计风格,卡片式的栅格系统使内容的呈现非常简洁,而细节处动画提升了整体品质。经过一天时间我把Q平台从Bootstrap换到MDL,大致总结如下: MDL与Bootstrap设计理念相差不大,不需要什么学习曲线 跟Bootstrap相比,MDL的组件仍然单薄,不适合大型项目 下面是一些需要注意的地方: MDL的栅格系统跟Bootstrap很像,也是分成十二列。mdl-grid类就像row,而mdl-cell则对应于col-x-y。但不同之处在于,MDL的栅格系统使用flex属性来控制内部块,首先兼容性略差,但是终于解决了不同列等高的...

07/2015
基于Nodejs前端开发的一些想法

前端的一个魅力之处在于它并不像很多其他语言那样有着完善的开发方式或者流程。它的混乱和自由同样也是它的可爱及可恨之处。@xufei的说法是 没有哪个别的领域像前端圈能出现这么混乱而欣欣向荣的景象,一方面说明前端的创造力很旺盛,一方面却说明了基础设施是不完善的。 在iOS开发的时候,安装第三方库除了手动编译以外,有且只有一个cocoapods,开发有完整的MVC模式,只要xcode在手打遍天下都不怕。在开发过程中,如果我想重复使用某个组件(比如说定制好的UIWebView),只需要单独写一个类,之后可以轻松重复使用,而在前端开发却有很多种方式。 最原始的方式,比如在Django框架的模板中,写一个base.html的基础模板,然后在不同的block里引入模块。然而这里引入的只是html内容。由于web页面相对app页面来说内容较多,交互复杂,因此产生的不同种类组件较为繁杂。...

05/2015