Wednesday, September 30, 2015

Practical API Design: Confessions of a Java Framework Architect



http://wiki.apidesign.org/wiki/Category:APIDesignPatterns
http://craft6.cn/detail/practical_api_design_note.do

https://my.oschina.net/tingzi/blog/133163

https://my.oschina.net/tingzi/blog/135538
    API需要一个小团队进行评审,好的API设计需要满足以下条件:
1、用例驱动的API设计
2、API设计的一致性
3、简单明了的API
4、少即是多
5、支持改进

API的演化需要考虑的因素,比起一般的接口与类的设计,要更加地复杂与困难。面向对象设计有一个非常重要的原则是“开放-封闭原则(OCP),利用抽象以应对扩展,利用封装以隐藏实现,从而避免修改。
好的设计原则可以放之四海而皆准,而设计的缺陷却各有各的表现特征。

http://m.oschina.net/blog/133766
http://m.oschina.net/blog/133163
http://blog.domlib.com/articles/171.html
框架向后兼容性,和可扩展性.

一.只公开你需要公开的内容。必须要限制对外公开的方法和属性的数量,包括public 和protected的,这些API一旦公布,就代表了对外的一种承诺,你永远不能去改变他们。否则就会带来框架版本的兼容问题。只有框架内部使用的公开方法,也不应该对外公开,给上一个“此方法仅框架使用,外部不可以使用”这样的文档注释是很糟糕的。但是原生提供的internal修饰符又只支持包内访问。针对这个问题,书里还特别提供了一种在Java里能巧妙的跨包访问又能对外屏蔽的方法

二.避免深层次的继承。子类可以通过覆盖父类的方法来改变父类行为。但继承的重点不是用来改变行为的,而是扩展功能的作用。子类跟父类应的关系该是跟描述自然世界里的关系一样。子类屏蔽掉自己额外的功能后就一定可以完全被当做父类来使用。如果只是为了复用父类的部分代码,应该使用接口。

工厂方法由于构造函数
1、工厂方法返回的实例不一定是该类的实例,可以是它的子类的实例。但是构造函数只能new出该类的实例;
2、工厂方法创建的对象可以缓存,以便下次使用,构造函数不可以;
3、对于同步的控制,工厂方法可以将创建对象前后的代码进行统一处理,构造函数就无能为力了;
4、工厂方法支持参数化返回类型,构造函数不支持。
例如:
在java1.5之前,我们有以下代码:
?
1
2
3
4
5
6
public final class Template extends Object {
  private final Class type;
  public Template(Class type) { this.type = type; }
  public Class getType() { return type; }
  public Template() { this(Object.class); }
}
java1.5加入了泛型,因此,我们改写上面的代码为:
?
1
2
3
4
5
6
7
public final class Template<T> extends Object {
  private final Class<T> type;
  public Template(Class<T> type) { this.type = type; }
  public Class<T> getType() { return type; }
  // now what!?
  public Template() { this(Object.class); }
}
这个类的最后一个函数有问题,不能编译通过。
如果一开始设计时就用工厂方法,就没有这个问题了。我们知道,最后一个函数想返回的是Template<Object>对象实例,如下:
?
1
2
3
4
5
6
7
8
9
10
11
public final class Template<T> extends Object {
  private final Class<T> type;
  public Template(Class<T> type) { this.type = type; }
  public Class<T> getType() { return type; }
  @Deprecated
  @SuppressWarnings("unchecked")
  public Template() { this((Class<T>)Object.class); }
  public static Template<Object> create() {
    return new Template<Object>(Object.class);
  }
}

对于使用API的用户来说,让他们更新版本,有时是困难的,因为他们要冒着软件在新版本上不能用或者出现其他问题的风险。因此,他们对于API中有重要bug的问题,会更新版本,但是对于普通可以接受的bug,他们宁愿不更新版本。
http://my.oschina.net/tingzi/blog/135980
    Swing框架中的Frame类,间接继承了Component,其实是一个错误的设计。这样继承表示可以使用Component类的地方,都可以使用Frame对象,但是运行起来,估计未必可行。
    Frame之所以继承自Component,完全是出于实现该类的代码比较方便,只是想复用Component类中的一部分代码。这种误用在深层次继承中表现明显。
   因此,一旦发现继承体系超过两层,一定要打住。想想是在设计API还是在复用代码,如果是后者,那么要重新审视,并严格设计这个API。
    package级别访问控制将api的权限设定在只能在包内部使用。有时,我们需要扩展这个功能。比如:我们设计了两个内部包,api不对外开放,那么这两个包中互相访问应该用什么访问控制权限呢?
    作为NetBeans库核心API的开发人员,经常会被抱怨,因为其他开发API的开发人员基本都要用到这个核心库。这样,随着新的需求的增多等等需要变化的问题,经常会因为改变一些东西而破坏一些东西。要改变这种状态,有一种方法,就是设置“保卫者”。每一次新的调整,我都会先写一个“保卫者”,再去实现API代码,然后用之前用过的保卫者来来进行检查
这里所指的“保卫者”就是自动化测试。但是即使这样,也不能保证会到达最终目标,只能说不至于原地徘徊。
面向用例的重要性
要监督开发进度,使软件后续可维护,就需要以用例的方式,并写javadoc。
    API需要一个小团队进行评审,好的API设计需要满足以下条件:
1、用例驱动的API设计
2、API设计的一致性
3、简单明了的API
4、少即是多
5、支持改进
http://my.oschina.net/tingzi/blog/133766
    也就是说,具体实现可能和预期差别很大,新版本的发布和旧版本差别也很大,就像阿米巴虫一样,形状变幻无穷。我们只能负上责任,尽量减少阿米巴虫效应。
    API要有运行时的类库、javadoc、指导教程。最重要的是,这些内容必须保持一致性。不能有的说某个功能可以实现,有的说某个功能不能实现。
    要保证开发者编写代码时输入时和运行时都正确。IDE实现了半自动化编码,来保证输入时正确。
    举个开发时和运行时不一致的例子。javax.swing.JFrame是java.awt.Component的子类。因此,所有可以使用java.awt.Component对象的地方,理论上讲都可以用javax.swing.JFrame,比如说把JFrame控件放到一个java.awt.Container控件容器中。很明显,这是行不通的,不可能把一个顶层的窗口放到一个对话框中。但是代码编译可以通过。对于有经验的人,是不会犯这种错误的,但是对于初学者来说,Swing类库在开发时和运行时的不一致性,却会打击他们使用Swing的积极性。
    这种设计和运行时不一致的例子估计俯仰皆是。这也是没有办法的事情,因为代码运行时所表现的计算能力就像一台图灵机。事实上常用的编程语言都有自己的类型,并不完全遵守图灵理论,所以编程语言无法正确表达所有运行时的内容。不可能消除所有的不同,所以一旦出现这种问题,只能说是运气不好了。但对于出现的问题,API的用户需要了解设计和运行的区别,要找到在程序运行时出现的非预期问题。如果想让用户再不了解API内幕的时候也能很好地开发代码,就必须将这种设计和运行的不一致最小化。
http://my.oschina.net/tingzi/blog/132855
    记住一点:“少就是多,API暴露的内容越少,那么重用就会越容易”。不要通过环境配置等使API变得复杂,从而限制用户使用某个API。
    设计时既要想到用户使用API的通用用法,也要想到那些不常见的场景,从而在设计时在两者之间取一个平衡。

软件熵
避免滥用setter方法
http://my.oschina.net/tingzi/blog/135583
    以javax.swing.Action为例,这个类违反了标题中的原则,它定义了setEnable(boolean)方法,而这个方法是不会用到的,使用API的人用到的是isEnable(),setEnable(boolean)这个方法只是开发API的人员使用的内部方法,是不应该暴露出去的。
中心思想是:模块间去耦合。
举例说明:
  随机显示一个经过扰乱处理的不规则单词,而用户则要将扰乱后的单词纠正为正确的单词。其中,一个类用来生成原始单词,一个业务逻辑层用来扰乱单词,还有一个用户界面模块负责将这个单词展示给用户看。定义接口如下:
?
1
2
3
public interface Scrambler {
  public String scramble(String word);
}
?
1
2
3
public interface WordLibrary {
  public String[] getWords();
}

?
1
2
3
public interface UI {
  public void display();
}

Word to API providers: Make it simple for developers

http://chickenwing.software/scratches/programming/annoying-apis
Annoyance the first – trsnss
Yes, name-ification of things is hard. Still, common sense could go a long way. You gotta hand it to the Unix folks for their heroic efforts to save a keystroke – why say dupe when we can save that valuable E and say dup?
Number two is related:
Annoyance the second – makingNamesMuchTooLongToBePractical
Apple, in contrast, gives us gems like

1
outputImageProviderFromBufferWithPixelFormat:pixelsWide:pixelsHigh:baseAddress:bytesPerRow:releaseCallback:releaseContext:colorSpace:shouldColorMatch:
Vexation number three – Using synonyms
Oh, Android, I’m looking at you.
Apparently there’s a difference between a “BlankActivity” and an “EmptyActivity.” What’s the difference? I once knew, but now I’m drawing an empty – I mean a blank.
Android gives us tool bars, which at some point got renamed app bars, also known as action bars, giving us lovely code like:
1
2
   // Set the toolbar as my app bar
   setSupportActionBar(myToolbar);
To abbreviate or not to abbreviate. That’s apparently not the question at the Googleplex. Por que no los dos? Cross referencegetExternalDirectory and getExternalFilesDir. These return two different locations, by the way, because sometimes in a directory you want to store files, and sometimes you want to store… I dunno, something else.
What’s the difference between a tap and a touch? I have no idea (at least not on a phone), and neither does the Android design team, who also sometimes calls it a click.
Hey, what version are you running? Oh, it’s KitKat. Or is it 4.1? No, maybe it’s SDK version 19… Oh wait, those all mean the same thing. Good luck keeping them straight.
And a final Android example. Want to make a project asset available by URL? Simply put it in the /assets/ directory in your source tree and construct a URL starting with “file:///android_asset/”. Yep, one is plural, one is singular. One has android_ in front, one doesn’t. Why? Because they’re Google and they can do whatever the hell they want, that’s why. What are you gonna do, use FirefoxOS?
Annoyance the fourth – Poor (or absence of) documentation
Speaking of asset URLs, you won’t find out about them by reading the documentation, aside from an offhand mention of it on theWebSettings.setAllowFileAccess method – a method which has zero affect on whether you can access files this way. Yes indeed, the old semi-documented feature.
Annoyance the 5.1beta3 – Version incompatibility

Annoyance the 6 – Overcomplimification (easy things made hard!)



7. XML




Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts