Category Archives: 编程

OA平台技术分享

为公司其他部门做的技术分享,在一定程度上也算是在公司内部推广Python。不过很不幸的是由于某些原因,该分享不幸夭折。

PPT在这里:http://vik.haoluobo.com/static/slide/oa/

下面是更为详细的文案。

OA平台概况

  • Nginx
    • 使用Nginx作为前端服务器,负责静态资源处理及HTTP请求分发
    • 在需要扩展到多服务器时,Nginx可以用做负载均衡服务器
  • UCenter(统一认证中心)
    • 统一的用户登陆管理
    • 用户信息存储在公司的AD域中
  • OA
    • 业务平台,公司的行政、人力等各项OA业务都在该平台搭建
    • 同携程、inTrack平台对接实现相关业务
    • 数据的汇总及分析

OA构架

  • 基于Django搭建的可插拔APP平台
    • 核心APP(基础APP)
      • 核心APP包括:UI框架、权限认证、流程引擎、用户、员工、部门管理等
      • 作为系统的核心模块,需要被其他各个业务模块所用到。
      • 为具体业务做支撑,大多不同具体业务相关
      • 核心模块在系统上线后将不太做改动,只需要少量的核心开发人员维护即可
      • 核心模块也是可复用的
        • UCenter同OA就是公用的相同的UI框架
    • 可插拔APP(业务APP)
      • 可插拔APP包括:人力模,请假出差、财务模块,报销、预算、行政、固定资产管理…
      • 同具体业务相关,依赖核心模块。
      • 业务需求多,且易变,在平台建设初期难以做周全的计划。
      • 各个业务模块相对独立,各业务模块可独立开发。
      • 多个业务模块可由多人并行开发。

Django

  • The web framework for perfectionists with deadlines.
  • 全功能的Web开发框架,依托Python提供快速开发的支持
    – 提供模板、控制器、URL路由、表单、验证、ORM等各项Web开发需要的基础功能
    – ORM及其强大,即使不懂SQL也可使用。
    – 支持数据库的版本管理,并可自动更新线上数据库结构
    – 模板支持继承清晰易用,对前后端分离提供很好的支持。

    • 成熟的社区环境,大量现成的APP可用
    • 被广泛应用,有成功易用范例:Instagram、OpenStack

流程引擎

  • 采用Python自主开发
  • 编码同配置结合在确保使用便携性的同时确保的功能的强大
    • 表单、业务处理逻辑编码实现
      • 数据模型通常变动不大,采用配置方式实现不但实现复杂,也不会能为开发维护带来多少便利
      • 流程常用的,同意、驳回、打回、撤销等基础操作流程引擎已自动实现,不需要额外开发。
      • 如在流程流转需要进行特殊操作,需用代码给出对应的实现。
        • 比如新员工入职流程结束后需要自动在系统中创建员工账号等
      • 配合代码生成器的使用,对于标准流程编码工作流程只需要完成数据模型的设计即可。
    • 流程流转用配置实现
      • 流程的审批节点,审批人变动概率较大,采用编码方式实现既不方便又不灵活
      • 流程流转的功能需要比较清晰,使用配置方式即可比较好的满足需求
        • 流转方式:抢先,会签
        • 流程节点的审批人、周知人、权限分享。
        • 流程分支支持
    • OA上所有流程都基于流程引擎开发
  • 提供代码生成工具生成流程框架
    • 对于简单的流程,只需要实现数据模型即可生成完整的业务代码

Why

  • Why

    • Python

      • Python is powerful… and fast;
        • 这里的快更多的是开发速度快。语法丰富,简洁
        • 开发效率高是我们选择Python的一个重要原因。
          • 信息部就2人,需要负责需求整理、设计、开发、测试所有工作,对开发效率要求非常高。
        • 不需要编译,启动时间快节约开发时间
          • 一个大Java项目编译要超过一分钟,Web服务器启动又会超过一分钟
          • OA对比原有的KM。KM启动时间超过1分钟,OA可在5秒内完成重启。
        • Python本身并不慢,
        • 真正影响性能的代码所占总代码的比重很少。
          • Python可方便的同C集成,用C扩展性能
          • 注:使用Cython可直接在Python里写C代码以提高性能
          • 目前不少性能敏感的库都采用C扩展的方式进行加速,方案成熟
      • plays well with others;
        • 对C友好,使用ctypes可直接使用C接口的动态库
        • 很多软件都有提供Python接口。如:OpenCV、MATLAB
      • runs everywhere;
        • 支持几乎所有的操作系统(包括各类嵌入式系统)
      • is friendly & easy to learn;
        • 非常容易入门。对有经验的开发者,花一天时间熟悉语法就可直接使用
      • is Open.
      • Python的第三方资源足够丰富,应用也足够广泛
        • 有很多采用Python的成功应用
          • OpenStack、Dropbox、Youtube、Mercurial
        • 虽然比不上Java,但Python的资源也非常丰富。
          • Django(Web)、Cython(在Python中直接写C)、NumPy(可选计算)、PyQT(UI)、QPython(Python on Android)
      • Python无所不能,但并不适合做所有事情。比如Android移动端的开发还是用Java更合适

      • 开发效率高

        • 信息部人少,需要快速实现需求
        • Java严谨、Java有接口等概念,在大项目协作时更容易。但由此带来的开销是在小团队情况下开发效率更低。
    • Django
  • Why Not
    • Java
      • Java严谨、Java有接口等概念,在大项目协作时更容易。但由此带来的开销是在小团队情况下开发效率更低。
      • 信息部是个小团,Java带来的好处不如优点大。
      • 即使是一个大团队,也可通过模块化的方式来减少规模化带来的沟通开销。除阿里这样的超大公司外,很多时候Java都不是一个很好的选择。
      • Java在Web开发方面一直是由多个开源项目所推动,本身就缺乏一个很好的体系。
        • Java的各个开源项目独立发展,在开发初期并未仔细考虑过如何同其他项目协作。
        • Java主流实现都是围绕如何实现一个超大规模项目来设计,对小项目来说负担太重。
        • 使用Java实现一个非常小的功能也需要写大量的代码及超多的XML配置。现阶段Java开发已经简化很多,但相比Python依旧太过繁琐。
    • Node.js
      • 近年来前端技术发展非常迅速。
      • 前端开发只能用JS,因此会JS的群体非常广泛。
      • Chrome V8,Node.js将JS引入服务端,收到广大前端爱好者的支持,迅速发展。
      • Node.js天生异步,有着不错的性能。
      • 使用callback实现异步,大量的callback导致代码不容易理解。
    • redis(Cache)
      • 开发应当优先考虑功能的稳定性,然后才是性能问题。
      • 性能问题更多的是构架问题,应当优先优化构架。
      • 以我们公司的规模还远没到需要增加缓存的情况。
      • 缓存会增加系统复杂度,也可能带来一定的潜在风险。

前端技术构架

  • UI
    • AdminLTE(Bootstrap)
      • 信息部人少,缺少专业的UI及前端人员,尽可能的利用现有可用的资源。
      • AdminLTE是一套基础Bootstrap的界面框架,提供了大量基础的界面功能。
      • Bootstrap是当前非常流行的前端框架,有着丰富的资源。
  • JS
    • 使用Bower管理静态资源。
      • 静态资源的包管理工具
      • 方便静态资源的升级管理
      • 避免将静态资源直接复制到代码库,为代码库增加存储以及响应压力
    • JQuery
      • JS事实上的标准库,可极大的加速JS开发。
    • formset.js、datepicker等
      • 实现formset,日期选择等节目效果。
    • 使用Django-Compressor进行静态资源的压缩优化。
  • Why Not
    • Webpack
      • 近几年前端发展速度非常快,前端开始变的复杂。JS不仅仅是为Web页面锦上添花。为配合使用JS进行大规模项目的开发,需要相关工具进行配合。
      • 前端打包工具,可对JS库进行依赖管理,控制JS包的按需加载。可对JS/CSS编译(ES6/TypeScript/SCSS/LESS),压缩,图片优化等
      • OA前端应用相对比较简单,Django-Compressor可以满足要求现阶段需求。相比Webpack能带来的好处,没必要为项目增加不必要的复杂度。
    • React
      • 用来构建用户界面的 JavaScript 库
      • 更适合单页面的应用,如为手机提供类似APP的体验。
      • 不采用原因同Webpack一样。

LBForum后续计划

开源应当是一件很认真的事。

  • 保证持续的维护与更新,保证该项目的活力。
  • 有完善的测试用例,方便在添加功能以及merge其他人的改动后进行功能测试。保证软件的质量。
  • 完善的文档,让初次接触该项目的人可以快速的知道如何使用。

我写的一些东西基本上都是出于个人兴趣,因此有些随性,兴趣来了就写一写,兴趣过了这个项目就荒废了。
LBForum曾一度荒废,近期由于集成到公司系统,顺道做了一些更新。接下来可能还会陆陆续续做些更新。

  • 增加Python3的支持
    • 单纯的增加Python3的支持并不难。由于我的测试用例并不完善,增加Python3后测试的工作量会增加,因此一直没有做。
    • 注:现在以及可以支持Python3了。比预计的要顺利不少,只做了很少的改动就完成了Python3的支持。
  • 增加Rest接口
    • 之前的Rest接口一直都是手动实现而且也还挺方便,想试试Django REST Framework看能减少多少工作量。
  • iOS的论坛APP
    • 一直想做个移动APP,刚好用论坛来尝试一下。
    • 第一个版本应当只有浏览功能,登陆、回帖、发帖等功能将在日后逐步添加。

React

之前简单的对比过React和Vue.js。React组件化程度很高,粒度很细,“模板”分散在整个JS文件中。Vue.js模板和JS文件分离,看上去要清晰不少。当时比较倾向于Vue.js。
近期又去了解了一下两个框架。Vue.js居然也计划要支持JSX了,模板和JS分离这本是我偏好Vue.js的一个重要原因。此外就网上的评价来看Vue.js的坑也并不比React少。考虑到React的背景,以及周边成熟的生态环境,决定再给React一个机会。
把React的《QUICK START》完整的看了一遍。React的入门并不难。如果不想将系统改造成“单页面应用”,只将页面上部分功能组件化也不存在困难。React的粒度很细,但拆分完后各部分会比较简单。
按照React的说法,React会颠覆大家对传统Web开发的认知,但一旦熟悉就会发现这很棒。
React是否真的很棒?因为没真正用过,还不敢断言。但React的组件化思想还是有些意思,本身的概念也比较清晰,加上并不复杂,或许值得一试。

目前项目用的一些东西

项目基于Django构建,如果你们也在用Django,可以参考下。

源代码管理 HG

之所以用HG完全是因为公司代码库用的是HG,如果让我选当然更愿意用Git。大多情况下HG也已经够用了。
项目中开发的Python公共模块使用submodule的方式引入。采用submodule的方式对子模块的更改和更新都会比较方便。

JS等静态资源管理 Bower

作为一个Web项目自然少不了用到jQuery等第三方JS库。将这些第三方库全部下回来丢到代码库里一是让代码库变的不必要的臃肿,另一方面库之间的依赖关系也不容易管理。引入Bower后代码库要干净很多。

Web前端框架 Bootstrap

现在用Bootstrap的网站有些太多了,以至于Bootstrap让人有些审美疲劳,不过对于缺少专业前端的团队来说Bootstrap绝对是个利器。

JS/CSS压缩 django-compressor

使用django-compressor可以对JS/CSS进行压缩,加快网站加载速度。

表单 crispy_forms

如果是做互联网应用crispy_forms的作用可能不大,但是对管理后台来说crispy_forms非常棒。

django-impersonate

让你可以方便的切换成其他用户。在系统维护的时候会方便很多。

异常日志 Sentry

Sentry 是一个实时的事件日志和聚合平台,基于 Django 构建。Sentry可以将程序的所有异常自动记录下来,然后在一个好用的 UI 上呈现和搜索。如果你还没用过Sentry,强烈推荐一定要试试。

为什么没有用

  • React/Angular
    • 我们的应用场景还是传统的WEB应用,React/Angular可能更适合Web APP的场景,应用起来可能不能带来太多的便利性。
  • Webpack
    • Webpack 是当下最热门的前端资源模块化管理和打包工具。也曾想试试,不过我们这里前端部分还不算太复杂,冒然引入Webpack似乎也不是太必要。目前Bower+django-compressor已可以较好的满足我们的需求了。

Swift

最近在看Swift。已经很久没有这么“悠闲”的看一本书了,从头开始认真的看一本书的感觉还不错。
Swift给我的感觉是一门挺“特别”的编程语言。Swift是一门动态语言却加入了很多静态语言的特性,从一定程度上说Swift比很多静态语言还更严谨。

  • 在Swift里所有数据都是有类型。Swift有着强大的“类型推导”,因此很多地方是不需要指定数据类型的。也正是因为所有数据都有类型,相比大多脚本语言,编译器能检查出更多的问题,IDE的自动化程度也很高。
  • Swift和Objective-C采用ARC进行垃圾回收。以极低的性能损耗换取了接近全自动垃圾回收的便捷性。(注:官方宣称Swift比Objective-C要快很多)
  • Swift有这众多的动态特性以及语法糖,使用便捷且功能强大。

Swift中的?以及!

之前在其他语言中没有见过类似语法,初次接触时非常困惑。但一旦理解了之后就会发现这其实非常简单。
String?表示String或nil。首先要理解 String? 同 String 并不是同一个类型。 ?是一个封包的操作符号,将String封装成 ? 类型。(注:有点类似泛型,按照泛型的写法是 ?<String>
!则是解包操作,将String?转换为String。如果被解包的数据是nil,则会解包失败抛出异常。

Swift中的Dictionary以及NSDictionary

Swift中的Dictionary同NSDictionary可以通用(NSArray类似),但实际上它们并不是同一个东西。它们在混用的时候,编译器是需要对数据进行转换的。如果你代码中涉及大量的Dictionary/NSDictionary转换,很可能导致你的代码出现性能问题。(注:据说Swift中JSON处理速度慢就是该问题引起的)

django-lbutils

在Github上公开了不少项目,不过其中大多都算不上“开源”。在我看来开源也应当是一件认真的事情,需要对项目持续的维护,同时也需要提供必要测试用例及文档以保证项目的质量。
最近打算将自用的Django工具组件做个简单的整理然后发布了。为了让项目不要太“随意”,开始补测试用例及文档。因为是自用,测试用例和文档几乎为零。最初只是想简单的修葺,不想真正做起来工作比预期的要高出很多。整了许久代码中的注释依旧很不全,测试的覆盖率都还未达到80%,文档更是没开始动。因为文档还没弄完,所以项目也不算正式发布,如果你感兴趣可以先去看看django-lbutils
为了这个项目,尝试了一些之前经常看到却一直没怎么使用过的工具。

Tox

Tox是一个Python的自动打包测试用具,用来测试Python库在不同环境下的兼容性。因为是自用,本机环境跑起来是没啥问题。不过在兼容性测试时部分测试用例在Python3以及Django的某些版本下跑起来会有问题。为了搞定兼容性花费了不少时间。

Travis CI

Travis CI是一个在线的持续构建平台。Travis CI会检查你在Github上项目的变化,每当有新push的时候进行自动编译。我现在是每次改动后,直接在Travis CI看测试用例的执行情况。

Coveralls

Coveralls测试覆盖率查看工具。结合Travis CI,可在每次测试完成后将测试覆盖率信息推送到Coveralls。在Coveralls可方便查看当前的测试覆盖率。

Read the Docs

Read the Docs文档托管服务。可从Github抓取文档并自动编译好生成在线文档,目前几乎所有的Python库都将文档托管在上面。

用程序生成word文档(DOC)

很多程序都支持导出PDF文档,不过如果需要对导出文档进行编辑PDF就显得不那么方便了。就国内环境而言,导出word文档对有编辑需求的文档而言更为合适。
由于我使用python,因此这里只讨论python下可用的方案。目前找到的解决方案主要有下面几种

  • python-docx
    目前能找到支持word格式的库非常的少,就python而言只找到 python-docx 算是相对可用的解决方案。python-docx 的功能非常的弱,有很多的限制,比如不支持模板等。如果想生成复杂文档那就无能为力了。
  • POD
    POD是Appy框架的一部分,可使用ODF (Open Document Format)文件做为模板,并输出ODF格式的文件,并可调用LibreOffice将生成的文件转换成DOC等格式。相比python-docx,POD用于生成更为复杂的文档。但如果你需要动态生成一些复杂表格,POD可能会有些问题。
  • unoconv
    unoconv是个文档转换工具,可调用LibreOffice对文档格式进行转换。unoconv可将HTML转换为DOC格式。因此可先生成HTML,然后再将HTML转换为DOC。生成HTML对广大的WEB开发者而言无疑是轻而易举的,这也是我最终选择的方案。不过要注意的是用unoconv将HTML转换成DOC,遍地是坑-_-!。

    • 只支持有限的HTML语法。很多CSS语法根本就不支持,看到的和转换出来的效果完全不一样。解决办法:在LibreOffice中编辑文档,然后保存成HTML,然后对保存的HTML进行编辑。
    • unoconv的-t参数可传入.ott格式的文档模板。默认情况下LibreOffice转换出的表格的行高远大于文字的高度,更糟糕的是文字还是顶对齐,非常不美观。编辑个空文档,然后保存为.ott,转换的时候指定模板文件可解决该问题。
    • 生成的文档的左右边距不一致。恩…,这个我还没有找到解决办法。

单元测试的一些体会

以前发布开源项目时被国外的网友一阵鄙视,之后在自己的一些小项目中陆陆续续的有写一些单元测试。你一旦真正接受单元测试,并实行起来还是很容易体会到单元测试的优点的。只是尽管单元测试有很多优点,在国内的环境下写单元测试的公司依旧不多。
单元测试的好不是立竿见影,需要时间的累计。在最求“速成”的环境下,单元测试没法推行也是显而易见的。

单元测试的问题

  • 单元测试并是立即见效的
    单元测试代码的书写也需要花费一定的时间,有时还需要不少时间。如只是从一次测试的效果来看单元测试多半是不划算的。单元测试解决的是之后代码改动之后再测试的时间。如果时间进度紧张,即使知道单元测试的好处也难有心去写。毕竟要先解决燃眉之急,更何况某些代码的生命周期很短,还不足以让单元测试发挥价值。
  • 单元测试的基础测试数据需要积累
    一些复杂的业务系统业务数据之间的逻辑关系会比较复杂。比如你需要有基础的客户数据、员工数据后才可进行合同创建等功能的测试。如果没有前期测试数据的积累,你要直接给合同模块写单元测试。想到要将员工、客户等数据补上,立马就退缩了。(注:其实手动测试也要将员工、客户先创建好,只是因为之前手动测试时相关数据已创建好)

如何开始

  • 在一些小项目中先用,真正体会一下单元测试的优点。
  • 从项目的一开始就使用单元测试。单元测试的书写和项目的书写一样,都是一个循序渐进的过程。
  • 只写一些必要的单元测试,不要最求大而全。即使手动测试你也不可能测试到所有小概率情况,所以可以只写一些最必要的单元测试,让单元测试代码发挥最大价值。

douban的Android客户端

最近想给Android开发一个小应用,找了一些Android应用来做参考。感觉豆瓣客户端挺有意思。

豆瓣为小组、活动等功能开发了独立的客户端。在使用的时候有时候会在APP里直接调用douban的WEB站点或是WAP站点。Facebook放弃HTML5被看成是原生APP的一次巨大胜利。但是WEB APP在跨平台以及开发的便捷性方面都有着一定的优势。在人力资源不是太过充足的情况下采用原生+WEB的开发模式可能是个不错的选择。

在用户使用频繁对用户体验要求高,性能敏感的地方使用原生开发。一些相对简单的页面直接使用WebView即可达到原生应用同样的体验,对这些页面直接使用HTML开发。还有些用户不太常用的功能在前期可以先调用WEB版的原始页面。

PS:

  • 就目前而言用HTML5开发移动应用很难提供很好的用户体验。但我相信技术在发展,HTML5还将是趋势,主要问题还是时间,2年?
  • Android手机上Metro风格的应用越来越多了。苹果将模物化设计做到了极致,接下来是Metro设计极简的逆袭?

随机迷宫生成算法

在线迷宫游戏地址: [email protected]
项目地址: [email protected]

最近研究了下迷宫的生成算法,然后做了个简单的在线迷宫游戏。游戏地址和对应的开源项目地址可以通过上面的链接找到。开源项目中没有包含服务端的代码,因为服务端的代码实在太简单了。下面将简单的介绍下随机迷宫的生成算法。一旦理解后你会发现这个算法到底有多简单。

  • 将迷宫地图分成多个房间,每个房间都有四面墙。
  • 让“人”从地图任意一点A出发,开始在迷宫里游荡。从A房间的1/2/3/4个方向中的任选一个方向前进。在从A房间走到B房间的过程中,推倒A/B房间之间的墙。
  • 如果方向x对面的房间已经走过,则选择其他方向。如果所有方向的房间都已经走过,则退回上一个房间看是否还有可选道路。
  • 走到真正无路可走时,说明已经走过了所有房间,迷宫也生成好了。

下面是该算法的python实现(核心部分)

注: 由于采用该方法生成的迷宫道路的分支数量并不是太多,coffeescript版在生成迷宫的过程中增加了随机处理,对应算法也稍微复杂一点点。