App架构经验总结

原文链接:http://keeganlee.me/post/architecture/20160303
版权声明:本文刊载在《程序员》杂志2016年3期,版权归《程序员》所有,未经许可不得转载


架构因人而异,不同的架构师大多会有不同的看法;架构也因项目而异,不同的项目需求不同,相应的架构也会不同。然而,有些东西还是通用的,是所有架构师都需要考虑的,也是所有项目都会有的需求,比如API如何设计?架构如何分层?开发环境和生产环境如何分离?这几年,我负责研发过的App,有餐饮类的、社交类的、智能家居类的、电商类的、新闻媒体类的等等。当有了一定的经验之后,你总会有一些自己的心得体会。而以下内容就是根据我的这些经历提炼出来的关于以上几个问题方面的经验总结,内容不多,旨在抛砖引玉。

从API开始

一个App,最核心的东西,其实就是数据,而数据的主要来源,就是API。我之前负责的项目,因为API的坑已经受过了不少苦,因此,之后对App项目的架构设计我都会先从API开始。

制定安全机制

设计API第一个需要考虑的是API的安全机制。我负责的上一个项目,因为API的安全问题,就被人攻击了两次。之后经过分析,主要存在两个漏洞:一是因为缺少对调用者进行安全验证的方式,二是因为数据传输不够安全。那么,制定API的安全机制,主要就是为了解决这两个问题:

  1. 保证API的调用者是经过自己授权的App;
  2. 保证数据传输的安全。

第一个问题的解决方案,我主要采用设计签名的方式。对每个客户端,Android、iOS、WeChat,分别分配一个AppKey和AppSecret。需要调用API时,将AppKey加入请求参数列表,并将AppSecret和所有参数一起,根据某种签名算法生成一个签名字符串,然后调用API时把该签名字符串也一起带上。服务端收到请求之后,根据请求中的AppKey查询相应的AppSecret,按照同样的签名算法,也生成一个签名字符串,当服务端生成的签名和请求带过来的签名一致的时候,那就表示这个请求的调用者是经过自己授权的,证明这个请求是安全的。而且,每个端都有一个Key,也方便不同端的标识和统计。为了防止AppSecret被别人获取,这个AppSecret一般写死在代码里面。另外,签名算法也需要有一定的复杂度,不能轻易被别人破解,最好是采用自己规定的一套签名算法,而不是采用外部公开的签名算法。另外,在参数列表中再加入一个时间戳,还可以防止部分重放攻击。

第二个问题的解决方案,主要就是采用HTTPS了。HTTPS因为添加了SSL安全协议,自动对请求数据进行了压缩加密,在一定程序可以防止监听、防止劫持、防止重发,主要就是防止中间人攻击。苹果从iOS9开始,默认就采用HTTPS了。而关于在Android中如何使用HTTPS,Google官方也给出了很多安全建议。不过,大部分App并没有按照安全建议去实现,主要就是没有对SSL证书进行安全性检查,这就成为了一个很大的漏洞,中间人利用此漏洞用假证书就可以通过检查,从而可以劫持到所有数据了。因此,为了安全考虑,建议对SSL证书进行强校验,包括签名CA是否合法、域名是否匹配、是不是自签名证书、证书是否过期等。

接口协议标准化

API返回的数据,一般都是采用JSON格式进行传输。然而,JSON的值只有六种数据类型:

  • Number:整数或浮点数
  • String:字符串
  • Boolean:true 或 false
  • Array:数组包含在方括号[]中
  • Object:对象包含在大括号{}中
  • Null:空类型

我遇到过的,关于API的坑有大部分就是因为JSON数据和实体对象转化时出错导致的,而且是各种各样的错误都有,其中不乏有一些很奇葩的错误。

最麻烦的就是处理Date类型,因为JSON本身没有Date类型,因此,JSON库将Date类型的数据序列化时会转为String。这时,不同环境,不同平台,以及用不同的JSON解析库,转换后的结果经常会不同。比如,你在开发机上可能得到的结果是”2016-1-1 17:11:11”,但放到服务器后结果却变成了“Jan 1,2016 5:11:11 PM” ,客户端进行反序列化时无疑会失败。后来,我取消了所有Date类型,统一采用时间戳表示,就再没有转化的烦恼了。

另外,接口的开发人员有时候会将一些数据错误地转换为了String,导致客户端使用时因类型错误而异常。例如,本来是数字的1,被转成了"1",客户端做运算时就会出错,或用switch判断时也会出错,或其他无法转换的情况发生时;例如,为空时JSON正确地表示应该是null,但如果转为了String就变成了"null",那问题就来了,我遇到的因为这个错误的转换导致的程序奔溃已经好几次了,第一次的时候,查了一整天才定位到问题所在。

还有,因为接口的开发人员不同,很多时候还会出现不同接口同一个意思的参数名称却不同。比如,对于有分页数据的接口,一般都有当前页的参数,A开发人员可能将参数命名为currentPage,第一页是从0开始;B开发人员在另一个接口则命名为currPage,第一页却从1开始;C开发人员在另一个接口又命名为presentPage,第一页又是从0开始。客户端的开发人员看到也是醉了。

每个技术团队一般都会有一份接口协议文档,主要内容包括每个接口的描述、入参、输出结果等,但一般并不严谨,很多地方没有统一标准,从而容易出现很多坑。因此,有一份统一标准且严格执行的接口协议非常重要。协议的内容除了规定每个接口,包括接口中每个数据具体的数据类型,还需要规定一套共用的数据字典,以及其他需要统一定义的信息,比如签名算法等。一旦有了这份统一标准且严格执行的接口协议,很多问题都将迎刃而解。

接口版本控制

我们已经不止一次因为接口发生变动而导致旧版本的App出错的问题,而且变动不一定是修改了接口本身,有可能是底层增加了一种新的数据结构,接口把新数据也返回给客户端了,但客户端旧版本是解析不了的,从而就导致出错了。

为了解决接口的兼容性问题,需要做好接口版本控制。实现上,一般有两种做法:

  1. 每个接口有各自的版本,一般为接口添加个version的参数;
  2. 整个接口系统有统一的版本,一般在URL中添加版本号,比如http://api.domain.com/v2。

平时小版本的更新,就采用第一种方式,我们的做法是根据不同版本号做不同分支处理。大版本的更新,则用第二种方式,这时候,基本就是一套全新的接口系统了,跟旧版本是相对独立的。

当版本越来越多时,维护就会成为一个大问题,我们没那么多精力去维护所有版本,因此,太旧的版本一般就不会再维护了。这时候,如果有用户还在使用即将废弃的旧版本,需要提醒用户升级到新版本。

架构分层

API的设计完成之后,接下来我就会考虑App项目的整体架构了。整体如何架构,我也曾经做过不少尝试。早期的时候,Android就是将所有操作都放在Activity里完成,包括界面数据处理、业务逻辑处理、调用API。后来发现Activity越来越臃肿,代码越来越复杂,很难维护。于是就开始思考如何拆分,如何才能做到松耦合高内聚。

前面也说过,一个App的核心就是数据,那么,从App对数据处理的角色划分出发,最简单的划分就是:数据管理、数据加工、数据展示。相应的也就有了三层架构:数据层、业务层、展示层。它们之间的关系如下图,数据层是三层中的最底层,往下,它接入API;往上,它向业务层交付数据。业务层夹在三层中间,属于数据的加工厂,将数据层提供上来的数据加工成展示层需要展示的数据。展示层处于三层中的最上层,主要就是将从业务层取得的数据展示到界面上。

数据层

数据层是数据管理者,主要任务就是封装API,并将数据结果交付给上层,中间会再加个数据缓存。整个主流程如下图:

  1. 业务层向数据层请求数据;
  2. 数据层检查缓存中有没有请求需要的数据;
  3. 如果有缓存数据,则直接返回缓存数据;
  4. 如果没有缓存数据,则从网络API获取数据,并将数据加入缓存,然后返回数据。

调用网络API时,还要判断网络状态,根据不同状态做不同处理。如果网络不可用,就无需发起请求了。网络可用时,也要区分是连接WIFI还是连接移动网络。连接移动网络时,一般需要限制调用比较耗流量的请求。曾经,我们没有对移动网络状态下的请求进行限制,结果,测试时流量DuangDuangDuang地一下子就不见了十几M。连接WIFI时,则无需设置这种限制,而且还可以预先请求一些接口,比如请求当前分页数据时,可以将下一页的数据也预先请求。

缓存也需要缓存策略,不同的接口需要做不同的缓存处理。首先,缓存只适用于获取数据的接口,对于修改数据的接口则不适用。其次,不同接口缓存时间一般也不同,对于很少变动的数据缓存时间可以设置长一些,而频繁变动的数据缓存时间则比较短,甚至不进行缓存。最后,缓存数据因为比较多,我们一般保存在数据库,而对于调用频率高、最新的数据,还会在内存中也拥有一份缓存,不过缓存时间比较短。请求缓存数据时,会先检查内存缓存中有没有,有则直接将缓存的数据返回,没有才从数据库获取。

那么,如何将数据交付给业务层呢?这是整个数据层模块与外部交互的部分,当与外部交互的时候,一般都要符合面向接口编程的原则,因此只要提供开放的数据接口就可以了。对于接口的参数需要说明一下,上面提到的参数有appKey、version、currentPage这几个,还有签名sign、时间戳time,其实可以分为两类:系统参数和业务参数。像appKey、version、sign、time这些属于系统参数,而currentPage,或username之类的则属于业务参数。数据层开放的数据接口的参数只需要包含业务参数就可以了,业务层并不需要关心系统参数是什么,系统参数在数据层内部封装API时指定就可以了。

业务层

业务层是数据加工者,主要就是从数据层获取数据,然后经过业务逻辑处理后转化成展示层需要的数据。业务层因为夹在数据层和展示层中间,起着承上启下的作用。也因此,业务层很容易沦落为只是一个数据的中转站,主要就是因为对业务层具体的作用和职责没有理解清楚。

这里用一个例子来说明业务层具体的工作吧,就举个用户注册的例子。用户注册时,界面上需要用户提供手机号、短信验证码、密码、确认密码。那么,最简单的操作就是,带上这些参数调用数据层的注册接口。好了,问题来了,注册接口并没有提供确认密码的参数。那好,调用注册接口之前先判断下密码和确认密码是否一致,不一致则返回错误提示给用户,一致了才调用注册接口。好了,第二个问题来了,用户等网络请求等了一段时间后,请求结果返回说手机号少了一位。下一次,又等了一段时间,这次又返回说手机号多了一位。就因为一个小错误要让用户等那么久,用户肯定有意见。后台也有意见,各种非法的请求都发过来,是嫌服务器压力不够大啊。那好,调用接口之前对这些参数做有效性检查吧,手机号要规范,短信验证码只能为六位数字,密码不能少于六位。终于注册成功了,第三个问题又来了,注册接口是没有返回用户的accessToken的,只有登录接口才会返回。让用户手动再登录一下?这用户体验不太好啊。正确的姿势应该是注册成功后再自动调用一次登录接口,如果因为网络问题第一次登录失败,后面还需要再自动调用多一次,如果还是调用失败,才让用户手动登录。

上面的例子中,对参数的有效性检查,注册成功后的自动登录,都属于业务逻辑的处理,也就是说都是业务层的工作。

业务层交付给展示层的数据也是通过接口的方式,不过,和数据层交付给业务层时不同的是:交付给展示层的数据应该是通过异步回调返回的。因为获取数据是一个比较耗时的任务,通过异步回调才不会阻塞UI主线程。

展示层

展示层作为数据展示者,它只要关心数据如何展示就可以了。不过,数据如何展示却不是那么简单。展示层是三层架构中最复杂的一层了,要考虑的东西远远多于其他两层,涉及的东西包括但不限于界面布局、屏幕适配、图片资源、文本资源、颜色资源等等。在开发一段时间后,展示层出现代码混乱是最常见的。因此,做好展示层,就需要保持高质量的代码。要保持高质量代码,我觉得至少应该遵循几条基本的原则:

  1. 保持规范性:定义好开发规范,包括书写规范、命名规范、注释规范等,并按照规范严格执行;
  2. 保持单一性:布局就只做布局,内容就只做内容,各自分离好,每个方法、每个类,也只做一件事情;
  3. 保持简洁性:保持代码和结构的简洁,每个方法,每个类,每个包,每个文件,都不要塞太多代码或资源,感觉多了就应该拆分。

所谓无规矩不成方圆,展示层的设计,要从开发规范开始。一份好的开发规范,是保证代码有较高的可读性的基础。iOS方面,苹果已经有一套Coding Guidelines,主要属于命名方面的规范。当我们制定自己的开发规范时,首先就要遵守苹果的这份规范,在此基础上再加上自己的规范。Android方面,我也在我的博客中分享过一套(Android技术积累:开发规范),主要分为书写规范、命名规范、注释规范三部分。

最重要的不是开发规范的制定,而是开发规范的执行。如果没有按照开发规范去执行,那开发规范就等于形同虚设,那代码混乱的问题依然得不到解决。

说到单一性,面向对象设计中,有一个基本原则就是单一职责原则,它规定一个类应该只有一个发生变化的原因。保持单一性是减低耦合度的关键标准,其目的就是各方面的解耦。而我这里说的单一性不只是规定类的单一,也包括界面的单一、方法的单一、资源文件的单一等。

界面的单一,首先是界面的布局和界面的数据应该分离。另外,界面数据的获取和展示也应该分离。一句话,保持界面的单一性就是要保持界面上每个维度都做好分离,从界面的布局,到数据的获取,数据的检查,数据的展示。

方法的单一,则表现为一个方法是对一个行为的封装。行为又可以拆分为多个步骤,每个步骤其实也是更细化的行为。因此,方法嵌套方法是一种常态。那么,保持方法的单一性,关键不在于怎么定义这个方法的行为,而在于这个行为要怎么拆分成更细的行为。举个例子,通常在Activity的onCreate方法,做初始化操作,细分出来就分为了:控件的初始化、逻辑变量的初始化、数据的初始化。数据的初始化又可以再细分:数据的获取、数据的展示。每个细化的行为都应该封装为一个独立的方法,这样,才真正符合方法的单一性。

资源文件的单一,主要是指Android的各类资源文件,包括存放字符串的strings.xml,存放字符串数组的arrays.xml,存放颜色值的colors.xml,存放尺寸值的dimens.xml,等等。资源文件的单一,是说所有相关的资源信息要在资源文件里定义并引用到代码或布局文件里,而不是在代码或布局文件里直接定义。这样做,可以很方便地做各种适配和修改,比如支持国际化,比如不同分辨率的屏幕用不同尺寸值。iOS则没有提供和Android一样的资源文件分离的机制,但可以参考Android的做法自己去实现。

环境分离

每个App项目,至少都会有两个环境:测试环境和生产环境。多的甚至有四个环境:开发环境、测试环境、预生产环境和生产环境。开发人员经常需要在环境之间切换,测试人员也同样。经常出现测试人员今天需要测试环境的最新版本,叫App开发人员打包一个给她,明天需要切换到生产版本,再叫App开发人员打包一个生产环境的给她。我们知道,一个App,在一台手机上要么只能是测试环境的,要么只能是生产环境的。测试人员要测试两个环境,只能不断替换不同环境的同个App,这实在太麻烦了。为了解决此问题,最好的方案就是环境分离,不同环境有不同的App。

一个App的唯一标识,Android是用包名,iOS是用Bundle Identify。那么,在一个系统想安装不同环境的App,只要每个环境App的包名和Bundle Identify不同即可。比如,生产版的包名和Bundle Identify命名为com.mydomain.myapp,测试版的包名和Bundle Identify则命名为com.mydomain.myapp.beta,这样,Android和iOS都会识别为两个不同的App了。

不过,只改包名和Bundle Identify是不够的,应用图标和应用名称也要修改,不然安装之后很难区分哪个App是哪个环境的。一般做法就是,非生产环境的App图标就是在生产图标的基础上添加一个环境标签,同时App的应用名称也是在生产的基础上添加环境后缀名。另外,因为包名和Bundle Identify不同了,微信、微博、百度地图等这些第三方平台也都需要为不同环境的App分别申请不同的appID。

实现上,最笨的方法就是拷贝当前工程,然后修改,缺陷很明显,维护成本很高。不过,好在Android和iOS都有很方便的修改方式。

Android有了Gradle,可以设置多个不同的Flavors,每个Flavor都有一个applicationId属性,其实就是App的包名。比如,生产版和测试版的设置如下:

productFlavors {
    myapp {
        applicationId "com.mydomain.myapp"
    }
    myappBeta {
        applicationId 'com.mydomain.myapp.beta'
    }
}

这样,其实就有两个App了。然后,源代码新建一个和main同级的目录,命名为myappBeta,然后,将图标、名称和第三方设置之类的,和main保持一样的位置、文件名、属性等,就可以替换成环境相关的了。

iOS则可以通过创建多个环境的Target来实现环境分离,不同Target可以设置不同的Bundle Identify、Bundle display name、更换图标。另外,每个Target也各自有自己的一份plist文件的,环境变量和第三方设置之类的,都可以设置在相应的plist文件里。

写在最后

至此,关于App架构方面的经验总结就先讲这么多了。其中,部分内容在我以往的博客上也已经有所体现,有兴趣的读者可以前往我的博客了解并欢迎参与讨论。


扫描以下二维码即可关注订阅号。

  • 有态度网友06MY5Z2016-03-03 12:07

    这是我在《程序员》杂志的第一篇稿

  • 有态度网友06MY6e2016-03-03 18:01

    赞一个先,很喜欢你的文章,希望后期能出更多的文章学习,最近做电商的app,需求频繁修改,代码耦合度太高,正愁着怎么进行重构

  • 有态度网友06MY5V2016-03-03 18:48

    很感谢能分享自己的经验供新手学习,博主是否能就fragment和activity在架构层级中的定位详细谈一下呢,对新手很重要啊

  • 种黄瓜的小菜2016-03-03 20:33

    顶下,作为一个菜鸟程序员,从钢哥的文章中学到不少东西。

  • 有态度网友06MY5V2016-03-06 10:31

    大神,你的Blog有feed吗?我没找到,有的话发我一下

  • 有态度网友06MY5V2016-03-06 10:32

    找到了,域名加feed/就行了。:)

  • Mini--黄华东2016-03-17 13:56

    如果你的程序被破解 AppSecret 被别人知道了 怎么办,还有当你的程序员离职了 知道AppSecret,也是危险

  • 有态度网友06MY5Z2016-03-17 14:27

    破解方面可以做好混淆,加大被破解的难度;而至于程序员离职,如果连这个都要防,那就真要费很大心思了,尤其是对于设计该系统的人离职了怎么办?

  • Mini--黄华东2016-03-21 13:54

    我只是给你提点建议,因为这种情况是有的,公司都会涉及到的做好及时的方案处理

  • 有态度网友06MY5Z2016-03-21 16:33

    我们只能做到一定程度的安全,更高要求的安全需要投入更复杂的解决方案,不过目前,我还没对你提出的这两个问题有更健全的解决方案,尤其是程序员离职的问题,真的不好解决。

  • 微凉ぐ季2016-03-23 20:01

    环境那个是不是有更好的办法呢。

  • 有态度网友06MY5Z2016-03-23 22:12

    什么办法呢?

  • 小阳撒2016-03-24 09:16

    这个不是可以定期刷新获取新token。这里又涉及到token 生成的机制问题。

  • 有态度网友06MY5Z2016-03-24 09:47

    token的问题我在《App架构设计经验谈:接口的设计》中有提到,生成的机制也没什么复杂的啊

  • 龙佳林2016-03-25 16:57

    也在做电商项目给我发个email 交流下不 lingyins@163.com

  • 有态度网友06MY5V2016-03-27 20:47

    为啥不用现成的jwt呢?

  • 有态度网友06MY7z2016-03-27 21:54

    1、我倒是可以就安全性上给一点建议,客户端链接主动申请一个密钥,这个密钥是动态分配的,和用户身份或机器标识等一一对应,这个请求通道通过HTTPS或其他SSL安全机制,这个密钥是有时效性的,比如7天内有效,过期了就自动重新申请就可以了,不要使用固定密钥
    2、另外公开安全算法的安全级别一般是高于私有算法的,这个在算法安全性上一个公认的常识。

  • 有态度网友06MY5Z2016-03-29 09:19

    谢谢你的建议,这两个建议都很不错。我还想到了另外一点,对于不同的安全数据还可以用不同的加密方式,也可以用不同的动态密钥,例如登录密码、支付密码,都可以用不同的加密方式。

  • 有态度网友06MY5Z2016-03-29 09:20

    jwt是啥?

  • _____野比大熊2016-03-30 10:07

    为了防止AppSecret被别人获取,这个AppSecret一般写死在代码里面。 android反编译不是很容易就得到appsecret了?

  • _____野比大熊2016-03-30 10:08

    不认同,AppSecret作为字符串反编译之后smali文件中是一个固定的常亮字符串,混淆不起作用。

  • 有态度网友06MY5Z2016-03-30 10:19

    那你有什么更好的方案吗?

  • 有态度网友06MY5V2016-04-06 23:46

    语言接地气,看着不费劲。大爱!

  • 有态度网友06MY5V2016-04-07 11:06

    AppSecret被反编译出来,还谈何安全?一种方案是,Server给Client分发token,Client每次请求附带这个token,Server对token进行验证。

  • 有态度网友06MY5Z2016-04-07 14:17

    第一,token基本都会用的;第二,基本不会只用token。

  • 反革命攻城狮CasaTa2016-04-11 20:53

    大家可以去参照casatwy.com的架构谈文章,比这里出的早,而且这里的思想其实都在casatwy.com找得到,最重要的是,写得比这里好。

  • 有态度网友06MY5Z2016-04-12 11:02

    iOS应用架构谈的系列文章的确挺不错,我也有拜读过。只是,你这广告在我这里每一篇App架构的文章都发一遍,而且还置顶,着实让我吃惊。话说,你是田伟宇本人吗?

  • 反革命攻城狮CasaTa2016-04-12 13:56

    是啊,我就是本人。
    我发每一条置顶的目的就是希望大家去比对,就会发现你的文章内容大部分思想出处都是在我这儿,甚至文风都跟我的一样。这个就算了,你竟然不refer。
    这让我看到很不开心。

  • 反革命攻城狮CasaTa2016-04-12 14:00

    另外还有一个最重要的是:借鉴了思想却没有吃透,导致文章中逻辑断裂的地方太多

  • 有态度网友06MY5Z2016-04-12 14:54

    不好意思,我想有必要做个解释。首先,我文章中大部分的思想是我自己在实际经验中的总结,我做Java web时,到后来转Android,之后又踏足了iOS,基本都是遵循这样的架构思想。当我看到你的系列文章时,很多观点我也赞同,因为我也是这么想的。不过,也并不是全部赞同。当然,我的文章没有你写的那么细,也因此,你会觉得逻辑断裂吧。另外,其实,我是写了这个系列的文章后才看到你的文章的。而文风,我写作的文风一直都是这样子的,而且感觉和你的根本完全不一样啊。

  • 反革命攻城狮CasaTa2016-04-12 15:11

    你自己的这套解释那只是你自己希望别人这么想,我已经跟infoQ和CSDN的人都说过了,以及我的朋友圈也公布了。根据反馈来看,看来业界里大家都不是傻子,所以你也不要自欺欺人了。

  • 有态度网友06MY5Z2016-04-12 15:28

    你们都是业内大佬,我只是一个小人物,你们都是对的,我全是错的。

  • 有态度网友06MY5V2016-04-13 09:59

    做自己就好。

  • 有态度网友06MY5V2016-04-13 10:03

    架构这个东西本来就是相通的。架构这么大的内容,在网上一搜一大片,难道你写的内容,在你之前就完全没有人写吗?
    而且,既然你已经这么牛逼了,就善良一点,不要阻挡别人进步了吧.....
    你可以给他一些建议嘛,他借鉴了,到底是哪里没有吃透呢?逻辑哪里断裂了?
    这才能体现出你是真的厉害。
    如果光是在这扯来扯去,大家都看在眼里。

  • 有态度网友06MY5Z2016-04-13 12:34

    谢谢你的理解[可怜]

  • 反革命攻城狮CasaTa2016-04-13 17:00

    你可以去做一个比对。
    如果真的只是巧合,谁都能够看得出来,完整的逻辑在我的文章里是能够看得到的。如果你看清楚了我文章的逻辑,你就会发现这里的逻辑其实都只是我提出的逻辑的加工片段。
    若不是痕迹这么重,我也是懒得去理的。我倒是真的很希望能够跟李纪纲当面对质,有录像有录音,如果这真的不是他自己的逻辑,是经不起我当面跟他推敲的。到时候真假一试便知。
    李纪纲,你敢不敢?

  • 有态度网友06MY5Z2016-04-14 10:23

    那你说,我窃取了你的哪些逻辑?列出来一个个对!
    我敢说,你就只是看到了这一篇文章,我的其他文章你根本没看过,看过后也许还是觉得和你的逻辑很像,也许还会继续觉得我很早之前就窃取了你的这些逻辑,从2015年6月5号我发布的第一篇App架构方面的系列文章就开始了。

    本来,圈子里写App架构方面的文章非常少,尤其在我写完《Android项目重构之路》系列之后更发现很多程序员对这方面的需求很大,但出来分享的人的确很少,而鉴于我已经有了六七年工作经验,经历过的App也不算少了,所以想将我的经验总结分享出来,虽然我不敢说自己很牛,但毕竟有多年经验,总有些沉淀。
    当看到你的iOS应用架构谈的时候,是在infoQ看到的,有种遇到同道中人的感觉。昨天发现你还只是个90后,年纪轻轻就已经有这等水平实属不易,我更欣赏你了。昨天,我跟博文视点的人聊的时候,他刚好也谈到了你的iOS架构的文章,我还问他为什么没找你写书。
    但是,你现在的表现,显得很不成熟。现在,我自己竟然还在这跟一个90后撕逼,这也是一种不成熟的表现。我更希望我们是可以成为朋友,讨论架构讨论技术,这远比在这撕逼有意义得多。

  • 反革命攻城狮CasaTa2016-04-14 18:14

    你的架构谈系列文章出得比我晚吧?你的架构谈系列文章结构跟我雷同吧?你的架构谈系列文章思路跟我雷同吧?
    我看到的只是你的架构谈系列文章,而且交付同行评审之后,都看出来是抄袭而不是巧合了。
    另外,你问了博文视点的人了之后,怎么没把人家的回答说出来呀?博文视点和华章都找过我。不过这不是我们的讨论重点。还有,你也只是比我大两三岁吧?说得好像你多老似的。而且我写代码的时间只会比你早不会比你晚,你刚工作第一年的时候,我就已经写了7年代码了。不过这也不是重点。
    我们俩也别撕逼,如果你不想当面对质,那么我们就各自找同行评审,你在你的渠道把我的文章和你的文章放一起发布出去,我在我的渠道把我的文章和你的文章放一起发布出去,大家看同行反馈。
    你的思路到底是巧合还是抄袭,还是很容易分辨的。如果你硬要说你写文章的时候没看过我的文章,这种无法被证伪的说辞,还是不要说了。我们找同行评审,看大家什么看法就OK。
    怎么样?这儿不是私聊,已经有很多人在看了。

  • 有态度网友06MY5Z2016-04-14 20:19

    那我没什么好说的了,这儿不是私聊,是很多人都在看,那就让看的人自己评价吧

  • 我在找你的海角2016-04-14 20:22

    说得自己好像很傻逼那样,真那么牛还在人家博客唧唧歪歪,什么同行大咖都搬出来,我笑了…都在聊架构,难道还有完全不一致的?知道很多人在看,不服啊?要拉人啊?是不是每个人都看你的才是正道?搞个什么鬼,乌烟瘴气的,有空敲敲你的代码吧,人家当然不老了,你也不年轻了,没必要这么幼稚!还以为网络幼稚行为多数是女人在做,没想到一个大男人这么无理取闹!人家辛辛苦苦写的博客,关你鸟事啊?不喜欢还跑人家这边叽歪个毛!

  • 有态度网友06MY5Z2016-04-14 20:30

    还有,我比你大五岁,另外,你觉得我是刚工作第一年才开始写代码的吗?

  • 我在找你的海角2016-04-14 20:39

    什么是业内大老?黑社会啊?混多两年不一定比你厉害你自己写得辛辛苦苦的,写自己的博客,关别人什么事

  • 我在找你的海角2016-04-14 20:41

    赞同你说的,装逼的还真不少,自以为是!好像人家的努力都是抄他的!尤其是难道你写的内容,在你之前就完全没有人写吗?好像他写的是外星文一样,地球有雷同就是抄袭

  • 反革命攻城狮CasaTa2016-04-14 23:50

    哈哈?你竟然有水军?

  • 反革命攻城狮CasaTa2016-04-14 23:51

    喂,你这么有理,走同行评审吧,没空跟你撕逼了,你都上水军了,哈哈。你要是真的底气足,不会不敢走同行评审的。

  • 我在找你的海角2016-04-15 00:20

    果然还挺关注他的!这么快回了!看来还真有空,是多牛的人啊…今晚刚好被我看到你这些无理的评论!真是人善被人欺!我受不了你这种无理取闹,对着他装逼,骂他的!OK?你凭神马无理取闹地骂我爱的人!谁是水军?我老公踏踏实实地工作,生活,关你什么事?本来他让我不要管这事‘平时他在电脑旁抽空认认真真写博客,我都没关注过,他这么努力,要你管?我还在旁边叫他不用这么温和对你!是个男人吗你!还说自己多牛逼!他平时花了多少时间和精力在写博客,我比你清楚!连我孕期都是在写博客,我只能挺着个肚子在旁陪着,什么同行评审?哪来的大佬?有个大号还直接盗用他的博客原文搬过去,都是别人举报告诉他的,写个博客盗你的资料干嘛,你写你的,他说他自己的,你不要在人家博客这么没礼貌!喂什么!看来是没必要理你!还有!什么是水军?水你的头!现实中让我见到你,我也肯定挫挫你种高傲嚣张的锐气!你不是闲人吧??不!要!再!来!这!个!干!净!的!博!客!吵!闹!!

  • 我在找你的海角2016-04-15 00:22

    他还要水军来管你啊?

  • 我在找你的海角2016-04-15 00:24

    来来来!你很有空,刚好姐也闲着,来吵吵,你还有同行评审?哈哈哈,我笑了,写个博客,弄个同行评审这词,是有多大的事要在这争辩

  • 反革命攻城狮CasaTa2016-04-15 21:08

    不敢同行评审?为什么不敢呀?要真是一身正气,同行评审怎么了?心虚就不要把老婆也搬出来,这算男人?

  • 反革命攻城狮CasaTa2016-04-15 21:14

    对呀,是没多大事情要争辩,尊夫人您请回吧,同行评审一下那就什么都清楚了,哈哈。再用功还是在照着别人的思路写,关键是写得还断片,要想人不知除非己莫为啊,我看这功是白用了。

  • 有态度网友06MY8j2016-04-27 19:43

    你好,请教下问题:
    1. 这个 HTTPS 或者其他 SSL 安全机制,抓包都抓不到么。
    2. 如果这个 HTTPS 抓包抓不到,但是可以通过动态插入 smail 代码,拿到这个临时密钥,就算这个临时密钥有效期,只有15分钟,数据库也可以被拖光了。

  • 有态度网友06MY8m2016-04-29 16:44

    我不是他的水军,但我看你这逼就不爽,你的文章也就罢了,烂人也写不出啥好货

  • 有态度网友06MY7z2016-04-29 23:25

    HTTPS是基本能够保证包不被监听破解的,但是如果是手机都被植入了smail代码,那么这个手机就做任何安全机制都可以认为无效了。等于我把银行卡和密码都盗走,再牛逼的算法都无法阻止拿到你银行卡和密码的人取走你的钱。我认为这个世界上是没有绝对安全算法,所有的安全算法都是有条件的有目标的。但是临时密钥方案可以保证在一台手机上被破解了,而在其他手机上还是相对安全的,破解者需要一台台手机去破解,我觉得就是使用临时密钥算法最大的意义。

  • 有态度网友06MY7z2016-04-29 23:30

    架构师不要考虑找到一个完美的架构,而应该是根据业务和手上的资源找出最优解。

  • 有态度网友06MY5Z2016-04-30 11:47

    说得很好,没有绝对的安全,没有完美的架构,只能根据需求对各方面进行权衡

  • 有态度网友06MY8j2016-04-30 17:14

    不是说,手机被植入 smali 代码,而是 apk 。最近就试验了一次,通过植入 smali 代码,破解了一个通过MD5鉴权的商业app了。的确没有完美的架构,安全也不可能有绝对的安全,但是想想,可以植入 smali 代码,不少加密方案都没效了。 在你心中,目前最安全的 API 鉴权方式是怎样的了?方便交流下么。

  • 有态度网友06MY7z2016-05-01 01:54

    目前我项目用的移动API鉴权设计,就是用户登录后返回一个临时密钥,这个密钥是这台机器和这个用户独有的,而且密钥有有效期,有效期由服务端控制,这个密钥也就是如果你获取了也就等于打开了你个人数据的大门,但是被影响到的也只有一个人而已,而不是所有人;如果有更高级别的安全要求,比如个人余额账户使用,可以要求每次使用时进行预设的手机短信验证。一般对于代码植入我觉得程序算法是没有任何直接办法防备的。只能在业务流程上想办法,比如手机短信验证,安全问题验证等等,但是这个又会让用户体验很差,所以只能用在某些关键业务上。你觉得了?

  • 有态度网友06MY7z2016-05-01 02:02

    对于API安全,其实在还有一个角度,就是成本角度。只要破解需要的成本大于破解后获取的利益成本,这个算法就是好的算法。

  • 有态度网友06MY8j2016-05-03 16:10

    成本角度,这个很赞。每个临时密钥和用户以及设备绑定,这种设计,把数据划分到每个人身上,这种设计也很棒。可是:
    1. 不过密钥的保存也是一个问题。
    2. 如果对于有自动登录需求的 APP 来说,密钥到了有效期,需要重新获取,用户体验可能怪怪的。

  • 有态度网友06MY7z2016-05-04 23:08

    1、密钥保存就在手机本地,可以加密,也可以不加密,个人觉得意义不大。还是我开始说的手机或APP都被入侵了,什么保护手段都意义不大了。
    2、密钥获取,我的算法是借鉴了oauth2.0的,密钥分为签名密钥和刷新密钥,签名密钥有效期比较短,所有API都使用签名密钥做签名,如果签名密钥过期,APP就通过刷新密钥获取新的签名密钥,这个过程对用户是透明的,由程序自动完成。刷新密钥有效期比较长,如果过期了,就提示用户重新登录了,这个周期很长,对用户体验来说我觉得影响不大。

  • 有态度网友06MY8j2016-05-05 11:07

    设计的不错,感谢你的分享。

  • 有态度网友06MY8A2016-05-19 09:17

    mark

  • 有态度网友06MY5V2016-05-27 13:54

    首先我不是水军,其次你为人真的很垃圾,从你们的回复记录可以看出来。技术层面不说,博主的格局比你大太多了。你那个同行评审很搞笑[嘻嘻]

  • 有态度网友06MY8M2016-06-07 16:04

    傻逼一个

  • 一个小屁孩儿2016-06-12 16:44

    哇塞!!!看到好文章,我转转转 !我是一个搬运工咿呀咿呀哟!!!

  • 一个小屁孩儿2016-06-12 16:45

    都到我的碗里来!!!!嘎嘎

  • 有态度网友06MY5V2016-08-03 11:32

    博主厉害,iOS Android通杀啊

  • 有态度网友06MY5V2016-08-11 15:37

    菜鸟程序员 之前没看过app架构的文章 上个项目自己独立开发项目的时候就自己按照经验设计的 刚刚看到博主的架构文章惊人的相似 甚至在接口返回的json类型我也是定的3种
    所以我想说 app架构这种东西真的大体想通 抄袭什么的太搞笑了

  • 有态度网友06MY9I2016-09-22 16:31

    总有人觉得别人都欠他的,不必理会。我是做java后端的,你写的是你个人的宝贵经验,不必多说

  • 有态度网友06MY5V2016-10-21 09:58

    我真无语了 我现在作为第三者 看到这评论我觉得你们在这撕逼也太搞笑了 我不知道是谁先发架构之类文章 我只知道 反正有个人一直在那抱怨另一个人抄袭或者借鉴另一个人的文章文字 我想说的是 中国就是因为你这个人在那抱怨别人抄袭你的文章侵犯你的著作权才会给整个开发环境带来滞后 架构之说就算你发明的 你既然讲出来了 你就是要公布于世 别人就算是看了你文章抄袭你的又怎么样 你还真当这个是你私有的了 再说了 你之前就没有抄袭过别人的文章或者思路吗 你现在的知识难道不是从别人的智慧那里窃取来的? 现在是相互学习 相互让这个架构说法公诸于世 你为什么发布出来 不就是让别人学习和进步吗 现在人家文章博客就算是你所谓的抄袭你的想法 但是人家也在宣传此思维逻辑和知识 人家是在促进社会进步 你在这贬低别人跑来 这博客叫嚣 你这就是在阻止社会进步 宣传知识方式多样化 难道非要你这个所谓的发明者才能有资格宣扬知识吗? 什么苟笔玩意儿 就算你发扬了很多知识 一样是人渣 开源精神你懂不 就算你所谓你的知识产权 那你为何要公布于众 在你公布于众的时候 你应该想清楚了 你到底开源还是私有 你既然公布那就是你想清楚了 开源 开源你还怕别人学会你知识 这不是搬起石头砸自己的脚吗 那你还不如自己私用得了

  • 潮汐猎人st2016-10-27 15:47

    你这博客在哪个论坛写的? 怎么可以自定义域名

  • 潮汐猎人st2016-10-27 15:48

    helloWorld 写熟了吗

  • 有态度网友06MY5Z2016-10-28 10:17

    Farbox

  • 雅慧清玄zZ2016-11-15 12:18

    真的是有趣,博主的架构思想就是凭经验积累出来的,我没看过啥JBcasa的博客,我的架构想法也和博主大同小异,老子也是看了你的博客的么?所有有这种思想的都是看了你博客的?大神?

  • 张翔同学2017-04-07 19:17

    佩服您!智者也

  • 张翔同学2017-04-07 19:22

    我可说的是@Keegan小钢