Thursday, March 29, 2012

企业应用软件开发,正孕育着一场革新



笔者自述

我从事软件开发行业至今已经将近十二年,经历了从Windows 3.2第一次登陆中国 到苹果 安卓统一移动应用市场的一场场变革。着这场商战中,把握住未来发展的方向才是确保再竞争中生存的硬道理。由此发起本文。

引文

多年来一直在探寻企业级应用的未来发展方向,发现对于技术的积累与重用是这个行业的提高竞争力的重要因素之一。
(当然这并不只是成功的唯一条件)让我以技术的重用性为视角来看一下这个行业的发展兴衰。

很多小型软件开发团队在创业初期,往往承接外包软件开发工作为主要业务来源,在面对市场竞争时,
大部分人不断将客户需求中的共性积累起来,设法将带有共性的业务逻辑分立出来用于在其它项目中重用,这样可以逐渐降低未来的开发人力成本,听起来是个不错的逻辑,但在实际应用中却很少真的见到效果。 

是什么导致这个美好的设想实施困难呢? 
  • 客户的需求过于制定化,
  • 系统在设计过程中被多次彻底修改(而非所期待的“扩展”)
  • 客户对时间要求的紧迫,对费用预算的苛刻,让你无法停下来去思考架构,只能一个功能一个功能的修改完整个项目

这种外包开发的商业模式,遇到的最常见的尖锐问题是什么呢?
  • 客户的费用承受能力,他会不断的拿给你的开发费和某国际500强企业的成熟产品的零售价格去比较
  • 客户的对周边业务逻辑的不认可,如果他的需求是开发一个制定的产品数据管理系统,他决不会愿意去为一些貌似和产品管理无关的周边业务逻辑去付出费用和时间,例如:处理用户登陆逻辑,用户会话管理,找回密码,用户权限控制,数据缓存和性能优化。
  • 客户对细节的无限的完美化的要求 和原则上不可能增加开发预算,
  • 客户很难理解一个没有用户界面但必须存在的功能特性。不理解当然不愿意买单了。
  • 例如: 客户问“你说的那个 用户会话管理 和 高级缓存 功能,我点哪能看到? ”

天哪,怎么办?! 想生存,要么你想办法解决问题, 要么被问题解决掉。
如果你对上述我曾经遇到过的问题也有同感,那么“兄弟”, 我们一起来看我是如何应对的这些矛盾的。


如何平衡核心业务逻辑 与 周边业务逻辑 的比重
让我们以某大企业需要开发一套企业内部的资源共享平台为例:
这个项目的核心业务(被用户最关注的部分)是: 如果通过系统来共享公司的各种业务资料,并且可以确保数据的访问权限安全可控。
如果你承接了这样一个项目,你要面对的周边业务呢?按我的经验分析这些工作肯定不能少,(就算你减少了 客户也会在付款验收前要求你加上)
1、用户管理,如何创建,删除,编辑用户,找回密码,会话控制,登陆日志
2、权限管理,谁可以访问某个模块 某个功能, 某个文件夹 某个文件,如何多人同时对某个文件都有不同级别的访问权限
3、部门管理,如何创建,删除等,而且能够在系统内重现客户公司的组织结构,还要考虑一些极端情况,例如某位高人 同时在多个部门任职。
4、用户界面设计与模板引擎,即便客户说软件的美观性无所谓,你也是需要一个表单不少的把他们都设计制作出来,
5、站内导航与菜单模块,这些功能都在哪 如何访问肯定需要一个菜单树
6、电子邮件通知模块,例如我共享了一个数据,怎么自动通知对方

90%以上的客户只关注他们的核心业务逻辑,而往往对于中小系统的开发核心业务逻辑最多只占整体项目工作的不到50%。
以这个范例来说,核心业务似乎简单的仅相当于整体项目的20%.

哇 现在你认为这个项目不管费用多少,就这些工作怎么也要开发个半年吧。
但客户认为这个功能就相当于FTP软件或者Openbiz的文档管理,人家免费的软件都有,我就是在其基础上增加一点点小小的适应我公司的改动为什么,找你这样的小软件公司,你看1个月时间,一共2万开发费能搞定么。

如果你说对这样客户说Lets see(看吧),哪只能寄希望与你的高级谈判和斡旋能力了,可你通常是技术团队啊 一般不是外交和谈判专家
如果你对这样的客户说NO,这意味着你大约会失去70%以上的同类同级别客户需求,由于你的竞争力薄弱,丢掉机会和市场
如果你说对这样客户说YES,你确定你不是在自虐?

到现在为止,解决这个矛盾 和 提高你团队竞争力的 关键因素在于,如何最小代价的消化掉这些周边业务逻辑所带来的看不见的成本。

重用性!把这些你能想到在每个企业的开发需求中肯定都会出现的业务逻辑 抽象分离出来。例如,用户、部门(组)、权限管理这些。
现在我们可以说 谁能用革新的办法把这些周边业务逻辑解决,谁就可能成为以后的老大。

对象化与框架化开发模式,实现业务逻辑重用
面向对象开发 和 框架这些概念 从被提出到今天大约已经有8年以上的历史了,这不是一个新的话题。
目前市面上的任何一种语言都已经完美实现了面向对象这种语言特性,而框架呢,例如微软公司的.Net Framework,Java的hiberNate, Spring,PHP语言的Zend, ThinkPHP ,  还有在美国比较流行的CakePHP 和 Openbiz 等。

而就我研究,这些框架级解决方案主要解决的是,从数据底层到业务逻辑曾的抽象化,例如各种框架中均实现了如何创建抽象数据对象以简化对数据库编程操作的,如何实现高速缓存例如 Zend_Cache, Openbiz 的CacheService等

好吧,这样确实能减轻我门的核心业务逻辑开发工作,可是真正具有重用价值的是例如 用户管理,权限管理这样的模块级的部件。
那么这么说,也许谁通过这些高级框架技术,将这些常见业务逻辑开发成可通用化使用的私有平台,谁就可能成为以后的老大。

新的极致化“模块重用”思想,平台式应用系统开发
思考到这里我们先停下来,看一下美国的小型软件公司是如何解决这样的问题的。
软件这个行业美国的水平还是很有参考价值的。这两年突然发现一种新的开发模式叫 平台式应用系统开发。
就是说一个系统,用户管理,权限划分,部门划分,高级缓存,多语言化等这些你能想到的周边特性 都给你设计好了。
在这个系统之上你只需要去做你20%比重的核心业务逻辑就好了。 而出来的系统是一个界面特别专业,周边功能又丰富整体系统。

这种平台特性最先进的是美国 Openbiz Cubi 平台,还有早期Xoops 也先后提出了 Web Application System这一概念。虽然Xoops的概念提出的比较早,比较了一下底层功能模块的丰富程度,还是Openbiz Cubi的更丰富一些,而且个人而言认为Openbiz的UI比较亲苹果风格,特别细腻。

在早期具有同样级别完善程度的私有应用平台在美国已经产生了一些,例如,Joomla,Druple,Magentoo的私有应用程序框架 ,也有一些开发团队基于CMS系统,或这种Shop系统的用户权限模型的基础去“改装”,不过可想而知,一个是楞改出来的,一个是设计的目的就是为了重用的。
特别对于中文用户来说,Openbiz 的汉化水平是Xoops所不能及的。据了解Openbiz的创始人团队中还有咱们海外华人。

现在对于软件公司而言,不用费力自己去开发通用逻辑了,也不用想着怎么基于什么系统修改。不管是 Openbiz Cubi 还是 Xoops 选择一个你看好的阵营,进行平台化开发,来提升你的核心竞争力。

那么,原来谁先平台化,谁将能称雄 ?

极致市场化战略,让我们app store!吧
当客户项目的积累到达一定程度,也许你已经开始思考这些制定项目的通用性,
例如前文提到过的 资源共享系统 , 去掉当时客户提出的制定化的特性,让它变为一个可以针对某行业应用的软件。
这样以来,小型软件开发团队就拥有自有的软件产品。 从创业初期的劳动力输出,到了现在的产品输出。

随之我们发现,很多当年的创业者成长了起来,形成“诸侯割据”的局面,那么不如我们一起加入个“联盟”
设想,所有符合Openbiz 标准 或 Xoops 标准的应用程序,可以集中在一个类似 安卓市场 或者 苹果App store的市场中集中发售这些软件。
这才是一场真正意义的革新!

移动终端上先辈们发明了App store概念,在PC领域中 QQ软件管家 与 360 争霸天下,Web级企业应用市场 怎么可能无动于衷呢。
如果不想在这场革新中被淘汰,只能抓住时机向平台化进军。



Sunday, May 30, 2010

Openbiz Cubi Menu

Cubi Menu is the core component that manages the application navigation.

Normally, a web application (or web site) hand code several navigation elements, such as menus, tabs, breadcrumb and so on. This was the way used in previous Openbiz application - manually add left menu items on each view or template.

Let's talk how the new menu system works in Openbiz Cubi.
1. Definition of menu
  • Menu is a tree structure
  • Each menu item include navigation attributes like name, title, url, icon...
2. Menu presentation on web page
Menu is tree structure. It can be presented as application tab, breadcrumb, navigation menu, sitemap on a web page.


The diagram below shows how the menu tree maps to UI elements.


3. How to add menu in your own module
Each module can add entries in Cubi menu. In module/mod.xml, there is a Menu section to add MenuItem. The key to append module menu to system menu is
  • In the top MenuItem element, set Parent="existing_menuitem". It will append this menu as a child of specified menuitem
  • Or leave the Parent="". It will tell this menu as a root first level menu item.



4. How to manage menu in the Cubi application
Once a module is loaded in the system, its menu is inserted as well. Then you can see the menu items appear on proper place like navigation menu or application tab.

If you are admin, you can manage menu items in "Menu Management" views. This will be cover in separate topic.

Sunday, May 23, 2010

Cubi module enhancement

The goal of Cubi module is to allow developers to write their own components and plug in to Cubi application. So each module should have its own
  • module description information
  • database tables and preload data
  • menu definition. menu tells users where to access the module functionality
  • depend-on modules who need to be installed before this module
Let's see how cubi enhance its module management. The mod.xml is the main description file. It schema has 3 major part:
  1. ACL
  2. Menu
  3. Dependency
Sample mod.xml can be found in cubi/modules/help/mod.xml

Developer can add the module specific sql in
  • mod.install.sql and
  • mod.uninstall.sql
Cubi provides a command line tool to load module. The command is cubi/install/load_module.php
# php load_module.php module_name

To help prepare fresh cubi installation data, developer can use script at cubi/install/create_cubidb.php
# php create_cubidb.php
This script create a fresh database called "cubi_install". You can dump the database to cubi/install/cubi.sql. This database will be used in installation wizard.

Monday, May 17, 2010

Cubi cronjob manager

Every week Openbiz makes progress on feature implementation and bug fixes. I should have worked more harder to record them in the blog.

Cronjob manager is added in Cubi. What cronjob manager does?
  • Provide a backend management UI to allow administrator to add/edit/delete command in cronjob format
  • A job manager script that reads and parses the jobs in the cronjob list, then execute them.
A cronjob defined in Cubi can have following attributes.
  • name
  • minute, hour, day, month, weekday. Unix cronjob format is used. Note: */N format is not supported.
  • command. This is the command to run in this job.
  • sendmail. This field includes the emails to be sent after completing executing the job.
  • max_run. max_run tells how many concurrent execution of this job. By default max_run=1. It means only single job can run as the same time. If max_run=0, then no limit of the concurrent job execution.
  • description
To start cronjob manager, add "cubi/bin/cronjob/cron.php" in system crontab.

cronjob log files are outputted to cubi/log. Each job will have its own log.

Cubi provides a helper command called run_svc.php that can invoke service with following format.
usage: php run_svc.php service_name method parameter1 parameter2 ...

Cronjob manager can add this command to the job list.

Sunday, February 21, 2010

Cubi clean url

In Openbiz baseapp, a typical url to access a view is like http://host/baseapp/bin/controller.php?view=a.b.viewname. We call it raw openbiz url.

Cubi will map cleaner urls to raw urls by adding an index.php and .htaccess under the root directory of cubi installation.

View mapping syntax:
  • /cubi/a/x maps to /cubi/bin/controller.php?view=a.view.XView. Example: /cubi/system/userList
  • /cubi/a/x_y maps to /cubi/bin/controller.php?view=a.view.XYView. Example: /cubi/system/user_list
  • /cubi/a/x/number maps to /cubi/bin/controller.php?view=a.view.XView&fld:Id=number. Example: /cubi/system/user_detail/5
  • /cubi/a/x/word_number maps to /cubi/bin/controller.php?view=a.view.XView&fld:word=number
If .htaccess is not recognized by web server (e.g. installed on IIS), then you need to do the following:
  • Add "?" right after /cubi/. This assumes that index.php is the default script configured in web server. For example, http://host/cubi/?/system/user_list
  • Or add "index.php?" right after /cubi/. For example, http://host/cubi/index.php?/system/user_list

Saturday, February 20, 2010

Cubi new openbiz.js

In previous openbiz baseapp, clientUtil.js is the main js library to support openbiz browser end logic. It handles Ajax call, form behavior, popup, dialog, richeditor, auto suggestion ... When more functions are inserted in the js file, the code get more messy. Cubi replaces clientUtil.js with openbiz.js in order to get the browser code more organized.

The code structure in openbiz.js
  • Openbiz - main Openbiz namespace. It manages the form objects and provide entry of openbiz ajax call
  • Openbiz.ActionType. It defines the action types of openbiz ajax call.
  • Openbiz.Form. Each openbiz form instance will have a javascript Openbiz.Form instance
  • Openbiz.TableForm. This is the js instance of openbiz List/grid form.
  • Openbiz.Net. It provides network related functions like ajax call.
  • Openbiz.Window. It manages popup, dialog logic.
  • Openbiz.Util. It has some utility functions.
  • Openbiz.Menu. It has functions to show and hide context menu
  • Openbiz.CKEditor. It has functions that integrate CKEditor with ajax call.
  • Openbiz.AutoSuggest. It has functions that initiates autosuggestion control
  • Openbiz.Validator. It has functions that validate user entries on client side only.
With the replacement of clientUtil.js to openbiz.js, there will be some change needed on the existing template, code that worked with clientUtil.js. For example.
  • Replace CallFunction with Openbiz.CallFunction in the list template file
Most changes are done in the openbiz code already to work with the new openbiz.js.

Openbiz.js introduce another importance changes.
  • User JSON in all ajax call.

Cubi metadata naming convention

Before Cubi, Openbiz developers can name their metadata with any name. For example, an user list form can be named as
  • FM_UserList.xml
  • f_userlist.xml
In Cubi, metadata name follows the syntax as "NameType". For the user list form, Cubi will use
  • UserListForm.xml
The advantage of this name besides its clarity is that its custom form class can have the same name. To define a custom class, you just need to set
in the UserListForm.xml
Then add UserListForm.php in the same directory.

Sample metadata names from Cubi/modules/system directory
For DataObject metadata
/do/UserDO.xml
/do/RoleDO.xml

For Form metadata
/form/UserListForm.xml
/form/UserEditForm.xml
/form/UserNewForm.xml

For View metadata
/view/UserListView.xml
/view/UserEditView.xml
/view/UserNewView.xml

Wednesday, January 27, 2010

Cubi Access Control (ACL)

Cubi will extend the existing Openbiz access control approach by allowing administrator the manage role access to system resources. The following chapter outlines how ACL is managed in Cubi.

Basic ideas: define how a role can access application resource.

1. Define resource and its actions
In each module, it can have mod.xml under the module root directory. In mod.xml, there can be a "ACL" section which can have multiple resources. Each resource can have more than 1 actions. For example,
<ACL>
<Resource Name="User">
<Action Name="Administer_Users" Description="Administration of users"/>

2. Link Access resource action to Object
In each Openbiz object, developer can set Access attribute to certain resource action. For example,
<EasyView Name="UserListView"... Access="User.Administer_User">
gives the administer user access to the system.view.UserListView

3. Assign Role permission to resource action
In the role detail page, user can pick "Allow" or "Deny" to all available resource actions. Say, we give role "member" a "Deny" to User.Administer_User. Then when a user with member role tries to access the RoleListView, an access deny page will shown to the user.

Access attribute can be given to View, Form, Element, DataObj.

Saturday, January 23, 2010

Cubi Menu module (1)

Menu plays a key role in any application. Not only it helps user to navigation the application, it also help to organize content.

Generally Menu can be classified into 2 types:
  • Static menu. Menu items are hard-coded in page, template, metadata files or source code. User cannot change the menu in the application.
  • Dynamic menu. Menu is generated from the database and user can configure menu in the application.
Static menu is simple and widely used in most applications where navigation in the application is designed in the product. While dynamic menu is commonly used in content rich systems (like CMS, forum ...) where the site administrator can configure menu to let user to navigate into growing content.

Cubi is going to support both static and dynamic menus. In Cubi first release, static menu will be supported. In Openbiz 2.4, there are 3 different types of navigation components.
  • Tab. Include top-level application tab and in page tab (2nd level)
  • Menu. It support pull down menu up to 3 levels
  • Tree. It organize menu items in tree style
All 3 of components are currently have their own metadata even though they are telling the same things internally. In Cubi, we will have a separate Menu module. It is featured with
  1. Same metadata for tab, menu and tree.
  2. Different template to render tab, menu or tree.
  3. Have "Application tab" and "Admin menu" for Cubi to use.
Menu metadata can use the one in openbiz baseapp.

<menu Name="" Class="" TemplateEngine="PHP" TemplateFile="">
<menuitem url="" target="" text="a" icon="a.gif">
<menuitem url="" target="" text="a1" icon="a1.gif">

Thursday, January 21, 2010

Add more security on the server actions

Openbiz framework makes it open for browser client to invoke the server object method through Ajax call. Of course, developers can add rules to protect different actions (e.g. use UpdateCondition and DeleteCondition in 2.3 and use ACL control in Cubi), people may want to have some easier approach to filter out unsafe actions triggered from the browser.

Here is the proposal for so called "safe actions filter" on Openbiz 2.4. This will be released in the 2.4 SVN before Feb.

First, only Form object method calls from browser are allowed. Other objects method calls are blocked by the controller.

Second, EadyForm class will have a new method
public function getMethodsWhiteList()
This method returns a list of methods that are exposed to browser client. By default EasyForm will compose the list with:
  • All methods that are defined in the form metadata EventHandlers. Say you have 2 EventHandlers of 2 button elements on user.AccountForm. They link to methods "editAccount" and "resetPassword". Then only these 2 methods are in the white list.
  • Some safe methods like "selectRecord" which is usually not linking to a event handler.
When an server action is invoked (through Ajax for example), the controller will check if the target object is a form object, then check if the called method is in the white list. This approach will give more security on the server side logic.

getMethodsWhiteList() can be overrided by your any form class to implement custom logic.