Pages

Monday, May 28, 2012

啃啃老菜:Spring IOC核心源码学习(一)

from: http://www.iteye.com/magazines/72



本文主要以spring ioc容器基本代码骨架为切入点,理解ioc容器的基本代码组件结构,各代码组件细节剖析将放在后面的学习文章里。

关于IOC容器

IoC容器:最主要是完成了完成对象的创建和依赖的管理注入等等。
先从我们自己设计这样一个视角来考虑:
所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。这个描述最具体表现就是我们可配置的文件。
对象和对象关系怎么表示?
可以用xmlproperties文件等语义化配置文件表示。
描述对象关系的文件存放在哪里?
可能是classpathfilesystem,或者是URL网络资源,servletContext等。
回到正题,有了配置文件,还需要对配置文件解析。
不同的配置文件对对象的描述不一样,如标准的,自定义声明式的,如何统一? 在内部需要有一个统一的关于对象的定义,所有外部的描述都必须转化成统一的描述定义。
如何对不同的配置文件进行解析?需要对不同的配置文件语法,采用不同的解析器。

基于以上问题,对应过来,刚好是 spring ioc 容器抽象的的几个主要接口:
Resource
BeanDefinition
BeanDefinitionReader
BeanFactory
ApplicationContext
以上五个都是接口,都有各式各样的实现,正是这5个接口定义了spring ioc容器的基本代码组件结构。而其组件各种实现的组合关系组成了一个运行时的具体容器。

各代码组件详解

1.Resource

是对资源的抽象,每一个接口实现类都代表了一种资源类型,如ClasspathResourceURLResourceFileSystemResource等。每一个资源类型都封装了对某一种特定资源的访问策略。它是spring资源访问策略的一个基础实现,应用在很多场景。




具体可以参考文章:
Spring 资源访问剖析和策略模式应用


2.BeanDefinition
用来抽象和描述一个具体bean对象。是描述一个bean对象的基本数据结构。
3.BeanDefinitionReader
BeanDefinitionReader将外部资源对象描述的bean定义统一转化为统一的内部数据结构BeanDefinition。对应不同的描述需要有不同的Reader。如XmlBeanDefinitionReader用来读取xml描述配置的bean对象。


 
4.BeanFactory
用来定义一个很纯粹的bean容器。它是一个bean容器的必备结构。同时和外部应用环境等隔离。BeanDefinition是它的基本数据结构。它维护一个BeanDefinitions Map,并可根据BeanDefinition的描述进行bean的创建和管理。


 
5.ApplicationContext
从名字来看叫应用上下文,是和应用环境息息相关的。没错这个就是我们平时开发中经常直接使用打交道的一个类,应用上下文,或者也叫做spring容器。其实它的基本实现是会持有一个BeanFactory对象,并基于此提供一些包装和功能扩展。为什么要这么做呢?因为BeanFactory实现了一个容器基本结构和功能,但是与外部环境隔离。那么读取配置文件,并将配置文件解析成BeanDefinition,然后注册到BeanFactory的这一个过程的封装自然就需要ApplicationContextApplicationContext和应用环境细细相关,常见实现有ClasspathXmlApplicationContext,FileSystemXmlApplicationContext,WebApplicationContext等。ClasspathxmlFileSystemWeb等词都代表了应用和环境相关的一些意思,从字面上不难理解各自代表的含义。
当然ApplicationContextBeanFactory的区别远不止于此,有:
1.  资源访问功能:在ResourceResourceLoader的基础上可以灵活的访问不同的资源。
2.  支持不同的信息源。
3.  支持应用事件:继承了接口ApplicationEventPublisher,这样在上下文中为bean之间提供了事件机制。
……


 

以上5个组件基本代表了ioc容器的一个最基本组成,而组件的组合是放在ApplicationContext的实现这一层来完成。

以ClasspathXmlApplicationContext 容器实现为例,其组合关系如下:


ClassPathXmlApplicationContext的refresh() 方法负责完成了整个容器的初始化。
为什么叫refresh?也就是说其实是刷新的意思,该IOC容器里面维护了一个单例的BeanFactory,如果bean的配置有修改,也可以直接调用refresh方法,它将销毁之前的BeanFactory,重新创建一个BeanFactory。所以叫refresh也是能理解的。
以下是Refresh的基本步骤:
1.把配置xml文件转换成resource。resource的转换是先通过ResourcePatternResolver来解析可识别格式的配置文件的路径
(如"classpath*:"等),如果没有指定格式,默认会按照类路径的资源来处理。
2.利用XmlBeanDefinitionReader完成对xml的解析,将xml Resource里定义的bean对象转换成统一的BeanDefinition。
3.将BeanDefinition注册到BeanFactory,完成对BeanFactory的初始化。BeanFactory里将会维护一个BeanDefinition的Map。

当getBean的时候就会根据调用BeanFactory,根据bean的BeanDifinition来实例化一个bean。当然根据bean的lazy-init、protetype等属性设置不同以上过程略有差别。

refresh()代码如下:
Java代码 
  1. public void refresh() throws BeansException, IllegalStateException {  
  2.     synchronized (this.startupShutdownMonitor) {  
  3.         // Prepare this context for refreshing.  
  4.         prepareRefresh();  
  5.   
  6.         // Tell the subclass to refresh the internal bean factory.  
  7.         ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
  8.   
  9.         // Prepare the bean factory for use in this context.  
  10.         prepareBeanFactory(beanFactory);  
  11.   
  12.         try {  
  13.             // Allows post-processing of the bean factory in context subclasses.  
  14.             postProcessBeanFactory(beanFactory);  
  15.   
  16.             // Invoke factory processors registered as beans in the context.  
  17.             invokeBeanFactoryPostProcessors(beanFactory);  
  18.   
  19.             // Register bean processors that intercept bean creation.  
  20.             registerBeanPostProcessors(beanFactory);  
  21.   
  22.             // Initialize message source for this context.  
  23.             initMessageSource();  
  24.   
  25.             // Initialize event multicaster for this context.  
  26.             initApplicationEventMulticaster();  
  27.   
  28.             // Initialize other special beans in specific context subclasses.  
  29.             onRefresh();  
  30.   
  31.             // Check for listener beans and register them.  
  32.             registerListeners();  
  33.   
  34.             // Instantiate all remaining (non-lazy-init) singletons.  
  35.             finishBeanFactoryInitialization(beanFactory);  
  36.   
  37.             // Last step: publish corresponding event.  
  38.             finishRefresh();  
  39.         }  
  40.   
  41.         catch (BeansException ex) {  
  42.             // Destroy already created singletons to avoid dangling resources.  
  43.             beanFactory.destroySingletons();  
  44.   
  45.             // Reset 'active' flag.  
  46.             cancelRefresh(ex);  
  47.   
  48.             // Propagate exception to caller.  
  49.             throw ex;  
  50.         }  
  51.     }  
  52. }  
 以上的obtainFreshBeanFactory是很关键的一个方法,里面会调用loadBeanDefinition方法,如下:
Java代码 
  1. protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {  
  2.     // Create a new XmlBeanDefinitionReader for the given BeanFactory.  
  3.     XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  
  4.   
  5.     // Configure the bean definition reader with this context's  
  6.     // resource loading environment.  
  7.     beanDefinitionReader.setResourceLoader(this);  
  8.     beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));  
  9.   
  10.     // Allow a subclass to provide custom initialization of the reader,  
  11.     // then proceed with actually loading the bean definitions.  
  12.     initBeanDefinitionReader(beanDefinitionReader);  
  13.     loadBeanDefinitions(beanDefinitionReader);  
  14. }  
 LoadBeanDifinition方法很关键,这里特定于整个IOC容器,实例化了一个XmlBeanDefinitionReader来解析Resource文件。关于Resource文件如何初始化和xml文件如何解析都在
Java代码 
  1. loadBeanDefinitions(beanDefinitionReader);  
 里面的层层调用完成,这里不在累述。

小结 

Spring的扩展性是毋庸置疑的,学习spring的设计是一个很好的实践理论结合。主要个人觉得有几点:
1.  框架顶层的设计有着很好的抽象,遵循面向接口编程的规范。ResourceBeanFactoryApplicationContext都是非常好的接口抽象,非常明确的定义了该组件的一些功能。
2.  利用组合模式。
3.  个组件的实现里大量使用了模板方法模式,提升了同一组件代码的复用性。
4.  各种设计保留了扩展的接口,很多基于spring的框架都可以很容易的介入实现了自己的一些扩展。
5.  框架里采用里很多经典的设计模式,如代理、装饰、策略等等。

find more on http://sunfeng.ca/

Tuesday, May 22, 2012

Java编程中“为了性能”尽量要做到的一些地方


最近的机器内存又爆满了,除了新增机器内存外,还应该好好review一下我们的代码,有很多代码编写过于随意化,这些不好的习惯或对程序语言的不了解是应该好好打压打压了。

下面是参考网络资源总结的一些在Java编程中尽可能要做到的一些地方。
1. 尽量在合适的场合使用单例

使用单例可以减轻加载的负担,缩短加载的时间,提高加载的效率,但并不是所有地方都适用于单例,简单来说,单例主要适用于以下三个方面:
第一,控制资源的使用,通过线程同步来控制资源的并发访问;
第二,控制实例的产生,以达到节约资源的目的;
第三,控制数据共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信。

2. 尽量避免随意使用静态变量

要知道,当某个对象被定义为stataic变量所引用,那么gc通常是不会回收这个对象所占有的内存,如

Java代码 
  1. public class A{  
  2. static B b = new B();  
  3. }  
 
此时静态变量b的生命周期与A类同步,如果A类不会卸载,那么b对象会常驻内存,直到程序终止。
3. 尽量避免过多过常的创建Java对象

尽量避免在经常调用的方法,循环中new对象,由于系统不仅要花费时间来创建对象,而且还要花时间对这些对象进行垃圾回收和处理,在我们可以控制的范围内,最大限度的重用对象,最好能用基本的数据类型或数组来替代对象。

4. 尽量使用final修饰符

带有final修饰符的类是不可派生的。在Java核心API中,有许多应用final的例子,例如java.lang.String。为String类指定final防止了使用者覆盖length()方法。另外,如果一个类是final的,则该类所有方法都是final的。Java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能平均提高50%。

5. 尽量使用局部变量

调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。
6. 尽量处理好包装类型和基本类型两者的使用场所

虽然包装类型和基本类型在使用过程中是可以相互转换,但它们两者所产生的内存区域是完全不同的,基本类型数据产生和处理都在栈中处理,包装类型是对象,是在堆中产生实例。
在集合类对象,有对象方面需要的处理适用包装类型,其他的处理提倡使用基本类型。
7. 慎用synchronized,尽量减小synchronize的方法

都知道,实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。synchronize方法被调用时,直接会把当前对象锁 了,在方法执行完之前其他线程无法调用当前对象的其他方法。所以synchronize的方法尽量小,并且应尽量使用方法同步代替代码块同步。
8. 尽量使用StringBuilder和StringBuffer进行字符串连接

这个就不多讲了。
9. 尽量不要使用finalize方法

实际上,将资源清理放在finalize方法中完成是非常不好的选择,由于GC的工作量很大,尤其是回收Young代内存时,大都会引起应用程序暂停,所以再选择使用finalize方法进行资源清理,会导致GC负担更大,程序运行效率更差。

10. 尽量使用基本数据类型代替对象

String str = "hello";
上面这种方式会创建一个“hello”字符串,而且JVM的字符缓存池还会缓存这个字符串;
String str = new String("hello");
此时程序除创建字符串外,str所引用的String对象底层还包含一个char[]数组,这个char[]数组依次存放了h,e,l,l,o

11. 单线程应尽量使用HashMap、ArrayList

HashTable、Vector等使用了同步机制,降低了性能。

12. 尽量合理的创建HashMap

当你要创建一个比较大的hashMap时,充分利用另一个构造函数
public HashMap(int initialCapacity, float loadFactor)
避免HashMap多次进行了hash重构,扩容是一件很耗费性能的事,在默认中initialCapacity只有16,而loadFactor是 0.75,需要多大的容量,你最好能准确的估计你所需要的最佳大小,同样的Hashtable,Vectors也是一样的道理。

13. 尽量减少对变量的重复计算

for(int i=0;i<list.size();i++)
应该改为
for(int i=0,len=list.size();i<len;i++)
并且在循环中应该避免使用复杂的表达式,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。

14. 尽量避免不必要的创建

A a = new A();
if(i==1){list.add(a);}
应该改为
if(i==1){
A a = new A();
list.add(a);}

15. 尽量在finally块中释放资源

程序中使用到的资源应当被释放,以避免资源泄漏。这最好在finally块中去做。不管程序执行的结果如何,finally块总是会执行的,以确保资源的正确关闭。

16. 尽量使用移位来代替'a/b'的操作

"/"是一个代价很高的操作,使用移位的操作将会更快和更有效
int num = a / 4;
int num = a / 8;
应该改为
int num = a >> 2;
int num = a >> 3;
但注意的是使用移位应添加注释,因为移位操作不直观,比较难理解

17.尽量使用移位来代替'a*b'的操作

同样的,对于'*'操作,使用移位的操作将会更快和更有效
int num = a * 4;
int num = a * 8;
应该改为
int num = a << 2;
int num = a << 3;

18. 尽量确定StringBuffer的容量

StringBuffer 的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小,就会重新分配内存,创建一个更大的数组,并将原先的数组复制过来,再 丢弃旧的数组。在大多数情况下,你可以在创建 StringBuffer的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。 
如:StringBuffer buffer = new StringBuffer(1000);

19. 尽量早释放无用对象的引用

大部分时,方法局部引用变量所引用的对象 会随着方法结束而变成垃圾,因此,大部分时候程序无需将局部,引用变量显式设为null。
例如:

Java代码 
  1. Public void test(){  
  2. Object obj = new Object();  
  3. ……  
  4. Obj=null;  
  5. }  
 
上面这个就没必要了,随着方法test()的执行完成,程序中obj引用变量的作用域就结束了。但是如果是改成下面:

Java代码 
  1. Public void test(){  
  2. Object obj = new Object();  
  3. ……  
  4. Obj=null;  
  5. //执行耗时,耗内存操作;或调用耗时,耗内存的方法  
  6. ……  
  7. }  
 
这时候就有必要将obj赋值为null,可以尽早的释放对Object对象的引用。

20. 尽量避免使用二维数组

二维数据占用的内存空间比一维数组多得多,大概10倍以上。

21. 尽量避免使用split

除非是必须的,否则应该避免使用split,split由于支持正则表达式,所以效率比较低,如果是频繁的几十,几百万的调用将会耗费大量资源,如果确实需 要频繁的调用split,可以考虑使用apache的StringUtils.split(string,char),频繁split的可以缓存结果。

22. ArrayList & LinkedList

一 个是线性表,一个是链表,一句话,随机查询尽量使用ArrayList,ArrayList优于LinkedList,LinkedList还要移动指 针,添加删除的操作LinkedList优于ArrayList,ArrayList还要移动数据,不过这是理论性分析,事实未必如此,重要的是理解好2 者得数据结构,对症下药。

23. 尽量使用System.arraycopy ()代替通过来循环复制数组

System.arraycopy() 要比通过循环来复制数组快的多

24. 尽量缓存经常使用的对象

尽可能将经常使用的对象进行缓存,可以使用数组,或HashMap的容器来进行缓存,但这种方式可能导致系统占用过多的缓存,性能下降,推荐可以使用一些第三方的开源工具,如EhCache,Oscache进行缓存,他们基本都实现了FIFO/FLU等缓存算法。

25. 尽量避免非常大的内存分配

有时候问题不是由当时的堆状态造成的,而是因为分配失败造成的。分配的内存块都必须是连续的,而随着堆越来越满,找到较大的连续块越来越困难。

26. 慎用异常

当创建一个异常时,需要收集一个栈跟踪(stack track),这个栈跟踪用于描述异常是在何处创建的。构建这些栈跟踪时需要为运行时栈做一份快照,正是这一部分开销很大。当需要创建一个 Exception 时,JVM 不得不说:先别动,我想就您现在的样子存一份快照,所以暂时停止入栈和出栈操作。栈跟踪不只包含运行时栈中的一两个元素,而是包含这个栈中的每一个元素。
如 果您创建一个 Exception ,就得付出代价。好在捕获异常开销不大,因此可以使用 try-catch 将核心内容包起来。从技术上讲,您甚至可以随意地抛出异常,而不用花费很大的代价。招致性能损失的并不是 throw 操作——尽管在没有预先创建异常的情况下就抛出异常是有点不寻常。真正要花代价的是创建异常。幸运的是,好的编程习惯已教会我们,不应该不管三七二十一就 抛出异常。异常是为异常的情况而设计的,使用时也应该牢记这一原则。

相关回复:
xuanyuan 写道
7.慎用synchronized,尽量减小synchronize的方法
re:同意,不过文中有个地方说错了,使用synchronized关键字并不一定都是锁定当前对象的,要看具体的锁是什么。如果是在方法上加的synchronized,则是以对象本身为锁的,如果是静态方法则锁的粒度是类。
---------------
9.尽量不要使用finalize方法
re:同意,其实不推荐用finalize方法的根本原因在于,JVM的规范并不保证何时执行该方法,所以用这个方法来释放资源很不合适,有可能造成长时间资源得不到释放。
---------------
16.尽量使用移位来代替'a/b'的操作;17.尽量使用移位来代替'a*b'的操作
re:个人不太同意这两条。这样做确实有更好的性能,但是却牺牲了可读性。这两个操作符对很多程序员来说并不直观。我认为在如今硬件价格不那么昂贵的情况下,略微牺牲一些性能,换来更好的可读性和可维护性是好的选择。
 

wuzhengju 写道
19.尽量早释放无用对象的引用
大部分时,方法局部引用变量所引用的对象 会随着方法结束而变成垃圾,因此,大部分时候程序无需将局部,引用变量显式设为null。
例如:
Public void test(){
Object obj = new Object();
……
Obj=null;
}
上面这个就没必要了,随着方法test()的执行完成,程序中obj引用变量的作用域就结束了。但是如果是改成下面:
Public void test(){
Object obj = new Object();
……
Obj=null;
//执行耗时,耗内存操作;或调用耗时,耗内存的方法
……
}
如果Object obj = new Object(); 如果这对象并不是大对象,这有必要吗?Obj=null;只是告诉jvm这个对象已经成为垃圾,至于什么时候回收,还不能确定! 这可读性也不好!
 

Tuesday, May 1, 2012

What is a framework

from:http://www.codeproject.com/Articles/5381/What-Is-A-Framework

Preface

The What is better? Smarter programmers or safer programming environments?   is the impetus for this article.  After I stuck my foot in it (again), saying that .NET and MFC are not frameworks, Paul Watson asked one of the two obvious questions--"what is a framework?" (the other obvious question being, "If .NET and MFC are not frameworks, then what are they?")  Well, Paul's question is an excellent one (and the better of the two, I think), and it led me down this road in an attempt to put my money where my mouth is, as it were.  So, here goes.    I'd like to hear your opinions as to whether you agree or disagree with my analysis, what areas you'd like to have explored in further detail, and whether you think this fits in your own experiences.  I've tried to keep this article brief (isn't that a welcome change?), and I'll leave it to the reader responses to determine if there's anything that needs elaboration.

Introduction

From my perspective, a framework does several things:
  • it makes it easier to work with complex technologies
  • it ties together a bunch of discrete objects/components into something more useful
  • it forces the team (or just me) to implement code in a way that promotes consistent coding, fewer bugs, and more flexible applications
  • everyone can easily test and debug the code, even code that they didn't write
If I look at this list of vague framework requirements, I come up with a set of specific classifications that define a framework:
  • wrappers.  A wrapper:
    • simplifies an interface to a technology
    • reduces/eliminates repetitive tasks
    • increases application flexibility through abstraction
    • are often re-usable regardless of high level design considerations
  • architectures.  An architecture:
    • manages a collection of discrete objects
    • implements a set of specific design elements
  • methodologies: A methodology:
    • enforces the adherence to a consistent design approach
    • decouples object dependencies
    • are often re-usable regardless application requirements
So, before talking about frameworks, we need to talk about wrappers, architectures, and methodologies.  After that, I'm not sure what will be left to say about frameworks!

A Framework Is...

A Wrapper


A wrapper is way of repackaging a function or set of functions (related or not) to achieve one or more of the following goals (probably incomplete):
  • Simplification of use
  • Consistency in interface
  • Enhancement of core functionality
  • Collecting discrete processes into a logical association (an object)
It's easy to fall into the idea that everything is a wrapper, just like saying "everything is relative" (which is untrue, because that statement itself is an absolute), but if you think about it, not everything is a wrapper.  Most of MFC and .NET are wrappers are the core API's.  Some are laughably so, providing classes that merely wrap messages into inline methods.  Other wrappers are more complex.  For example, I've written a wrapper for the Visio COM object that takes all the grunt work out of using Visio's primitive functions (primitive in the sense of "fundamental", as opposed to "poorly implemented") to do basic things like drop shapes, connect shapes, and read a shape collection.
But then, you get into implementation that truly provides new functionality.  Yes, it utilizes other objects, other API's, even other wrappers, but it isn't a wrapper in itself because it does something totally new, rather than just adding to, subtracting from, or managing a collection of existing work.  A wrapper modifies existing behavior.  There's a lot of code out there that creates new behavior (thus becoming subject to

An Architecture


An architecture is a style that incorporates specific design elements.  Obviously, a framework needs to have a design.  Its architecture is separate from the collection of wrappers that it implements and from the enforcement of a specific implementation methodology.  MFC's document-view classes are an architecture.  Essentially, an architecture implements associations between objects--inheritance, container, proxy, collection, etc.  Architectures have the interesting attribute that, if you don't like them, you can usually ignore them or replace them (at least at the beginning of a project).  Architectures can and are useful because they create a re-usable structure (a collection of objects) that provide some enhanced functionality, but once you start using them, you're pretty much stuck with them unless you do some major refactoring.

A Methodology


Let's look at this word:
  • Method - a way of doing something
  • -ology - in a "scientific" manner--designed, consistent, repeatable, testable, proven
or, if you want to look it up in the dictionary: A body of practices, procedures, and rules used by those who work in a discipline.
OK, we've all worked with design methodologies, but not too many people have worked with a framework that implements a particular methodology.  I don't think arguing that MFC is a methodology (with exceptions) is the right way to think about classes.  While a class specifies visibility, interface, and inheritance usage, and these, along with language syntax, can certainly be classified as "a body of practices, procedures, and rules", saying that a class or a collection of classes is a methodology is like saying that a bunch of leaves make a tree.  A methodology fills in the supporting structure.  Is MFC's message mapping implementation a methodology?  Mostly, yes.  While I view it primarily as an architecture that wraps the underlying API, and you don't have to use it if you don't want to, in some cases you pretty much can't avoid using it, especially when you want to define specialized message handlers.  You have to use the method that MFC implements in order to specify and override the base class implementation.  And since this is an application wide issue, it fits better into the definition of a methodology than a wrapper (which it is) or an architecture (which it is).  So, things can be fuzzy, and sometimes they can feel like splitting hairs, but it doesn't detract from the value of looking at methodology as a classification.
While architectures deal with the associations between things, a methodology deals with the interaction between things.  The first is a passive relationship and the second is an activity.  Most of the methodology that I implement is in the activity of communicating between objects, managing data persistence, responding to user events, etc.  Within those activities are architectures that associate interrelated objects.

Design Patterns

Design patterns are both architectures and methodologies.  The structural patterns are more architecture, when the creational and behavioral patterns are more methodologies because their usage enforces a particular method of interaction.  However you implement, say, behavioral patterns, you're entire application has to adhere to that implementation.  However, I will say this one thing--design patterns are in a category that I would call "lightweight methodologies".  They are not necessarily heavy handed about how components and objects interact with each other.

Heavyweight Frameworks

The Application Automation Layer that I've written about (you really didn't think I'd write about frameworks without mentioning the AAL, did you?) is what I'd call a heavyweight framework.  It strictly enforces (to within the reasonable realm of the possible) component management, data interaction, the usage of external XML files for GUI definitions, scripting driven functional programming, etc.  Now, you may all say that this is excessive, but I must disagree.  We need frameworks like this to improve quality, consistency, and usability.  Furthermore, a heavyweight framework can (and has been proven to) allow even junior programmers to be productive in a large scale development effort with minimal guidance.  Why?  Because the framework doesn't provide a lot of room for, well, screwing up.  Even as an experienced programmer, it helps me from screwing up (for example, taking shortcuts) as well!

Thoughts About Frameworks

Rather Black & White, Isn't It?

At some point, a framework becomes all three simply out of necessity.  You can't implement a methodology without implementing wrappers and an architecture.  Like any other kind of programming, abstract concepts don't necessarily translate directly into concrete implementation, and the same is true for the wrapper-architecture-methodology view.  But it's still useful to look at these two topics separately so that, come implementation time, we can make better decisions regarding the goals of the framework we are implementing.  For example, the issue of re-use regarding wrapper vs. architecture vs. methodology is different because the focus of the re-use is different.  For wrappers, the focus of the re-use is the process, whereas for an architecture, it is the associations between objects, whereas for a methodology, the focus of the re-use is in the interactions between objects.

Why Should A Framework Enforce A Methodology?

Well, I wanted to avoid analogies to architecture and buildings, but this seems like such a good place for one, but, I'm sure you can figure out the rest of what I can say!  So why say it?  Well, sometimes it's important to pour a thought down on paper so it becomes a bit more concrete (no pun intended).  If you only have wrappers, your team (or just you) is left to build the application in whatever way their experiences (or lack thereof) have taught them.  In the end (if you even get to the end), you've got a collection of different styles, approaches, and solutions that have no consistency.  This is hard to debug, hard to maintain, and hard to extend.  And you when you're done, you almost certainly don't want to repeat the experience.  A framework that enforces a methodology, on the other hand, tells each programmer how to do important things like interface with other objects/components/technologies, how to manage and persist data, and how to avoid crossing application layers (as examples).  The resulting application is easy to debug, easy to maintain, and very flexible.

Code Reviews

Code reviews are fine, but they're misapplied if you use them to fix coding consistency issues.  It's like health--you want to be proactive in preventing disease (dis-ease, ha ha ha), rather than taking a handful of pills after you get sick.  So, code reviews should be used to prevent sickness rather than to cure a sick implementation.  This means, a code review should always look at whether the framework methodology is being applied properly, is itself appropriate, and that the code is, in other ways, handling its requirements correctly.

Unit Testing

If your methodology includes unit testing (and thus a framework to support this methodology), the issue of meeting requirements becomes preventative--the unit tests prevent the code from becoming sick in the first place.  However, unit tests can be a lot like the new age idea of using magnets to cure arthritis--they can be quite useless.  And I'm not going to write about good unit tests here--you can read my articles on unit testing if you're interested. 

Agile Methods

OK, touchy subject with very opinionated people in all camps.  So, I'm going to skirt around the issue and say only that agile methods talk about how to manage a project more than they talk about how to design the objects or implement the actual code.  This is why they're not much help, in my opinion.  What I've found is that just about every job, customer, or article requires a unique approach.  There is no cookie-cutter method for working with a customer, figuring out what the application needs to do, and managing the process of implementation.  There is, however, considerable re-use achievable in how each application is designed, and the framework and wrappers that are used to reduce implementation time.  Agile methods on the other hand are really good as ideas you can use to work with the customer or other people in the company.

What About Creativity?

This argument (which, believe it or not, I've heard many times) holds no water for me.  A two year old can be creative with paint and a canvas, but you won't get the Mona Lisa.  An trained artist uses a method which allows him to channel his creative forces into creating his work within the confines of the chosen method.  Even Jackson Pollock had a method to his paintings, although they do look a bit like what a two year old would do.  The point is, a good methodology actually frees you from the mundane task of figuring out basic things, so you can apply your creativity in better user interface design, better performing functions, smoother user experience by using threads, etc.  The result is something aesthetically pleasing to the user.  As a programmer, I can immediately tell you when a product did not have a good framework methodology because it is clunky, clumsy, rough in performance, and most likely, buggy (and the biggest indicator of all--it got delivered a year later than promised).  Are you listening, Microsoft?

An Example: The Document-View Architecture

What would it take for the document-view architecture to be a true framework?  In my opinion, this would require an automatic coupling between GUI controls and the document.  The programmer need only specify issues such as data lifetime, the control representing the data, and the document (or documents!) containing the data.  The framework would then handle all persistence issues, data translation between the representation of data in the document and the representation of the data in the view, and would do so without requiring any coding.  A document-view implementation at this level wraps data translation, provides an architecture for coupling data with documents, and enforces a methodology by implementing and hiding the coupling between the GUI control and the document.

What Does The Rest Of The World Say?

A framework is a set of common and prefabricated software building blocks that programmers can use, extend or customize for specific computing solutions. With frameworks developers do not have to start from scratch each time they write an application. Frameworks are built from collection of objects so both the design and code of the framework may be reused. - JavaFramework.
That sounds like an architecture and a collection of wrappers.  OK, 2 out of 3.
A skeleton of an application into which developers plug in their code and provides most of the common functionality.  -- E. Gamma, et al., "Design Patterns", Addison-Wesley, 1995
Well, now that's a radically different definition, and in my thinking certainly incorporates the idea of a methodology, if for no other reason than because the "skeleton" has to define how developers plug in their code and how they interface with the common functionality provided by the "skeleton".  Implied here (but not necessarily) may also be how the code intercommunicates.
A set of classes which defines a model of interaction among objects… -- Moduleco (of course, they totally blow it in the additional definitions)
OK, this falls into the category of a methodology because it clearly enforces the interaction style between objects, but it leaves out the wrapper and architectural aspects.
  • A comprehensive, integrated class library
  • An entire architecture is the unit of reuse
  • Defines the control logic and class interactions of the application's architecture
  • Reduces "dog work" at the cost of some flexibility
-- Software Engineering Associates, Inc Hmm.  OK, that encompasses the three things I'm talking about--wrappers (integrated class library), architecture (an entire architecture), and methodology (defines the control logic and class interactions).  Although, this may not exactly be what the authors had in mind, especially when reading what they think a design pattern is, but you never know.
So far, we've seen:
  • building blocks
  • skeleton
  • interaction model
  • all of the above (sort of).
Frankly, I'm not sure that there really is a good definition out there.  But really, the one I like best is from the authors of Design Patterns:
"When you use a toolkit, you write the main body of the application and call the code you want to reuse.  When you use a framework, you reuse the main body and write the code it calls."
"Not only can you build applications faster as a result, but the applications have similar structures.  They are easier to maintain, and they seem more consistent o their users.  On the other hand, you lose some creative freedom, since many design decisions have been made for you."
"If applications are hard to design, and toolkits are harder, then frameworks are hardest of all.  ...Any substantive change to the framework's design would reduce its benefits considerably, since the framework's main contribution to an application is the architecture it defines.  Therefore it's imperative to design the framework to be as flexible and extensible as possible."
This doesn't formally spell out the idea of a framework consisting of wrappers, architecture, and methodology, but it's certainly all there, between the lines.  And it provides a different definition for what most of MFC and .NET really are--toolkits, not frameworks.  Which is the answer to the other question--what are MFC and .NET if not frameworks?

Conclusion

By thinking about what a framework is, I think I've come up with a fairly good analysis of the subject as an introductory topic.  Maybe what I'm talking about is something different from a framework, but in my mind, this is what a framework should be and do.  There are a lot of different ideas out there as to what a framework is, so now you have mine as well.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Marc Clifton



United States United States

Member

Marc is the creator of two open source projets, MyXaml, a declarative (XML) instantiation engine and the Advanced Unit Testing framework, and Interacx, a commercial n-tier RAD application suite.  Visit his website, www.marcclifton.com, where you will find many of his articles and his blog.

Marc lives in Philmont, NY with his son Ian.