欢迎访问 ==>
高焕堂:MISOO(大数据.大思考)联盟.台北中心和东京(日本)分社.总教练
EE EE
本文共 6657 字,大约阅读时间需要 22 分钟。
前言:其实大家都知道,架构师最关键的任务就是:接口(Interface)设计。所以,”足够好架构”的核心部分就是:接口的定义(Definition)和表述(Representation)。那么,有什么有效的方法能清晰而明确地定义和表述接口设计呢?
ee ee
欢迎访问 ==>
高焕堂:MISOO(大数据.大思考)联盟.台北中心和东京(日本)分社.总教练
EE EE
前言
在敏捷开发里,流行的敏捷设计观点是:“敏捷是把原来架构设计里的详细设计放到了编码的过程中,开发人员要有架构师的思维,架构师的预先架构设计要<正好足够>。”在敏捷中,将传统的架构设计分成:架构 + 设计。
敏捷开发的架构师,将架构部分做到”足够好”即可。
然后,将(详细)设计转移到代码撰写阶段、重构阶段、以及单元测试阶段等。
简而言之,在敏捷中,架构设计仅止于”足够好”的架构,不进行详细设计。但详细设计仍然存在,只是转移到了开发阶段而已。这些详细设计需要花费大量的时间,包含详细的流程、数据结构等设计;而且在编程阶段,也蕴含了很多详细设计的内容。如果直接将设计表现于代码中(Code is design),就能避免开发人员同时既要维护一套设计,又要维护一套代码;可大幅减轻开发者的负担,提升效率。
1. 如何表述(Represent)”足够好的架构”呢?
架构设计被切分为”足够好的架构”和”详细设计”两个部分,那么这两部分又如何相互衔接呢?
其实大家都知道,架构师最关键的任务就是:接口(Interface)设计。所以,”足够好架构”的核心部分就是:接口的定义(Definition)和表述(Representation)。那么,有什么有效的方法能清晰而明确地定义和表述接口设计呢?
答案是:代码造形(Code Form)。
2. 什么是代码造形?
顾名思义,代码造形就是代码层级的设计造形(Form)。代码造形就是开发者常用的词汇(Vocabulary),其能直接对映(Map)到程序语言的基本结构,此结构大多定义成为关键词(Key word)。例如,指令(Instruction)、函数(Function)和类(Class)。[]
3. 代码造形在软件开发上的用处
因为代码造形能直接对映到程序语言的结构,具有高度的精确性(Precision),架构师能准精确地传达设计的涵义。
因为代码造形是开发者的词汇,架构师以<代码造形>表述架构,基于共同词汇,提升了共识(Shared Understanding),开发者很容易理解其架构的设计涵意。
所以,代码造形能大幅提升开发者的效率;而且迅速配合需求变更、架构创新(或重构)设计,大幅提升了整体团队的敏捷性。
架构师如同妈妈,使用kid language来与小孩交谈,非常有助于小孩语言天份的开发。同样地,架构师以<代码造形>来表述架构,来与开发者交谈;非常有助于开发者设计能力的提升。
架构师自由创意去思考架构设计(加法设计),但是都以一致的<代码造形>来表述架构设计(减法设计)。就如同唐诗的<七言绝句>造形,李白、杜甫、白居易人人都能发挥创意、尽情思考,但都以一致的造形来表述(Representation)。不但没有伤害创意,而且还基于<诗同形>而相互激发创作的氛围。
即使架构尚未达到”足够好”,只要能清晰而明确地表述,就能随着敏捷迭代而互相切磋着磨而达到”足够好”的境界了。
4.大家熟悉的2种代码造形:函数和类
在软件开发中,大家最熟悉的代码层级的基本造形有二:函数(Function)和类(Class)。
1970年代的主要造形:函数(Function)
像C语言的代码基本结构就是函数,例如:
/* C语言程序代码 */
int function add( int x, int y)
{int sum;
sum = x + y; return sum; } int function mul( int x, int y) {int sum;
sum = x * y; return sum; } int function exec( int a, int b) { int k = mul( add(a, b), 100); } void main(){
printf(“%d”, exec(3, 5)); }函数造形简单,其内部的组成要素是:指令(Instruction),或称叙述(Statement)。也有简单的造形组合规律:线性排列,并相互调用(Function call)。
1980年代的主要造形:类(Class)
自从1980年代到今天,软件开发的主要造形是:类(Class)。类造形并不难理解,它只是对函数造形加以扩大;也就是以函数为基础(保留了函数的各项功能),扩大结合了属性(Attribute);让开发者拥有更大的视野,具有更好的整体观。就如同太极图,引导人们掌握更宏大的整体观。
像C++语言的代码基本结构就是类,例如:
// C++程序代码
class Calculator { int x, y, value; public: void set(m, n){ x = m; y = n; } void add() { value = x + y; } void mul() { value = x * y; } int get() { return value; } } //----------------------------------------------- class Adder extends Calculator { public: int exec(int m, int n){ set(m, n); add(); set(get(), 100); mul(); return get(); } } //------------------------------------------------ void main(){ Adder adderObj = new Adder(); printf(“%d”, adderObj.exec(3, 5); }自从1986年C++语言问世以来,类(Class)都是主要的软件代码造形(Form),例如C++、Objective-C、Java和C#等语言的主要代码造形就是类。 类造形内含2个要素(更小的组成单位):属性(Attribute)和函数(Function)。也有清晰的造形组合规律:定义了类与类之间的组合关系,例如上述范例里的”扩充( Extends)”关系等;并透过内含的函数来相互调用。
5. 介绍新的EIT代码造形
EIT造形的涵意
自从1996年Java问世之后,接口(Interface)成为Java语言的关键词(Key Word)。于是,<接口>的位阶已经提升了,其与<类>是同位阶了,而不再隐藏于类造形里。这意味着,我们可以设计一个更大的代码造形来包容类和接口两种元素。为了凸显接口角色,就得考虑两项特性:
为了清楚地定义一个接口(主角),需要两个类来当配角。
此外,接口以能实现为类(造形)。
于是,高焕堂 老师将3个<类造形>组合起来,成为一个更大的造形;就像生物DNA的螺旋结构,组合如下图:
在上图里,为于中间的类就是接口实现类。高老师将其命名为EIT造形:
EIT造形也不难理解,它只是对类造形加以扩大;也就是以类为基础(保留了类的各项功能),将3个类结合在一起,各扮演不同角色;让开发者拥有更大的视野,具有更好的整体观。例如,Java语言的程序:
class Tasks implements Runnable{
public void run() { int sum = 0; for (int i = 0; i <= 100; i++) sum += i; System.out.println("Result: " + sum); }
}
// ----------------------------------------------------------public class JMain { public static void main(String[] args) { Thread t = new Thread( new Tasks()); t.start(); System.out.println("Waiting..."); }}其主要意图是:凸显出<接口>元素与类同位阶的角色。为了清楚地定义一个接口(主角),需要两个类来当配角。例如,为了凸显Runnable接口,而且要精确地表述它,就需要Thread和Tasks两个类来陪衬,如下图:
由于接口定义是架构师的主要职责,所以EIT可以协助架构师清晰地定义接口,非常有助于清晰表达架构。
EIT造形的重复组合
EIT造形也内部结构简单,也能透过内含的类的组合关系,将EIT造形组合起来,轻易地组合出大型而复杂的系统。例如,EIT造形能像DNA螺旋结构一样,组合起来:
EIT造形提供更宏大的整体观,更易于重构,迅速从简单组合出复杂系统。
这是由两个EIT造形(即Thread造形和View造形)所组成的。
在游戏软件应用上,这个Thread造形里的小线程(由UI线程所诞生的)扮演一个特殊的角色:成为游戏的主控循环(Game Loop),而UI线程则专注于响应UI 的事件,创造出两个线程完美分工。由于这个线程专注于游戏主控循环,所以又称为游戏线程(Game Thread)。游戏线程调用postInvalidate()函数,间接触发UI线程去调用invalidate()函数了,也触发View重新调用App子类的onDraw()去重新绘图了。现在就将上图落实为Android程序码,如下:
// GameLoop.java
package com.misoo.pk001;public class GameLoop implements Runnable {
myView mView; GameLoop(myView v){ mView = v; } public void run() { mView.doUpdate(); mView.postInvalidateDelayed(1000); }}// myView.java
package com.misoo.pk001;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.view.View;public class myView extends View {
private Paint paint= new Paint(); private int x, y; private int line_x = 100; private int line_y = 100; private float count = 0;myView(Context ctx)
{ super(ctx); } public void doUpdate(){ if( count > 12) count = 0; x = (int) (75.0 * Math.cos(2*Math.PI * count/12.0)); y = (int) (75.0 * Math.sin(2*Math.PI * count/12.0)); count++; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.WHITE); paint.setColor(Color.BLUE); paint.setStrokeWidth(3); canvas.drawLine(line_x, line_y, line_x+x, line_y+y, paint); paint.setStrokeWidth(2); paint.setColor(Color.RED); canvas.drawRect(line_x-5, line_y - 5, line_x+5, line_y + 5, paint); paint.setColor(Color.CYAN); canvas.drawRect(line_x-3, line_y - 3, line_x+3, line_y + 3, paint); Thread gt = new Thread(new GameThread(this)); gt.start(); }}
// myActivity.java
package com.misoo.pk001;import com.misoo.pk001.R;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.LinearLayout;public class myActivity extends Activity implements OnClickListener {
private myView mv = null; private Button ibtn; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); show_layout_01(); } public void show_layout_01(){ LinearLayout layout = new LinearLayout(this); layout.setOrientation(LinearLayout.VERTICAL); mv = new myView(this); LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(200, 200); param.topMargin = 10; param.leftMargin = 10; layout.addView(mv, param); //---------------------------------------------- ibtn = new Button(this); ibtn.setOnClickListener(this); ibtn.setText("Exit"); ibtn.setBackgroundResource(R.drawable.gray); LinearLayout.LayoutParams param1 = new LinearLayout.LayoutParams(200, 65); param1.topMargin = 10; param1.leftMargin = 10; layout.addView(ibtn, param1); //----------------------------------------------- setContentView(layout); } public void onClick(View v) { finish(); } }由于EIT造形只是对类造形加以扩大;也就是以类为基础(保留了类的各项功能),将3个类结合在一起,各扮演不同角色。所以,只要利用类造形既有的组合机制,就能将EIT造形组合起来,成为复杂的系统了。例如,也能组合如下图:
这通称为:双层EIT造形的架构设计。◆
转载地址:http://cbgkx.baihongyu.com/