一起来看看淘宝首页的个性化

随着互联网技术以及软硬件技术的快速发展,网络已经成为人们生活中不可或缺的一部分,在长期的互联网冲浪中,网民对网络信息的辨识度日益增进,网络信息提供方也必须与时俱进,抓住用户的要害。

就拿我们淘宝的业务来看,几年前看到最多的是以商品为维度分类、分层;而现在,一切以人为中心,围绕用户做产品,帮助用户挖掘消费区间,帮助用户找到自己感兴趣的东西。淘宝首页就被拿出来开了一刀,作为淘宝的门户,它承载了万千入口,如何让用户直达兴趣之地?那自然少不了千人千面地展现内容。今年淘宝首页的改版,无处不散发个性化的味道:

淘宝首页的个性化需求

首页的内容运营不是一两个人可以完成的,四五十个业务,每个业务又有很多子业务方向,为了让所有运营有序的在首页编辑数据,主体采用 TMS 搭建,目的是隔离模块权限(当然,目前淘系也没有比 TMS 更适合的平台来搭建首页)。

为了满足不同产品的需求,同时更好地展现产品特征,设计中采用了大量的色彩,如下图所示:

多彩的模块

同时也为业务提供了多套可供选择的模板:

多套模板

在满足业务需求的前提下,更重要的是以人为中心,把用户喜欢的东西放到最醒目的位置。如下图「我常逛的」区块,通过算法介入,打分排序,从业务池子中的几十个模块中选出四个:

我常逛的

每个模块中的很多数据都是通过个性化接口获取的,并且为了提高运营的执行效率,需要前端实现以下功能:

  • 对于整个区块,运营可以对业务置顶、排序
  • 对于区块中的每个业务模块,支持运营配置其版式,以及配置该模块是否需要关闭个性化
  • 对于模块中的每个数据坑位,支持运营干预是否需要个性化
  • 对于部分业务模块,支持运营配置多条数据,然后算法决定出哪几条
  • 而有部分业务,会采用自己的业务数据,该模块的渲染则需要独立处理

简单而言,就是需要实现模块的位置、模板、内容(或者部分内容)个性化,同时对每个维度做开关控制。为了更好地告诉用户自己的属性,也会在导航上为用户打标:

打标

设计也会有个性化的需求,如不同地域的人群展示不同的内容:

member 区域背景个性化

前端面临的问题

先记住一句话:「不能相信任何数据源」,数据源出来的数据偶尔出乎你的意料,数据缺少条目、格式不对、状态不对、回调不对等等。

从上面的个性化需求可以看出,前端面临的问题还是不少的。

首先,数据的来源较多。 每个区块采用的算法不一样,所以每个区块对应的数据接口也各不会相同,并且一个模块中,并不是所有数据都会走个性化接口,还有一部分数据来自运营的手工填写(运营手工填写的内容,部分同步渲染,部分异步渲染)。有些运营为了方便管理投放,如多个运营维护一个坑位的情况,会采用其他平台投放,前端需要通过平台接口获取数据;再加上部分业务有自己的后端服务,前端只能通过他们的后端接口获取数据;页面上还有不少阿里妈妈的广告,自然也是走他们的接口。约摸算来,整个首页的数据接口不下于 15 个。

大多数区块的渲染,需要经历两次串行的请求 。首先通过算法接口拿到需要展示的模块 id 、模块排序和模块的个性化数据,然后通过模块 id 加载对应的非个性化数据(非个性化数据中包含了运营对个性化数据的干预逻辑),合并两个数据后才能渲染一个区块。有人问:

  • 是不是可以并行请求两者?答案是不能,业务模块实在是太多了,如果把所有 id 的模块数据都拿过来,数据太多。
  • 算法那边是否可以将所有业务的数据都拿过去,然后只给前端传输整合后的数据?答案依然是不行,业务数据可能被实时修改,算法那边同步是个问题,目前没有较好的设施完成这套数据同步。
  • 是否可以让算法的数据流过业务数据,将最后需要的数据过滤出来?答案是这很靠谱,然而这套体系还没有完善,本次改版无缘用上。

第三个问题是,数据匹配问题。业务模块有一个 id,这个 id 需要前端与后端约定好;而业务的非个性化数据因为要异步加载,也有一个数据请求 id,这个 id 由 TMS 平台产生,业务模块较多,两类 id 需要人肉匹配。在前后端的交互过程中,可能会出现如下问题:

  • 算法提供的数据 id 中有一个在前端这里找不到
  • 算法提供的数据存在重复/过少/过多
  • 算法提供的数据中某一项的数据格式不对

前端还有一个模板匹配的问题,为了保证数据的纯洁性(其实是为了让运营配置后台清爽),光看业务数据是不知道该数据匹配哪种模板的,前端在区块配置列表中还得加上模块的模板 id,可以看看区块的配置后台:

区块配置后台

第四,也是一个让人头疼的问题,兜底容灾的处理,对于单模块单数据源的渲染,容灾是一件相当轻松的事情。而对于多模块多数据源的容灾处理,其逻辑的复杂程度超乎想象。

黄金准则

为了让页面能够流畅地渲染,技术上下点功夫那是必须的!站在用户体验的角度去思考,其实很多问题都会迎刃而解:

  • 首屏一定要快
  • 滚屏一定要流畅
  • 能不加载的先别加载
  • 能不执行的先别执行
  • 渐进展现、圆滑展现

在快的基础上做到手感丝滑,需要优化的点有很多,下篇将给大家带来淘宝首页的性能优化实践。

本文同步自 小胡子哥的个人网站,原文地址: http://www.barretlee.com/blog/2016/03/31/personality-in-taobao-home-page/

一起来看看淘宝首页的个性化

对系统链路问题排查的一些看法

页面上发现几个模块展示比较缓慢,白了大约 5s 之后展示兜底,显然,是接口请求超时了,打开控制台一看,果然,接口挂了。看了下相关页面,因为大量用到这个接口,模块也都加载超时了。换一台电脑看了下,存在一样的问题,确认是接口挂了。

10 min 左右后接口却又恢复正常。于是出现下面系列流程:

  • 联系相应的同学,最后找到能排查问题的人。
  • 查看监控平台,发现确实没有数据过来。
  • 查看服务器日志,发现确实没有日志进来,确认监控数据未出错。
  • 结论是平台无错误。

继续溯源,

  • 平台上一层是统一接入,查看 lvs,发现没有流量进来
  • 查看机器系统日志,lvs 有人在调试

当然,问题在这里已经找到了。如果这一步还没有找到,就需要继续溯源,看看域名解析是否有问题,DNS 解析是否有问题了。

自动化的检测

当用户发现网页模块超时加载后,

  • 前端系统警报
  • 触发对应接口的链路查询
  • 检查 DNS 解析是否正常
  • 检查证书是否过期,是否正确部署
  • 检查统一接入层是否有流量异常
  • 检查平台监控数据是否异常
  • 检查服务器日志是否异常
  • 检查程序是否报错

而这条链路也可以在平时正向冒烟测试,定期检查是否存在问题,提早发现问题,这样才能发挥监控的价值。

本文同步自 小胡子哥的个人网站,原文地址: http://www.barretlee.com/blog/2016/03/19/problem-debugging/

对系统链路问题排查的一些看法

多 SSH Key 管理技巧与 Git 多账户登录问题

对很多开发者,尤其是手握几台甚至几十台机器的同学而言,登录到远程机器处理事务应该是家常便饭。如果你也是其中一员,悄悄问一句,你平时是如何记住一堆帐号、机器地址以及一些附加登录选项的呢?或许你也是这么干的:

倘若你有一个远程服务器,地址为 test.server.com, 防止人为攻击,你将 ssh 的端口号从 22 改成了 8892,当你需要登录到这台机器时,需要这么做:

➜  ~ ssh YOURNAME@test.server.com -p 8892password: *******

尚好。如果你先前已经将已经注册了一个公钥/私钥对,并且正确的部署到了远程机器,你可以省却输入密码这个环节(推荐学习 ssh-copy-id 命令)。

为了可以再懒一点,索性将这一串代码添加一个 alias:

➜  ~ alias test='ssh YOURNAME@test.server.com -p 8892'➜  ~ test

一条 test 命令即可让你登录到服务器,对于只有一两台远程机器的你,应该算是特别便捷了。

多 SSH Key 的管理

SSH 连接建立之前,会在系统中寻找它的配置,一般有两个位置。

  • /etc/ssh/ssh_config 这里是对所有用户适用的全局配置
  • ~/.ssh/config 或者 $HOME/.ssh/config 这是用户的个人配置,这些配置会覆盖全局配置

注意:一般来说,我们给 ~/.ssh 文件夹赋予的权限为 0700

配置格式比较简单,以下配置等同于上面我们的登录命令设置:

Host test  HostName test.server.com  User YOURNAME  Port 8892

可以是 param value 也可以为 param=value,其中 param 对大小写不敏感,value 对大小写敏感。

使用 ssh test 即可完成登录,当我们有稍微麻烦点配置的时候,如数据库的 3306 端口对外不开放,可以开放另一个接口,然后内部跳转到 3306,使用命令行的写法是:

ssh -f -N -L 8999:127.0.0.1:3306 test@database.server.com

大串的命令行,过多的参数,实在是有点不好记。而在 config 文件中的配置就一目了然:

Host test  HostName test.server.com  User YOURNAME  LocalForward 8999 127.0.0.1:3306

当你有多台远程终端的时候,config 文件的优势就更加明显了:

# serverlist Host list  HostName *.serverlist.com  User YOURNAME  IdentityFile ~/.ssh/serverlist.com.key# personal server  Host personal  HostName proxy1.barretlee.com proxy2.barretlee.com  User barretlee  IdentityFile ~/.ssh/proxy.barretlee.com.key# schoolHostName 222.20.74.89  User school  LocalForward 8999 127.0.0.1:3306  IdentityFile ~/.ssh/school.key# and so on.

这里常用的的 param 也不是很多:

  • Host,SSH 连接名
  • HostName,如上所示,可以是通配符,可以是 IP,也可以是域名等
  • User,登录的用户名
  • IdentifyFile,version 1 协议下默认是 ~/.ssh/identify,version 2 协议下,默认是依次匹配:~/.ssh/id_dsa~/.ssh/id_ecdsa~/.ssh/id_rsa,还有 version 2 兼容模式。
  • LocalForward 端口的内部跳转
  • Port,端口设置,默认 SSH 的端口是 22
  • Protocal,协议版本号,1 或者 2

Git 多账户登录问题

向仓库 push 代码之前,我们都会做一番设置,简单归纳为如下几步:

  • 注册获取用户名 barretlee
  • 创建仓库 barretlee/test.git
  • 创建密钥,ssh-keygen -t rsa -C "barret.china@gmail.com"
  • 将公钥 id_rsa.pub 填到 Git Server 上(如果没有可视化界面,还需要登录到 Server 命令行操作推送)
  • 本地通过 ssh-agent 将密钥添加到 session 中,ssh-add id_rsa,部分终端中还需要手动开启 ssh-agent
  • 然后测试连接,如 github 中, ssh -T git@git.github.com
  • 看到了 ‘welcome barretlee…’ 的提示,开始 push 你的代码

突然有一天,你又注册了一个帐号 xiaohuzige,也走了一遍上面的流程,发现死活也连接不上,服务器总是提示:You have no permission to access this repo,这是怎么回事呢?

这个时候,你可以输入这个命令,看看是哪个环节出了问题:

➜  ~ ssh -vT git@github.comOpenSSH_6.9p1, LibreSSL 2.1.7debug1: Reading configuration data /Users/barretlee/.ssh/configdebug1: /Users/barretlee/.ssh/config line 2: Applying options for *debug1: Reading configuration data /etc/ssh/ssh_configdebug1: /etc/ssh/ssh_config line 20: Applying options for *debug1: /etc/ssh/ssh_config line 102: Applying options for *debug1: Connecting to github.com [192.30.252.128] port 22.debug1: Connection established.debug1: key_load_public: No such file or directorydebug1: identity file /Users/barretlee/.ssh/id_rsa type -1debug1: key_load_public: No such file or directorydebug1: identity file /Users/barretlee/.ssh/id_rsa-cert type -1debug1: key_load_public: No such file or directorydebug1: identity file /Users/barretlee/.ssh/id_dsa type -1debug1: key_load_public: No such file or directorydebug1: identity file /Users/barretlee/.ssh/id_dsa-cert type -1debug1: key_load_public: No such file or directorydebug1: identity file /Users/barretlee/.ssh/id_ecdsa type -1debug1: key_load_public: No such file or directorydebug1: identity file /Users/barretlee/.ssh/id_ecdsa-cert type -1debug1: key_load_public: No such file or directorydebug1: identity file /Users/barretlee/.ssh/id_ed25519 type -1debug1: key_load_public: No such file or directorydebug1: identity file /Users/barretlee/.ssh/id_ed25519-cert type -1debug1: Enabling compatibility mode for protocol 2.0debug1: Local version string SSH-2.0-OpenSSH_6.9debug1: Remote protocol version 2.0, remote software version libssh-0.7.0debug1: no match: libssh-0.7.0debug1: Authenticating to github.com:22 as 'git'debug1: SSH2_MSG_KEXINIT sentdebug1: SSH2_MSG_KEXINIT receiveddebug1: kex: server->client chacha20-poly1305@openssh.com <implicit> nonedebug1: kex: client->server chacha20-poly1305@openssh.com <implicit> nonedebug1: expecting SSH2_MSG_KEX_ECDH_REPLYdebug1: Server host key: ssh-rsa SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8debug1: Host 'github.com' is known and matches the RSA host key.debug1: Found key in /Users/barretlee/.ssh/known_hosts:4Warning: Permanently added the RSA host key for IP address '192.30.252.128' to the list of known hosts.debug1: SSH2_MSG_NEWKEYS sentdebug1: expecting SSH2_MSG_NEWKEYSdebug1: SSH2_MSG_NEWKEYS receiveddebug1: Roaming not allowed by serverdebug1: SSH2_MSG_SERVICE_REQUEST sentdebug1: SSH2_MSG_SERVICE_ACCEPT receiveddebug1: Authentications that can continue: publickeydebug1: Next authentication method: publickeydebug1: Trying private key: /Users/barretlee/.ssh/id_rsadebug1: Trying private key: /Users/barretlee/.ssh/id_dsadebug1: Trying private key: /Users/barretlee/.ssh/id_ecdsadebug1: Trying private key: /Users/barretlee/.ssh/id_ed25519debug1: No more authentication methods to try.Permission denied (publickey).

不加 v 参数,输出的内容很简洁:

➜  ~ ssh -T git@github.comWarning: Permanently added the RSA host key for IP address '192.30.252.129' to the list of known hosts.Permission denied (publickey).

好吧,我知道你看不懂上面一长串的内容,也没心情看下去,但是你可以把焦点落到重复的那几段:

debug1: ...debug1: xxx, No such file or directorydebug1: ...debug1: Trying private key: /Users/barretlee/.ssh/xxxdebug1: ...

之前我们提到了 Protocal Version 1 和 Version 2,不同的版本号,默认的私钥地址不一样,所以程序会不断去尝试寻找默认的地址,如果没找到,最后会提示,授权失败,禁止访问。

我们可以在 push 代码之前,使用 ssh-agent 来管理私钥的 session,如:

➜  ~ ssh-add .ssh/coding_barretleeIdentity added: ~/.ssh/coding_barretlee (coding_barretlee)➜  ~ ssh-add .ssh/github_barretleeIdentity added: ~/.ssh/github_barretlee (github_barretlee)

那么当程序寻找私钥的时候,就会优先到 ssh-agent 添加的 session 中寻找。session 的生命周期不是很长,当你重启电脑之后它就没了。如果你有遇到了 Permission Denied 的提示,请重新执行 ssh-add 命令。

当你在某个 Git 服务器上有多个帐号的时候,可能某个帐号总是提示:Permission Denied。拿 coding.net 上来说,我有两个账户,一个是 barretlee,另一个是 taobaofed,由于先前我一直用的 barretlee 账户,后来者 taobaofed 的代码死活推不上去。反反复复地检查配置,反反复复地检查上传的公钥,反反复复地使用 ssh -T git@git.coding.net 测试,没看到哪里不对,然而 taobaofed 的代码就是推不上去,这是怎么回事呢?

当然,上面 SSH 介绍了那么多,其简明易懂的配置在这里也是可以用上的:

### default for all ##Host *     ForwardAgent no     ForwardX11 no     ForwardX11Trusted yes     User nixcraft     Port 22     Protocol 2     ServerAliveInterval 60     ServerAliveCountMax 30## barretlee coding ##Host coding-barretlee     HostName git.coding.net     User barretlee     IdentityFile ~/.ssh/coding_barretlee## taobaofed coding ##Host coding-taobaofed     HostName git.coding.net     User taobaofed     IdentityFile ~/.ssh/coding_taobaofed

使用这种配置,我们可以避免使用 ssh-agent 添加 session 操作。可是,我就是按照上面的方式配置的呀,依然不行!

这里的问题在于,我们的 User 项不正确,每次推送代码的时候,git 会读取上次的的 User 配置,而我的配置是 barretlee,那么下次提交代码的时候虽然 IdentityFile 用对了,但是 User 不是 taobaofed,所以死活也推不动代码。

解决的方案很简单,如果在下载代码之前就已经设置好了两个帐号,你可以通过如下命令克隆代码:

➜  ~ git clone git@coding-taobaofed:taobaofed/blog.git

如果是在已有的仓库中,其默认 origin 配置会是:https://git.coding.net/taobaofed/blog.git 或者 git@git.coding.net:taobaofed/blog.git,你可以改仓库下的 .git/config 文件修改下:

[remote "origin"]  url = git@coding-taobaofed:taobaofed/blog.git  fetch = +refs/heads/*:refs/remotes/origin/*

防止克隆其他仓库代码也出现问题,我们可以将 ~/.ssh/config 稍加修改:

## barretlee coding ##Host git.coding.net coding-barretlee     HostName git.coding.net     User barretlee     IdentityFile ~/.ssh/coding_barretlee## taobaofed coding ##Host coding-taobaofed     HostName git.coding.net     User taobaofed     IdentityFile ~/.ssh/coding_taobaofed

那么,通过正常的 clone 如(git clone git@git.coding.net:barretlee/blog.git)就不会出现 Permission Denied 的提示了。

最后

撰写本文之前,我已经踩坑三小时,花了三个小时,摸索出来这么些东西,感觉以后妈妈再也不用担心我的 Git/SSH 的配置问题了。

最主要的手段依然是通过 ssh -vT 查看 SSH 交互过程中出现了什么障碍,debug 信息还是很有考究价值的!

本文同步自 小胡子哥的个人网站,原文地址: http://www.barretlee.com/blog/2016/03/09/config-in-ssh-after-troubling-git-connection/

多 SSH Key 管理技巧与 Git 多账户登录问题

认识网页无障碍

最近忙里偷闲坚持了好几个星期网页无障碍相关的学习和研究,看了很多文档,也在 Google 中寻觅了不少博客文章,总的来说就一个感受:规范文档太细节太长,博客指导性不强。

上文 中提到,信息无障碍并不是一种爱心公益活动,只是在大多数公司中,这方面的技术/产品投入难以带来可观的利润,于是信息无障碍难以进入开发的流程之中,即便有工程师零零碎碎地在页面中加入了无障碍优化,一段时间的产品迭代之后,这些优化又荡然无存了。

我希望,通过一段时间的研究和实践,能够把我对网页无障碍化的理解表达出来,在学习的过程中,会去盲人社区交流,切身体会视障人士的处境,同时也会跟国内几位做了比较长时间网页无障碍研究的盲人开发者沟通,收获一些心得。

认识网页无障碍化

站在一个用户的角度思考。当用户进入你的网站,他的目的应该是很明确的,在最短的时间内通过最快的方式找到自己想要的信息。正常人通过眼睛去捕捉网页上的信息,而视障人士主要通过耳朵,并使用读屏软件辅助读取页面的信息。

如果网页很长,链接很多,比如一些门户网站,盲人用起来就会特别吃力,PC 上通过 TAB 键从头开始往后聚焦,成千上万个链接堆叠在一坨,其恶心程度可以想象,我觉得能够鼓起勇气进入这些网站的盲人都是脾气相当不错的(如果是你,你会砸键盘么🙈)。

读屏软件不知道哪些信息是「重要信息」和「次要信息」,更加不清楚哪些信息是重复信息,有的时候读屏软件还会读到一些干扰信息(比如图形字符等)。

所谓的网页无障碍化,就是将网页信息有序的排列在一起,并且提供几个快捷入口让用户迅速找到关注点,然后排除干扰,我简单地理了下无障碍化的思路:

  • 第一步,让用户知道页面上有什么内容,比如使用 HTML5 的语义化标签以及 WAI-ARIA 中的 landmark 地标;
  • 第二步,让用户可以轻松在页面的板块之间切换,比如添加快捷键支持;
  • 第三步,让用户知道哪些是主要部分,甚至在进入页面的时候就提供快捷方式跳到主要内容的锚点;
  • 第四步,去除页面干扰,如 iconfont 文字,相邻重复的链接等;
  • 第五步,提供页面的交互支持,让自定义的组件如 tab、slide 都具备无障碍属性。

稍微厘清上面五个步骤的思路,其实很简单,就是让信息模块化地呈现,这样就可以让耳朵更好的代替眼睛办事儿。

理解和实践网页无障碍化

掌握了整体的思路后就会清楚,哪些操作是有益于网页整体无障碍的,哪些操作是局部的微小优化,对于很多网站而言,我们可能不需要去关注细微的优化,因为这些事情读屏软件可以胜任。只要能够在整体上将一个网页乃至一个网站的无障碍体验做好,这就是网页无障碍化的最佳实践!

有些同学在做无障碍实践的时候没有真实理解盲人的需求,所以做出来的东西反而比没优化之前更加难用,比如滥用 tabindex,把网页内容的顺序排列得支离破碎,如果你正在做或者正准备做网页无障碍,请你一定要站在盲人的角度看问题。当然,最好你还能闭上眼睛拿着读屏软件测试下你写的页面。

不同的平台会有不同的读屏软件,由于各读屏软件对标准的实现存在偏差,甚至存在删减,最后导致不同平台下的读屏体验是不一样的,如同我们关注各浏览器之间的兼容性一般,在做无障碍测试的时候,也要关注不同读屏软件的差异。

最后

文本主要从网页无障碍的思路上做了一些阐述,可能不严谨,也可能有表述不当的地方,如果你对这方面有研究,欢迎提出你的观点,也期待更多人关注网页无障碍化。

本文同步自 小胡子哥的个人网站,原文地址: http://www.barretlee.com/blog/2016/03/05/steps-of-web-content-accessibility/

认识网页无障碍