GWA2-Java built-in cache with connection pool design/带连接池的缓存流程设计

最近花很大力气在 -GWA2-Java 中实现了带连接池的缓存设计流程(GWA2-Java built-in cache with connection pool design)并部署成功。之所以花很大力气,是由于这些功能在 -GWA2-PHP 中均没有碰到,兹整理记录如下。

按此前在 -GWA2-PHP 中实现的 built-in cache( -GWA2 更新缓存调用built-in cache方法,  -R/r2SH ),其大致思路是:
1) 应用对象 myObject 调取父类 WebApp的方法,
2) WebApp进一步地前转读取 Cache 的请求给CacheAdmin (Cachea);
3) CacheA 被调用后,首先查询配置及运行时参数,决定连接哪个在线服务,
4) 在获得服务器相关信息后,进一步地的查询配置及运行时参数,决定使用哪种驱动程序;
5)获得服务信息及驱动信息后,比如最终连接 CacheMaster主机,使用 Memcached 驱动,然后Memcached的实例被创建,Memcached完成初始化后,进行读写操作;
6) Memcached获得相应结果后,前转查询结果给Cachea,Cachea进一步地前转查询结果给WebApp及myObject调用对象。

这一流程可以用上图表示,其中一个完整的查询涉及到五个对象,五个流程分叉判断。五个对象为:myObject, WebApp, CacheAdmin, CacheMaster, Memcached;
五个分叉流程判断为:
1)是否读取Db还是Object对象数据?
2)是否读取Cache?
3)连接哪个Cache主机?
4) 使用哪种驱动程序读取Cache?
5) 是否有连接池到指定的Cache主机?

相比 -GWA2-PHP 的实现,-GWA2-Java 中需要额外地创建了 CacheDriver 接口 以此来约束和规范各个驱动程序模块,额外地创建和维护连接池程序,额外地创建Memcached Java Client。

这三种新的创造,单独拿其中一块都可以大书特书一篇。CacheDriver 接口相对容易,由于在 Cachea 需要预设一种对象类型,使之能够被赋值为某种驱动模块的实例,自然这就非 Java Interface 莫属,Interface CacheDriver 同时定义和约束了各个不同的驱动模块来实现相应的方法,从而保证数据流的正常流转。

Socket Connect Pool(SocketPool)相对复杂,但思路很简单,依赖Java Servlet Container可以维护运行状态的特性,创建一个可以寄宿其上的数据对象,并约定一定的状态管理机制即可实现。与Servlet Container本身提供的连接池(如JDBC的连接池)相比,这个需要自我手工实现。幸运的是,基于Java的连接池管理,早于2005年,我们在 -ChinaM 最早的解决方案中就有相应的实践及成功应用,这次是优化升级,并增加了根据先进的 SocketStream 和 SocketString 来应对不同的IO读写。

连接池能够极大地提升服务器性能表现,所以在最常见的场景,连接数据库时,Resin,Tomcat等均提供了针对数据库的连接池。而 Session, Cache 或者其他网络服务的连接池,则需要自行手工提供。这也是 -Java 在某些地方性能优胜的关键之一。在 201807年的一次针对 -PHP 应用环境的优化分析中,由于一个改进数据库连接的修改,直接优化节省一台数据库服务器。这个数据库连接由于在开发初期被置于某个循环体内的Bug,每次运行时,都会初始化向数据库的连接,导致开销大增。

比较难的模块是Memcached Java Client (Memcached, -R/r2ST ). 这个模块在 -GWA2-PHP 中是跟随PHP源码提供的,编译进去即可。而在 -GWA2-Java 中,则需要手工实现。好在有前人探索,也不需要重新造轮子,我们经过对比,选择了 -GitHub 上的 gwhalin 的 Memcached Java Client . 由于需要融合到 -GWA2 中,而且也觉得可以在优化一些该版本,主要修改如下:
1)  expiry 参数由 Date 修改为 int ;
2) 摘除自带的 SocketIOPool,融合上文提到的 GWA2 实现的 Socket Pool;
3) 改进对传入连接主机服务的支持;
4) 改进 if(a==1) b=2; 等不规范的为 if(a==1){ b=2; } ;
5) 改进key的 sanitize操作,用 -Base62x 替代 UrlEncoder,Base62x 比 UrlEncoder提供了跟“干净、短小”的字符编码; 判断当key 长度大于 32时,启用 MD5 操作等等。
从根本上来说,Memcached也不算复杂,就是操作Socket读写,类似Java Mail等类库一样。

至此,-GWA2-Java 基本完善,一段时间针对Java版本的集中优化基本完成,可以考虑将其应用到具体生产环境了。她的各种性能表现及更高级的优化,需要在实践中不断加深、加强。

-GWA2 是”通用网络应用架构( General Web Application Architeture )”,基于 -GWA2 可以轻便构建各种网络应用程序,
包括复杂的在线购物商城、 旅游交易平台、社群或者社交网站和新闻资讯网站等,
也包括各种企事业单位网上门户,在线交互及服务作业系统等.
还可以包括为NativeApp做服务器端支持, 甚至是WebApp的全部.
-GWA2 是为数不多的支持跨开发语言的应用框架,目前支持 -Java, -PHP, -Perl, -Aspx and -Python .

-GWA2 is a “General Web Application Architecture” and based on -GWA2 developers can easily build a variety of network applications,
including complex online shopping malls, travel trading platforms, community or social networking sites and news information sites, etc.
Also the applications include various online portals of enterprises and institutions, online interaction and service operations systems.
Moreover it contains server-side support for NativeApp, or even all of the WebApp.
-GWA2 is one of the web frameworks which provide cross-language support for -Java, -PHP, -Perl, -Aspx and -Python at present.

-GWA2 is E.A.S.Y 
Easy Along, Swift Yield
轻松启动, 快速产出.

 

Posted in -GWA2, 服务器运维, 编程技术, 计算机技术 | Tagged , , , , , | Leave a comment

-Java forEach中 Lambda Expr中的 final变量要求

本文是关于 -Java Lambda Expression在forEach方法的应用讨论。对比其他编程语言的foreach 操作(文末附带7种主要编程语言的Loop HashMap by forEach的程序片段),Java 8引入的运用 Lambda Expression方式的 forEach操作方法是最接近语言所要表达的本意,且简洁、直接。
在持续优化 -GWA2 in -Java 过程中,由于 -GWA2 多层结构设计,层间数据传递很多依赖Map/HashMap完成,经常用到这个 forEach 并碰到一些问题(引入外部变量,有条件筛选及终止等),兹记录相关探索过程如下。

通常在 -Java 中遍历一个数据集合是常见的操作场景,比如遍历数组 (-R/G2ST ):

int[] numbers = 
             {1,2,3,4,5,6,7,8,9,10};
for (int item : numbers) {
    System.out.println("Count is: " + item);
}

再比如常规的借助 keySet遍历一个key-value结构的 Map / Hash, 哈希 (-R/k2SP ):

for (KeyType key : m.keySet()){
    System.out.println(key+", "+m.get(key));
}

-R/k2SP 列举了三种方法进行遍历key-value 的Map, 实际上根据 -R/92SS  页面上第二个回答所进行的测试,大概有十多种方法可以实现遍历一个 key-value 的Map. 这么多方法中,又以 forEach 的表达最为直接、高效,所以推荐使用 Map.forEach .

forEach 本质上是建造一个 Lambda Expression 并进行运算,其中 Map.forEach 等同的表达式也是针对  keySet的调用( -R/V2SQ )。

//- Map.forEach is equivalent to:
for (Map.Entry<K, V> entry : map.entrySet()) action.accept(entry.getKey(), entry.getValue());

//- an example
HashMap<String, Integer> hm = new HashMap<String, Integer>();
hm.forEach((key, val)->{
    System.out.println(key+”, “+val);
    });

由于 Lambda Expression 是一个 enclosing scope,它与代码区块外的沟通成为问题,外部变量无法在 Lambda 内部调用,内部变量也无法在外部访问到。在这近乎隔离的运行时环境里,还留了final变量可以穿行的缝隙,如果要实现将Lambda Expr与外部变量进行数据交换,就需要在代码区块外部定义final类型变量作为数据信息载体。常见的应用有如下两个场景.

  1. 将Map/HashMap的数据遍历并加工
    例子程序:
    HashMap<String, Integer> hm = new HashMap<String, Integer>();
    final HashMap<String, Integer> hm2 = new HashMap<String, Integer>();
    hm.forEach((key, val)->{
        System.out.println(key+”, “+val);
        hm2.put(key, val + 1);
        });

    借助 Lambda Expression 对 final变量的支持,可以容易地将遍历并加工后的数据中转取出做进一步的操作.
    final 变量由于无法再次出现在赋值语句的左边,也即无法对对象做再次赋值操作。但这不影响我们后续将 hm2的值进行遍历或者将其复制到另外一个非final的对象中去,如上例中的 hm.
    同样地,作为final的 hm2 无法整体被赋值,但可以对其本身进行操作,如上例中的,通过 hm2.put 将某个元素放入这个容器中。类似的还有,比如 StringBuffer 的操作。

    StringBuffer pageIdsb = new StringBuffer(“0”);
    pageList.forEach((k, v)->{
        HashMap tmphm = (HashMap)v;
        pageIdsb.append(“,”).append(tmphm.get(“id”));
        });

    public final class StringBuffer
    extends Object
    implements Serializable, CharSequence

    由 StringBuffer 类的定义(-R/V2SQ ),我们知道其是 final 类,于是在初始化后,可以在 Lambda Expr中通过 pageIdsb.append 的方式进行其值的操作与变化。

  2. 有条件过滤或推出、终止遍历
    在遍历Map/HashMap等对象集合时,有时候需要有条件的过滤或者终止,如果将外部约束条件带入?
    又如何定义内部自循环变量?
    一种可行的方式,依然是使用 final变量,然后基本变量类型,如果定义为final之后则不能被直接修改,无法满足循环体内计数的需求.
    于是就需要设计一个复合final类的变量,其成员一个负责约束条件,另外一个负责循环计数。
    HashMap<String, Integer> hm = new HashMap<String, Integer>();
    final HashMap<String, Integer> hm2 = new HashMap<String, Integer>(){{
        put(“iCount”, 0);
        put(“maxCount”, 4);
        }};
    hm.forEach((key, val)->{
        int iCount = Wht.parseInt(hm2.get(“iCount”));
        int maxCount = Wht.parseInt(hm2.get(“maxCount”));
        if(iCount < maxCount){
            System.out.println(key+”, “+val);
        }
        hm2.put(“iCount”, iCount + 1);
        });

    在上面的例子程序中,我们定义了循环体内计数变量 iCount 和 满足退出条件 maxCount 每次循环时取出并做对比,每次循环时, iCount++ 。
    上面例子程序中的 Wht.parseInt 是 -GWA2 的基础设施类,可以在 -GWA2@Github (-R/h2SO )下载到.
    上面例子程序中的hm2 的声明实例中,通过构造方法并以一个匿名类完成了两个 put操作。关于匿名类 Anonymous Class,参考 -Java 文档(-R/i2SP ), 在 -GWA2 in -Java 里也有不少应用。
     

-Java 中引入的 forEach 操作,尽管是以 Lambda Expression为载体的一个 Consumer / BiConsumer对象,运行在一个 enclosing scope,依靠可以外部 final 变量这个渠道,可以提供媲美其他编程语言一样的 foreach 效果,对增加程序可读性、可维护性有一定的帮助,已有的评测 forEach也表现出不错的性能,值得更多地应用。

 

-GWA2 是”通用网络应用架构( General Web Application Architeture )”,基于 -GWA2 可以轻便构建各种网络应用程序,
包括复杂的在线购物商城、 旅游交易平台、社群或者社交网站和新闻资讯网站等,
也包括各种企事业单位网上门户,在线交互及服务作业系统等.
还可以包括为NativeApp做服务器端支持, 甚至是WebApp的全部.
-GWA2 是为数不多的支持跨开发语言的应用框架,目前支持 -Java, -PHP, -Perl, -Aspx and -Python .

-GWA2 is a “General Web Application Architecture” and based on -GWA2 developers can easily build a variety of network applications,
including complex online shopping malls, travel trading platforms, community or social networking sites and news information sites, etc.
Also the applications include various online portals of enterprises and institutions, online interaction and service operations systems.
Moreover it contains server-side support for NativeApp, or even all of the WebApp.
-GWA2 is one of the web frameworks which provide cross-language support for -Java, -PHP, -Perl, -Aspx and -Python at present.

-GWA2 is E.A.S.Y 
Easy Along, Swift Yield
轻松启动, 快速产出.


(1) Loop HashMap in PHP ****

$hm = array(“a”=>1, “b”=>2, “c”=>3);
foreach($hm as $key=>$val){
    print “key:$key , val:$val\n”;
}

(2) Loop HashMap in Perl ***

my %hm = (“a”=>1, “b”=>2, “c”=>3);
foreach my $key (keys %hm){
    my $val = $hm{$key};
    print “key:$key , val:$val\n”;
}

(3) Loop HashMap in Swift *****

let hm = [“a”:1, “b”:2, “c”:3];
for (key, val) in hm {
    print(“key:\(key) , val:\(val)\n”);
}

(4) Loop HashMap in Python ***

hm = {“a”:1, “b”:2, “c”:3};
for key in hm:
    print(“key:{} , val:{}”.format(key, hm[key]));

(5) Loop HashMap in C++ *

std::map<std::string, std::int> hm {
    {“a”, 1},
    {“b”, 1},
    {“c”, 3}
};
for(const auto& key : hm){
    std::cout << “key:” << key.first
        << ” , val:” << key.second
        << “\n”;
}

(6) Loop HashMap in JavaScript ***

var hm = {“a”:1, “b”:2, “c”:3};
for (var key in hm){
    console.log(“key:”+key+” , val:”+hm[key]);
};

(7) Loop HashMap in Java ***

HashMap<String, Integer> hm = new HashMap<String, Integer>(){{
    put(“a”, 1″);
    put(“b”, 2);
    put(“c”, 3);
}};
hm.forEach((key, val)->{
    System.out.println(key+”, “+val);
    });

 

Posted in -GWA2, 编程技术, 计算机技术 | Tagged , , , , , | Leave a comment

参观“纪念马克思诞辰200周年主题展览”有感, Karl max, 200 Ani Exhi

2018年6月28日下午,在北京位于天安门广场东侧的国家博物馆参观了正在展出的“真理的力量——纪念马克思诞辰200周年主题展览”。

国家博物馆门口人潮涌动,工农商学兵各界,东西南北中各地的人群络绎不绝前来参观学习。主题展览位于国家博物馆的南区1、2和3号馆。入口处即是巨幅卡尔马克思的幕墙,然后映入眼帘的是卡尔马克思和弗恩格斯的合影铜像。各厅内展出了大量图像、史料、实物和相关人物,真实再现了卡尔马克思波澜壮阔的精彩人生,全面生动展示了马克思的生平、革命实践、理论贡献和精神境界,展现了马克思主义在中国传播运用和丰富发展的光辉历程。

或许是由于时序的关系,在领略其出生、成长、成才、奋斗、贡献等各个精彩的人生篇章后,当我驻足在卡尔马克思辞世的那副巨型油画前时,思绪感慨万千,久久未曾移开。

这副油画作者是当代著名艺术家艾中信先生。为纪念马克思诞辰200周年,艾中信创作了这幅油画《三月十四日》(1883年3月14日),再现了马克思在躺椅中溘然长逝的凝固瞬间。艾中信师从和追随徐悲鸿、吴作人等第一代油画大师,是我国的杰出画家、艺术家。

触动我的情感和思绪并引发我共鸣和思考的是这副油画的几个细节:老人、沙发、毛毯和掉落在地上的书籍。这无疑给人一种安详的感觉,作为全人类最为著名的无神论领袖之一,卡尔马克思辞世的瞬间却生动而自然地呈现了无疾而终天人合一至善至美的景象。

根据弗恩格斯后来在《在马克思墓前的讲话》中的细节描述,“3月14日下午两点三刻,当代最伟大的思想家停止思想了。让他一个人留在房里还不到两分钟,当我们进去的时候,便发现他在安乐椅上安静地睡着了——但已经永远地睡着了。”

卡尔马克思及其创建的共产主义是坚定的无神论者。如果不是因为这个,他的离世确切地符合佛教中的得道高僧的“圆寂”,这通常是一个人的大福报,是灵魂的得道升仙,成就不死的永恒。也许正是因为他的奋斗的一生、奉献的一世而得到上帝的垂怜或者眷顾,能够做到自然而然地油尽灯枯、溘然长逝,仿佛睡着了一般,永远地。

作为无神论者,显然不能这样推演。然而从唯物主义历史观出发,似乎有两个结论可以推测出来。一是,卡尔马克思对自身的内省认识,对个体生命的整体观念;二是弗恩格斯及其他卡尔马克思的亲密团队对生命的认识,对人生的思考。

与我们现在经常在新闻传播中听到、读到或者看到的领导人逝世,离得最近的词语就是“因病医治无效,于某某医院离世”。卡尔马克思的辞世时,为何是在家里,躺在沙发上,盖着毛毯,捧着书本? 这是多么享受的一幕,多么安详的画面,仿佛我们每个人都曾经历或者经常体验的那样——某个慵懒的午后,躺在自家的沙发上,看了一会书,然后就倦意袭来,昏昏睡去……

也许可以推测,卡尔马克思本人已经对生死有某种超然脱然的认识,所以当生命的终点或者尽头来临时,他选择的是待在自己熟悉的、温暖的家里,以自己舒服的姿势、读着自己喜欢的书,以此沉沉永远地睡去。

正是基于这一对生命的超脱认识,他选择了以家作为终点,而不是“于某某医院离世”。

其二,弗恩格斯及其他亲密团队成员,充分尊重卡尔马克思的选择,没有强行在卡尔马克思有生命危险时进行重度医疗。可以设想,以当时卡尔马克思的社会声望及地位,如果他需要医疗,可以召来全世界当时最好的医生团队,进行各种极其高精尖的治疗。

显然,卡尔马克思没有要求,甚至可以说是拒绝了进一步的治疗,信奉进化论的他懂得生死更替的大自然的规律。同时,他身边的人,也理解到这一点,并给予充分的尊重。我们无法还原每一个细节,甚至还没有充分的史料来表述与支持这些推测的想法,只能说这些或更贴近已经看到的这副油画。又或许这副油画是艺术的加工,当其时情景并不是那么和谐,这些都不重要了。

如果可以再多一些佐证的话,可以考虑近几年前离世的美国苹果公司的创始人之一史提夫乔布斯先生,当时他被诊断出某种疾病,但他淡然的接受并放弃过度医疗,自然地离去。史提夫乔布斯当时位列全球富人榜前列,以他的社会声望与财富,以近两百年后的不断进步的医学技术,他本应可以续命好多年,然而他却选择了放弃。

个体生命或许是相同的,思想的高度应是差异巨大的,尤其是在庸俗、平凡与卓越、领袖之间。这种巨大的差异不单体现在辉煌的事业上,亦表征在挥别这个美好世界的一刻。

Posted in 社会生活 | Tagged , , , , | Leave a comment

SQL查询优化: 既有Unique Index为何还要另加Index?

在使用 -GWA2 进行WebApp开发时,我们创建基于MySQL的相关数据表时,都会有意识地在数据表的关键字段上增加索引,以期待查询时能够较快地返回结果集。

在我们现有的生产线上的数据观测中,同样一张数据表,通常当数据达到10M+时,如果某个待检索字段(用在Where里作为查询字段)没有使用索引,一次查询大约需要耗时50s+,如果增加了相应的索引,则单次查询大约耗时5s左右,性能提升10倍以上。

所以,理论联系实际,我们都应该在相关待检索的字段上增加索引,这次要提及和澄清的是增加Unique Index还是Index? 只增加Unique Index,还是Index即可?或者两种Index都需要? 在检索方面,Unique Index保持了数据的唯一性,实际兼有Index的功能,在被检索时提供同样的优化性能。

情况稍微复杂一些的例子是这样,当一个Unique Index增加到多个字段的组合上时,其Index的作用并不能想当然地将Index效果追加到每一个组合中的字段上。如下是 -MySQL 官方文档对于组合字段的Unique Index的描述。

-R/u2SN  ) “If the table has a multiple-column index, any leftmost prefix of the index can be used by the optimizer to look up rows. For example, if you have a three-column index on (col1, col2, col3), you have indexed search capabilities on (col1)(col1, col2), and (col1, col2, col3).
MySQL cannot use the index to perform lookups if the columns do not form a leftmost prefix of the index. ”

用简略地话来说,Unique Index的Index作用:1)当只有一个字段时,其Index作用也同样地施加到该字段上;2)当为多个字段的组合时,其Index的作用,只施加到组合的第一个字段上。

所谓差之毫厘,谬之千里。当待检索的字段是某个Unique Index的组合字段之一,且不是第一个时,被用做Where的查询条件,查询性能将急剧下降,每次皆是全表扫描,逐行对比。

这种性能隐患,在开发初期并不容易发现,只有当数据量级增长到10M+时,查询耗时才会逐步显现出来。

 

gwa2-logo-201606.v2

-GWA2 是”通用网络应用架构( General Web Application Architeture )”,基于 -GWA2 可以轻便构建各种网络应用程序, 
包括复杂的在线购物商城、 旅游交易平台、社群或者社交网站和新闻资讯网站等, 
也包括各种企事业单位网上门户,在线交互及服务作业系统等. 
还可以包括为NativeApp做服务器端支持, 甚至是WebApp的全部.
-GWA2 是为数不多的支持跨开发语言的应用框架,目前支持 -Java, -PHP, -Perl, -Aspx and -Python .
-GWA2 is a “General Web Application Architecture”, and based on -GWA2 developers can easily build a variety of network applications,
Including complex online shopping malls, travel trading platforms, community or social networking sites and news information sites, etc.
Also the applications include various enterprises and institutions online portals, online interaction and service operations systems.
And it also includes server-side support for NativeApp, or even all of the WebApp.
-GWA2 is one of the web frameworks which provide cross-language support for -Java, -PHP, -Perl, -Aspx and -Python at present.

-GWA2 is E.A.S.Y 
Easy Along, Swift Yield
轻松启动, 快速产出. 

Posted in -GWA2, 服务器运维, 计算机技术 | Tagged , , , , , | Leave a comment

Apache-Tomcat: 虚拟主机VirtualHosts

接续此前的 “嘗試 Apache + Apache Tomcat (簡稱 Tomcat)融合” , -R/H2SL ,和 第二篇,“apache tomcat: mod_jk missing uri map”, -R/n2SK ,  这次叙述一下在 Apache 和 Tomcat 下融合搭配虚拟主机 Virtual Hosts的事, 顺带回应前述,为何技术选型是 Apache + Tomcat ,而不是 Nginx + Resin ?

1. 为何选用“Apache + Tomcat”?
单一就性能而言, Ningx 在服务静态页面胜过 Apache , Resin 在服务动态页面上胜过 Tomcat,那么强强联手,Ningx + Resin 的搭配应该会胜过 Apache + Resin. 至少理论上是这样,然而理性的技术选型中,技术性能是一方面,也会考虑经济性,这也是一些互联网公司曾经有过的关于去 IOE (IBM, ORACLE和EMC,分别代表大规模计算, 数据处理和存储)的浪潮的一个依据。

在从计算机&IT业早期,我所接触的就是 Resin 作为Java的Application Server,多年过去之后,当我再次思考这个问题的时候,我的认识发生了改变,这次我选择了 Tomcat,而不是 Resin,经济是一方面,其开源和社区属性应该是另外一面,相应地性能优势已经不是那么明显。
由于硬件性能几十年来一直以摩尔定律(单位面积上的集成电路晶体管数量每18-24个月翻一倍,性能提升而价格-成本下降)的速度在发展,如果纯粹的开源软件无需考虑这些,而如果是以一定的成本购买来的性能提升,是否该软件带来的性能提升速度能够跟得上硬件摩尔定律的发展?
设若以1000$的硬件运行A软件(1000$)获得性能为1000个并发,B软件(0$)为500个并发;一两年后,1000$的硬件自然地能够运行B软件(0$)获得1000个并发。此时如果A软件(1000$)相应地预期应该能够获得2000个并发,如果不能,我们认为这笔开支是不理性的。实际运营需求,可能对性能的要求并没有快过硬件的摩尔定律式的发展。这一问题回归,就是花成本在购置软件上的获得性能提升是否值得或者经济,尤其是在分布式,云计算大行其道的情况下? 可能的场景是,如果现在花1000$购置某闭源软件带来+500个并发性能,而1-2年后,同样的硬件成本可以0$的获得+500个并发性能,此时额外的1000$到底该不该花?

决策时的另一个考虑是,无论是 Ningx 还是 Resin 其开源版本总是给人一种“阉割版”的印象,要想要更高级的功能,都需要花钱才能实现,这多少令人不爽。开源和闭源都可能打造较好的软件,但免费推出“阉割版”,然后根据高级功能收费,这种做法,在我看来是不合适的,只好对 Ningx 和 Resin 说再见,尽管他们在性能上有优秀的表现,我更相信对 Apache 和 Tomcat 的站队投资,能促使其不断成长、优化和改进,形成良性循环。

多年来,随着 -gMIS-GWA2 的成长、成熟,从软件开发者的角度,我越来越能理解到,一款所谓好的软件,就是有人不断地使用,不断地应对新的scenarios,不断地修正bugs,从而不断地健壮、丰富和强大。Apache, Tomcat 应该也是这样,软件发展注定会是马太效应,强者更强,弱者更弱,某个细分领域,某个独特场景下,最终可能只会存在1-2款软件。

几年前,在 -人民网 进行某个互联网项目前期调研时,其中对互联网应用的发展趋势,有个小结是,互联网因的越来越具有服务方式的排他性和内容格式的统一性——大白话就是某种应用(服务)只存在其本身就够了,天下无二;在其上,各种内容兼容并包,既有文字、图片、动画,也有音频和视频,基于这些小众内容分类创新也基本不用想了。

这是今次我这么选择 Apache + Tomcat 的原因。接下来继续回复关于在 Apache 和 Tomcat 下设置虚拟主机VirtualHost的细节。

2. Tomcat 的虚拟主机配置
虚拟主机的配置,在以前的blog里提到过,”apache, resin, ssl对虚拟主机的支持”,  -R/12SY , 这次就不再重复在 Apache 里设置虚拟主机的情况,转而重点在 Tomcat 对虚拟主机的支持及设置情况.

Tomcat对虚拟主机的支持,官方文档和网上教程也有一些,下面是一个小结。

在 Tomcat 的 conf/server.xml 中,在
<Server>
    –> <Service>
        –> <Engine>
            –> <Host> 
中并列地新增一个 <Host> 标记即可。例如,默认的 <Host> 形式为

<Host name=”localhost” autoDeploy=”true” appBase=”webapps” …

在此之后,并列的新增一个针对虚拟主机的 <Host>设置,一般情况的形式为

<Host name=”srvXXX.ufqi.com” autoDeploy=”true” appBase=”/www/webroot/srvXXX”>
    <Context path=”” docBase=”/www/webroot/srvXXX”></Context>
    <!– something else –>
</Host>

其中 “<Context>” 需求强调的是,如果不通过其设置 docBase, 按 Tomcat的默认,则请求 http://srvXXX.ufqi.com/abc.jsp 时会将解析指向默认 <Host> 的默认 docBase ,通常是 默认 <Host> 的 appBase , 也即 webapps/ROOT .
通过 <Context> 设置新的 docBase之后,这可以解决这一解析寻址路径,再次请求 http://srvXXX.ufqi.com/abc.jsp 路径时,会按图索骥地在 /www/webroot/srvXXX 目录下进行寻找,从而能够获得预期的请求资源。

进一步地,由于 Tomcat 的部署默认对象单位是 application,所以即便不指定 docBase ,在 /www/webroot/srcXXX 子目录(application)下的相应资源是能够被准确定位的。上述情况,如果不指定 docBase , 通过访问路径 http://srvXXX.ufqi.com/pathX/abc.jsp 则是能够获得相应地资源的。

3. 对SSL 的支持
在设置相应的虚拟主机时,如果在 Apache 上启用了 SSL支持,可能一般情况下都会启用,而且以后会成为默认选项。
按 “apache, resin, ssl对虚拟主机的支持”,  -R/12SY  的描述需要在 Apache 的 conf/extra/http-ssl.conf 中做相应的设置,才能使得 Apache + Tomcat 对 SSL 的预期的支持。

Posted in 服务器运维, 编程技术, 计算机技术 | Tagged , , , | Leave a comment

-gMIS持续优化更新, +InSiteSearch站内搜索

-gMIS 部署和应用的场景越来越多,最近在考虑为所有gMIS承载管理的数据库系统增加一个站内搜索功能, +InSiteSearch 。前因是在 2017年11月份的更新中,我们设想“层级目录导航是“传统”的,属于 Yahoo 时代的产物,未来的导航应该是 Google 式的智能导航。
未来拟开发一个 gMIS 域内全文搜索引擎,这样用户就无需使用或者记录层级目录。” (-R/p2SM)。 约半年后,我们实现了这方面的一个探索。

主要动机可以类比为Yahoo时代的目录搜索与Google时代的全文检索,当 -gMIS 所管理的对象超过一定数量级后,管理人员面临的问题就自然而然地迷失在多层复杂的目录式的导航中,如何有效地定位到目标功能模块成为迫切需要解决的问题。(在Google出现之前,用户想找某个主题/关键词的内容,需要去Yahoo的站点目录里去逐层逐级的查找相应的站点,Yahoo提供的网站目录满足了当时的需求)

站内搜索也被称之为局域网搜索Intranet search /Onsite search有别于互联网搜索Internet search. 其目的是搜索网址内部通常不公开的,格式化或者非格式化的内容。-gMIS 针对此项的规划远景是集成一个智能助理。

  1. 站内搜索InSiteSearch主要思路

    格式化数据的搜索是一个老课题。相对于非格式化数据,比如常见的网页数据,格式化数据有得天独厚的优势,我们能确切的预先知道,数据的格式、类型与规模。
    在获得这些之后又该怎样实现站内搜索呢?
    大致有两个思路,列如下。

    一是将待搜索的数据,读取到某个index service上实现对数据的indexing,当有某种关键词进行搜索时,按indexing的数据进行相应数据的返回。
    这种方式,是事先、同步地将所有格式化数据同步到indexing 服务,并实现相应的增删改的操作同步。
    也即,在格式化数据库/表之外,需要独立的建立一套应对全文搜索的数据结构存储系统,通常为 keyword–>pagelist 结构,也即某个待搜索关键词会对应一个包含该关键词的文档列表,其中列表的排序规则为某个权重值,其主要指标是为了表名当前关键词与当前文档的依存关系。
    若无意外,该indexing的数据存储结果将同等尺寸于原始格式化数据。
    另外一种思路,也即,是否可以为待搜索的数据提供某种roadmap(路书、地图),当有某种关键词进行搜索时,知道在什么地方以什么方式进行搜索。而实际数据的增删改人保留在原数据库/表中,当下的站内搜索InSiteSearch只是提供某种ShortCut服务,该服务能够实现以较为经济的、智能的方式,帮助调用者以较合理地方式返回预期的搜索内容。
    可以设想,在这种思路下,系统不需要创建一套indexing服务,也不需要额外地复制全部格式化数据副本作为待检索的对象。
    也即,当触发在全域进行某个关键词进行搜索时,InSiteSearch知道该关键词最可能出现在某些数据表的数据字段项上,而不太可能出现在其他字段项或者其他数据表相应的字段项上。
    这种路书(地图)导引式的搜索辅助设施,将极大地提升搜索范围和搜索精度,在格式化数据的搜索上,很好的契合了搜索需求的应用场景。

    两相比较,在 -gMIS 中,我们选用了,基于路书的指引式站内搜索方式。

  2. 站内搜索InSiteSearch的实现方式

    依据前述讨论,我们在 -gMIS 中实现了基于导引式地站内搜索实现。其主要操作内容如下。
    A. 创建 insitesearch 表
    用于存储当有基于某个关键词进行搜索时,所依赖的数据表路径。
    insitesearch表的生成主要依赖 /act/insitesearchsort.php 程序。
    该程序读取当前数据库连接下的所有数据表,并分析每个数据表的每个字段,如果发现当前字段数据可被检索字符串类型,通常为char(4-255),则将该数据库、数据表的数据字段记为待检索字段。
    以此循环所有数据表的所有数据字段,生成待检索数据字段列表。
    当有待搜索关键词递交到系统程序时, /extra/insitesearch.php , 站内搜索引擎程序按图索骥地逐个待搜索数据库、数据表、数据字段的进行检索。
    根据当前页的size设置,搜索到N个结果时,自动返回给调用者,以此形成翻页功能。

    B. 增加站内搜索入口
    对应地,我们在 进入系统主页和list view识图页面,在顶部导航栏增加了对 站内搜索 的接入功能,若用户需要进行站全域站内搜索,只需将待搜索关键词递交给搜索模块即可实现该功能。

    C. 动态更新搜索源
    辅助地,我们在 

    Π 首页  桌面 & 系统配置 → 搜索源配置 | 搜索源配置 

    增加了对 搜索源的配置与管理,在该模块可以实现对待搜索列表的手工更新与配置。当有新的数据模块被手工添加到当前数据库时,可以通过 “更新搜索源列表” 来实现对待搜索资源列表的更新与维护。

    D. 精细化操作的黑白名单设置
    同样地,我们在

    Π 首页  桌面 & 系统配置 → 搜索源黑白名单 | 搜索源黑白名单

    额外地增加了对待搜索源的黑白名单设置,以满足特性的运营需求,比如当某个数据库的数据表的数据字段被程序规则判定为“黑名单”时,可以在此将相应的条件设置为允许“白名单”;同样地,当某个数据库的数据表的字段被程序判断为“白名单”而通过系统检测,可以在此将相应条件设置为“黑名单”,以阻止其进入待搜索队列。

  3. UI批量更新与优化
    单条记录更新模块,增加了行间距,当字段之间跟容易识别;
    字段名称加粗显示,区别与字段值、字段备注等信息;
    列表显示时,增加了 break-all 属性,数据表默认不再撑破窗口,在纵向滚动和横向滚动中选择其一,仍不能排除某些情况下,纵横项同时滚动的可能;
    更新GTAjax,修正增加对 Array.sort 的支持;
    增加对List View下的活跃记录的所有字段值加粗显示,响应鼠标事件;
    增加对JavaScript更多的异步调用,页面提速更快;
    bugfix for getSelectOption;
    +checkSQLKeyword
    +allow multiple order fields

  4. 增删改查搜算
    截至 InSiteSearch 功能发布以后, -gMIS 的核心功能已经由 增删改查 升级为 增删改查搜算 (Create, Retrieve, Update, Delete, +Search, +Statistics)。
    其中”搜” 指的是增加了站内搜索功能,而算 则是指 -gMIS 中的数据透视功能,可以轻易地实现对目标数据表的各种维度的数据统计计算功能。
    可以预见 -gMIS 将从普通的通用信息管理功能逐渐升级改进,增加更多的商业智能功能模块,为业务运营支撑提供更多的信息数据与决策支持。

  5. GitHub 被 Microsoft 收购
    会影响到 -gMIS 在 -Github 的托管与开源吗?

 

gmis-logo-201606

-gMIS 是一种基于 -GWA2 的通用管理信息系统(Management Information System)软件,具有可配置的输入和输出接口。
可以在其上构建各种管理应用软件系统,如
内容管理系统(CMS),客户资源管理(CRM), 企业资源计划管理(ERP),
办公自动化系统(OA)等, 以及各种行业应用管理系统软件,如
人力资源管理系统(HR),学生管理,档案管理,旅游管理,图书管理,
商品管理及业务运营支撑系统等等。
实现零代码开发、快速搭建各种管理信息系统(MIS).

-gMIS is a -GWA2 based Management Information System (MIS) software with configurable input and output interfaces.
Various management application software systems can be built on it, such as
Content Management System (CMS), Customer Resource Management (CRM), Enterprise Resource Planning Management (ERP),
Office automation systems (OA), as well as different industry application management system softwares, such as
Human Resource Management System (HR), Student Management, Archive Management, Tourism Management, Book Management,
Commodity management and business operations support systems, etc.
With zero code development, -gMIS can build a set of management information systems (MIS) software in a minute.

Lower Costs, Better Productivity.
降低成本, 提高效率.

Posted in -gMIS, 服务器运维, 编程技术, 计算机技术 | Tagged , , , | 2 Comments

商业组织忠诚与职业道德

最近在读《Investments》(投资学, -R/G2SS )第十版,在其中“Excerpts from CFA Institute Standards of Professional Conduct”章节提到CFA对客户第一条要“Loyalty(忠诚)”,对雇主的要求中第一条也是要“Loyalty(忠诚)”。尤其是对客户的忠诚里,要求必须把客户利益的优先级放在自己的利益前面。这听起来与某些党派的对组织忠诚、先人后己的要求很相似,如果是这样,是不是觉得“党性”要求不那么苛刻?

顺着这个忠诚的话题,我捡了几个反例叙述,商业不忠诚及职业不道德的例子示以警示。

  1. 中介员工自己跳单
    做中介的最怕跳单,大意是在居间服务市场,买家和买家通过中介取得联系后自行交易,绕过了中介一方。这在中介市场是严重不允许的,中介居间费用也是中介赖以生存的源泉。所以如果买家、卖家任一方试图绕过中介进行跳单,必遭中介追诉。
    据闻眼下,有某中介组织员工可以自己设定跳单并私吞中介服务费用。当某员工履行职责引荐买家、卖家之后,撮合达成交易收取居间费用,但上报给中介组织的内容却是交易未达成,并以服务费打折、优惠为条件劝诱买、卖双方与自己保持一致的说辞。然后再通过某种方式取消此次买卖标的物的邀约。一切像没发生过一样。
    买家、卖家、中介员工三方均受益,而唯一受损的一方是中介组织。

    类似例子,似乎并不止于中介服务,其他组织中应该也存在,员工利用其组织平台谋取私利,并对组织谎报内容。

    以损害组织利益谋取私利实在罪有应得,却屡禁不绝,大致是人的本性使然,组织如何在一定程度上使之不能、不敢、不想这样?

    也据闻眼下有在不损害组织利益的情况下谋取私利,比如统计数据修改。

  2. 程序“魔法值”修改账单
    统计数据是组织进行商务活动所依赖的根本。实施统计数据修改,一般是内外勾结在一起进行。员工A与外部合作伙伴甲达成利益输送,员工A在其数据底层,通过修改日志、统计数据输出,将原本属于合作伙伴乙的收益算入到合作伙伴甲账上。进而,合作伙伴甲收到额外的空账后再分赃给员工A。
    表面上看,似乎天衣无缝一般。组织总账平衡,不多不少,员工A和合作伙伴甲都受益,唯一受损的是合作伙伴乙,但其并不知情。

    这一犯罪的实施,需要修改生产系统或者统计程序的源代码,而且要通过某种“魔法值”(未经定义的常量,语见《码出高效——阿里巴巴Java开发手册》,-R/92SP )来进行,也即所说的“后门”的一种。

    计算机程序代码通用规范中明确要求不能使用这种“魔法值”,而一些不遵守这样约定的软件通常以“高效”等要求直接在代码中使用这些魔法值,通过使用这样的“魔法值”来满足日益复杂多变的运营需求。久而久之陷入混乱的恶性循环,也为通过这样的“魔法值”修改来实施利益输送提供了温床。

    大型的软件及互联网企业,严格要求这一项,既有技术层面的代码规范、可读性要求,还有言下之意不允许额外的特例出现在代码层,从根本上杜绝了通过“魔法值”来实施犯罪。

    如果某些作业系统程序复杂、多变,且充满了“魔法值”,则这样的犯罪实施起来将得心应手,且死无对证。除了员工A和合作伙伴甲,无人知晓,而利益受损方合作伙伴乙并无感知,也不会发起追诉。

本质上,个体是趋利的,理性的思维又要求个体要遵守商业文明。个体选择扭曲价值观的不忠诚、犯罪,一定是群体的体制机制存在一定问题。列以上反例,大致也能从侧面显示商业环境的恶劣、人性的扭曲和制度的崩溃。

法国经济学家Thomas Piketty在其著作《Capital in the Twenty-First Century 》(21世纪资本)(-R/M2SM )中表示,社会财富正由拥有资产(土地、工厂、设备)等的“地主”向拥有知识与创新的“精英”转移,职业经理人将在财富分配中扮演越来越重要的角色,其对组织的忠诚度似乎也显得格外重要。

这种白手起家或靠发明创造而快速巨额致富成为可能的社会,被现任英国首相Theresa May在其演讲中称之为“MeritCracy”(-R/F2SO ),这似乎是对经济学家的发现的印证。 

经理人或员工是人,人本性是自私的,如果一个组织不能抑私扬善,职务犯罪则防不胜防,组织最终将溃于一个个自私的蚁穴。就像一个社会,如果不能弘扬正义、彰显公平,各种犯罪则愈演愈烈,社会最终将泯灭于一件件自私的犯罪下。

Posted in 社会生活 | Tagged , , , , | Leave a comment

[转]母亲的舍得

【编按】微信朋友圈传的文章,题目是自拟的,有人说可比语文课的《父亲的背影》,微言大义,是为推荐。

父亲去世10年后,在我的“软硬兼施”下,母亲终于同意来郑州跟着我——她最小的女儿一起生活。这一年,母亲70岁,我40岁。70岁的母亲瘦瘦的,原本只有一米五的身高,被岁月又缩减了几厘米,看起来更加瘦小,面容却仍然光洁,不见太多沧桑的痕迹,头发亦未全白,些许黑发倔强地生长着。 

我们借了一辆车回去接她,她早把居住了几十年的老屋收拾妥当,整理好了自己的行李。那些行李中有两袋面,是她用家里的麦子专门为我们磨的,这种面有麦香。但那天,那两袋面我决定不带了,因为车的后备箱太小,我们要带的东西太多。母亲却坚持把面带着,一定要带,她说。 

她这样说的时候,我忽然愣了一下,看着她,便想明白了什么,示意先生把面搬到里屋,我伸手在外面试探着去摸。果然,在底部,软软的面里有一小团硬硬的东西。如果我没猜错,里面是母亲要给我们的钱。 

把钱放在粮食里,是母亲很多年的秘密。十几年前,我刚刚结婚,在郑州租了很小的房子住,正是生活最拮据的时候。那时,我最想要的不是房子,不是一份更有前途的工作,只是一个像样的衣柜。就是那年冬天,母亲托人捎来半袋小米。后来先生将小米倒入米桶时,发现里面藏着500块钱,还有一张小字条,是父亲的笔迹:给梅买个衣柜。出嫁时,母亲给我的嫁妆中已有买衣柜的钱。后来她知道我将这笔钱挪做他用,便又补了过来。那天晚上,我拿着10元一张厚厚的一沓钱,哭了。那些年,母亲就是一次次把她节省下来的钱放在粮食里,让人带给我,带给大姐二姐,在我们都出嫁多年后,仍贴补着我们的生活。但那些钱,她是如何从那几亩田里攒出来的,我们都不得而知。这一次,即使她随我们同行,也还是将钱放到了面袋里,在她看来,那是最安全的。

面被带回来后,我把钱取出来交还母亲,母亲说,这是我给童童买车用的。童童是她的外孙,这段时间他一直想要辆赛车,因为贵,我没有给他买,上次回老家,他许是说给母亲听了,母亲便记下这件事。2000块,是她几亩地里一年的收成吧,我们都不舍得,但她舍得。记忆中,母亲一直是个舍得的人,对我们,对亲戚,对左邻右舍,爱舍得付出, 东西舍得给,钱舍得借,力气也舍得花。有时不知道她一个瘦小的农村妇人,为什么会这样舍得。母亲住下来,每天清晨,她早早起来做饭,小米粥、小包子、鸡蛋饼……变着花样儿。中午下班我们再也不用急赶着去买菜,所有家务母亲全部包揽。阳台上还新添了两盆绿莹莹的蒜苗,有了母亲的家,多了种说不出的安逸。 

母亲带来的两袋面,一袋倒入桶里,另外一袋被先生放到了阳台上。过了几天,我却发现阳台地板上的那袋面被移到了高处的平台上晾晒。先生是个粗心的人,应该不会是他放的,我疑惑地问母亲,她说,啊,我放上去的,晒晒,别坏了。我一听就跟她急了,那平台, 一米多高 ,那袋面,六七十斤,身高不足 一米五,体重不足90斤的母亲,竟然自己把它搬了上去。我冲她大喊,你怎么弄上去的?那么沉,闪着腰怎么办?砸着你怎么办?出点儿什么事怎么办……一连串地凶她。她却只是笑,围着围裙站在那里,等我发完脾气,小声说,这不没事吗?有事就晚了!我还是后怕,但更多的是心疼。直到母亲向我保证,以后不再干任何重活,我才慢慢消了气。 

母亲来后不久,有天对先生说,星期天你喊你那些同学回家来吃饭吧,我都来了大半个月了,没见他们来过呢。先生是在郑州读的大学,本市同学的确很多,关系也都不错,起初还会在各家之间串门,但现在,大家都已习惯了在饭店里聚会。城市生活就是这样繁华而淡漠,不是非常亲近的,一般不会在家里待客了。我便替先生解释,妈,他们经常在外面聚呢。母亲摇头,外面哪儿有家里好,外面饭菜贵不说,也不卫生。再说了,哪儿能不来家呢?来家才显得亲。然后,母亲态度坚决地让先生在周末把同学们带回家来聚一聚。我们拗不过她,答应了。 

先生分别给同学中几个关系最亲近的老乡打了电话,邀请他们周末来我们家。周末一整天,母亲都在厨房忙碌。下午,先生的同学陆续过来了,象征性地提了些礼品。我将母亲做好的饭菜一一端出,那几个事业有成、几乎天天在饭店应酬的男人,立刻被几盘小菜和几样面食小点吸引过去。其中一个忍不住伸手捏起一个菜饺,喃喃说,小时候最爱吃母亲做的菜饺,很多年没吃过了。母亲便把整盘菜饺端到他面前,说,喜欢就多吃,以后常来家里吃,我给你们做。那个男人点着头,眼圈忽然就红了,他的母亲已经去世多年,他也已经很久没回过家乡了。 

那天晚上,大家酒喝得少,饭却吃得足,话也说得多。那话的内容,也不是平日在饭店里说的生意场或单位里、社会上的事。很少提及的家事,被慢慢聊起来,说到家乡,说到父母……竟是久违的亲近。那以后,家里空前热闹起来。母亲说,这样才好,人活在世上,总要相互亲近的。 

母亲来后的第三个月,一个周末的下午,有人敲门,是住在对面的女人,端着一盆洗干净的大樱桃。女人有点儿不好意思地说,送给大娘尝尝。我诧异不已,当初搬过来时,因为装修走线的问题,我们和她家闹了点儿矛盾。原本就不熟络,这样一来,关系更冷了下来,住了3年多,没有任何往来。连门前的楼道,都是各扫各的那一小块儿地方。她冷不丁送来刚刚上市的新鲜樱桃,我因摸不着头脑,一时竟不知该说什么好。她的脸就那样红着,有点儿语无伦次,大娘做的点心,孩子可爱吃呢……我才恍然明白过来,是母亲。母亲并不知道我们有点儿过节儿,其实即使知道了,她还是会那么做,在母亲看来,”远亲不如近邻”是句最有道理的话。所以她先敲了人家的门,给人家送小点心,送自己包的粽子,还送自己种的新鲜小蒜苗……诚恳地帮我们打开了邻居家的门。后来,我和那女人成了朋友,她的孩子也经常来我们家,奶奶长奶奶短地跟在母亲身后,亲好得犹如一家人。 

邻居们,不仅仅是对门,前后左右,同一个社区住着的许多人,母亲都照应着。她常在社区的花园和先生同事的父母聊天,帮他们照顾孙子。不仅如此,还有物质上的往来,母亲常常会自制一些风味小点,热情地送给街坊四邻,这也是母亲在农村生活时养成的习惯。小点心虽然并不贵重,却因有着外面买不到的醇香味道,充满了浓浓的人情味。 

有一次,得知先生一个同事的孩子患了白血病,母亲要我们送些钱过去。因为是来往并不亲密的同事,我们只想象征性地表示一下,母亲却坚决不答应,说,人这辈子,谁都可能会碰到难事,你舍得帮人家,等你有事了,人家才会舍得帮你。孩子生病对人家是天大的难事,咱们碰上了,能帮的就得帮。我们听了母亲的。 

在母亲过来半年后,先生竟然意外升职,在单位的推荐选举上,他的票数明显占了优势。先生回来笑着说,这次是妈的功劳呢,我这票是妈给拉来的。我们才发现,最近我们的人际关系竟然空前好起来,那种好,明显地少了客套多了真诚。一个字都不识的母亲,只是因为舍得,竟不动声色地为我们赢得了那么多,是我们曾经一直想要赢来却一直得不到的。再想她说过的话,你舍得对人家好,人家才会舍得对你好。于她,这是一个农村妇人最朴实本真的话;于我们,无疑是一个太过深刻的道理。 

温煦的日子里,我很想带母亲到处走走。可母亲因为天生晕车,坐次车如生场大病,于是常拒绝出门。那个周末,我决定带她去动物园。母亲说,没有见过大象呢。动物园离家不远,几站路的样子。母亲说,走着去吧。我不同意,几站路,对一个70岁的老人,还是太远了。可她又坚决不坐车,我灵机一动,妈,我骑车带你去。母亲笑着同意了。我推出车子,小心地将她抱到前面的横梁上,一只胳膊刚好揽住她。抱的时候,心里一疼,她竟然那么轻,蜷在我身前,像个孩子。 

途中要经过两个路口,其中一个正好在闹市区。小心地骑到路口,是红灯,我轻轻下车,还未站稳,却有警察从人流中穿过来,走到我面前说,不许带人你不知道吗?还在前面带。说完,低头便开罚单。母亲愣了一下,攥着我的胳膊要下来,我赶忙扶稳她,跟那个年轻的警察说了声对不起,解释说,我母亲晕车,年纪大了,不能坐车,我想带她去动物园看看…… 

警察也愣了一下,这才看清我带的是一位老人,还不等他说什么,母亲责备我,你怎么不告诉我城里骑车不让带人呢?然后坚持要下来。我正不知所措,那个警察伸手一把搀住了母亲,大娘,对不起,是我没有看清楚, 城里只是不让骑车带孩子,您坐好。然后他忽然抬起手,向我认认真真地敬了个礼。接着,他转身让前面的人给我腾出一个空间,打着手势,阻止了四面车辆的前行,招手示意我通过。我带着母亲,缓缓地穿过那个宽阔的路口,四面的车辆静止行人停步,只有我带着母亲在众人的目光里骄傲前行。 

那是我有生以来第一次受到如此厚重的礼遇。因为母亲,因为舍得给予她一次小小的爱,一个萍水相逢的年轻警察,便舍得为我破例,舍得给我这样高的尊敬。这礼遇,是母亲送给我的。 

母亲是在跟着我第三年时查出肺癌的。 结果出来以后,有个做医生的朋友诚恳地对我说,如果为老太太好,不要做手术了,听天命尽人事吧。这是一个医生不该对患者家属说的话,却是真心话。和先生商议过后,决定听从医生的安排,把母亲带回了家。又决定不向母亲隐瞒,于是对她讲了实情。母亲很平静地听我们说完,点头,说,这就对了。然后,母亲提出要回老家。 
母亲在世的最后一段时间,我陪在她身边。药物只是用来止疼,抵挡不了癌症的肆虐。她的身体飞快地憔悴下去,已经不能站立,天好的时候,我会抱她出来,小心地放在躺椅上,陪着她晒晒太阳。她渐渐吃不下饭去,喝口水都会吐出来,却从来没有流露过任何痛苦的神情,那些许黑发依旧倔强地蓬勃着,面容消瘦却光洁,只要醒着,脸上便漾着微微的笑容。那天,母亲对我说,你爸他想我了。妈,可是我舍不得。我握着她的手,握在掌心里,想握牢,又不敢用力,只能轻轻地。梅,这次,你得舍得。她笑起来,轻轻将手抽回,拍着我的手。但是这一次,母亲,我舍不得。我说不出来,心就那么疼啊疼得碎掉了。母亲走的那天,送葬的队伍浩浩荡荡,从村头排到村尾,除了亲戚,还有我和先生的同学、朋友、同事,我们社区前后左右的邻居们……很多很多人,里面不仅有大人,还有孩子,是农村罕见的大场面。 
队伍缓缓穿行,出了村,依稀听见围观的路人中有人议论,是个当官的吧?或者是孩子在外面当大官的……母亲这一生,育有一子三女,都是最普通的老百姓,不官不商。母亲本人,更是平凡如草芥,未见过大的世面,亦没有读过书,没有受过任何正规教育,她只是有一颗舍得爱人的心。而她人生最后的盛大场面,便是用她一生的舍得之心,无意间为自己赢得的。 

Posted in 社会生活 | Tagged | Leave a comment

apache tomcat: mod_jk missing uri map

接续此前的 “嘗試 Apache + Apache Tomcat (簡稱 Tomcat)融合” , -R/H2SL , 出现异常,在 https 下tomcat可以接管解析jsp页面,但在http却不行,于是使劲检查如下。

apache tomcat: mod_jk missing uri map

首先排除了所有因为url格式不匹配的情况下,在 conf/extra/httpd-jk.conf  打开日志为 trace :

# Our JK log level (trace,debug,info,warn,error)
JkLogLevel trace

需要检查,URI的匹配的写法,在 

conf/extra/uriworkermap.properties

中进行修正:

# java ??
/*\.jsp=balancer 

如果仍有问题,需要进行下面的配置命令的检查。

JkMountCopy On 

的设置,这一语句通常需要在所有 VirtualHost 和 SSL 的 VirtualHost 里面,

涉及到的Apache Httpd的配置文件有

conf/extra/httpd-vhosts.conf 
conf/extra/httpd-ssl.conf 

 

Posted in 服务器运维, 编程技术, 计算机技术 | Tagged , , | Leave a comment

-gMIS 中操作同时并发操作和管理多个数据库multiple databases

如前所述,我们实现了 -gMIS 中可以同时并列/并行/并发管理多个数据库的目标数据表,
“-gMIS 更新多库连接及工作流workflow” , -R/b2SI ,

新近部署了一个 -gMIS 的应用实例,也涉及到跨数据库的信息管理系统,于是归集整理了在 -gMIS 中操作多个数据库的使用步骤,列如下,备忘。

  1.  inc/config.class 中添加数据库配置信息
    ….
    # db slave info
    $conf[‘dbhost_slave’] = ‘127.0.0.1’; 
    $conf[‘dbport_slave’] = ‘3306’;
    $conf[‘dbuser_slave’] = ‘dbuser’;
    $conf[‘dbpassword_slave’] = ‘dbpassword’;
    $conf[‘dbname_slave’] = ‘dbname’; 
    ….

  2.  inc/conn.class 中创建数据库连接所需的对象
    ….

    class Db_Slave{

        var $mDbHost = “”;

        var $mDbUser = “”;

        var $mDbPassword = “”;

        var $mDbPort = “”;

        var $mDbDatabase = “”;

        function __construct(){

            $db_suffix = ‘_slave’;

            $gconf = new Gconf();

            $this->mDbHost = $gconf->get(‘dbhost’.$db_suffix);

            $this->mDbPort = $gconf->get(‘dbport’.$db_suffix);

            $this->mDbUser = $gconf->get(‘dbuser’.$db_suffix);

            $this->mDbPassword = $gconf->get(‘dbpassword’.$db_suffix);

            $this->mDbDatabase = $gconf->get(‘dbname’.$db_suffix);

        }

    }
    ….

     

  3.  class/gtbl.class 中添加所需指定数据的连接对象

    在类的 __construct 方法中,在调用父类的 __construct 之前,
    ….

    if($args[‘dbconf’] == ‘default’){

        $args[‘dbconf’] = ‘Db_Master’;

    }

    else if($args[‘dbconf’] == ‘slavedb’){

        $args[‘dbconf’] = ‘Db_Slave’;

    }

    ….

  4.  在管理界面设置数据表所需连接的数据库名称(别名)
    在 Π 首页  桌面 & 系统配置 → 菜单调整 | 菜单调整 路径中增加针对某个被管理对象表时,指定所需连接的数据库.


    在 菜单管理中,增加对被管理对象时,设置所需链接的数据库.

 

-gMIS 是一种基于 -GWA2 的通用管理信息系统软件,具有可配置的输入和输出接口。
可以在其上构建各种管理应用软件系统,如
内容管理系统(CMS),客户资源管理(CRM), 企业资源计划管理(ERP),
办公自动化系统(OA)等, 以及各种行业应用管理系统软件,如
人力资源管理系统(HR),学生管理,档案管理,旅游管理,图书管理,
商品管理及业务运营支撑系统等等。
实现零代码开发、搭建各种管理信息系统(MIS).

Lower Costs, 降低成本; Better Productivity, 提高效率.

Posted in -gMIS, 编程技术, 计算机技术 | Tagged , , , | Leave a comment

信息加解密与摘要Encryption and Message Digest

这篇短文最早写在 -Maimai 上,后来转发到 -Linkedin 上,再后来备份到 -Wordpress-wadelau 上,现在再复制到 -Ufqi-Blog 上。

关于账号密码的保存,昨天回复的仓促,重理一下。

先区分是加密和信息摘要,两者区别是内容是否可逆。能从密文恢复到原文的是加密,不能的是消息摘要,或信息摘要。加密又可分为算法加密和使用秘钥加密,区别是在加解密过程中是否使用“秘钥”。置换、交换、取模异或等可看做无秘钥加密,仅依靠某种算法实现加密。

使用“秘钥”加密又分为对称加密和非对称加密。区别是对称加密收发两方用同一个密钥,非对称基于一对密钥: 公钥和私钥。发方用收方的公钥加密,收方用自己的私钥解密密文;或者发方用自己的私钥加密,收方用发方的公钥解密。

回到密码保存这个话题,明文存储不是人干的事。密文存储是业界标准做法。至于密文是加密后内容,还是明文的消息摘要,一般从形式上可以判断,消息摘要多会生成一个由0-9, a-f的字符串。密文则各种字符串形态均有,如 -base62x 的输出。

消息摘要一般能满足账号密码保护需求,但自从md5被碰撞算法找回原型后,md5就不安全用在密码上了。这方面可以选升级的md6, sha1, sha256, sha512, sha1024等。

至于加密的对称算法,有很多。加密的非对称算法,也有不少,多用rsa。

加解密,矛和盾。哪个锐利,哪个坚厚?

%e5%8a%a0%e5%af%86encrypt%0a%e6%b6%88%e6%81%af%e6%91%98%e8%a6%81digest%0a%e7%bc%96%e7%a0%81coding%0abyxenxin-201608

Posted in Base62x, 编程技术, 计算机技术 | Tagged , , , , , , | Leave a comment

擰巴 Apache Httpd 和 Tomcat 到一起

此前Apache HTTPD (簡稱Apache) + Caucho Resin作爲 Java 容器,

現在嘗試 Apache + Apache Tomcat (簡稱 Tomcat)融合在一起愉快地工作。

爲何不是 Ningx + Resin 融合在一起工作?

  1. 安裝 Apache Httpd
    配置站點根目錄 /path/to/apache/document_root
  2. 檢視Apache是否成功安裝
    查看 apxs目錄, /path/to/apache/bin/apxs
  3. 安裝mod_j
    下載 tomcat-connectors
    按手冊配置,./configure –with-apxs=/path/to/apache/bin/apxs
    編譯出 mod_jk.so
    複製 mod_jk.so 到 /path/to/apache/modules/mod_jk.so
    複製  tomcat-connectors/conf下的 httpd-jk.conf 到 /path/to/apache/conf/extra 下
    複製 tomcat-connectors/conf下的 uriworkermap.properties  , workers.properties 到 /path/to/apache/conf/extra 下
    修改 apache/conf/httpd.conf 增加: 
        # java
        Include conf/extra/httpd-jk.conf
    修改 apache/conf/extra/httpd-jk.conf :
         JkWorkersFile conf/extra/workers.properties
         JkMountFile conf/extra/uriworkermap.properties
        JkLogLevel trace 
        info –> trace 跟進觀察所有流程
    修改 apache/conf/extra/workers.properties :
          worker.node1.port=8009
          worker.node2.port=8009 
          如果衹有一個node的話,將loadbalancer的兩個端口改爲一樣,
         具體端口數字需要與Tomcat的實際保持一樣
    修改 apache/onf/extra/uriworkermap.properties :
          /*.jsp=balancer
          攔截所有 .jsp 的程序給 Tomcat 來處理
    如果Apache 啓用了SSL,則需要修改 apache/conf/extra/httpd-ssl.conf:
           在 <VirtualHost _default_:443> 項下,增加:
            # java?
            JkMountCopy On
  4. 檢視mod_jk是否安裝成功
    如果 訪問 /a.jsp 被映射到 tomcat ,則測試成功
  5. 安裝Apache Tomcat
    配置 tomcat/webapps/ROOT 為 apache的document_root :
          shell> ln -s /path/to/apache/document_root /path/to/tomcat/webapps/ROOT
  6. 檢視Tomcat是否安裝成功
  7. 融合在一起
  8. 檢視融合在一起
Posted in 服务器运维, 编程技术, 计算机技术 | Tagged , , , , , | 1 Comment

Base62x比Base64的编码速度更快吗?

Base62x与Base64的编码速度测评

现在几乎所有企事业单位、政府机构、军工系统等的IT生产系统都会用到Base64编码,从RSA安全密钥到管理信息系统登录入口回跳,目前越来越多的IT系统研发者开始使用 Base62x 替换 Base64.

Base62x 提供了一种无符号输出的Base64的编码方案,在许多应用场合其纯字母和数字的输出形式,可以有效的规避因为符号带来的各种负面影响,并能够有效削减或兼容各种Base64的变种形式。

借着 Base62x 在 -GitHub 上获得几个赞之后,我们探讨另外一个问题,Base62x 的编码在输出文本形式上略胜一筹,是值得推荐的替代方案,但其编码速度和效率如何?

为此我们设计一个评测任务,分别使用Base62x 和 Base64进行20万次编码操作,其中Base62x 使用 PHP的ext module方式实现的 base62x_encode , Base64 也是 PHP内置的 base64_encode , 两种均是使用C语言实现,并通过扩展方式集成在 PHP中,相对而言,可比性较好. 运行主机是在 Windows下虚拟主机运行 OpenSuSE 42,Nginx 1.12, PHP 7.0.
通过脚本Command Line调用方式进行20万次编码任务,对比测试数据:

base62x 200000 timestart:1513077337.6748 timecost:0.30399990081787
base64 200000 timestart:1513077337.9788 timecost:0.16817998886108

base62x 200000 timestart:1513077401.2177 timecost:0.29567098617554
base64 200000 timestart:1513077401.5134 timecost:0.17081189155579

base62x 200000 timestart:1513077424.234 timecost:0.30112099647522
base64 200000 timestart:1513077424.5351 timecost:0.1718909740448

base62x 200000 timestart:1513077447.9861 timecost:0.29450607299805
base64 200000 timestart:1513077448.2806 timecost:0.16546702384949

base62x 200000 timestart:1513077470.7367 timecost:0.45493698120117
base64 200000 timestart:1513077471.1917 timecost:0.24029588699341

运行5次之后,Base62x 和 Base64 其均值分别为,0.330047 和 0.183329 . 由此可见,Base62x 比 Base64 在编码速度上稍慢,20万次操作耗时比值为 1:0.555 , 尽管每次操作其耗时差(7.33589E-07)可以忽略不计,但考察比值,Base62x 慢了大约 44.5%,大致是 Base64 完成两个编码操作, 目前版本的 Base62x 完成一个多一点的编码操作。

如果加上在应用层的各种判断,使用 Base62x 替代 Base64 可能是有优势的,比如判断是否包括+,进而转化为空格,是否包括等号等,因为任何一步额外的判断或替换操作,其耗时将可能远超过 Base62x 与 Base64 操作耗时的差值。

比如其中一个 URLEncode 的应用场景,在 -github/wadelau/gMIS/comm/ido.js 中( -R/J2SI ):

var actx = unescape(tObj.action);
actx = actx.replace(+, );  

取代的改进使用Base62x的方案是:

var actx = Base62x.decode(tObj.action);
 /* no more action needed */

从代码层分析耗时差值原因,尽管两者都使用了位操作进行计算,但 Base62x 在单位编码长度上多了数值判断,由此导致其速度下降。Base62x 还是新事物,其代码应该还有可以再改进优化的空间。

如果进一步改进优化,Base62x 有可能与 Base64 相同的编码速度吗?

有没有可能存在另外一种不需要数值判断,也能够满足与 Base62x 一样无符号输出的64进制编码方案?

小结,单就编码速度而言, Base64 方案快,如果加上其他判断与替换操作, Base62x 方案胜出,未来可能会有鱼(无符号输出)和熊掌(速度)兼得的新编码方案出现。

Posted in Base62x, 编程技术, 计算机技术 | Tagged , , , | 2 Comments

软件编程技术水平的标志性关键点分析

Title: 软件编程技术水平的标志性关键点分析

刘振兴 / Liu Zhenxing

摘要:软件编程技术水平的考评与分级是困难的, 同时也是必要的。本文在相关文献检索和经验总结的基础上提出了软件编程技术水平的三个具有标志性的关键点并逐一对其进行简述和应用分析. 这三个分水岭一样的关键点是正则表达式、软件开发框架的掌握与运用和现实世界问题数学模型创建技能的掌握与运用。与之对应地我们称呼具备相应技能水平的人员为工程师、高级工程师和技术专家。

关键词:软件编程;技术水平;正则表达式;软件开发框架;数学建模

中图分类号:TP311.5                     文献标识码:

An Analysis on Key Points of Software Programming Technology Level

LIU Zhen-Xing[1]

【Abstract】It is not only difficult but also necessary for software programming technology level of assessment and classification in software industry and Internet+ sectors. Based on the related literature search and directional experience, this paper puts forward three key points of software programming technology level and analyzes them briefly on their applications one by one. The watershed-like three points are regular expression, the mastery and application of the software development framework and the mastery and application of the creation of skills in the mathematical model of the real world. Correspondingly, we call them with the appropriate level of skills as the engineers, senior engineers and technical experts.

【Key words】Software Programming; Technology Level; Regular Expression; Software Framework; Mathematical Modelling

1   引言

计算机专业及软件产业属知识密集型领域,其中最重要的资源是人力资源,软件开发人才的培养与甄选日益重要。同时,传统软件行业的快速发展叠加移动互联网、互联网+、人工智能战略布局稳步推进,催生了大量的软件开发从业人员。对软件编程水平及能力的评估是一件复杂而又严肃的事情( -R/02SI , [1] [2]),出于对自身或者同行技术能力的评估需求 [3],也需要在某些方面从某种程度上,对编程水平及能力有些大概粗略的感性认识。关于软件工程美国IBM公司的软件技术专家布鲁克斯(Frederick Brooks)在其论文中提到软件编程受目标任务的复杂度、一致性、可变性和不可见性的约束,在各种约束条件下取得均衡和达成目标就是对软件编程技术及水平的考察与验证 [4] [5]。

IT行业技术巨头往往会开展一些编程技术水平认证,如微软公司的MSDN,思科公司的CCIE等;一些行业学会、协会也会推出一些编程技术水平认证,如美国IEEE下计算机协会的各种认证和中国计算机学会的“CCF计算机职业资格认证” [6]。这些认证往往是基于某些厂商自家产品或者囿于特定领域的认证。是否有通用的可供参考的软件编程水平的参考标准?带着这个疑问,我们进行一些文献检索,同时结合我们多年学习、工作中编程实践、思考与经验总结,在本文如下部分提供如下三点作为软件编程技术水平的参考。

中国近代学者王国维将做学问的状况划分为三个境界,分别是“望尽天涯路”、“为伊消得人憔悴”和“那人却在灯火阑珊处”。写程序研发软件也有如下三个具有标志性的关键点,我们称之为软件编程的三个分水岭一样的标志性关键点,他们分别是正则表达式的运用、软件开发框架的掌握与运用和现实问题数学建模的掌握与运用。

余下的章节中,第二节我们讨论了正则表达式及模式识别相关的理论及技术应用,第三节讨论了软件开发框架在软件研发及其生命周期中的地位及作用,第四节讨论了针对现实世界问题进行数学模型创建的相关应用,然后是针对全文的总结和展望。

2   正则表达式

正则表达式(Regular Expression)使用单个字符串来描述、匹配一系列符合某个句法规则的字符串,可以视之为狭义上的模式识别(Pattern Recognition),也可以将其视作在某种编程语言下的子类语言——用来描述其他语言的“语法”。使用它有一定的难度,句法全由符号表达,看起来抽象,可读性差,不容易理解。比如,

/^([0-9]{1,6})$/g

表示任意1位到6位的数字,也即0~999999 ,在匹配结果集中,将反向引用被匹配到的数字串,

/^(\d{1,6})$/

表示与前文相关的语法。下图(图 1)展示一个正则表达式工作机制的应用程序 [6],将前述正则表达式输入到“Regular Expression”相关区域,在“Test String”里输入相应待检测、匹配的文字,则下面“Match Information”区域会显示匹配过程及结果。


图 1 正则表达式匹配样例
Figure 1 Example of Regular Expression

正则表达式被广泛的应用于很多软件中,包括 *nix(Linux, Unix等)、HP 等操作系统,PHP、C#、Java 等开发环境,以及很多的应用软件中,都可以看到正则表达式的影子。如对外部输入的校验、提取,对目标对象的格式化等。

每种编程语言在进阶开发和使用时都有不少需要特别关注的地方,如指针、内存、链表和树、正则匹配等,若在这些不同的语言之间寻找共性的进阶开发所需掌握的技能,则正则表达式是其中关键点之一。

掌握了某种编程语言的基本数据结构和流程控制之后,一名软件工程师(或称程序员)若能够运用某种编程语言进行读写文件、数据库和通过网络收发数据,则其就是一名合格的软件工程师。具备这样素质的人可以胜任一般的软件开发任务,能够面向任务较好地完成给定的软件开发需求,实现相应的功能。

由于计算机科学兴起之处,其主要应用是对数据和文本的处理,所以正则表达式成为进阶开发的必由之路也在情理之中。初阶的开发人员往往止步于使用字符串查找、分割等方式来部分地完成相应功能。

正则表达式本身就是一门学问,已经有很多书籍专门就此展开详述,其中有本《精通正则表达式》(Mastering Regular Expressions)的书 [8],在豆瓣网有一个广为赞许的评价为面向“愿意从一个代码工人向专家进化的” (-R/A2SI )。

相比较而言,掌握和熟练使用正则表达式工具的软件编程人员能够高效而准确地实现相应的功能,我们称之为第一个分水岭。

3   软件开发框架

软件开发框架(Software Development Framework)软件开发框架(Framework)是代码组织和软件逻辑实现的思考方式。这种思考更多的是“管理”的视角,而非计算科学技术的视角。这种管理的方式是建立在对软件编程技术较深入、全面理解的基础上的。一般意义上的软件框架,是指为解决一个开放性的计算问题而设计的具有一定约束性的软件支撑结构。在此结构上可以根据具体问题扩展、安插更多的组成部分,从而更迅速和方便地构建完整的解决问题的IT技术方案 [9] [10] [11] [12]。软件框架本质上是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法。简而言之,是构建结构及实例交互方法的结合体。

一名软件编程人员在掌握了某一种编程语言之后,随着所解决的单个、多个任务的积累,终将会面临一个复杂任务——任务复杂到不能通过一个或几个小程序能够实现和满足其功能,这时候就需要从整体上思考,需要多少个程序(模块),这些程序和模块之间如何交互?软件框架就是要回答这些问题。

3.1          软件开发框架的特征

软件框架是成功软件项目的一般化实现。进入视野或者进行开源的多数软件框架都经历过一个或者多个成功项目的检验,是成功经验的积累。软件编程者当完成一个项目后,如果发现项目本身有可以进行一般化处理的代码段或功能模块,会对其进行封装以便后续使用,软件的组成架构设计也是这样,当发现所用的设计具有一般性后,就可以在随后的项目中继续使用,继而形成“框架”。框架不一定都开源,一些私有的或者基于开源定制的框架可能在某些方面具有更好的表现。

软件框架普遍实现了关注点分离设计(Separation of Concerns)和代码复用(Code Resue)。分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特定领域问题代码的调用,业务逻辑同特定领域问题的关系通过侧面来封装、维护,这样原本分散在整个应用程序中的变动就可以很好的管理起来,如常见的MVC分层设计(模块Module、视图View和控制器Controller)。


图 2 架构设计中的关注点分离
Figure 2 Separation of Concerns in Framework Design

代码复用本质上就是对曾经编写过的程序代码的一部分甚至全部重新加以利用,从而构建新的程序。使用这种方法就可以将程序员从费时费力的重复劳动中解放出来。框架(类库)是一种代码复用的很好的形式。编程人员可以创建内部抽象以便程序的部分代码可被复用,或者直接创建一个自定义库给自己使用。一个规划和设计良好的框架应该是实现了上述两点。

清晰的关注点分离和高效的代码复用是避免软件项目陷入泥潭(the ball of mud)的基础和前提,也是软件项目成功的保证。

3.2          跨语言的软件开发框架

各种编程语言分别有许多不同的软件框架。例如,C++编程语言的框架(类库)有.Net、STL、Boost、Qt、MFC等;Java编程语言的框架有Structs、JSF、Spring MVC、Wicket、Stripes、Seam、GWA2等;PHP编程语言的框架有Zend Framework、Yii、Code Igniter、Lavarel、Symfony2、GWA2等;JavaScript编程语言的开发框架有Angular.js、Backbone.js、D3、jQuery.js、React.js等。

一个软件开发框架一般都与所使用的某种编程语言高度绑定。这一方面是框架需要高度复合利用了编程语言的特性,使之能够在该框架下将其性能发挥至极致;另一方面是框架的开发者和使用者需要具备指定开发语言的软件编程的基本知识。在此之外,也有为数不多的跨编程语言的软件开发框架,比如上文提到的“通用网络应用架构(GWA2) [13]”——提出一种软件架构思路,然后分别使用Java、PHP、Perl、C#等语言进行实现,从而有了针对各个编程语言的软件开发框架的版本。软件开发人员在其中一门编程语言下使用GWA2之后,可以无缝平滑地切换到另外一种开发语言继续使用对应版本的GWA2进行开发,重新学习成本降低为几乎为零。


图 3 GWA2 多层架构设计(DBA)
Figure 3 Multiple Layers in GWA2 (DBA)

通常软件编程对软件框架的应用可以分为两类:学习和使用一种软件框架,或者自行开发一套软件框架。学习有学习的成本 [14],开发也有相应的开发风险。显然,前者会更多一些,许多软件编写都是遵循某种软件框架而进行的。对软件框架和类库应该持有某种谨慎的态度,我们在早前针对JavaScript编程的框架做过一些分析(《自行创建类jQuery的JavaScript库》, -R/02SH , [15]),在学习成本、需求匹配度和框架性能三个方面需要做一些权衡。

相比较而言,我们推荐使用具有跨语言特性的软件开发框架,由于软件技术自身发展和开发人员自身成长是日新月异的,所处的时空变换要求每一名开发人员要掌握两种以上软件开发语言,相应地,如果其所依赖和学习的软件开发框架没有跨语言特性,则软件开发人员就需要付出两倍的学习成本;相反地,如果开发人员使用的是具有跨语言特性的开发框架,如上所述的GWA2,则可以平滑无缝地切换到新编程语言中去,无需再从零开始学习另外一种软件开发框架。

像武学的拳术一样,一招一式组成一套拳法,也像文学的八股一样,起承转合组成一篇文字,软件编程中的这套拳法就是“框架”。软件框架没有好坏,或者都是“好的”,使用者所需工作是寻找“合适的”,因时因地使用能够满足业务需求的框架就是合适的,是好的,既要避免不足(Underqualified),也要考虑不会多余(Overqualified)。 

我们将软件编程的第二个分水岭视为使用软件框架进行开发。无论是学习一个现有的软件框架或者开发一个全新的框架,都需要完整的软件框架知识。开发一个全新的框架需要知识、勇气和精力,而学习一个现有的框架其应用水平该如何来衡量呢?是否对原软件框架的源代码递交过Bug或做过修改、打过补丁,这是在读懂源代码的基础上对软件框架有进一步提升的动议。

4   现实问题数学建模

学习计算科学与技术,在掌握了基本的学科知识之后,应用层面所面临的专业细化就是使用计算机进行文本分析与处理,进行图像的分析与处理,对音频的分析与处理。对文本、图像和音频的计算是三个主要方向,后续可能还有机器学习或者人工智能,这些是使用计算机技术解决现实客观世界的主要方法和途径。本质上看,作为人工智能的代表方法之一机器学习就是计算机利用输入的样本,调整一个通用数学模型的参数,使得这个模型能正确地回应新的输入 [16]。

在掌握了某一种编程需要的单个程序应用,熟悉了由多个程序组成的软件项目的组织结构和运行流程,接下来就是使用这些知识和技能解决现实世界的问题。对现实世界的问题进行数学建模是主要方法之一,这样才能对问题进行计算。

具有一定的数学思维是进行数学建模的前提。观察客观世界的现象,抓住其主要特征,抽象出概念或者建立模型;进行探索,通过直觉判断或者归纳推理、类比推理以及联想等作出猜测;然后进行深入分析和逻辑推理以及计算,揭示事物的内在规律,从而使纷繁复杂的现象变得井然有序。这其中进行分析、推理和计算的过程,就需要借助计算机进行软件编程。

计算机领域的实际问题数学建模(Mathematical Modeling)需要根据现实问题设计相应的算法(计算过程),求解描述实际问题的数学公式、函数等,进而通过这些数学公式、函数解释、验证实际问题,对当下进行计算,对未来进行分析、预测等 [17]。这类知识、规律的发现越来广泛应用到各种个性化、智能化服务当中。


图 4 数学建模的逻辑表述
Figure  Mathematical Modeling in Logic Representation

基于全样本的大数据集,运用测试分析方法开展的机器学习、人工智能等越来越多的被应用到各种软件编程应用场景。利用机器使用测试分析方法逐渐取代人工的机理分析,成为发现知识和规律的主要途径之一。

问题建模是将现实问题简化,使其变成“可计算”,然后使用编程将可计算的部分以软件功能的形式表现出来。编程是建模实现的一种重要工具和手段,针对问题进行数据建模后的拟合、仿真和计算过程才是软件编程大展身手的地方。在数学建模的实践中,几乎没有哪个模型是不需要用到如MatLab、SPSS、Lingo、C/C++或Python这样的编程工具的。这些将我们用数学语言描述的问题再通过计算机来实现,编制良好的程序确实能极大地帮助我们模型的实现,甚至取得更好的效用。

网络发展的如此迅速,一些IT公司会面临各种实际问题需要进行数学建模,而这些互联网公司往往没有数学专家,只有计算科学与技术专家,这就需要此前从事软件编程工作的人员对实际问题进行数学建模,并使用软件编程来实现它。IT公司面临的问题既有其本身发展的需要产生的,也由全社会发展面临的难题。机器翻译是这样的,人脸识别、人工智能都是这样的。逐渐多的,面向各种问题的“算法”工程师、技术专家的需求量增加,正是这一趋势的发展现象。

能不能对现实世界的实际问题进行数学建模,成为我们称之为第三个分水岭的关键点。 

5   结论与展望

本文简要分析了软件编程技术水平的三个具有标志性的关键点——正则表达式、软件开发框架和数学建模。这些分水岭似的关键点有助于软件开发人员甄选,也对软件开发人员自身水平认识起到一定的参考作用。同时,这些知识点也能够从另外一些方面引导软件编程、开发人员尽快、尽早的掌握这些知识和技能,提升自身知识水平。

对软件编程的技能对计算科学与技术的水平进行分层分级是困难的,我们就此列出的三个具有标志性意义的考察点在某些场合并不适用。然而,在一般意义上来说,能够熟练掌握正则表达式、能够掌握并对已有软件框架进行修正或者开发一种软件框架我们将之视为高级计算技术人员;能够对现实世界需求问题进行数学建模,并将其映射为软件应用,我们称之为技术专家。

计算机及软件行业在不断发展变化中。一些编程语言或者编程工具会随着整体发展或日益完善或日渐凋零,只有那些隐藏在编程技能背后的原理与思想保持不变,并随着技术的进步以另外一种编程语言或表现形式再次出现在软件研发行业。

因此,对软件编程技术水平的考评既不能以某一个厂商的某种产品为基准,也不能以一时的技术平台或编程工具为依托,从技术或技能背后的编程原理、编程思想来设计相应的考评体系更能够全面整体地反映出从业人员的真实水平,也许未来可能有其他等同于正则表达式等这三点的参考标志出现。

[参考文献] (References)

[1]

中国计算机技术职业资格网, “计算机技术与软件专业技术资格(水平)考试简介,” 10 2015. [联机]. Available: http://www.ruankao.org.cn/focusExam/ksjs/detail/news-00005/. [访问日期: 09 2017].

[2]

李二霞, 软件编程高端人才效标群体研究, 西南大学, 2010.

[3]

冯向科,邓莹,彭勇, “高职软件技术专业学生的面向对象分析、设计和编程能力培养的研究,” 科教导刊, 卷 28, pp. 41-42, 2011.

[4]

布鲁克斯(FrederickP.Brooks.Jr.), “没有银弹-软件工程中的根本和次要问题,” 出处 人月神话, 北京, 清华大学出版社, 2002.

[5]

李娜, “浅谈软件工程技术发展,” 软件, pp. 204-205, 03 2014.

[6]

中国计算机学会, “CCF计算机职业资格认证简介,” 02 2014. [联机]. Available: http://cspro.org/lead/info.do?__action=info_view&catalog=notice&id=hrvnsypp-1gg&__forward=true. [访问日期: 09 2017].

[7]

F. Dib, “Regular Expression 101,” 08 2012. [联机]. Available: https://regex101.com/. [访问日期: 09 2017].

[8]

J. E·F·Friedl, 精通正则表达式(Mastering regular expressions), 第三版, 北京: 电子工业出版社, 2007.

[9]

D. Riehle 和 T. Gross, “Role Model Based Framework Design and Integration,” 出处 Proceedings of the 1998 Conference on OOP Systems, Languages and Applications, ACM Press, 1998.

[10]

袁立国, 陈中育, 李方 和 郭婷, “一种软件开发框架的设计优化,” 计算机系统应用, 卷 22, 编号 5, pp. 70-74, 2013.

[11]

O. Vogel, I. Arnold, A. Chughtai 和 T. Kehrer, Software Architecture: A Comprehensive Framework and Guide for Practitioners, Heidelberg, Germany: Springer Science & Business Media, 2011.

[12]

张合 和 刘小红, “面向对象的对象建模技术及其应用研究,” 软件, pp. 66-68+72, 03 2011.

[13]

刘振兴, “GWA2,” UFQI.COM, 11 2011. [联机]. Available: https://ufqi.com/dev/gwa2/?_via=-naturedns. [访问日期: 09 2017].

[14]

金旭亮, “如何学习复杂的软件技术开发框架?,” 07 2017. [联机]. Available: https://weibo.com/ttarticle/p/show?id=2309404135192531986821#_0. [访问日期: 09 2017].

[15]

刘振兴 和 张楠, “自行创建类jQuery的JavaScript库,” 中国计算机学会通讯, 卷 06, 编号 6, 2013.

[16]

应行仁, “什么是机器学习,” 中国计算机学会通讯, pp. 42-45, 04 2017.

[17]

谢金星 和 姜启源, “清华大学公开课:数学模型-现实世界的理性视角,” 网易公开课, 04 2013. [联机]. Available: http://open.163.com/movie/2013/4/9/6/M98EVI91I_M98PE9E96.html. [访问日期: 09 2017].

 

作者简介:刘振兴(1977-),男,硕士研究生,原人民网研究院网络技术研究员,中国计算机学会会员(14229M),主要研究领域包括计算机网络通信协议、互联网后台支撑技术和网络架构与安全等.

(原文登载于 《软件》(Computer Engineering & Software),2017年11月号,有改动)

Posted in -GWA2, 编程技术, 计算机技术 | Tagged , , , , | 1 Comment

gMIS吉密斯导航Navimenu、自动安装等更新

gMIS吉密斯通用管理信息系统在使用中不断被优化和更新,这次主要改进和修正的内容如下:导航菜单,录入修改表单项和自动安装程序等,以下分述备忘。

  1. 导航菜单的Bug及更新
    1. 导航菜单二级/三级目录不显示的Bug
      导航菜单使用层级式CSS和JavaScript实现,在实际使用中,如果某个终端设备其屏幕分辨率设置的很高,其相应的显示字体就会变小,此时用户为了获得较大较清晰的字体显示,会在操作系统层面调整字体显示比例,比如将 Text Size调整为 125%,150%,如此高分辨率叠加扩增字体设置,导致gMIS的二级/三级菜单无法展出。

      解决这一问题的思路是,回退操作系统层面的Text Size,然后二级菜单就会重新显示展开,如果获得较大较清晰的显示,可以降低屏幕分辨率分辨率的方式。

      为兼容这一情况,我们升级了gMIS的导航,在三级目录无法展开的情况下,通过点击父级目录能够在 Index 层面以宫格的形式展开该目录的子目录模块,再进一步地点击子目录,可以展开孙目录,如此递进可以抵达任意层级子目录。

      在通过Index导航时,我们还修正了以Extra命名的菜单,也即某个菜单指向的链接,其Module Name为空,但又不是Directory Name,此时需要将访问目标调整为指向动态参数(Dynamic Parameter)所设置但Extra模块。

    2. 菜单路径的最贴合选择
      由于gMIS的菜单设计支持动态参数(Dynamic Parameters)的特色功能,所以同一个模块,使用不同的动态参数进入,可以呈现不同的内容。依据此功能,我们可以在进入某功能模块时,显示A/B项,这样可以将一个功能模块复用为多个。于是就产生了可以在菜单中的多个入口指向同一个模块(带有不同参数)。

      问题发生在,如果多个入口进入同一个模块,在Moudle Path中显示哪一个的问题。

      预期的效果应该是展示最贴合当前路径的那个菜单设置,此时就需要确切知道菜单的层级位置 Levelcode 参数。于是我们进一步地修改Module Path模块,改进单一依靠模块名称生成Module Path的做法,优先使用菜单的Level Code来生成Module Path。

      这样就生成最贴合当前菜单的路径。

    3. 未来规划
      层级目录导航是“传统”的,属于 Yahoo 时代的产物,未来的导航应该是 Google 式的智能导航。
      未来拟开发一个 gMIS 域内全文搜索引擎,这样用户就无需使用或者记录层级目录。
      再未来,可能会有交互方式的改进及人工智能的引入,比如一个能够交互使用自然语言进行交互的管理信息管理系统.

  2. 录入、修改表单项
    1. Add/Modify UI Middle/Bottom -> Top
      在新增。修改UI界面,调整和优化了显示方式。
      主要修改是,当 textarea 和 text普通录入框等并列显示时,text但布局没有作处理。问题发生在textarea但竖向设置为 top,而Text默认设置为bottom/middle,于是就产生了不协调。
      此次我们修改和调整了Text但设置,默认都修改为在竖向使用Top方式,取得一致都显示效果,预览更方便直接。

    2. Caption Font + Bold
       同样是在Add/Modify都界面上,我们还修改了数据项的显示,使用加粗的方式使之能够更进一步地的一目了然。
      这一修改还同步到View模块。

  3.  自动安装程序的改进
    根据网友反馈在新用户使用gMIS自动安装程序进行安装时没有报错信息的情况,默认启用了 is_debug;

    修改了cache设置,改为默认不启用服务器端 Cache Service;

    修改了新版 MySQL 连接时 localhost 报错信息,改为默认使用 127.0.0.1 连接本地 MySQL 数据库;

    修改了下载(wget)、解压(unzip)和验证安装程序的一些内置命令参数。

gmis-logo-201606

-gMIS 是一种基于 -GWA2 的通用管理信息系统(Management Information System)软件,具有可配置的输入和输出接口。
可以在其上构建各种管理应用软件系统,如
内容管理系统(CMS),客户资源管理(CRM), 企业资源计划管理(ERP),
办公自动化系统(OA)等, 以及各种行业应用管理系统软件,如
人力资源管理系统(HR),学生管理,档案管理,旅游管理,图书管理,
商品管理及业务运营支撑系统等等。
实现零代码开发、搭建各种管理信息系统(MIS).

Lower Costs, Better Productivity.
降低成本, 提高效率.

Posted in -gMIS, 计算机技术 | Tagged , , , , | Leave a comment