智能手机贴膜的那些事儿

以下内容,土豪可以完全忽略,不适合你。本文适合爱惜自己物品,有点完美主义情节的朋友。

自从有了触摸屏智能手机,是不是要贴膜就有了论战,至今未休。

反对贴膜者说,贴膜影响手感,好手机屏幕,比如iPhone,比较贵的安卓机都用大猩猩屏幕,已经很耐划耐磨了,不用贴。再者,手机使用寿命相对较短,生命期内用的痛快就好

支持贴膜者说,再耐磨也拦不住石英砂的灰尘颗粒,这个国家最不缺的就是灰。另外,一不留神手一滑,摔在地上,有钢化膜保护的屏幕损坏概率低的多。

本人支持贴膜,特别是支持贴钢化膜。因为已经亲眼看见数起钢化膜牺牲自己,挽救了原装屏幕的光荣事迹。贴膜磕碎了,屏幕完好无损,这不就是贴膜的意义么?一个贴膜10-20块就不错了,换个原装屏幕多少钱?十倍的钱你还找不着原装货。去原厂返修,价钱能抵得上半个手机。以小换大,值得的。越贵的手机越值得贴,特别是iPhone。越大的屏幕越值得贴,大屏手机第一高的损害率就是屏幕。而且如今,钢化膜质量也越来越好,与原装屏幕的手感差异几乎可以忽略不计。

另外,额外的保护套也值得使用。设计合理的保护套对手机边角的保护很有价值。这正是手机屏幕破损最常发生的地方。

那么,下面的问题是:怎么贴?

本人提供一个简单可靠的办法,争取一次性搞定。

记住:无尘的地方没有,少尘的地方难找,屏幕容易带静电,吸附灰尘颗粒,你跟灰尘作战的斗争是赢不了的,适可而止,没明显差别就别计较了。

准备材料:
1、信用卡类硬质塑料卡片,用途是刮平、压平贴膜,去气泡。
2、不干胶胶带一截,用途是定位、粘灰尘。
3、放手机的桌凳。

地点:家庭浴室。一般浴室比较小,灰尘要比其它房间少得多。离马桶远点!

操作方法:
1、手机屏幕用软布擦干净,观察一下,不要留下毛屑、灰尘颗粒。
2、把贴膜对准屏幕,先不要撕下保护层,先用不干胶把贴膜左侧和下面的手机粘起来。这是定位办法。只要一放,位置就不会错,不用反复揭开,容易进灰。

上面是示意图,已经贴好了,演示而已,定位要把胶带粘在手机后盖上。
3、撕掉贴膜护层,像翻盖一样,往下一翻,用信用卡一推即可。钢化膜比普通高透膜容易平整。
4、观察一下是否有灰尘在里面,如果没有大功告成。如果有,记得位置,趁没粘合紧密,用指甲、小刀撬一下边角,揭起来。钢化膜不是普通塑料膜,不要用蛮力,否则可能碎裂。
5、去灰时,轻轻的再揭开后,一手卡住钢化膜的边角,一手用不干胶胶带,轻轻的沾一下灰尘颗粒,然后放下。绝对不要用手指头抠,你会发现指纹比灰尘更糟糕、更难以去除,弄不好贴膜只能报废。
6、检查、重复处理。贴好后去除不干胶定位胶带

 

 

 

 

发表在 Misc | 留下评论

Nginx使用FastCGI模式运行PHP-Phalcon框架时,对fastcgi_param的研究

最近在用PHP的Phalcon框架做一个网站。遇到一些问题,干脆研究个透彻,免得心里面不踏实 – 我是喜欢刨根问底,凡事都要知道个为什么的人。

安装

作为多年C++开发出身,对脚本性能的追求刻在了骨子里。PHP当然要装PHP7,但Phalcon的安装文档说明的并不准确,没有针对PHP7说明,一些步骤并不需要。

从源码安装Phalcon是很方便的,也是最通用的办法。

1、安装PHP7,要选择PHP 7.0.x,不要用PHP 7.1.x。因为Phalcon紧密的跟PHP内核结合,对版本的依赖性很强,没有针对测试过的内核安装,大概率得到:Segmentation fault。这是使用这种框架必然要付出的代价,对Phalcon不满的声音,很多来自于此。目前可以选PHP 7.0.14,建议从源码安装,一键安装包很多。

2、 选择phalcon 3.0.x分支:git clone -b 3.0.x https://github.com/phalcon/cphalcon.git

这个版本是正式版,针对PHP 7.0.x测试过的。不需要安装其它PHP5的头文件,的比如php5-dev。php5-dev php5-mysql 这类,都不要安装,版本也和PHP7对不上,从源码安装了PHP7,这些头文件都有了。

3、进入phalcon代码目录:cphalcon/build,执行./install。这个install是个shell脚本,它会自动的运行phpize,设置一些编译参数,查看你的PHP的版本,选择合适的代码编译。要从这里开始。提前安装编译工具包是必须的,但前面用源码安装PHP7,GCC这些已经有了。编译成功后,要设置php.ini,最后面增加:

[phalcon]
extension=phalcon.so

4、使用php -m测试一下,看看phalcon模块是否安装成功,如果有错误,基本都是Segmentation fault.

Nginx的配置

官方文档有错误。按照它那个设置,运行得到的是:Access denied.

问题在哪里?谷歌了一番,大概明白了,不过心里不踏实,干脆直接查源码,一探究竟。这是开源的巨大优点:代码前面藏不住秘密,只要你肯去看,能看明白。对于熟悉C/C++开发的人来说,这点更是不成问题,老本行,代码风格熟悉的很。

理解这个,要首先阐述一下Nginx+PHP的运行模式。Nginx是Web服务器,它不处理脚本的解析,可以说一无所知。那如何运行PHP脚本?当然要PHP自己的解析器。这就需要一个纽带,把它们连接起来 – CGI协议。这个其实符合UNIX程序精神:程序只做一件事,要做好;做专业的程序,不做大而全的程序。程序之间用各种机制组合起来。FastCGI是对传统CGI模式的改进,程序可以常驻内存,使用进程池,避免根据请求反复创建进程。PHP-FPM就实现了这个模式,已经整合进入核心,编译后就有这个程序了。Nginx的配置文件有相关的指令可以把两者连接起来,PHP脚本就能顺利解析运行了。

其实对于其它脚本道理也是一样,比如Python。Nginx把外部请求转换成了CGI协议,用规定协议跟脚本通信,然后返回脚本运行结果给外部请求,一般是浏览器。相当于一个网关管道,有进有出。

具体说是这样:Nginx收到请求,比如 index.php。它发现不是能处理的静态文件,就转给配置里面写好的处理器,是这条指令:fastcgi_pass unix:/dev/shm/php-cgi.sock;。

光有这个还不行,还需要一些相关的信息,比如脚本具体位置,参数等等。这个是fastcgi_param参数干的事情。一般Nginx安装包,配置文件目录都有一个fastcgi_params文件,还有fastcgi.conf,两者只差了一行代码。里面包装的就是Nginx和PHP通信的参数信息。

路由模式:

可是因为一些框架的设计需求,还需要其它的配置指令。所有的web框架,都有个路由设计问题,大体分成几种:

  • 原生模式:index.php?q=index&a=run… Url有点丑陋
  • rewrite模式:index/run/?id=1 需要开启rewrite模块
  • pathinfo模式:index/run/id/1 用path传递操作的模块、参数信息
  • html模式:index-run.htm?uid=xxx 需要开启rewrite

如果你把网站想象成一个App,那么路由其实就是一个入口操作问题。它把网站内所有的请求,都集中导入到一个地方判断、分配处理器。这个模式被无数框架使用,优点多多。但怎么选择路由模式,各个框架不一样。Phalcon/yaf等框架,选择了pathinfo模式。这个模式的Url比较优雅,但是需要额外的配置,框架需要知道传进来的路径信息,分解后才能处理它。

讨论了半天,那个“Access denied.”咋处理?哪里错了?有技术文章说,解决办法是:打开PHP的配置参数:php.ini -> cgi.fix_pathinfo=1,就解决了。试验了一下,确实立刻OK。但是此法绝不可取,因为它留下了巨大的安全漏洞。

For instance, if a request is made for /forum/avatar/1232.jpg/file.php which does not exist but if /forum/avatar/1232.jpgdoes, the PHP interpreter will process /forum/avatar/1232.jpg instead. If this contains embedded PHP code, this code will be executed accordingly.

PHP的官方配置文档说明里面也提到:

cgi.fix_pathinfo boolean
Provides real PATH_INFO/ PATH_TRANSLATED support for CGI. PHP’s previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok what PATH_INFO is. For more information on PATH_INFO, see the CGI specs. Setting this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting of zero causes PHP to behave as before. It is turned on by default. You should fix your scripts to use SCRIPT_FILENAME rather than PATH_TRANSLATED.

更简单的办法:是删除这行配置:

fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;

就解决了。它是不需要的,可以看源码:

源码探究:
php -> fpm_main.c -> main()
/* library is already initialized, now init our request */
request = fpm_init_request(fcgi_fd);
zend_first_try {
while (EXPECTED(fcgi_accept_request(request) >= 0)) {
char *primary_script = NULL;
request_body_fd = -1;
SG(server_context) = (void *) request;
//call init
init_request_info();
fpm_request_info();
……………………….
static void init_request_info(void)
{
fcgi_request *request = (fcgi_request*) SG(server_context);
char *env_script_filename = FCGI_GETENV(request, “SCRIPT_FILENAME”);
char *env_path_translated = FCGI_GETENV(request, “PATH_TRANSLATED”);
//这里写的很明白:默认要用SCRIPT_FILENAME的值,而不是PATH_TRANSLATED
//所以PATH_TRANSLATED可以废弃了,保留应该只是兼容性需求。如果设置了
//PATH_TRANSLATED,后面因为用这个值计算,反而导致了路径错误,变成
//Access denied.
char *script_path_translated = env_script_filename;
char *ini;
int apache_was_here = 0;
/* some broken servers do not have script_filename or argv0
* an example, IIS configured in some ways. then they do more
* broken stuff and set path_translated to the cgi script location */
if (!script_path_translated && env_path_translated) {
script_path_translated = env_path_translated;
}
……………………….

一个Nginx配置:

server {
listen 80;
listen 443 ssl http2;
server_name phpdev.com www.phpdev.com;
access_log /data/wwwlogs/phpdev.com_nginx.log combined;
index index.html index.htm index.php;
root /data/wwwroot/phpdev.com;
location / {
try_files $uri $uri/ /index.php;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/dev/shm/php-cgi.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$ {
expires 30d;
access_log off;
}
location ~ .*\.(js|css)?$ {
expires 7d;
access_log off;
}
location ~ /\.ht {
deny all;
}
}

fastcgi_split_path_info ^(.+\.php)(/.+)$;

这行是关键,把path_info信息分解。

一些参考资料:

这篇文章,对fastcgi参数阐述的非常清楚。
https://www.digitalocean.com/community/tutorials/understanding-and-implementing-fastcgi-proxying-in-nginx
Nginx官方PHP配置wiki:
https://www.nginx.com/resources/wiki/start/topics/examples/phpfcgi/
不错的nginx配置参考:
https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/

发表在 技术探索 | Nginx使用FastCGI模式运行PHP-Phalcon框架时,对fastcgi_param的研究已关闭评论

对C++(C Plus Plus)的反思

转载,说的还是有很多道理的。

最近两年 C++又有很多人出来追捧,并且追捧者充满了各种优越感,似乎不写 C++你就一辈子是低端程序员了,面对这种现象,要不要出来适时的黑一下 C++呢?呵呵呵。

咱们要有点娱乐精神,关于 C++的笑话数都数不清:

笑话:C++是一门不吉祥的语言,据说波音公司之前用ADA为飞机硬件编程,一直用的好好的,后来招聘了一伙大学生,学生们说我靠还在用这么落后的语言,然后换成C++重构后飞机就坠毁了。

笑话:什么是C++程序员呢?就是本来10行写得完的程序,他非要用30行来完成,并自称“封装”,但每每到第二个项目的时候却将80%打破重写,并美其名曰 “重构”。

笑话:C容易擦枪走火打到自己的脚,用C++虽然不容易,但一旦走火,就会把你整条腿给炸飞了。

笑话:同时学习两年 Java的程序员在一起讨论的是面向对象和设计模式,而同时学习两年 C++的程序员,在一起讨论的是 template和各种语言规范到底怎么回事情。

笑话:教别人学 C++的人都挣大钱了,而很多真正用 C++的人,都死的很惨。

笑话:C++有太多地方可以让一个人表现自己“很聪明”,所以使用C++越久的人,约觉得自己“很聪明”结果步入陷阱都不知道,掉坑里了还觉得估计是自己没学好 C++。

笑话:好多写了十多年 C++程序的人,至今说不清楚 C++到底有多少规范,至今仍然时不时的落入某些坑中。

笑话:很多认为 C++方便跨平台的人,实际编写跨平台代码时,都会发现自己难找到两个支持相同标准的 C++编译器。
—————

Q:那 C++为什么还能看到那么多粉丝呢?
A:其实是因为 Windows,因为 Windows的兴起带动了 C++,C++本来就是一门只适合开发 GUI的语言。

Q:为何 C++只适合开发 GUI呢?
A:你看 Unix下没有 GUI,为啥清一色的 C呀?所有的系统级问题都能在 C里找到成熟的解决方案,应用级问题都能用其他高级语言很好地解决,哪里有 C++什么事情呀?

Q:你强词夺理,Unix下也有 C++的项目呀。
A:有,没错,你任然可以用任何语言编写任何糟糕的代码。

Q:别瞎扯了,你都在说些什么?连C++和 Windows 都扯到一起去了。
A:回想下当年的情景,一个大牛在教一群初学者如何编程。一边开发一边指着屏幕上说,你看,这是一个 Button,我们可以用一个对象来描述它,那是一个 panel我们也可以用一个对象来描述它,并且你们有没有发现,其实 Button和 Panel是有血缘关系的,你们看。。。这样就出来了。。。。下面的学生以前都是学着学校落后的教材,有些甚至还在用 turboc的 bgi库来画一些点和圆。哪里见过这么这么华丽的 Windows 界面呀。大牛说的话,象金科玉律一样的铭刻在自己幼小的心理。一边学着 Windows,一边发现,果然,他们都需要一个基类,果然,他们是兄弟关系,共同包含一些基本属性,可以放到基类去。他们越用越爽,潜意识里觉得因为 C++这么顺利的帮他们解决那么多界面问题,那看来 C++可以帮他们解决一切问题了。于是开发完界面以后,他们继续开发,当他们碰到各种设计问题时,反而认为肯定自己没有用好 C++。于是强迫自己用下去,然后就完蛋了。

(点击 more展开)

—————
关于 C++的笑话我有一箩筐,各位 C++粉用不着对号入座。言归正传,为什么要黑 C++呢?谈不上黑不黑,我从94年开始使用 C++(先前是 C 和 Pascal),一路看着 C++成长壮大,用 C++写过的代码,加起来应该超过 10MB了吧,C++的各种宝典我也都读过,一直到 2004年开始切回 C,主要原因是发现很多没法用 C++思路继续解决下去的问题,或者说用 C++思路解决下去会很糟糕的问题。

那时候(2004-2005)正是 C++满天飞的时候,言必称 C++,用必用模版,我跳出来说你们醒醒吧,别过火了,这个世界并不是都是抽象数据结构和算法就可以描述清楚的。于是很多人激动的跳出来说:“你没领会到 C++精髓,你根本都不会用 C++”。我问他们:“语言是用来解决问题的,如果一个语言学了三四年都会经常掉沟里,算好语言么?如果编写十多年 C++的程序员都很难掌握得了,这算好语言么”。他们又说:“语言是死的,人是活的”。

我记得当时一位国内 C++大牛,为了纠正我的 “错误观点”,给我看过他写的一套十分强大的库,我打开一看,倒吸了一口冷气,全部是 .h文件。我只能回他三个字:“你牛逼”。当然这是一个极端的例子,那家伙后来终于也开始把 .h里面的东西逐步挪到 .cpp里面了,这是好事。

当时和云风在一家公司,2004年新人培训时,他给新人布置了一个实现内存分配器的作业,批改作业的时候,他经常边看边问人家,“不够C++呀,你能不能百分之百OOP?”,“1%的 C都不要留”。我当时在公司内部邮件列表里面发过关于 C++的问题,大部分人都表示:“你看没有C++我们怎么写3D引擎呢?”。我跟他们讲:“John Carmack直到 Quake3都还在用着 ANSI C,后来因为不得不支持 D3D,改用 C++了。为啥 C不能写 3D引擎了?”。他们告诉我:“你看,Point,就是个对象,Matrix也是个对象,那么多 Vector的代数计算,用 C++的算术重载是多么美妙的事情,三维世界就是对象的世界。”。

确实当时客户端 GUI的话,只有 C++,图形引擎也只有 C++,这两个正是C++最强的地方,所以我也没和他们争辩,强迫他们承认 C也可以很漂亮的写图形,而且C写的可以写的很优雅。我又不是闲着没事情,何必去质疑人家的核心价值观呢,呵呵。当年我正在接手一个 C++项目,代码超过 800KB,每次崩溃都需要花费很长时间去定位,项目中大量的前后依赖,改一个地方,前后要看好几处,一处遗漏,整个系统就傻逼了。我开始重构后,画了两个星期,将性能敏感的核心部分剥离出来用 C实现(代码量仅 200KB),然后导出 Python接口,用Python来完成剩下的部分,整个脚本层代码量只有 150KB。整个世界清爽了,整个 C++项目原来的工期为 2个程序员四个月,我一个人重构的时间加起来就 1.5个月,而且代码量比远来少了两倍还多,各种奇特的 BUG也一扫而尽。我看看左边的 800KB一团乱麻的 C++代码,再看看右边整洁的 300多 KB 纯 C + Python,琢磨着,这个项目干嘛不一开始就这么做?

 

跨语言接口

 

现代项目开发,不但需要更高的性能,而且需要更强大的语言描述能力。而 C++正处在一个尴尬的地方,比底层,它不如 C能够精确的控制内存和硬件,各种隐式构造让你防不胜防;比描述能力,比快速业务开发和错误定位,它又赶不上 Python, Ruby, Lua等动态语言,处于东线和西线同时遭受挤压和蚕食的地步。

很快,2006-2007年左右,其他项目组各种滥用 C++的问题开始显现出来:当时脚本化已经在工程实践中获得极大的成功,然而某些项目一方面又要追求 100%的 C++,另一方面又需要对脚本导出接口,他们发现问题了,不知道该怎么把大量的 C++基础库和接口导给 Lua。

C的接口有各种方便的方式导给脚本,然而整个项目由一群从来就不消于使用脚本的cpp大牛开发出来,当他们要吧cpp类导出接口给脚本时,他们设计了一套牛逼的系统,lua自动生成机器码,去调用c++的各种类,没错,就是c++版本的cffi或者ctypes。他为调用vc的类写了一套机器码生产,又为调用gcc的类写了一套代码生成。那位cpp大牛写完后四处炫耀他的成果,后来他离职了,项目上线一而再再而三的出现无可查证的问题,后来云风去支援那个项目组,这套盘根错节的c++项目,这套盘大的代码自生成系统深深的把他给恶心到了。后来众所周知云风开始反C++,倡导回归C了,不知道是否和这个项目有关系。

于是发现个有趣的现象,但凡善于使用脚本来提高工程效率的人,基本都是C加动态语言解决大部分问题(除了gui和图形),但凡认为c++统治宇宙的人很多都是从来没使用过脚本或者用了还不知道该怎样去用的人。

凭借这样的方法,我们的产品同竞争对手比拼时,同样一个功能,同样的人力配置,竞争对手用纯C++要开发三月,我们一个月就弄出来了,同样的时间,对手只能试错一次,我们可以试错三次。后来,据我们招聘过来的同事说,竞争对手也开始逐步降低 C++的比例,增加 java的比例了,这是好事,大家都在进步嘛。

 

ABI的尴尬

 

ABI级别的 C++接口从来没有标准化过,以类为接口会引入很多隐藏问题,比如内存问题,一个类在一个库里面实例化的,如果再另外一个库里面释放它们就有很多问题,因为两个动态库可能内存管理系统是不一样的。你用这里的 allocator分配一块内存,又用那里的 allocator去释放,不出问题才怪。很多解决方法是加一个 Release 方法(比如 DX),告诉外面的人,用完的时候不要去 delete,而是要调用 Release。

项目写大了各个模块隔离成动态库是很正常的,而各种第三方库和自己写的库为追求高性能引入特定的内存管理机制也是很正常的。很多人不注意该调用release的地方错写成delete就掉沟里去了。更有胜者跨 ABI定义了很多inline方法的类,结果各种隐式构造和析构其实在这个库里生成,那个库里被析构,乱成一团乱麻。C就清晰很多,构造你就调用fopen,析构你就fclose,没有任何歧义。其实C++的矛盾在于一方面承认作为系统级语言内存管理应该交给用户决定,一方面自己却又定义很多不受用户控制的内存操作行为。所以跨 ABI层的c++标准迟迟无法被定义出来,不是因为多态 abi复杂,而是因为语言逻辑出现了相互矛盾。为了弥补这个矛盾,C++引入了operator new,delete,这new/delete重载是一个补丁并没从逻辑上让语言变得完备,它的出现,进一步将使用者拖入bug的深渊。

其实今天我们回过头去看这个问题,能发现两个基本原则:跨abi的级别上引入不可控的内存机制从语言上是有问题的,只能要靠开发者约定各种灵巧的基类和约定开发规范来解决,这个问题在语言层是解决不了的;其次你既然定义了各种隐式构造和析构,就该像java活着动态语言一样彻底接管内存,不允许用户再自定义任何内存管理方法,而不是一方面作为系统极语言要给用户控制的自由,一方面自己又要抢着和用户一起控制。

因此对象层 ABI接口迟迟无法标准化。而纯 C的 ABI不但可以轻松的跨动态库还能轻松的和汇编及各类语言融合,不是因为C设计多好,而是C作为系统层语言没有去管它不该管的东西。当年讨论到这个话题时 C++大牛们又开始重复那几句金科玉律来反驳我:“语言只是招式,你把内功练好,就能做到无招胜有招,拿起草来都可以当剑使,C++虽然有很多坑,你把设计做好不那么用不就行了”。我说:本来应该在语言层解决好的事情,由于语言逻辑不完备,将大量问题抛给开发者去解决极大的增加了开发者的思维负担,就像破屋上表浆糊一样。你金庸看多了吧,武术再高,当你拿到一把枪发现子弹不一定往前射,偶尔还会往后射时,请问你是该专心打敌人呢?还是时刻要提防自己的子弹射向自己?

 

系统层的挫败

 

C++遭受挫败是进军嵌入式和操作系统这样靠近硬件层的东西。大家觉得宇宙级别的编程语言,自然能够胜任一切任务,很快发现几个问题:

  • 无法分配内存:原来用 C可以完全不依赖内存分配,代码写几千行一个 malloc没有都行。嵌入式下处理器加电后,跳到特定地址(比如起始地址0),第一条指令一般用汇编来写,固定在0地址,就是简单初始化一下栈,然后跳转到 C语言的 start函数去,试想此时内存分配机制都还没有建立,你定义了两个类,怎么构造呀?资源有限的微处理器上大部分时候就是使用一块静态内存进行操作。C++写起来写爽了,各种隐式构造一出现,就傻了。
  • 标准库依赖:在语言层面,C语言的所有特性都可以不用依赖任何库就运行,这为编写系统层和跨平台跨语言代码带来了很方便的特性。而C++就不行,我要构造呀,我要异常呀,你为啥不能给我强大的运行时呢?什么你还想用 stl?不看看那套库有多臃肿呀(内存占用,代码尺寸)。
  • 异常处理问题:底层开发需要严格的处理所有错误返回,这一行调用,下一行就判断错误。而异常是一种松散的错误处理方式,应用层这么写没问题,系统层这么写就很狼狈了。每行调用都try一下和 C的调用后if判断结果有什么区别?C++的构造函数是没有返回值的,如果构造内部出错,就必须逼迫你catch构造函数的异常,即便你catch住了,构造异常的时候当然会自动触发相关内部对象的析构,但是有很多并没有析构的资源(比如系统资源,比如C接口的资源,他们都没有一个析构),整个过程是很难控制的,此时这个实例是一个半初始化实例,你该怎么处理它呢?于是有人把初始化代码移除构造函数,构造时只初始化一下变量,新增加一个带返回的init函数,这样的代码写的比C冗余很多。何况硬件中断发生时,在你不知道的情况下,同事调到一些第三方的库,你最外层没有把新的exception给 catch住,这个exception该往哪里抛呀?内存不够的时候你想抛出一个 OutOfMemoryException,可是内存已经不够了,此时完全无能力构造这个异常又该怎么办呢?
  • 处理器兼容:C++的类依赖基地址+偏移地址的寻址方式,很多非 Intel系列的微处理器上只有简单的给定地址寻址,不支持这样一条语句实现BASE+OFFSET的寻址,很多C++代码编译出来需要更多的指令来运算地址,导致性能下降很多,得不偿失。
  • 隐式操作问题:C的特点是简单直接,每行语句你都能清楚的知道会被翻译成什么样子,系统会严格按照你的代码去执行。而用C++,比如 str1 = str2 + “Hello” + str3; 这样的语句,没几个人真的说得清楚究竟有多少次构造和拷贝,这样的写法编写底层代码是很不负责任的,底层需要更为精细和严格的控制,用C语言控制力更强

当然,说道这里很多人又说,“C++本来就是 C的超集,特定的地方你完全可以按照C的写法来做呀。没人强迫你构造类或者使用异常呀”,没错,按 Linus的说法:“想要用 C++写出系统级的优秀的可移植和高效的代码,最终还是会限于使用 C本身提供的功能,而这些功能 C都已经完美提供了,所以系统层使用 C的意义就在于在语言层排除 C++的其他特性的干扰”。

很多人都记得 Linus在 2007年因为有人问 Git为什么不用 C++开发炮轰过一次C++。事实上2004年 C++如日中天的时候,有人问 Linux内核为何不用 C++开发,他就炮轰过一次了:

实际上,我们在1992年就尝试过在Linux使用 C++了。很恶心,相信我,用C++写内核是一个 “BLOODY STUPID IDEA”。事实上,C++编译器不值得信任,1992年时它们更糟糕,而一些基本的事实从没改变过:

– 整套 C++异常处理系统是 “fundamentally broken”。特别对于编写内核而言。
– 任何语言或编译器喜欢在你背后隐藏行为(如内存分配)对于开发内核并不是一个好选择。
– 任然可以用 C来编写面向对象代码(比如文件系统),而不需要用 C++写出一坨屎来。

总得来说,对任何希望用 C++来开发内核的人而言,他们都是在引入更多问题,无法象 C一样清晰的看到自己到底在写什么。

C++粉丝们在C++最火热的时候试图将 C++引入系统层开发,但是从来没有成功过。所以不管是嵌入式,还是操作系统,在靠近硬件底层的开发中,都是清一色的 C代码,完全没有 C++的立足之地。

 

应用层的反思

 

STL出来后,给人一种 C++可以方便开发应用层逻辑的错觉。由于很多语言层不严密的事情,让STL来以补丁的方式完成,于是很多以为可以象写 java一样写 C++的初学者落入了一个个的坑中。比如 list.size(),在 Windows下vc的 stl是保存了 list的长度的,size()直接 O(1)返回该变量,而在gcc的 stl中,没有保存 list长度,size()将搜索所有节点,O(n)的速度返回。

由于语言层不支持字符串,导致 std::string实现十分不统一,你拷贝构造一个字符串,有的实现是引用,才用 copy-on-write的方法引用。有的地方又是 new,有的实现又是用的内存池,有的实现线程安全,有的实现线程不安全,你完全没法说出同一个语句后面到底做了些什么(见孟岩的《Linux之父话糙理不糙》)。

再比如说我想使用 hash_map,为了跨平台(当你真正编写跨平台代码时,你很难决定目标编译器和他们的版本,想用也用不了 unordered_map),我很难指出一种唯一声明 hash_map的方法,为了保证在不同的编译器下正常的使用 hash_map,你不得不写成这样:

#ifdef __GNUC__
#ifdef __DEPRECATED
#undef __DEPRECATED
#endif
#include <ext/hash_map>
namespace stdext { using namespace __gnu_cxx; }
namespace __gnu_cxx {
template<> struct hash< std::string > {
size_t operator()( const std::string& x ) const {
return hash< const char* >()( x.c_str() );
}
};
}
#else
#ifndef _MSC_VER
#include <hash_map>
#elif (_MSC_VER < 1300)
#include <map>
#define IHAVE_NOT_HASH_MAP
#else
#include <hash_map>
#endif
#endif

#ifdef __GNUC__
using namespace __gnu_cxx;
typedef hash_map<uint32_t, XXXX*> HashXXXX;
#else
using namespace stdext;
typedef hash_map<uint32_t, XXXX*> HashXXXX;
#endif

如果有更好的跨平台写法,麻烦告诉我一下,实在是看不下去了。一个基础容器都让人用的那么辛苦,使得很多 C++程序员成天都在思考各种规范,没时间真正思考下程序设计。

由于语言层要兼容 C,又不肯象 C一样只做好系统层的工作,导致当 C++涉足应用层时,没法接管内存管理,没法支持语言层字符串,没法实现语言层基础容器。所以需要借助一些 stl之类的东西来提供便利,但 stl本身又是充满各种坑的。且不说内存占用大,程序体积大等问题,当编译速度就够呛了。所以为什么 C++下面大家乐意重复造轮子,实现各种基本容器和字符串,导致几乎每个不同的 C++项目,都有自己特定的字符串实现。就是因为大家踩了坑了,才开始觉得需要自己来控制这些细节。stl的出发点是好的,但是只能简单小程序里面随便用一下,真是大项目用,stl就容易把人带沟里了,所以很多大点的 C++项目都是自己实现一套类似 STL的东西,这难道不是违背了 stl设计的初衷了么?

语言层的缺失,让大家为了满足业务开发的快速迭代的需求,创造了很多很基础的设计灵巧的基类,来提供类似垃圾回收,引用计数,copy-on-write,delegate,等数不胜数的功能。每个项目都有一系列 BaseObject 之类的基础类,这样就引入一个误区,两年后你再来看你的代码,发现某个 BaseObject不满足需求了,或者你和另外一个项目 merge代码时,需要合并一些根本属性。图形和GUI这些万年不变的模型还好,应用类开发千变万化,一旦这些设计灵巧的基类不再适应项目发展时,往往面临着全面调整的代价。

打开一个个 C++大牛们 blog,很多地方在教你 std::string的原理,需要注意的事项。map的限制,vector的原理,教你如何实现一个 string。这就叫 “心智负担”,分散你的注意力,这是其他语言里从来见不到的现象。战士不研究怎么上前线杀敌,天天在琢磨抢和炮的原理,成天在思考怎么用枪不会走火,用炮不会炸到自己,这战还怎么打?

所以此后几年,越来越多的人开始反思前两年C++过热所带来的问题,比如高性能网络库 ZeroMQ作者 Martin Sustrik 的:《为什么我希望用C而不是C++来实现ZeroMQ》,比如云风的《云风的 BLOG: C 的回归》,比如引起热议的《Why C++ Is Not “Back”》。

 

全面被代替

 

2008年以后,行业竞争越来越激烈,正当大家一边苦恼如何提高开发效率,一边掉到C++的各种坑里的时候,越来越多的应用开发方案涌现出来,他们都能很好的代替 C++。各行各业的开发者逐步相见恨晚的发现了各种更加优秀的方案:需要底层控制追求性能的设计,大家退回到 C;而需要快速迭代的东西大家找到各种动态语言;介于性能和开发速度之间的,有java,知乎上好像很多黑java的,语言是有不足,但是比起C++好很多,没那么多坑,真正考虑面向对象,真正让人把心思放在设计上。所以再黑也不能挡住 java在 tiobe上和 C语言不是第一就是第二的事实,再黑也挡不住 java在云计算,分布式领域的卓越贡献。

所以2005年以后,C++处在一个全面被代替的过程中:

image_thumb7

 

  • 底层系统:进一步回归 C语言,更强的控制力,更精确的操作。
  • 网页开发:2006年左右,C++和 fastcgi就被一起赶出 web世界了。
  • 高性能服务:varnish, nginx, redis 等新的高性能网络服务器都是纯C开发的。
  • 分布式应用:2007年左右, C++被java和其他动态语言彻底赶跑。
  • 游戏服务端:2008年后进一步进化为 C 和 脚本,完全看不到胖C++服务端了。
  • 并行计算:2010年后,go, scala, erlang;而能方便同go接口的,是 C不是C++。
  • 游戏引擎:没错 C++和脚本,但是这年头越来越多的开源引擎下,引擎类需求越来越少。
  • 游戏逻辑:脚本
  • 多媒体:SDL纯C,ffmpeg是纯 C,webrtc的核心部分(DSP, codec)是纯C的。
  • 移动开发:早年C++还可以开发下塞班,现在基本被 java + objc + swift 赶跑了。
  • 桌面开发:Qt+Script, C#等都能做出漂亮的跨平台界面。且界面脚本化趋势,不需要C++了。
  • 网页前端:JavaScript, Html5, Flash
  • 操作系统:FreeBSD, Open Solaris, Linux, RTOS, Darwin(OS X 底层),都是纯 C
  • 虚拟技术:qemu / kvm (云计算的基石)纯 C,Xen 纯 C
  • 数据库:MySQL (核心纯C,外围工具 C++),SQLite 纯 C, PostgreSQL / BDB / unqlite 纯C
  • 编译器:C/C++并存,不过编译器用脚本写都没关系,我还在某平台用 java写的 C/C++编译器
  • 大数据:kafka, hadoop, storm, spark 都使用 Java / Jvm 系列技术
  • 云存储:openstack swift python, hdfs java, 还有好多方案用 go

可以看出,即便 C++的老本行,GUI和图形(确实也还存在一些短期内 C++无法替代的领域,就像交易系统里还有 COBOL一样),这年头也面临的越来越多的挑战,比如新发布的 Rust (如何看待 Rust 的应用前景? – 知乎用户的回答)。可以发现,开发技术多元化,用最适合的技术开发最适合的应用是未来的趋势。而为这些不同的技术编写高性能的可控的公共组件,并轻松的和其他语言接口,正是 C语言的强项。所以不管应用层语言千变万化,对系统级开发语言C的需求还是那么的稳定,而这个过程中,哪里还有 C++的影子呢?

 

话题总结

 

所以说未来的趋势是:C x 各种语言混搭 的趋势,从TIOBE上 C++的指数十年间下跌了三倍可以看出,未来还会涌现出更多技术来代替各个角落残存的C++方案,C++的使用情况还会进一步下降。所以题主问学习纯C是否有前途,我觉得如果题主能够左手熟练的掌握 C语言,培养系统化的思维习惯和精确控制内存和硬件的技巧;右手继续学习各种新兴的开发技术,能够应对各个细分领域的快速开发,碰到新问题时能左右开弓,那么未来工作上肯定是能上一个大台阶的。至于C++ 嘛,有时间看看就行,逼不得已要维护别人代码的情况下写两行即可。

 

故事分享

 

古代用弓箭进行远距离攻击时,对射手要求较高,瞄准难度大,需要一直使劲保持准心。战斗中一个弓箭手开弓二十次就需要比较长的休息时间。弩的威力远胜于弓,秦弩的制造就如现代的自动步枪一般精密无二,它既可以延长射击,又可以精确瞄准。弩箭的发射速度更是弓箭的数倍,威力惊人。因为弩的操作非常简单,不需要射击技巧,平民很容易掌握它的使用方法。秦国靠着弩兵,在战争中取得了不少优势,被人称为 “虎狼之师”。

日本投降时,天皇下罪己诏。很多士兵不愿意相信这时真的,找种种理由拒绝相信。有的士兵甚至以为天皇的广播是敌人诱降的把戏,于是躲到丛林里继续三五成群的收集情报,袭击可以攻击的目标,等待上司来给他们下达新命令。直到好几年后看到周围的人都穿着日常的便装了,而来巡山的 “敌人” 也从士兵变为了巡逻队,他们都还觉得这是敌人的伪装。而同时,德国战败时,最后的党卫军一直战斗到 1957年才肯投降。

—————————————–
很多人觉得 java慢,C++快java 10倍以上已经是上世纪的事情了,现代的 java 只比 C/C++慢 70%,C++连1倍都快不了 java。也不要觉得动态语言慢,javascript只比C/C++慢 2.7倍。luajit只比 C++慢 5.8倍。在 jit技术发展的今天,C++在性能上离动态语言/java的差距越来越小,可易用性和生产效率上的差距,却和动态语言/java 比起来越来越大。

image_thumb9

—————————
最后,补充一张图:

image_thumb8

发表在 技术探索 | 对C++(C Plus Plus)的反思已关闭评论

我为什么倾向于full-stack框架,而不太喜欢小框架+插件?

举几个例子:python开发的flask,前端的backbone等等。这些框架本身也算足够出色的,但是真要用起来,有一些问题让你头疼。

小框架本身故意设计的简单,以至于缺很多需要的功能。这些功能往往由插件提供。问题就在这里:这些插件的开发水平,经常良莠不齐,你需要付出选择的成本 – 看看哪个好,哪个不行。

插件往往存在概念、实现方式上与核心的不一致。这点是最让人恼火的。你核心的还没理解透彻,它已经给你改的面目全非了。使用插件出现概念错误,导致误用的比比皆是。很多错误出在理解失误上,而不是单纯的代码写错了。

full-stack框架虽比较大,但内部一致性,就要好得多了,优点正好弥补了小框架的缺陷。我用过几个小框架实现需求,搞到最后都想放弃,忍不住朝着屏幕吐口水,大骂fuck。

当然,你如果水平足够好,用啥都无所谓。但是对于还在学习曲线中,就要解决问题的,建议使用全栈框架为好。

 

 

发表在 技术探索 | 我为什么倾向于full-stack框架,而不太喜欢小框架+插件?已关闭评论

2016 年最受欢迎的编程语言是什么?

这两天 GitHub 对其官网进行了改版,紧接着又发布了一年一度的开源报告,我们程序员比较关心之后的趋势是什么,而 GitHub 毫无疑问代表了全世界编程领域的趋势,我们不妨先来解读下这份报告,然后再解答下你们关注的标题的答案。

事先声明,本篇文章的一些数据完全来自这份报告,地址在这里:

https://octoverse.github.com/

最流行的开源项目

首先发布的是过去一年在 GitHub 上最流行的开源项目,见下图:

图片描述

可以看到其中有不少是我在之前 GitHub 系列文章里介绍过的,如 awesome、free-program-books、React-native、on-my-zsh 等,不过令我没想到的是 lantern 竟然也入选了,足以说明全世界人们对自由上网的渴望,关于 lantern 是什么我不多说了,自己去了解吧。

最受欢迎的编程语言

这个世界有多少种编程语言你们知道么?我想没人说得清楚,GitHub 给出了答案。GitHub 上所有的开源项目包含了 316 种编程语言。不说不知道,一说吓一跳,要知道这世界上只有 226 个国家和地区,编程语言的数量超出了世界上国家的数量,有时候就在想,那么多不为人知的编程语言都是什么人在用?

要问 2016 年最受欢迎的编程语言是什么?同样 GitHub 也给出了答案。以下是 GitHub 根据过去 12 月提交的 PR 数量来排名的,虽然不完全准确,但是 PR 起码代表了项目的热度与欢迎度,还是值得可信的:

图片描述

可以看到排名第一的是 JavaScript 。我想有几方面的原因吧,一是本来 GitHub 上早期的一些开源项目都是 web 前端相关的,二是随着移动端各种跨平台框架的需求,js 被予以重任,如 React Native、weex 等,三是 js 领域各种框架层出不穷,如 vue.js、angular.js、react.js 等,所以 JavaScript 排名第一并不是很意外。所以有对 web 前端感兴趣的同学,js 是必备技能,想往这方面发展依然热度不减,而事实上国内需求目前对有经验的 web 前端工程师确实很缺乏,很多时候钱多活少离家近都招不到人。

另外老牌语言 Java 依然能排名第二蛮意外的,我想这其中很大部分是因为 Android 的发展让 Java 焕发了第二春。

紧接着是 Python、Ruby、PHP,这三种都是属于动态语言,对于我们 Android 开发所用的 Java 静态语言是不一样的,之前有人问过我想学习一门除了 Java 之外的语言,如果实在感兴趣的话我就建议学习下 Ruby 或者 Python ,能从中了解到很多 Java 层面没接触过的知识。另外都说 PHP 是世界上最好的编程语言,这排名名不副实啊!

另外这份排名很有意思,元老级编程语言 C++、C 几乎每年都上榜,所以根本不用担心自己用的编程语言会过时,如果真那样的话 C++、C 那些程序员早都丢饭碗了。

最后一经出来就被热捧的 Swift 排名有点对不起大家对它的期待,今年仍然比不过亲兄弟的 Objective C ,我觉得很大原因是因为亲爹 Apple 没有让开发者们强制使用 Swift,不过增长倒是很迅速,增长了 262%,相信这增长速度加上有个强大的爹,它的发展还是很期待的,只不过听说现在甚至还在改语法,所以还没有完全成熟,不要过于这么快就报太大的期待,不过如果 iOS 开发者们到现在还没有学习甚至了解就说不过去了。

所以,2016 年最受欢迎的编程语言是 JavaScript !

PS:作为 Android 开发者也蛮高兴的,毕竟我们所用的编程语言 Java 是 JavaScript 他哥!

开源贡献最多的组织

打死我都想不到 2016 年对开源贡献最多的竟然是微软,一向封闭为主的微软今年发力开源社区,竟然超越了 Google、Facebook,加上国内很大巨头也纷纷在开源社区发力,别的不说,就说 Android 界吧,今年包括腾讯、阿里等纷纷推出各自的开源项目,可能真的说明拥抱开源,才是王道吧!

图片描述

GitHub 新增用户

GitHub 已经有超过 520 万的用户和超 30 万的组织。而今年,中国是新用户增长最多的国家,比 15 年增长快翻了一番,而这其中,身为一个 Google、GitHub 真爱粉,我觉得我也出了一把力(装逼完成,逃…)

图片描述

当然还有很多其他有意思的数据,这里就不一一详细介绍了,感兴趣的不妨到这里去看下。

https://octoverse.github.com/

最后,GitHub 的这份报告代表着过去的数据,不过对于我们对未来的技术趋势判断有一定参考意义,所有编程从业者都有必要关注下这份报告,当然文中涉及到的一些观点纯属个人,不代表官方与任何组织,欢迎交流。

原文出处:http://blog.csdn.net/googdev/article/details/52575079

 

发表在 技术探索 | 2016 年最受欢迎的编程语言是什么?已关闭评论

十年来,编程领域有什么重要进展?

这篇文章总结的不错,转过来。补充一句:函数式编程开始流行并成为一种编程范式,这个变化,跟机器性能进步有很大关系。函数式编程有很多优点特性值得研究,其实它并不是新技术,而是因为不逢其时,尘封已久。


code

编程语言层出不穷,然而内核是万变不离其宗。我个人看法觉得是以下几个方面的变化比较明显。

语言本身:

1. 工业标准

网页标准有 W3C 控制,尤其是浏览器的开发,所有主流的浏览器都会自觉符合这个组织的标准,当然这些开发商本身就是这个组织的成员。所以新的 HTML5,CSS3,ES6 JavaScript 的新特性的得到顺利推动,让大部分主流浏览器都支持它,W3C 功不可没。

PHP 有 PHPFIG 组织,虽然不是强制性的,但是很多新的框架和库都自觉遵守这个组织的编程标准。

Java, C 语言都有各自的工业标准准则,来维护各自工业标准。

这个标准其实不是强制性的,虽然很多程序员在自己工作上,不遵守这些工业标准,但是要推出新的模块的话,不遵守这些工业标准的模块,是没有人会去使用的。如今是不是面向标准编程,是体现一个程序员是否专业,一个模块是不是专业模块的一个重要指标。

2.第三方模块走红

各种语言的框架和库,可能比自己的语言还出名,比如 CSS 的 Bootstrap,JavaScript 的 jQuery;一个好的框架和库甚至可以推动这个这个语言的发展,比如说 PHP 的 Laravel 框架,JavaScript 的 jQuery.

模块化的发展,大大加快了开发的速度。很多人也愿意开发各种框架和模块,不但可以锻炼自己的开发技能,也是一种展示自己的能力。

过去,程序员要成名,要开发出有用的软件,比如说求伯君开发出了 WPS,牛;张晓龙开发出了 Foxmail,牛。

现在,程序员要成名,开发出一个大家都会用的框架和模块也行。比如 Evan You 开发的 Vue.js,玉伯开发的 SeaJs。

3.模块化编程和依赖管理

在 2010 前,依赖管理工具只是个很时髦的概念,大家习惯手动到库的官方网站上下载后手动导入到项目中。升级也是个麻烦事。所以一般大家也就下载一两个必要的库,其他都自己手写完成。

如今,依赖管理工具已经是必备的了,大家不再手动导入库了;而且是能找到第三方模块的功能,就不再自己编写了,统统用工具导入项目;自己编写的程序代码,能模块化的代码统统模块化,甚至是独立出来,网上开源,然后使用依赖管理工具进行管理导入到自己的项目中。

这样好处也明显:

  • 代码量减少
  • 加快开发速度
  • 高度解耦
  • 定位 bug 容易,改动影响小
  • 写单元测试容易

如今大家更加愿意写小模块,而不是重复造轮子了。

4. 框架使用

更愿意先选一个合适的框架,再开始编程,而不是所有功能自己从头开始写了.

  • JavaScript 的框架多了,Vue,React, Backbone,AngularJs 等;
  • CSS 有 Bootstrap,Fundation 等;
  • PHP 有 Laravel,CakePHP 等
  • C#有 MVC
  • Java 有 Spring+Hibernate+struts

框架要先选好,模块的话,等需要慢慢加就行了。

5. 测试代码

2006 年,单元测试在开发过程中,重要性不是很大,可有可无,程序完成,功能能用就行。

如今的代码,没有单元测试部分,这个工程就不能算完结。甚至是,测试驱动开发已经成为主流,先写测试代码,然后开发。

测试代码的发展有不单单是单元测试部分。单元测试,集成测试,功能测试,性能测试,压力测试等等,都在开发过程中占了极大的位置。以前测试都是由专门的测试员进行人工测试,或者他们负责测试;如今单元测试和集成测试都是要开发者自己写。

6.跨设备,跨平台

Java 提出的跨平台,一次编译到处运行的梦想,其实至今未很好的实现。但是如今这个跨设备,跨平台编程趋势却越来越明显了。

跨设备,主要是指桌面和手机,尤其是针对显示器的最佳实践是层出不穷,如今是响应式成为了主流。

跨平台,出自于 Java 的一个概念,如今已经算普及了,尤其是 JavaScript,桌面,手机,服务器,浏览器,嵌入式都能看到 JavaScript 的身影,这大大归功于 JavaScript 标准化的推广。跨平台过去是说一次编译到处运行;如今是只要这个平台支持这个语言或标准,就能用。如今的跨平台编程,更讲究特性检查这个功能,如果你这个平台没有这个特性,那么就关闭这个有这个特性的功能,但其他功能还可以继续使用。

今后,各种设备层出不穷,VR 头盔,AR 眼镜,巨型屏幕,物联网等等,跨平台会有进一步的发展。

工程方面的:

1.工具化

我觉得工具化非常突出了,凡是能工具完成的事情,绝对不手工完成。以下几个方面都是可以找到相应工具,帮助开发者管理代码质量

  • 代码风格检查
  • 工业标准检查
  • 代码整理
  • 代码复杂度检查
  • 单元测试覆盖率检查
  • 依赖管理
  • 压缩代码
  • 重复代码检查
  • 无用代码检查

等等,

2. 工程化

工程化也是近年来最最突出的一个发展趋势,过去只是选择性的,现在是必须的。

工程化是以工具化为基础的,没有工具,那么工程化也无从谈起。

工程的核心就是流程自动化,又称之为构建,这些包括了:代码质量检测,代码压缩,代码合并,代码优化,代码编译,单元测试等等部分。构建就是把这些以工作流程的方式组合起来,然后用一个命令行运行这整个流程。它有点像批处理,但是是程序开发中使用的特殊批处理

在网页编程的过程中,现在又流行“实时编程”,就是当你在保存代码的时候,以上的构建流程就开始工作完成后自动刷新浏览器,保证新代码效果立刻反应在浏览器上。

现在,你去 GitHub 的项目库中找软件,首先翻看,是否有工程文件,看看它的构建流程是什么,就知道这个项目的专业程度和项目的质量了

而自己,没有一个配置一个工程化的流程系统,都不好意思说自己在做软件工程。

3. 自动化

自动化是以工程化为基础的,工程化本身就是一种流程自动化。而自动化有在工程化的过程中更进一步的自动化。

持续集成就是全自动化的一个终极体现。他的主要流程是:版本控制库 ->构建 ->测试 ->报告.

持续集成有点像 Windows 的定时任务,但是它是程序开发专用的定时任务。

持续集成的特点就是全自动,一个项目一次配置好了后,要求不变的话,就不用管了;然后开发者不断把代码加入到版本控制库里就行了,每当库有新代码时候,持续集成就会下载代码进行构建;当它完成构建和测试后,如果测试没有通过,就会报告给你,然后你根据报告结果进行修改代码。所以你每次往版本库加的新代码时候,持续集成就会全自动的帮你构建和测试代码,尽快的通知你代码的问题。这样程序员就可以更加集中精力编写功能代码和测试代码,而不用担心新代码是否会影响到过去的代码了。

持续集成在多人一起开发的时候,更是有用,谁上传的代码没通过测试,能马上知道。这样保证多人项目在代码顺利合并,体现“持续集成”的功效。

另外还有个持续部署,其实就是持续集成在测试成功后部署上产品服务器上的流程。如今有些网站一天就要部署几十次,有了持续部署后,部署多少次都毫无压力。

工具化,工程化,自动化的关系挺有意思,前者是后者的基础,而后者却极大推动了前者的发展。它们是相互积极作用,相互推动了对方的发展,形成了一个很好的良性循环

其他方面:

1. 版本控制,Git,GitHub

版本控制在编程界中的地位是越来越重要了。在编程界中有个说法:没有版本控制的项目,就等于没有这个项目。

版本控制的工具很多过去有 SVN,如今 Git 的强大,用的人也是越来越多,而它和 GitHub 的相同作用下,对编程界的积极影响和积极推动,是令人无法忽视的。比如几乎所有的依赖管理工具的库下载源,都是和 GitHub 绑定的, 就这一点来说,GitHub 的重要性在 IT 就不可估量。

而 GitHub 上和 Git 的方便管理,上传,查看,统计,bug 报告等功能更是极大地推动了程序员之间的合作;GitHub 上的开源更是改变了开源软件对世界的影响力。

GitHub 不是 Git 的全部,Git 也不是版本控制的全部,本质上来说,GitHub 只是一个网站而已;然后 GitHub 确实又是这个编程世界不可缺少的一个重要的模块,已经成为了一个不可或缺的组成部分了。甚至 GitHub 已经跳出了编程界,成为了一个世界级的不可或缺的服务平台了。然而 GitHub 是 2008 年建立的,真正开始流行是在 2012 年的。在 2015 年 Google 宣布关闭自己的 Google Code。可见 GitHub 的影响力,以及在业界的重要程度了。

2.生态圈意识

生态圈意识在业界是越来越强了,它应该和编程工具化和工程化有极大的关系。一个语言,框架或者库的出现,人们用它们,不但是因为它们本身的强大,更是因为它们背后的生态圈。

比如说人们选一个 JavaScript 的框架,选 React 还是选 Ember.js,更多是看支持他们的生态圈如何,React 是有 Facebook 支持的,更有很多程序员为它开发相关工具和库以及有很多文档教程。这样 React 的生态圈就很大,会让更多人愿意选择 React 作为第一开发框架。而 Ember.js 相对来说生态圈小,选择它的人可能就不会很多。

选语言也一样,选 JavaScript 编写爬虫还是选 PHP 编写爬虫还是用 Python?更多的是看他们的生态系统了,Python 的爬虫库强大且丰富,所以更多人选用 Python 编写爬虫。

一个新的语言出现,成熟与否,看的就是它的生态圈了,比如是否有测试框架,是否有 MVC 框架,成熟的时间库,数据库 SDK 等等,这些都是其必要的生态圈组成部分。

总结:

以上的这些现象和趋势,其实都是相辅相成的,最终成了一种良性循环。这些现象和趋势都会继续发展下去,并成为以后新趋势的基础。所以这些特点都是非常重要的,而且应该成为每个程序员都应该知道的知识。

给学生们的一些建议:

我在读编程专业的时候,这些东西大学都没有教过,甚至在工作中,公司都没有这些要求。大学主要教的是代码编写,能编译通过,能出正确结果就可以了。在工作中,代码能用,没有明显 bug 就行。

然而,在我个人工作实践中,逐渐的体会到这些趋势的重要性了,可维护性的高质量代码可以大大减少自己在维护中的难度和压力。作为准备成为一个合格的开发人员,应该熟练掌握这些知识和技能。如果大学没有教过,一定想办法自己学习和提高。

又想到几个发展,这里更新一下

1. WEB 技术的桌面化和 JavaScript 的全栈化

JavaScript 近些年发展火热,逐渐印证了一个 Atwood 法则:凡是可以用 JavaScript 实现的,最终都会用 JavaScript 实现

  • Nodejs 的出现,奠定了 JavaScript 走出浏览器,走向了服务器端
  • NW 的出现和 electron 正式版发布,JavaScript 走向了桌面
  • MongoDB 的出现,JavaScript 走向了数据库
  • Tessel 的出现,走向了硬件和物联网

如今一个全栈系统,从前端到数据库,可以完全使用 JavaScript 一种语言。还有很多人正在致力于把 JavaScript 推向更多的领域中。

而 Web 技术(html+css+JavaScript)由于 NW 和 Electron 的出现,已经可以编写桌面程序了。正是由于 JS 的优秀模块很多,以及 HTML+CSS 的界面容易编写和掌控,纠错工具丰富,很多人愿意用 WEB 技术进行开发。现在比较火的桌面工具有 VS-Code 编辑器和 Atom 编辑器。

总结一下:由于 WEB 技术的便利性,WEB 技术涉及的领域也就越来越多,再也不是浏览器的专利了。

2. Web API 的全面发展

Web API 虽然历史悠久,但是真正使其推广流行的应该是 Twitter,而后移动设备的普及使其得到更大发展和普及。移动设备如果没有 Web API 基本就不能工作了。Web API 的普及,也使得网络服务之间相互连通,形成一个更大的服务网络。总之,如今的 Web API 已经是不可或缺的存在了。

Web API 更多的是一种服务,或是一种数据交换模式。只要语言带有 HTTP 的网络访问功能,就都能使用。提供 Web API 的公司,发布 Web API 后,一般也会同时发布一些常用语言的 SDK,方便相应语言开发人员快速上手;但是如果语言比较小众,没有提供相应的 SDK 也没有关系,编写一段 HTTP 的请求,也是可以交换数据。

从编程的角度来归纳一下 Web API 特点就是:

  • 容易编写,就是个函数,无需界面
  • 语言无关性,无论 Web API 是个语言编写,几乎任何语言都能调用
  • 访问性好,无论在哪,只要网络能访问,Web API 就可以用。

3. 语言之间的相互借鉴

语言之间的相互借鉴也越来越明显了,比如:

  • PHP5.0 后支持了类,5.4 后支持了 Trait,5.5 后支持了生成器(Generator)
  • JavaScript ES6 支持了箭头匿名函数,生成器(Generator),类(不是 Prototype 的类)
  • C# 和 Java 相互借鉴
  • Coffee Script 借鉴 Python 和 Ruby

与其说是相互借鉴,不如说随着语言的发展,一些语言概念逐渐成为了标配,如果没有,就算是一个不完整的语言了。比如说类,匿名函数,常用数据结构等都成为了标配。

4. 语言解析器的工具化

语言解析器(Parser)在过去自是作为编译器的一部分存在的。如今,它已经独立出来作为一个模块或者工具来使用了,这个对于一个语言的生态有着很大的意义,促进了语言生态圈的良好发展。

独立出来的解析器,可以用来编写以下和语言有关的工具,这些工具都是用来优化代码质量的,提高编码体验的。

  • 语法检查,JavaScript 的 JSHint 用的就是 JavaScript 的一个解释器,被 JavaScript 重新解释一遍,把可能有问题的地方标记出来通知程序员,程序员可修改避免潜在错误。
  • 代码最小化,代码重写的一种形式,JavaScript 的最小化项目(比如 Urglify),是把语法正确读取后,进行最小化压缩。把单词变量转换成单字母变量。甚至是 if else 转换成?: 形式。
  • 语法扰乱器,就是代码重写的一种形式,让代码无法阅读,保护代码。
  • 语法整理器,代码重新的一个形式,把无法阅读的代码,转换成可阅读的代码,比如 beautifier。
  • 语法高亮,一般用于代码编辑器和代码显示组件的。
  • 代码分析器, 把可用的代码部分进行扫描,列出代码相关数据,比如用了多少类,多少对象,多少变量,多少全局变量等等
  • 代码清理器,分析器的加强,清理不用的变量,不用的对象和,不用的函数等。
  • 自动完成,一些 IDE 可以分析已经存在的变化和函数,以后在不断的打字中可以智能的自动完成。
  • 代码追踪,比如说某段代码被执行了几次,程序报错时候,函数被执行的顺序,测试程序时候的代码覆盖率等等
  • 虚拟执行,JavaScript 代码在一个保护区域内或环境执行,代码可以返回值,但不能影响非虚拟环境内的代码执行。比如说,代码里面有全局变量,但是虚拟执行后这个全局变量只在虚拟环境内,非虚拟环境的没有这个全局变量。

关于这点,我回答过下面的问题。

用 JavaScript 写成的 JavaScript 解释器,意义是什么? – 知乎用户的回答

5. 数据交换语言的发展

数据交换语言发展总体来说就是从 XML 主流逐渐发展到 JSON 主流的过程. 虽然 XML 现在应用还是非常广泛,但是由于其复杂和标签占用空间大,逐渐被轻量级的 JSON 给代替了。尤其 JSON 与 JavaScript 天然兼容,无需解析,直接使用。所以在很多网络技术中 JSON 是优先使用的。

而如今很多配置文件也是用 JSON 实现的,比如 Composer 和 node 的配置文件。

JSON 的阅读方式更符合程序员的阅读习惯,格式化后的结构一目了然,容易理解。

JSON 好处:

  • 结构符合程序员阅读习惯
  • 文件大小相对更小
  • JavaScript 可以直接使用
  • 在非 JavaScript 的脚步语言中,转化成数据结构更容易
  • 学习曲线很短

正是以上这些原因,使用 JSON 作为数据交换语言可以说在编程界里,是大势所趋了。

发表在 技术探索 | 十年来,编程领域有什么重要进展?已关闭评论

VS2015和Cordova开发套件的使用和评价

visual_studio_2015

最近接手了一个小工程,是使用VS2015+Cordova开发的。上手之后,大呼上当。因为VS2015+Cordova的坑实在太多。基本上是走一步跌个跟头,爬起来再摔一个。

回头询问客户,这种糟糕的东西谁上手做的?开发的人也能忍受?答曰:哦,不要用Visual Studio 2015,用命令行编译Cordova会好些。愕然,早说呀!我安装都搞了3天搞不定。

平心而论,这里面的症结,有一半不是微软的错,是防火长城的问题,特别是安装阶段。怎么处理?安卓开发包,选最小的,后面手工补足 – VS选项里面有个检查工具链完整性的功能,用这个查。要么,就安装全程透明番茄才行,即便如此,失败概率仍然很高。

编译也是。现在的开发套件,普遍采用与网络分发系统结合,及时下载的办法。但是,他们没有考虑到这里的网络条件。所以要么大面积的下载超时报错,要么下载半截,无法解压执行报错。解决方法:下载不下来的,找到那个文件地址,手工下载,放到它希望的位置就行了。

但MS不能免责。它的套件设计有问题。对于这种需要很多工具,操作链条很长的系统,不能搞成黑箱,而这个Cordova开发套件就是个黑箱。这会有什么问题呢?

1、出错找不着地方。如果一个链条报错了,你找不着谁调用的,连命令是啥都糊里糊涂,如何找到这个工具查验完整性?功能是否正确?不知道它放哪里了。这点很糟糕,工具链应该可以配置。

2、版本无法简单更替。开源的软件更新很快,特别是流行的包。但是微软搞成了黑箱,导致你很难直接替换掉原有的旧系统,而微软开发组还声明,只对某些版本做了测试,其它结果未知 – 没事,我们自己测试,你倒是让人能方便的更换呐?不要告诉我研究3、4天才能搞明白,这个跟实际工作并无多少联系,工具而已。

3、错误信息语焉不详。这是微软系统的老毛病了,错误提示跟真正的原因,十万八千里。不谷歌你是找不着原因的。这是过分封装工具链的问题,工具链的操作提示,它为了简化必然过滤,但如此便容易丢失真正的原因,让用户瞎忙一场。

所以,这个Visual Studio Cordova开发套件,建议不要用了。如果必须用,不要用VS2015的管理功能,直接当个编辑器。所有的编译打包操作,使用cordova命令行操作就行了,反而方便的多。顺便说一下,那个近似的xamarin开发套件,一样被无数人喷:BUG实在太多,忍无可忍。微软产品的品控,真是大不如前了。

2016-8-16 更新:

后续测试了其它几个支持cordova开发的IDE,体验结果是:还不如VS 2015完善,绕一圈又回来了。有不同认知的可以提看法,因为我体验的时间比较短。
1、VS 2015:坑多,软件关联性大,特别是版本有要求。但是功能比较多,支持iOS远程打包,调试容易。
2、VS Code:有个插件,功能比较简单,但是可用,也有一些问题,需要研究解决。可以调试。
3、Android Studio: 可以使用插件支持,导入Cordova工程。但是有两个根本缺陷:
1)代码不能修改,里面的www代码是复制过去的,不能改,否则引起同步问题;
2)不能实时调试,没有办法设置断点,基本就是个build、push安装的工具。
4、WebStorm:跟Android Studio实际上是一个内核: JetBrains。有个Cordova插件
可以建立工程,问题是不能连接真机,功能非常的有限、简单。

一句话,这个跨平台开发看似省事,实际上也有很多麻烦在里面。

发表在 技术探索 | VS2015和Cordova开发套件的使用和评价已关闭评论

学得快,记得牢,花的少 – 请尽快开发你的大脑

《程序员的思维修炼:开发认知潜能的九堂课》是几年前的书了。为什么我现在又找出来重看?当然是因为工作需要。在新的一年,我需要重新整理一下思维,为开展新的任务打个更好的基础。除非被证明,里面的理论是错的,否则这种书是不会过时的。

brain

为了重温本书的知识,我同时阅读参考了如下书籍资料:

《我们要自学》 – 图灵出品的另外一本学习书

《深度学习的艺术》 – 知乎采铜

《暗时间》 – 刘未鹏

《如何高效学习:1年完成MIT4年33门课程的整体性学习法》 – 斯科特·扬(Scott Young)

《认知心理学及其启示》 – 约翰·安德森

为什么读本书这么辛苦?我有主题阅读的习惯。不同的书讲同一个话题,相同的内容可以促进记忆,相互验证;不同的部分可以相互补充,切换看问题的角度。

关于本书,有些遗憾的是书名。我猜测可能是出于“时髦”,起了“程序员的思维修炼”这个名字。其实完全可以去掉,副标题就已经涵盖了一切:开发认知潜能的九堂课。我怀疑是书名迷惑了一批读者,让人以为它是程序开发类的图书,限制了读者群的范围。如果直译,书名其实可能是:《思维与学习的实用指南 – 重构你的湿件》

本书半行代码也没有,是切切实实的思维和学习指南,书籍内容和翻译,都可以打高分。

作为程序员,可能是这个社会里面学习压力最大的一个职业了。其它好多职业,上完大学就等于职业训练完成。工作个N年,积累了各种经验,处理业务会更圆滑老练,除非你要追踪世界前沿,否则一般不需要在职业知识更替上费多少心力。没见那么多穿越、玄幻小说大行其道、流行的一塌糊涂么?闲的。

程序员就惨了。作为知识更新代谢最快的行业,新技术、新思维、新框架层出不穷。你不学习更新,只能等着知识老化,个体价值也会逐渐消解。而如何让自己学的更快、效果更好、成本更低,则大有门道。

本书从多个部分,论述了这些内容。为了验证其有效性,一方面我自己尝试实践,另一方面在充满严肃学术味道的《认知心理学》里面寻找参照和来源。我认为它的知识还是可靠的。

对这样一本实用价值很高的图书进行评论,有些困难。因为我不想总是重复里面的内容。所以我尝试从自身对学习的理解角度来解读它。

在学习方法的研究上,我认为国内的认知还是比较落后的。传统文化上,推崇苦读 – “头悬梁锥刺股、十年寒窗”云云。快乐、轻松学习方法往往会被认为“不用功”,轻松又学的好的呢?则当成天才看待。学校教育上,充斥着死记硬背和填鸭式教学,对方法类的内容关注的不够。讲求方法,不代表你可以轻松、不费吹灰之力的完成学习任务,难的东西还是很难,它也不能抹平智商的差异。只是它通过对规律的总结和遵守,消除了你的各种无用功。同样的内容,你可以学得更快,记得更牢,花的时间更少,何乐而不为?

对于脑力劳动者来说,你的头脑是最重要的武器和财富,不断的打磨它,让它锋利、有威力,是必须的任务。

首先,你要客观看待学习成长的历程:本书开头的德雷福斯技能获取模型是个很有效的描述。达到专家级水准,是需要很长时间的训练的,所以才有了10000小时(10年成就专家)的说法。而且,练习、实践还必须有质量。这解释了真正的专家为什么这么少。这里还有一个有意思的概念:二阶不胜任 – 不知道自己不知道。这也提醒了读者:广泛阅读,保持好奇心,在头脑中多索引一些线索以便查找。

要学得好,首先了解你的大脑。书中有个词汇:wetware – 湿件,专指人脑。但是人类对自身大脑、意识的认识,是一项很困难的任务。认知心理学的历史,已经说明了这个困难:人类在认知心理学上的耗费,大半用于摆脱错误的观念。不过值得庆幸的是,由于各种设备的发明、改进,以及各种实验的开展,一些理论已经被证实或证伪。对学习过程中大脑的活动特征,人们认识的越来越多。我们不必再“摸着石头过河”了。

作者用了一个很出色的概念,来形容人类大脑的一个特性:内存和总线竞争。有点麻烦的是,这个双CPU模式、总线的概念似乎只有程序员最理解。不过看到里面的图也就秒懂了。认知心理学的内容如果照搬,读者多半读不下去了。

他一边阐述大脑的奥秘,一边顺势提出各种训练方法。比如用绘画训练刺激右脑、建立幽默感等等。这些方法可以提高思维能力和创造力,让你的大脑不会感到枯燥乏味,提高效能。还记得图灵的另外一本畅销书么?《黑客与画家》,实际上有异曲同工之妙。两本书都看过的人,会切实的体会到这一点。

了解了你的头脑的生理特性,剩下的就是扬长避短的使用针对性的方法了。里面可能会引起争议的一点是:作者认为短期培训没什么用。他称这种培训为“羊浸式”。因为缺乏明确的目标和有效的反馈,往往导致随机的结果。对于这个结论,不知道多少培训公司要反对他。

大部分人学习是从阅读开始的。我从各种材料上对照过,方法大同小异,都有共同强调的地方。比如,阅读应该是“问题导向”的。什么意思?你看书的时候,要发掘出问题来,让头脑有好奇心,去追着问题的答案。深度学习里面,称之为“建构主义”的模式。

  1. 针对当前的学习材料,我已具备了哪些相关的知识?
  2. 针对当前的学习材料,我又学到了哪些新的知识?这些知识对原有知识构成了何种补充或者挑战?
  3. 针对当前的学习材料,还有哪些未知的东西,且这些东西我通过简单的探索就可以了解?
  4. 针对当前的学习材料,还有哪些未知的东西,无法轻易地获得解答,同时又有价值成为我长期去探索的问题?

而高效学习的核心,我认为其实就一个:Connect。想方设法,千方百计的把知识串成线,织成网。利用有序重组无序,让旧知识和新内容建立联系。 只有这样,你的大脑才能有效的建立“索引结构”,迅速的提取需要的内容。

深度学习里面谈到:

…就像一根根富有韧性的细线,帮我们把各种知识、经验、观念和方法串在了一起,使散落的砂砾变成一串串富有光泽的珍珠项链。可以说,一个学习者越是成熟,他就越擅长做这类长时程的知识结构化的工作。

本书作者在穿插于书中的各种方法,大都是围绕着大脑生理进行的。里面有几条很有趣,效果立竿见影。比如他提到:压力扼杀认知 – 看看IT业那么多疯狂加班的公司吧,加班是不会带来创造性的突破的,它只会抑制创新;避免多任务处理;多用一台显示器就可以让你的生产力提升20%-30%。对于这一点,我是实践过的,双显示器甚至3显示器,真是方便多了。你可以一边看着资料,一般敲代码。

书中有非常多的“金句”式的闪光点和各种诀窍,你可以单独拿出来总结成文,用于指导实践。不过,事情从来都是说来容易做到难,战胜自己的习惯和惰性是相当不容易的。

好书不单给你指导,还会给你提供深入研究的各种索引。从这点上说,此书虽薄,意义却重。

发表在 学习的技术 | 标签为 | 学得快,记得牢,花的少 – 请尽快开发你的大脑已关闭评论