解惑

解己之惑,解人之惑

标签:设计

设计也不是个简单的事情

理论上,一个系统的设计如果有多种方案,应该是很容易决定出优劣的,但是现实往往不是这样,需要考虑很多种因素。

  • 参与决策的人的设计风格不同,有的喜欢Properties式的无约定扩展风格,有的喜欢超级父类式的运行时多态风格,还有的喜欢根据功能不断增加的API不断对应增加的风格,当然还有其他的一些根据三种风格的变种的风格。
  • 实现系统的人的能力和背景不同,某些很好的设计对于他们来说难度较大,因为实现的人不能充分的理解设计者的意图,最终好的设计变成糟糕的实现。
  • 时间约束,项目的时间很紧,某些设计方案需要做比较多的架构和框架方面的东西才能做业务方面的东西,导致前期更高级别的人看不到项目的直接而且直观的结果。
  • 需求的不确定,很多设计都是根据当前和可预见的需求来设计的,但是如果需求非常的不确定,很难决定那种设计更好,不同的关键需求的变更可能导致某些关键设计的失败。
  • 技术风险,某些设计存在一些技术风险,设计还没有成熟的先例,在大规模系统情况下存在不可预见的技术瓶颈。

Google式设计

今天看到的,觉得不错,转帖下备忘:

1、关注人——他们的生活,他们的工作,他们的梦想。
2、每一毫秒都至关重要。
3、简洁是有力的。
4、吸引新人,诱惑专家。
5、勇于创新。
6、设计放眼世界。
7、当下与未来的业务并重。
8、让人眼前一亮,又不会心有旁骛。
9、对得起人民的信任。
10、融入人性接触。

原文在这里

也谈Java基础的重要性(续)

呵呵,意犹未尽,继续批驳。
banq先生对自己的思维和真正想法并不是了然于胸,我想他不关心的是业务逻辑的实现了,他说他已经很多年不去翻J2SE了,那是因为他已经很多年不是“程序员”了,他不需要使用他的框架去完成一个实际的业务系统,你把这个框架做了,你鼓动别人去使用框架,去学习设计,还有意义吗?如果别人都去提高学习了,都去设计了,就不会有人用他的框架,而如果别人都不用,那他搞那个框架又是为了什么呢?
他说他自己对J2SE都忘记了,那么他是如何完成这个基于Java的框架的?难到都是拷贝别人的代码,然后就是debug?

再说他所谓的向上思维和向下思维,其实不是思维问题,而是开发方法问题,他所谓的向上思维是敏捷开发所推崇的,自底向上实现系统,发现问题就不断的重构系统,而CMM/CMMI以及RUP之类的开发方法就崇尚自顶向下实现,也就是他所谓的向下思维,这些方法的优劣现在本身就没有定论,也不会有定论,需求的不同导致使用不同的开发方法有不同的效果,IBM之类的大公司接单子都是预先浪费了无数的时间确定需求,然后签合同,完全按照合同的内容来执行,他们有资格使用自顶向下设计;而广大的中小软件公司没有那个本事,可怜兮兮的拿下一个单子也只能当孙子,客户让怎么改还不是怎么改?能拿到钱就不错了。所以这些公司使用自底向上就很自然了,因为快捷简单,能够更好的应付需求的变化(当然,要做好也非常的不简单)。

一个新技术不必关心它是如何做出来的,而是重点研究是如何使用它,使用的场合和条件是什么,这些就是模式啊”,天啊,这个是模式吗?模式是程序内部的设计好不好!怎么会和技术的使用场合和条件扯上关系呢?

如果我说不学习"数据结构,操作系统,编译原理,数学",照样可以作出架构优质的高性能Java系 统,你可能不惊奇了,Collection和数据库技术已经就是依据数学结构做出来的,你学了数学结构,自以为懂了很基础知识,碰到 COllection,你就会自然去打开看看,自豪运用你的数学结构理解它一番,可是这些对于你如何使用COllection根本是两个领域的知识(如何 使用Collection是模式领域知识),这些都是先入为主造成浪费时间,能力不足的表现
呵呵,他的那个叫做“作出”的吗?据我所知充其量是拼出来的,系统最核心的部分都是别人的(当然,这个也不惊奇,因为他最自豪的就是可以看懂别人的设计和使用别人的成果),当然不需要数据结构了。学习Collection的实现会浪费时间吗?看这个对于设计能力难到没有提高吗?看别人的设计就是能力不足了,想想自己当初是怎么学习设计模式的!
算了,不说了,记得原来gigix就写过一篇文章批驳过他的。

如何设计API?

每个人设计API的思路可能都不一样,而我们公司的一些代码的API的设计很有意思,一个例子:
    public AppGroupConfigValueObj get(UserSession _userSession, AppGroupConfigValueObj invo) throws DataException
    {
        long start = System.currentTimeMillis();
        try
        {
            Long id = (Long) invo.getId();
            if (isDebug() )
                SessionLogManager.getInstance().getLogger(this.getClass()).debug("get group" + id);
            AppGroupConfig eb = this.appGroupHome().findByPrimaryKey(id);
            if (isDebug() )
                SessionLogManager.getInstance().getLogger( this.getClass() ).debug("Get( UserSession _userSession, AppGroupConfigValueObj invo) elapsed time = "+ (System.currentTimeMillis()-start));
            return get(eb, invo);
        }
        catch (Exception e)
        {
            throwException(e);
        }
        return null;
    }

    private AppGroupConfigValueObj get(AppGroupConfig eb, AppGroupConfigValueObj invo)
            throws Exception
    {
        AppGroupConfigValueObj vo = (AppGroupConfigValueObj) ServerUtil.getValueObj(eb);

        if (invo.getApps() != null)
        {
            Collection collection = eb.getApplications();
            if (invo.getApps().getCount() == 0)
                vo.setApps(new ValueObjList(collection.size()));
            else
            {
                Iterator it = collection.iterator();
                while (it.hasNext())
                {
                    AppConfig a = (AppConfig) it.next();
                    vo.addApp((AppConfigValueObj) ServerUtil.getValueObj(a));
                }
            }
        }
        return vo;
    }

解释一下,这个API的功能是这样的,主要参数AppGroupConfigValueObj 是一个Map结构的对象,另外包含一些父子关系,如果你需要的是一个轻量级的结果,那么传入的对象只需要设置ID就可以,典型的用法是这样的:
get(cuSession, new AppGroupConfigValueObj(appGroupId))
如果你需要一个重量级的结果,也就是需要它的一些子表的数据,那么就要设置子表的关系,并添加一个空的对象:
                    AppGroupConfigValueObj appVo = new AppGroupConfigValueObj(appGroupId);
                    appVo.addApp(new AppConfigValueObj());
                    get(cuSession,appVo);
还有第三种用法,就是你希望那些子表数据不填充,但是需要知道子表数据有几个,那么你的调用代码就是:
                    AppGroupConfigValueObj appVo = new AppGroupConfigValueObj(appGroupId);
                    appVo.setApps(new ValueObjList());
                    get(cuSession,appVo);

我不知道这种做法源自何处,但是很明显是原来的某位高人,而比我资历更老的一些同事沿用了这个做法并且没有在文档中记录这种方法,当我苦苦寻找一个简单的get(cuSession, appGroupId)方法时没有任何结果,最后看其它部分的代码才知道了这个诀窍。

OO设计模式和设计原则(转帖)

很好的文章,下面是摘录,请直接下载原文阅读

1.1 设计正在“腐烂”的征兆(Symptoms of Rotting Design)
有四个主要的征兆告诉我们该软件设计正在“腐烂”中。它们并不是互相独立的,而是互相关联,它们是过于僵硬、过于脆弱、不可重用性和粘滞性过高。
1. 过于僵硬Rigidity
Rigidity 致使软件难以更改,每一个改动都会造成一连串的互相依靠的模块的改动,项目经理不敢改动,因为他永远也不知道一个改动何时才能完成。
2. 过于脆弱Fragility
Fragility 致使当软件改动时,系统会在许多地方出错。并且错误经常会发生在概念上与改动的地方没有联系的模块中。这样的软件无法维护,每一次维护都使软件变得更加难以维护。(恶性循环)
3. 不可重用性immobility
immobility 致使我们不能重用在其它项目中、或本项目中其它位置中的软件。工程师发现将他想重用的部分分离出来的工作量和风险太大,足以抵消他重用的积极性,因此软件用重写代替了重用。
4. 粘滞性过高viscosity
viscosity有两种形式:设计的viscosity和环境的viscosity。
当需要进行改动时,工程师通常发现有不止一个方法可以达到目的。但是这些方法中,一些会保留原有的设计不变,而另外一些则不会(也就是说,这些人是hacks)。一个设计如果使工程师作错比作对容易得多,那么这个设计的viscosity 就会很高。
环境的viscosity高是指开发环境速度很慢且效率很低。

2 面向对象的类设计原则
2.1 开放关闭原则The Open Closed Principle (OCP)
A module should be open for extension but closed for modification.一个模块应该只在扩展的时候被打开(暴露模块内部),在修改的时候是关闭的(模块是黑盒子)。
在所有的面向对象设计原则中,这一条最重要。该原则是说:我们应该能够不用修改模块的源代码,就能更改模块的行为。

2.1.1 动态多态性(Dynamic Polymorphism)
2.1.2 静态多态性(Static Polymorphism)
另外一种使用OCP的技术就是使用模板或范型,如Listing 2-3。LogOn函数不用修改代码就可以扩展出多种类型的modem。
阅读全文

我的持久层规范

昨天说了我的这个大轮子的大致情况,就是尽量保持简单,而配置最多的可能就是持久层和Action的配置,我的框架会完全取消这两个的配置,先说说持久层的情况。

  1. 类名和表名直接关联,关系是类名前带 t_
  2. 类的成员和表字段直接关联,名称完全一致,全部的表都需要一个名字为ID的主键,类型为long,由系统自动在插入的时候产生
  3. 表关联根据类之间的关联决定,如果两个类对对方都是直接引用,就是一对一,如果一个是直接引用,例外一个是集合,则是一对多,如果两边都是集合,就是多对多,对于集合的成员,其成员名是类名加s。多对多的表名是t_加两个类名,中间用_分隔,字段名就是类名加_id,如果是一对多,则外键名就是类名加_id
  4. 类型现在是自动匹配,也就是数据库的类型和类中的对应字段的类型是匹配的
  5. 主键的值在系统初始化的时候会从数据库表中读取最大值,然后缓存在系统中,每次加一
  6. 缓存的大小根据系统启动时数据库对应表的记录数决定,记录数小于一千的缓存100%,一千到一万的缓存50%,一万以上的缓存10%,十万以上缓存1%
  7. 类名可以分布在多个包中,配置文件配置都有那些包可以存放这些持久化对应的类,类名不可重复

根据这个规则,我完全取消了持久层的配置,对于新项目,这个规则的要求并不高,符合绝大部分的需要。至于查询,目前还没有完全想好,但是我考虑的是大部分的简单情况,只提供一个简单的对象表达式语法,复杂的查询还是使用SQL。

具体的例子:
阅读全文

© 2024 解惑

本主题由Anders Noren提供向上 ↑