错误处理很重要的另一个原则是,明确模块的职责。明确职责的目的在于分清所出现的错误将由哪一个模块去处理(比如,很多情形下需要写错误日志),从而避免同一个错误却被多个模块处理,进而产生大量的冗余。
     现在假设需要设计一个专用于TCP套接字(socket)通信的框架(后面简称框架),这个框架的目的是向上层应用程序提供对套接字的封装。从应用程序的角度来看,这个框架所呈现的概念只有两个:一个是session(会话),即TCP服务器端和客户端所建立的套接字连接;另一个则是acceptor(接受者),即用于侦听从客户端来的连接请求的软件实体,而没有套接字的概念。对于session,框架通过回调的方式,告知其状态的变迁。session被设计成存在已初始化(initialized)、正在建立(establishing)、已建立(established)、已中断(broken)和已终止(destroyed)共五个状态。
     现在的问题是,当一个session所封装的底层套接字出现错误时,框架应当如何处理这一错误?错误是否应当暴露给应用程序?如果向应用程序暴露,使用它的应用程序又应当如何处理?要回答这个问题就需要分清模块的职责。
     首先,前面提到了框架向上(应用层)所呈现的概念只有session和acceptor两个。当出现套接字错误以后,框架显然不能将套接字的错误直接向上层反映,而应通过回调方式告诉应用,session的状态已经变为已中断(broken)。应用程序收到这一通知以后,它不应输出任何的错误日志,但还是可以从应用的角度做相应的业务逻辑处理。比如,在得知session已断开的情形下,释放一定的资源,等等。虽然,应用不应输出任何的错误日志,但仍可以输出调试日志,以便软件在调试日志使能的情形下,让相关人员获取必要的调试信息。从框架的角度,由于它的职责是向上层屏蔽套接字相关的信息。因此,出现套接字错误时,框架应当负责输出错误日志。
     输出错误日志只是错误处理中的一个环节,还存在其它的处理内容。但无论是哪一种形式,在编码时,通过分清模块的职责能有效地掌握错误应由哪一个模块处理,从而避免因一个错误却造成连锁冗余处理。分清模块的职责将有助于在错误出现的根源上做文章,而不是做在错误的表象上。