pugWoo's Life   All-Posts  About

2016-我的这半年

今年5月份,我离开了Ali,在Ali做的项目是海关出口B类业务,我感觉B类业务的开发过于商业化和流程框架笨重,整个团队的氛围过于看中商业结果,不够关注产品体验,看事情不够长远。我还是喜欢小而美的互联网产品,加上毕业4年来都是在大公司,所以我想去小公司积累些经历。于是,就有了这半年来太多的感想,感觉比过去的几年,要丰富得多了。

柚A米公司

感悟到的一些想法

  1. 中小型公司招聘技术岗位的公司类型及个人选择:

    • 重构类或有历史包袱的公司,应聘职位必须是技术负责人身份或领导给予足够的权力和时间(后者实际上较难)。

    • 全新搭建系统,则看重业务和团队,只要在团队中有显眼的位置即可。

  2. 敏捷开发谁都喜欢,但并没有多少团队可以做到。靠流程的方式来规避技术缺陷是不太可能的。只有技术本身的提升可以解决技术缺陷。

    例如,规定每天的发布次数或晚上发布,并没有办法有效避免发布失败的问题。正确的方式是,预发布系统、回滚管理。

关于缓存的争论

我一直对缓存的使用有着非常慎重的态度,我认为使用缓存解决性能瓶颈时要非常小心,不然很容易出现分布式系统一致性问题。我在阿里时的团队,由于全局性缓存的使用,导致了几次系统大规模崩溃,最后团队才下决定不使用全局缓存。coolshell有篇文章缓存更新的套路非常系统和全面讲述了怎样使用缓存。

本质上,关系型数据库的事务和外部系统(如redis或消息队列等)的事务是没有简单办法保证强一致性。因此,两者的读写顺序和事务回滚策略需要精密设计。

刚到柚A米公司时,技术部负责人阳工,设计了一个全局的缓存方案,该缓存全局切面在web层,对所有URL的返回结果进行缓存,同时有对应的更新策略。我列举了很多弊端说明全局式切面式缓存容易失控、不好运维的情况:

  1. 强一致性问题,怎样快速发现快速修复?下单后快速看不到订单的问题如何解决?MYSQL的事务怎样和redis,mq等其它方式结合?

  2. 缓存数据由业务代码+数据库数据加工而成。当逻辑代码出行bug导致缓存数据错误时,怎样大规模更新缓存?当数据库发生数据订正时,怎样更新缓存数据?

  3. redis的运维稳定性和经验远弱于mysql。一个配置的redis ip被多个应用引用,一个数据存储被多个应用依赖,这也是不够内聚的。是否应该规范应用间调用仅存在SOA方式,方便治理,缓存只由一个应用管理。异步则仅用消息队列和定时任务方式。

  4. 这份缓存数据对预发环境可能不够友好,没有mysql对向下兼容的运维稳定性强。

  5. 对于前端的高并发接口,可以设置0.1秒的高速缓存来解决问题。不需要为冷门接口都设计缓存。

技术执念?iframe坚决不用

在网页技术使用方面,iframe一直是前端比较不建议使用的技术。但不代表其没有合适的场景。

公司在设计运营使用的管理后台,在是否使用iframe决议上,未经讨论即否定使用iframe,这是一个后台架构师前端能力不足而产生的技术选型一刀切?

实际上,对于后台运营系统,特别是异构系统比较多的情况,使用iframe可以很容易聚合各系统,包括互联网(例如查询快递)的工具页面。其次,后台人员对前端掌控力不像前端专业,使用iframe做首页菜单,可以使子页面无需嵌入菜单模版,简化页面开发。同时,也可以避免子页面影响了菜单而导致跳回麻烦。使用iframe的首页菜单非常稳定。

在最后实现上,也没有实现不同页面不同URL,使得运营人员可以收藏某个后台操作页面,快速进入该页面。如果使用iframe的话,可以使用锚点的方式实现。

实际上,在很多主流互联网页面上,都有iframe的身影,对于技术的使用,要思考其适用场景,利弊权衡点,切不可不加思考地一刀切。下面场景使用了iframe:

  1. QQ邮箱,QQ邮箱的左侧菜单栏是父页面,右侧的内容页是iframe。使用的原因猜想是QQ邮箱提供的服务非常复杂,iframe可以很好地聚合。而同时,在qq.com域名下的登录态是相同的,很容易嵌入一个漂游瓶的游戏页面,或QQ空间的订阅页面。

  2. QQ、淘宝等大型网站登录框。在网站的任意页面,只要需要登录态,就可以弹出登录框,这个登录框是一个iframe,在iframe子页面中完成登录,cookie会同步更新,登录之后回调关闭iframe,即可继续原页面操作,不需要跳转。如果不使用iframe,这样的操作将很难完成。每个页面都会高度耦合登录代码。

  3. 网易云音乐PC版。网易云音乐使用iframe实现了在各种跳转页面时,后台播放的歌曲仍旧继续。实际上,最下方的播放器才是父页面,而整个大页面实际上是iframe页面,页面URL使用锚点方式记录当前页面。

公司新来技术负责人设计的新架构问题

  1. 用于部署到测试、线上的war包,是在本地员工电脑编译完之后传上去的。

  2. web层没有使用全局异常拦截器,抛异常时会把异常栈信息显示给客户。

  3. web层前端接口传递的参数都放到了Map中,并传递给了service层,又继续传递到DAO层,最后到mybatis的xml配置文件。有三个问题:1)语义不明,看代码看不出map中有哪些参数;2)前端修改了变量名称,将直接导致sql出错,牵一发动全身。3)中间没有明确的参数校验和类型校验,容易出现SQL注入漏洞。

  4. 数据库和Java之间并没有明确的DO表达其对应关系,而是采用map的方式,这种太过于动态。

  5. 当前项目的域名管理应该比较散乱,导致了Access-Control-Allow-Origin: *的出现。

  6. DAO层抛出显式exception,导致service都需要抛出,最后由web层try-catch,代码比较繁杂。

  7. service层没有抽象出接口,对于后续暴露SOA服务、文档整理并不利。

  8. 前端返回值没有标准的格式,自行拼凑json,返回{status:1,msg:""}来表示成功,{status:0,msg:""}表示失败。这种字段的规范必须来自于java的POJO。

  9. logback日志配置没有区分error、归档、慢sql慢web等记录。慢sql可以通过druid来打印,不用通过mybatis。

  10. DO/DTO/VO 不是很明确,有的DTO被传递到了DAO层。