Month: April 2012

软件维护及可维护性的基本概念

软件维护是指: Software maintenance in software engineering is the modification of a software product after delivery to correct faults, to improve performance or other attributes. 软件维护是一种evolution的过程: Lehman demonstrated that systems continue to evolve over time. As they evolve, they grow more complex unless some action such as code refactoring is taken to reduce the complexity.  Lehman还提出了软件evlution的Lehman’s …

软件维护及可维护性的基本概念 Read More »

收集一些关于Software Maintenance & Evolution的文献 

收集一些关于Software Maintenance&Evolution的文献  wikipedia上的software maintenance页:  http://en.wikipedia.org/wiki/Software_maintenance,介绍了软件维护的概念和发展历史,主要篇幅用在:从软件工程的角度来介绍软件维护,比如规划、过程,成本、收益等 wikipedia上的software evolution页: http://en.wikipedia.org/wiki/Software_evolution wikipedia: 软件进化之Lehman’s law: http://en.wikipedia.org/wiki/Lehman%27s_laws_of_software_evolution wikipedia上的maintainability页:http://en.wikipedia.org/wiki/Maintainability infoq上的著名文章:架构腐化之迷: http://www.infoq.com/cn/articles/cjz-architecture-corruption 给开发维护大型项目开发者的建议:  http://blog.jobbole.com/16526/ 期刊: http://www3.interscience.wiley.com/cgi-bin/jhome/5391/ 书: Software Maintenance Management: Evaluation and Continuous Improvement (Practitioners)

缓存对象的数据结构要变更,怎么办?

如果缓存对象的数据结构要变更,也就是说,新的代码里将使用新的数据结构,那么上线时,线上已有缓存对象的数据结构可能跟新代码中定义的数据结构不匹配,在反序列化时可能会产生数据完整性的问题。 为了解决这个问题,就 要让新代码取不到旧缓存或者忽略旧缓存。 一个解决方案是在新代码中使用新的序列号,新代码获取旧缓存时会发生反序列化错误; 我们再显式地捕捉这种错误,在发生这种错误时再去后端取数据,并使用取来的数据覆盖旧缓存。 然而,“更新序列号”这个方案有个触不到的地方:泛型的更换。如果缓存对象的数据结构从ArrayList<A>变成了ArrayList<B>,即使A和B的序列号不同,新代码在遇到旧缓存时也不会发生序列化错误。后果是, 新代码以为它拿到的是ArrayList<B>对象,实际上却是ArrayList<A>对象,最终的后果就是在访问List中元素时发生ClassCastException. 你会问,能否侦测这种情况?比如说,新代码从缓存中拿到一个ArrayList时,判断它的泛型是不是ArrayList<B>,如果不是则忽略?  答案是做不到,java的“伪泛型”不支持这种判断。 另一个解决方案是上线前先清空所有旧缓存,这样新代码永远取不到旧缓存。然而它亦有短板: 如果你们采用了灰度发布流程,旧缓存仍然可能跟新代码接触。 所谓灰度发布是指将新代码发布到集群服务器时,先发到部分机器,针对这部分机器验证通过后再继续发下去。 显然,在这个过程中,新旧代码会同时存在于集群中;运行中的旧代码有可能会产生旧的缓存,且被新的代码获取,发生问题;同理,新代码产生的缓存也会被旧代码取到,照样发生问题。  清空旧缓存这种方案还有一个问题是,你需要在发布时手工介入,比较麻烦。 那怎么办才好呢? 有个方案是:除了使用新的序列号, 新代码也要使用新的缓存key.如果老代码使用 key_ record_id来存取,新代码就用new_key_ record_id来存取. 这样的话,新代码永远取不到老的缓存;老的代码也取不到新的缓存。 有了这个基础,泛型变换、灰度发布时的新旧代码共存都不是问题。 使用新的缓存key,可以把新旧缓存隔离开来,相当于在逻辑上产生了两套缓存空间,是一种相当彻底的解决方案; 另外,这种方案也非常简单,不需要在发布时手动做什么事情。 不过,实施这种方案有个前提:由于旧缓存会被新代码忽略,从而成为无用的缓存;新系统上线时会有大量的Cache Miss,你要确保这不会引发性能问题。