iOS开发(一):真机调试

苹果真机调试是比较麻烦的,需要代码签名,主要的作用就是确保程序是苹果认证的开发者开发,下面列出主要的步骤。

购买开发者帐号

之前iOS开发者帐号和Mac开发者帐号需要分开购买,现在都合并为Apple Developer Program了,所以只需要出一份钱了。打开 https://developer.apple.com/programs/, 点击右上角Enroll

点击start your enrollment

选择你是个人开发者还是企业,选择个人开发者

然后就按照步骤完成购买,一般需要几天才能审核通过。

创建证书请求申请 (Certificate Signing Request)

选择 “Certificate Assistant”,然后点击 “Request Certificate from A Certificate Authority.”

填入你的Email 名字,选择Save to Disk, 这是会生成一个CertificateSigningRequest.certSigningRequest 文件

创建开发者证书

登录开发者中心,选择证书Development, 然后点击右边添加

选择Development—>iOS App Development

这一步上传你刚才的CertificateSigningRequest.certSigningRequest 文件,点击Generate

Download 你的证书,然后双击就会加入系统

注册你的设备

如果不知道UUID, 打开iTunes, 双击Serial Number

创建App ID

看说明创建你需要的APP ID, 主要是Bundle ID, 一般我们类似这样确保唯一 com.jackwang.nbapp

创建Provisioning Profile

选择iOS development, 点击继续,然后选择你刚的App ID,继续,选择要包含的开发者证书,点击继续,选择要包含的设备, 随后就generate你的provisioning profile.

找到对应的Profile 下载后双击即可。

项目设置

设置项目的Bundle ID 为之前创建的APP ID

然后选择你对应的Code Sign

真机调试

插入你的设备,选择你的设备,点击运行,就可以真机调试了。

领域驱动设计系列(六):CQRS

CQRS是Command Query Responsibility Seperation(命令查询职责分离)的缩写。 世上很多事情都比较复杂,但是我们只要进行一些简单的分类后,那么事情就简单了很多,比如我们把人分为男人和女人,也可以把人分为大人和小孩,还比如,我们说国内和国外,城市和农村。经过一些类似这样的划分,我们的对不同的类就有不同的关注。 这样我们就会有妇女儿童医院专门让女人生孩子,而不会建一个医院让男女都生孩子。

##CRUD

CRUD (Create, Read, Update, Delete) 增查改删,我们很多系统都是对数据的增查改删。过去我们很多系统比较简单,基本上增加的数据就是你要查询的数据,所以很多时候其实一个简单的Excel就能搞定。 而且增删改查也足够的简单,所以我们很多系统分层后在数据层Repository里仍是对单表的增删改查,这样对不少的系统都符合。

但是,系统规模稍微大一点,我们都知道我们的数据库里的数据模型很难和我们业务层需要的模型一致。 于是我们引入了Domain Model, Repository里就会做Domain Model的来回转换

同时我们在UI层要的数据,往往又和具体的Domain不同,这个时候我们又要定义一个ViewModel. 而这些ViewModel又是组合不同的DomainModel得来。

传统的代码里的问题:

  • 领域里有很多分页和排序,尤其是Repository里
  • 查询的方法里暴露了很多不应该有的领域模型的属性,因为需要组装DTO
  • 如果使用ORM,预加载了很多数据以提高性能,但是占用大量内存,而且需要维护这些数据。
  • 加载组合庞大的数据,比如页面是需要一个名字,我们也会把整个User数据取出来。

重要的原来把数据混在一起,复杂的查询相当难以优化。 尤其是数据库出现大量的Join 系统性能极速下降。

最重要的是我们把读写都放在了一起,显得责任不够清晰,代码也更复杂了一些,比如读数据是不太关心事物的,读数据是不需要验证的,只有写的时候才需要做数据校验,这也比较符合SRP(单一职责),但是用CRUD的思维是我们全都混在了一起。

CQRS

我们仔细看CRUD, 其实可以更简单的分为读(R)和写(CUD), 我们想想大部分情况都是,一个方法要么是执行一个Command完成一个动作,要么就是查询返回数据。 比如我们回答问题的人不应该去修改问题。

当我们读写分离后,我们对应的代码也会分离。

数据存储

写的一端需要保证事物,所以一般数据存储为第三范式,
读的一端一般都是反范式可以避免Join操作,这样我们只需要把数据存储为第一范式

扩展

大部分的系统里写数据要远远少于读数据,并且一般都是每次修改很少的一部分数据,所以在写这端扩展都不是特别紧迫,读数据基本都远大于写数据的次数, 所以扩展就更重要。 我们很难建立同一个Model 既能给写数据和读数据公用而且能够保证性能都比较好的。

查询端

查询端由于只是读数据,那么所有的方法应该都是返回数据,而且返回的数据就是界面直接需要的DTO, 这样可以减少传统的方法中把DomainModel映射为ViewModel或者DTO. 同时可以减少传统的领域里的一些混乱。

写端

由于把读分离出去,所以我们就只关注写,那么我们写这一段需要保证事物,数据输入的验证,另外一般写这一端都不需要及时的看到结果,所以大部分都需要一个void方法就可以,那么让我们系统异步就更加方便。这样使系统的扩展性大大增强。

代码更容易集中处理

当我在一些系统中使用CQRS后,很多地方代码大大简化,比如我所有的写操作都是一个Command, 那么我定义一个UICommand, 让所有的Command集成这个,那么我可以在这个UICommand里做一些通用的处理,比如Validation

同时我只需要定义一个CommandBus, 然后把对应的CommandBus分发到对应的Handler里(我前面几篇有实例代码),那么代码的耦合度大大降低。

代码分工协作更容易

由于读这一端直接读数据,而且对数据库没有任何操作,那么我们可以根据UI定义对应的DTO, 那么开发的时候我们可以用Mock数据,至于数据怎么存的,那么我们随后只要添加一层Thin Data Layer即可,实际上当我们使用CQRS后,很多时候我们把数据保存的时候都直接保存为Denormalize的,那么从数据里直接查询单表的数据就可以拿到页面需要的数据,大大提升读取数据的性能,同时代码也会极其的简化,开发读这一段代码的开发人员甚至都不需要对业务有太多了解。

实现

简单的实现

使用的Event后

使用了Event Source 和Service bus后

  
 DDD

.Net WEB 程序员需要掌握的技能

最近公司里有新入职的员工,根据个人的理解和经验,我来列一下一个.Net WEB程序员需要掌握的知识

基础部分

  • C# 基础语法
  • OOP的概念,面向对象的理解
    • 继承
    • 封装
    • 多态
  • ASP.NET MVC (Web Form 用的越来越少,如果你不熟悉,可以不看)
  • JavaScript
    • 基础语法
    • 如何在HTML里使用JavaScript
    • 常用Dom 操作
  • SQL Server
    • 常用T-SQL 增删改查
    • SQL Managment studio 常用操作
  • jQuery 常用API
  • HTML
    • HTML 所有标签的语义,什么时候用什么标签
  • CSS
    • 常用CSS的知识,如何在HTML使用
    • 常用的布局
  • Bootstrap
  • C# 代码规范
  • CSS 代码规范
  • JavScript代码规范
  • Git的基本使用
    • 常用命令使用
    • 获取代码
    • 解决冲突
    • 提交代码
    • 新建分支,合并分支
  • Github
    • 帐号设置
    • SSH 配置
  • 三层设计
    • UI
    • Service
    • Repository
    • 事务的代码实现

提高部分

  • 单元测试

    • Nunit
    • Moq
    • 单元测试的基本知识 Arrange, Action, Assert
  • 依赖注入

    • 面向接口编程的理解
    • Castle Windsor
      • 与ASP.NET MVC 的集成
      • Installer
      • 不同的生命周期
  • Entity Framework Migration

  • JavaScript

    • 闭包
    • JavaScript 的面向对象
      • prototype
      • JavaScript的动态特性
  • AngularJS

  • .NET

    • Async
    • TPL
    • WCF 基本使用
  • Debug

    • VS 常用Debug 功能
    • Firebug / Chrome Developer
    • Fiddler
  • 常用的快捷键

    • windows
    • Visual studio
    • Resharper
    • Chrome

进阶部分

  • 常用设计模式
  • 常用设计原则的理解
    • S.O.L.I.D
    • DRY
  • Repsiotory Pattern
  • Unit Of Work
  • HTTP 协议
  • 前端常用的性能优化
  • .Net 常用性能优化的方法
  • RequireJS
  • Async.js
  • MVC 模式
  • MVVM 模式
  • SignalR
  • PowerShell

深入部分

  • AOP
  • 领域驱动设计DDD
    • CQRS
    • NServicebus
    • Event Sourcing
  • Event Driven
  • MSMQ/RabbitMQ
  • Load Balance
  • Memcache
  • NoSQL
    • MongoDB
    • Redis
  • Load Balance
    • Cache 问题
    • Session 问题

敏捷

  • SCRUM
  • TDD
  • BDD
  • 使用一个敏捷管理工具 JIRA Scrum/Kanban, Trello, Target Process, Pivotal Tracker, 国产的WorkTile应该也不错
  • XP
  • 持续集成 TeamCity
  • Grunt

扩展部分

  • Node.js 服务器端

  • Socket.io

  • Mobile APP

    • Hybrid APP Phonegap
    • Native APP
      • iOS Objective C /Swift
      • iPhone/iPad development
      • Xamarin Cross-platform development
  • 买一台Mac

    • 熟悉Mac 常用操作
    • 熟悉Shell
  • 学一门动态语言,比如Ruby

  • WPF 熟悉一下最新的Windows Desktop开发

推荐书籍

  

当我谈 "加班有罪" 我在谈什么?

前言

PS. 本文只描述IT行业。

博客园果真人气比较高,我之前准备写个 “领域驱动系列”,然后感觉大家不感兴趣,看来用的人不多,所以一直没动力续,但是昨天写了 加班有罪, 却收到了很多个赞,让我感到有点意外。

我今天看了很多评论,感觉很欣慰,大家其实对加班的看法和担忧其实都是正确的,但是很多人可能忽略了一些前提,如果盲目的下班就走,数着秒下班,那我写这篇文章就有罪了。

为什么加班是有罪的,加班有罪 这篇文章已经做了较多的阐述,那么光说加班有罪是不够的,公司或者老板可以提倡不加班的文化,但是如何才能做到不加班?直接一刀切,到六点就赶大家走这样肯定是不够的,可能很多公司如果现在立马这么做,可能就倒闭了,员工可能还得找工作。

加班有罪的对立面也不一定是正确的

我们很多人想问题,可能是非黑即白,我们提倡不加班,但是我们要想如何不加班,如果我们技术水平低,别人1个小时做完的,你可能一天也做不完,如果你写的程序员出现了紧急的bug, 如果你上班时间在看电影,QQ等,你再不加班把任务做完,哪个公司敢用你? 我前篇文章说过,并没有说你一分钟都不能多待,比如每个月有8个小时的加班,我认为都是正常的。

如果你上班时间也没有好好干,那么不加班更有罪,因为你是上班时间休息了。

如何不加班?

我们实行敏捷很多年了,但是同样有很多人一说到敏捷,就只知道SCRUM, 没有抓住敏捷的本质。就算过程用SCRUM, 那么其实也就是一个管理层或者从上到下的东西,但是并没有对程序员每日的工作有多大的帮助。我们同样需要很多的工程实践,技术成长等来提高我们每天的工作效率和质量。

那么我认为从程序员的角度,如果你想理直气壮的准点走人,那么一下几点可供参考。

  • 工作时间要保证

    我个人觉得上班时间工作是天经地义的,可能有的人羡慕Google等有更宽松的时间,羡慕很多公司都不需要工作8小时,但是前提先想一想,我们是否有那些公司的工程师的能力和效率,如果没有,还是在上班时间好好工作,如果有,与其羡慕,不如赶紧加入你羡慕的公司,前提是人家要你。

  • 上班的时间要用来工作

    我们很多人上班时间一会儿刷下微博,一会儿看看微信,尤其是QQ闪个不停,还有号称是要学习的,加了一堆技术的群,美其名曰学习技术,我也加了些群看看,实际上发现基本都在里面灌水。原因很简单,有的时候问个问题,基本问问题的人描述不清,别人怎么回答? 问问题,你就不能上StackOverflow吗? 原因是自己只会用百度,好吧,我无话可说。

  • 进公司隐瞒自己技术水平

    现在IT行业有个怪圈,我觉得迟早得拨乱反正,本来作为一个程序员答答题,上机写写程序等是非常正常的,但是你要是这样来招人,很多人就很不乐意,说我没那么多时间,我只给公司请了2个小时假来面试,你看着他的简历应该是会的样子,这就极其考验面试官,很多时候越是写程序不行的,越是最比较厉害,尤其是看到概念比较多的。你还真不容易判断出他不行,但是一进来,你发现就完全不行,ASP.NET 你让写个HttpModule不会,MVC你让统一地方处理一下异常不会,你说做权限控制,他写不了一个Filter, 你说WCF 想扩展功能写个Behavior 他说我们用的时候就是顶一个接口标记Contract, 深入的没看过,总之各种不行。然后你布置个很简单的任务,就是说一个高级程序员必须会的,他得花时间再学习,然后才能有产出,你说怎么办?上班时间都在学习,你说活还干吗?

    针对上面的情况,一种方案是直接不用这个人,第二种就是要争取个人同意让他多干一会儿,不然你还得背上黄世仁的名,其他人看到你说的不加班是假的。

  • 降低自己的薪水,给自己留学习的时间

    我们有的时候,确实进来后,发现周围的人都比自己强,而自己的薪水也和他们差不多,如何衡量,就是如果你的薪水比市场其它公司要高不少,而且你进来后发现你比别人差不少,就证明你要多了,这样公司可能按同级别薪水的人要求你,你的产出肯定是比别人少,这样你想完成任务,就得加班,那么就到了我说的恶心循环,最好的方式就是主动降点薪水,然后留下班后的时间给自己学习,公司也不会对你要求太多。其实这样,你的收益更大。

  • 提高工作效率,改变工作方式
    我们很多人,做事方式和方法有问题,比如连需求都没搞清楚,就开始写代码,然后删了又删,改了又该,这样很简单的一个东西,必然要做很长时间。有的人代码写完后自己下次都要想很久才能知道啥意思,这就需要我们多改进自己的工作方式,多向效率高的程序员学习等。 同时有很多东西提高效率,比如你是否可以并行的做一些事情来提高效率,比如使用Resharper就可以大大提高效率,写单元测试可以避免你为了测一个方法每次都要把系统跑起来debug呢?持续集成可以帮助你把你修复bug更靠近你产生bug的时候等等。

  • 下班后多学习

    上篇文章我也提出了,不加班不代表下班后不学习,我招人的时候,经常问的一个问题,就是你如何提高自己技术水平,很多人回答了我一个无法反驳的答案就是:”通过做公司的项目学习”,但是这是远远不够的,一般如果只是这样,除非你天赋异禀。我是不相信你这样就能够成为大牛的。 比如我们需要了解工程实践,了解新的技术,了解一切帮助提高质量和效率的东西,了解一切提高沟通和管理的书籍等。

  

加班有罪

前言

加班在很多行业司空见惯,于是 “过劳死” 开始为更多的人关注,
IT行业尤为严重,但是普通职员再关注也起不了多大的作用,老板让你加班,或者是潜规则让你加班。我们从几年前就开始不提倡加班,我们也基本没加班,但是最近做了一个项目,出现程序员加班,甚至我自己本人都投入了很多下班后的时间,让我又一次思考加班的问题。作为一个分公司经理,我鼓起勇气写下此文。

脑力劳动不应该加班

加班无非就是增加工作时间来增加工作产出,比如机器制造,我们让机器多转几小时,肯定多生产一些产品,比如我们让人搬砖,多搬几个小时,虽然最后比较累,无非就是搬的慢了,但是还是能多搬一些。但是这些可以说基本都是机械性的工作。

但是,软件行业其实是创造性的,同时很多时候依赖高度的抽象,加班会持续破坏创造力,我们想想,我们让孩子连续学8个小时的数学课试试,显然我们知道那不合理。而且我们知道脑力劳动比体力劳动很多时候更累,更需要休息,这个本来是显而易见的,我们每个人都切身体会,但是我们很多老板,很多客户都想不明白。

加班的恶性循环

这个场景是否遇到过?

晚上加班到11点,然后感觉很饿,然后外面饭店都关门了,只剩下肯德基了,于是打了个车去肯德鸡,由于好饿,买了个全家桶, 然后回家太累了立即上床睡觉,然后你发现吃的太撑了,睡不着,最后迷迷糊糊的睡着了,此时已经是半夜三点了,然后你做了个梦,梦见周末你在玩,老板打电话让你赶紧回去加班,这个时候闹铃想了,第二天该上班了,由于昨晚吃的太撑,早饭实在不想吃了,你飞一样赶上公交车或地铁,座位别人坐完了,车上全是人,一个女的挤了你一下,你抬了一下头用你那睁不开的眼睛看了一下他,那个女的觉得你很猥琐,恶狠狠瞪了你一眼,你心里正想着,老子眼睛都睁不开了,都累成马,还有心情看你? 你正郁闷,听到一声:”软件园站到了”,你就又开始了下一天的循环。

我们看到,如果上面的场景持续发生,先从你的身体开始,你的肚子开始圆了,作为男人的你胸部开始变大,头发开始变少,颈椎病也来了,同时,因为你天天加班,你反而不习惯周围的人不加班了,你开始觉得你的家人都很懒,你的客户都很懒,你的朋友都很懒,你的同事都不错,因为和你一样。最后你挂了,留下了大千世界给其他人。

加班导致创造力低下

我们看到很多人工作勤勤恳恳,看似非常努力,但是却很难做有创造性的工作,我们看到很多学生学习很幸苦,但是最近几百年中国都没有颠覆新的发明和创新,我们一直引以为傲的 “四大发明”,离我们都比较远了。当然国外也好不到哪里去,最近30年几乎没有什么大的创新。 飞机让我们飞上了蓝天,蒸汽机使我们有了火车,电话让我们更快的交流,互联网让我们有了更多的信息互通,等等这些都快一百年了。

我们人什么时间可以自己飞上天? 我们生命如何延长100年? 我们可以不睡觉吗? 我们如何只吃少量的食物能够存活?我们必须用大规模使用石油和天然气? 我觉得至今没有解决的原因,就是我们没有那么多的时间来思考和创造。

回到软件行业,加班使我们不段的做机械工作,不断的复制拷贝,我们大脑被这些东西塞的慢慢的,我们哪有时间去思考更好的解决问题的方法?我们哪有时间去学习何成长?

为什么说加班解决不了问题?

加班的主要目的是增加产出,但是我们大家最终选择了这种简单粗暴的方式,就是加班来增加产出,但是想一想,我们每天工作8个小时,就算一天不吃不喝不上厕所,我们也就是24个小时,产出最大也就三倍。

我们都知道,一个优秀的工程师是一个普通工程师效率的10倍,甚至百倍。那么我们就需要考虑的是,我们其实是要提高工作效率,也就是8个小时之内提高效率,比如,我们使用自动化,我们使用快捷键,我们使用持续集成等等这样的方式都可以提高效率,而加班却给大家造成了恶意引导,让大家觉得我总是可以通过加班来完成工作,而忽略了我们本质是要提高效率。如果我们一开始的出发点就是我们不要加班,我们提高效率,工程师自然就会更多的考虑8小时之内的效率,比如使用番茄工作法,比如不要写会儿代码,看会儿微信,就会想到单元测试保证质量避免返工等等,而真正提高了效率,我们个人才算是成长了。

不加班不代表下班后不学习

当我强调不加班的时候,很多人开心的露出了笑容,但是如果这样,那可能就完了,不加班不代表你不提高自己,不加班需要我们提高效率,如何提高效率,那就要不断找新的方法,不断的去学习,不断的提升解决问题的方法,不但的反思回顾。

下班后需要看书,IT人员,比如英语是不是需要学习? 技术需不需要学习?工程实践是不是需要学习? 架构,算法,设计模式,Clean Code等等都需要学习。同时,也需要看一些非技术之外的书,我们可以看到很多技术图书作者使用大量的比喻来描述问题,如果你不观察生活,你不读书,如何用这些简单的生活场景描述复杂的技术呢?

不加班不代表你的表的闹钟定到下午6点,我们提倡不加班,但是不代表你一分钟都不多干,你和单位划清界限,你是不是把今天的工作任务完成了,或者你至少把手上的单元测试通过了,你至少要把你今天的代码Commit了吧。所以,一般你一个月加班总时间不超过8个小时,我觉得应该是OK的。

今天不加班,各位老板你敢吗?

不加班需要勇气,需要能力,我们大家都顶着各样的压力在加班,但是我想说,我们这个世界不是东西太少而是太多了,美其名曰我们选择多,实际上我们得到的东西质量都下降了,企业之间相互抄袭,导致价格不但下降,利润不断降低,整体服务质量不断下降。各种创新越来越少。

一个没有创造力的行业是不长久的,总之,我觉得越来越多的公司会开始主要到提高员工工作效率,而避免加班,尤其是软件行业,谁敢抛弃短期利益(可能会丢掉一些项目),但是长远来看会大大增加企业的竞争力,因为员工成长,全员创造一定会极大提升企业的价值,最终一定是名利双收。

如果你觉得我文章写的很有道理,请推荐给你的老板。

  

欧美软件外包系列 (二): 谁说外包不需要技术

前言

由于之前一些外包公司对外包行业造成了一些不良的印象,其中很多程序员对外包的误解是就是外包缺乏技术,或者说外包行业里面学不到技术,我不知道别的外包公司,但是在我们公司,我觉得外包很多的项目对技术要求都不低。

技术

其实不管是外包还是非外包,都是要做项目,说到底就是产品,这些产品可以是一个商务网站,可以是一个企业内部的系统,也可以是是一个APP等,从我接触的项目来说,形形色色的项目都可以外包,要么是全包,要么是半包。

我们想想只要是一个软件产品,怎么会不需要技术呢? 总不能动动嘴皮子就出软件了?站在最终客户的角度,一个好的软件产品怎么样,他们需要的就是怎么样。当然,有的情况下,没有找到好的合作方式或者没有合适的价格,会经常出现一些凑合的产品或者失败的产品,这个后面我们会谈到如何避免,这里我们就是要说外包不是没技术。

外包(或者说软件项目)常常驱动一些技术

拥抱变化

更快的拿到 “WHAT TO DO”

软件业里流行一句话,就是:“不变就是变化本身”,所以需求会经常变化,尤其是外包或者是离岸外包,业务人员没有和开发人员座在一起,这样导致变化的成本就更加增加,另外我们需要把业务人员把需求转给开发人员这之间的时间尽量缩短,就像TCP/IP一样,我们需要两端数据传输 “快速、完整、准确”,那么我们就需要像很多办法,比如我们就用到比如BDD(Behaviour Drive Development), 我们就需要用到像NSpec, NUnit这样的东西。

更快的反馈 “What We Did Is Right Or Not”

同时,我们需要客户尽快的反馈,我们就需要用到自动集成的技术,我们就要用到Build系统,所以我们就用到了比如TeamCity, Jekins, Grunt, NAnt等等。我们需要解决 “防火墙”等问题,我们需要使用云比如Azure, Amazon等。

适应变化

更好的架构

为了支撑变化,我们需要根据不同的项目来设计好的架构,什么是好的架构呢? 就是“一点也不多,一点也不少”,每当增加新功能的时候,我们不用改太多代码,甚至我们只增加代码,不影响原来代码,这不就是OCP(开闭原则)吗? 我们希望写过的代码能够更多的重用,已有的代码能够更稳定,于是我们就需要分层设计,我们就需要多层的架构,我们就需要解耦,因此我们就用到了比如 MVC, MVVM, Domain Driven Design, Event Driven, CQRS, Event Soruce, Message Queue等等。

可靠的质量

为了提交高质量,我们除了需要一定的过程保证之外,同样需要很多技术的支撑,我们如何对我们提交的代码质量有信心呢?
我们需要Unit Testing, 我们甚至需要引入TDD, 我们需要引入一些自动化测试工具来做回归测试,比如Selenium, Watin 等。为了很好的进行单元测试,我们必须要面向接口编程,我们需要去掉系统里的New. 我们因此需要使用依赖注入比如Castle, NInject, 或者Unity等。

整洁的代码

为了更方便增加新功能,那么我们要更容易阅读之前的代码,这就要求我们不要产生 “Legacy Code”,因此就需要考虑什么是Clean Code, 因此我们就必须要学习S.O.L.I.D原则,我们就需要学到重构等相关的知识。

总结

学无止境

说到底,就是给客户提交高质量的软件,而且是高效率,也就是做出好东西,越快越好。

软件行业,聪明的人很多,他们不断在生产新的东西(语言,框架,工具)来帮助程序员提高软件的质量和效率,那么我们要想高质量,高效率做出软件,不管在哪里,我们都需要这些知识和技术。

外包更能学技术

我们在一些产品公司,我们其实很难去使用一些新的技术,原因如下:

  • 产品已经设计完成
  • 技术选型已经确定
  • 遗留代码太多
  • 项目的管理人员不拥抱新技术。

但是在外包公司,更能学技术。原因如下:

  1. 接触项目多,因此可以在不同的项目里学到多种技
  2. 同时针对不同的项目,会思考多种的架构方式。
  3. 如果和国外团队合作,可以看到很多优秀的代码。
  4. 欧美常常比较先引入一些新技术。
  5. 欧美常常比较先引入一些开发模式。
  6. 逼迫你提高英语,你能看到更广阔的世界。

最后,列一下我们现在的.Net项目用到的一些技术和开发方法。

####过程

  • SCRUM
  • Kanban

开发方法

  • TDD
  • BDD

架构

  • MVC
  • MVVM
  • SOA
  • Domain Driven Design
  • Event Driven

技术

  • C#
  • EntityFramwork, NHibernate, Dapper, NoSQL
  • ASP.NET MVC, ASP.NET Web API
  • WCF, Restful
  • jQuery, AngularJS
  • Nunit, NSpec, Selenium
  • Git, Github
  • TeamCity, PowerShell, NAnt, Grunt
  • Database Migration
  • Message Queue, NServicebus
  • Castle
  • Event Source, CQRS, DDD

所以,谁说外包无技术? 看你怎么做而已。

想加入我们吗? 发邮件到 wangds@shinetechchina.com.

领域驱动设计系列(五):事件驱动之异步事件

前言

上一篇讲了事件,以及为什么要使用事件,主要是为了解耦,但是有同学就问了,同步如果订阅事件的人太多,比如13亿人都关心上头条的事,那么RaiseEvent得等13亿人都处理完,那得多久呀,从此再也不敢发事件了。
举个例子,你在网上下单,下完单要通知库房,甚至要通知供应商补货,如果都是同步的话,消费者还不等急死呀,实际上你在电商网站上下个单, 一般你很快就能到订单页面,那个页面告诉你:“兄弟,订单已经创建成功,订单号是xxxxx-xxxxx-xxxx-xxxx,你的订单已经提交到库房” 等。然后你就很快了的下另一单了。好吧,
提问的同学,说好的妹子呢?

实现思路

发出事件

1
2
3
4
5
6
7
8
9
10
11
12
  public void Head()
{
var NewsPaper = new NewsPaper("南都娱乐");
NewsPaper.WriteToHeader("汪峰");

RaiseEvent(new HeadedEvent {Name = "汪峰"});
}

private void RaiseEvent(HeadedEvent headedEvent)
{
EventBus.Publish<HeadedEvent>(new HeadedEvent { Name = "汪峰" });
}

所以我们只需在代码里RaiseEvent就可以了。

订阅事件

其实很简单,因为我们要实现的是同步的事件,我们只需要找到所有处理这个事件的实现类,然后调用所有就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public interface IEventHandler<TEvent> where TEvent : Event
{
void Handle(TEvent e);
}

public class HeadedEvent:Event
{
public string Name { get; set; }
}

public class GuoJiZhangMotherEventHandler : IEventHandler<HeadedEvent>
{
public void Handle(HeadedEvent e)
{
Console.WriteLine(e.Name+", Are you kidding me?");
}
}

public class PiMingEventHandler:IEventHandler<HeadedEvent>
{
public void Handle(HeadedEvent e)
{
Console.WriteLine(e.Name+", Guo Ji Zhang is your last wife?");
}
}

我们可以看到正真的事件协调者是EventBus, 之前的代码如下是同步的。

1
2
3
4
5
6
7
8
9
10
11
public class EventBus
{
public static void Publish<T>(T concreteEvent) where T: Event
{
var handlers = _container.ResolveAll<IEventHandler<T>>();
foreach (var handle in handlers)
{
handle.Handle(concreteEvent);
}
}
}

为了提高性能,我们可以先来第一步改进

1
2
3
4
5
6
7
public void Publish<T>(T @event) where T : Event
{
var handlers = _eventHandlerFactory.GetHandlers<T>();

handlers.AsParallel().ForAll((h)=> h.Handle(@event));

}

我们可以看到,现在并行处理可以大大加快速度,但是有两个问题,第一个问题就是没有处理异常,所以让我们加上异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 public void Publish<T>(T @event) where T : Event
{
var handlers = _eventHandlerFactory.GetHandlers<T>();

handlers.AsParallel().ForAll((h)=> HandleEvent<T>(h,@event));

}

private void HandleEvent<T>(IEventHandler<T> handle, T @event) where T : Event
{
try
{
handle.Handle(@event);

}
catch (Exception e)
{

// Log the exception, as the caller don't care this
}
}
}

第二个问题,就是我们虽然用了并行加快了速度,但是还没有正真实现异步,整个程序还是等所有Handler处理完才返回。

1
2
3
4
5
6
7
public void Publish<T>(T @event) where T : Event
{
var handlers = _eventHandlerFactory.GetHandlers<T>();

handlers.Select(h => Task.Factory.StartNew(() => HandleEvent<T>(h, @event)));

}

这段代码执行完,尽然发现Handler没有执行,好吧,原因是IQueryable的延迟执行,所以我们需要调用一下ToList

1
2
3
4
5
6
7
public void Publish<T>(T @event) where T : Event
{
var handlers = _eventHandlerFactory.GetHandlers<T>();

handlers.Select(h => Task.Factory.StartNew(() => HandleEvent<T>(h, @event))).ToArray();

}

好了,我们就这样轻易的实现了一个AsyncEventBus, 是不是感谢.Net的强大?

总结

这里还只是一个系统内部的Async, 如果涉及到系统之间的交互,这个就不行了,而且如果异步处理有错误,我们就会有信息丢失,所以需要更健壮的异步事件处理系统,这个后面再讲,但是一般的系统我们只需要把出错的时间记录下来,然后再看要不要处理就可以。

另外,异步要处理的东西很多,比如处理完毕后,如何通知用户,还是让用户刷新? 我个人建议,一般情况下都不要用异步,只有在真的需要的时候再用。

  
 DDD

欧美软件外包系列 (一): 正确看待外包

前言

做欧美外包8年了,积累了很多对欧美外包的一些经验和认识。由于看到很多人对外包产生了很多误解,有很多发包方也在大家的误解中错误的看待外包团队,所以想让大家对外包有一个正确的认识。 由于我一直做的都是欧美外包,所以主要是在谈欧美外包。

欧美外包简介

欧美外包其实就是欧洲和美国的软件外包,主要是欧美发达国家和离岸顾团队的一种软件协作。

对外包的误解

国内很多的程序员一谈到外包就色变,什么没完没了的加班,做完项目就走人等等,最主要的是说外包项目没技术。

传言

我个人觉得这个不能全怪程序员,由于早期的外包,以及项目管理的方式都违背了一些软件开发的本源,导致出这样的一个结果,其实这些问题,在非外包公司里更严重,也同样存在,而软件行业又是外包的主要一个领域,就显得大家格外关注,而且程序员又是喜欢上网的一群人,所以对一个事情的传播非常快,而且年轻人居多,不乏一些FUD的人员。

国内某些不良外包公司

我们公司确实有一些程序员的上一家公司里是这样的,这样的公司大概是这样的:

  • 这个公司主要是做国内的外包,老板对软件没有什么概念,认为做软件跟盖楼是一样的。所以,有项目就堆人,找最便宜的人,项目不能按时完成就加人,我时常对这种情况,想说:“老板,你是黑色会吗? 做项目还是打架,靠人多?”

  • 这样的公司做项目时,第一要素是最大的利润,也就是最大化的从客户那里赚取利润,赚自己的钱,让客户无钱可赚,赚员工的钱,让员工够活命就行了。

  • 由于是搞房地产的,或者是有几个搞房地产的朋友,觉得自己也要搞个软件业的房地产,找一个技术好点的,剩下的都是能多便宜就多便宜,是不是像建筑行业从设计院设计个图纸,找个监理,剩下全都是找便宜的人? 但是软件行业是不一样,每一个软件就像每一片茶叶一样,哪那么容易相似,就算茶叶一样,泡茶的人也不同呀,亲! 我把这样的架构师叫做海鸥,在海上拉一坨翔后,飞走后你再也找不到了(你想想你会在一个地方看到同一个海鸥两次吗?)。 所以我们很多人就基于已有的设计来填空,不管尺码合不合适,也要硬往里面塞,结果能好吗?

我想个中痛苦你们经历过的人有共鸣。

欧美外包

其实欧美外包在这几年已经有了很大的进步,也越来越多的人愿意做欧美的外包,进步如下:

  • 发包方对软件的意识提高,不在把软件看做简单的一个产品发包出去,而是当做一个软件。
  • 敏捷开发的流行,在欧美国家有更好的认识,更多的发包方知道软件写作的重要性,而不是只是一开始给个需求。
  • 发包方愿意花更多时间参与,我们知道软件开发客户更多的协作的重要性,因为很多东西在开发过程中才能发现和改进。
  • 发包方里有更多人了解软件开发,开始接受重构这样的一些工作并且愿意为之付费。
  • SCRUM或者Kanban让异地的团队更好的协作

所以和欧美软件公司合作,你可以学到很多正确的做软件或者产品的方法。

总结

根据我的经验,欧美的软件公司更早,更多的开始使用正确的软件开发方式和对软件行业的正确认识,欧美很多国家软件从业者很受其它工作者的尊重,而中国很多的程序员还被称为 “程序猿”,“码农”,“IT男”,非诚勿扰你要敢说你是程序员,我想肯定是关上灯留下一屋子黑。(不过很多姑娘被别人留下一屋子黑后,还是觉得程序员挺好的)。

领域驱动设计系列 (四):事件驱动下

前言

上一篇说到为什么要使用事件驱动,但是只有概念是不够的,我们要代码呀!记得脸书的老总说过: “Talk is cheap, Show me the code!”

实现思路

发出事件

事件顾名思义就是一件事情发生了,比如我要上头条,这不是一个事件,这事一个Command, HeadCommand, 而我上头条了这就是一个事件HeadedEvent,事件就是一件事情已经发生了。 好,先来一个伪代码

1
2
3
4
5
6
7
public void Head()
{
var NewsPaper = new NewsPaper("南都娱乐");
NewsPaper.WriteToHeader("汪峰");

RaiseEvent(new HeadedEvent {Name = "汪峰"});
}

所以我们只需在代码里RaiseEvent就可以了。

那么如何订阅事件

其实很简单,因为我们要实现的是同步的事件,我们只需要找到所有处理这个事件的实现类,然后调用所有就可以了。

1
2
3
4
5
6
7
8
9
public interface IEventHandler<TEvent> where TEvent : Event
{
void Handle(TEvent e);
}

public class HeadedEvent:Event
{
public string Name { get; set; }
}

如果国际章的妈妈关注这个Event, 我们就实现一个GuoJiZhangMotherEventHandler

1
2
3
4
5
6
7
public class GuoJiZhangMotherEventHandler : IEventHandler<HeadedEvent>
{
public void Handle(HeadedEvent e)
{
Console.WriteLine(e.Name+", Are you kidding me?");
}
}

如果我等屁民也关心这个事件的话,我们只需要再实现一个 PiMingEventHandler

1
2
3
4
5
6
7
public class PiMingEventHandler:IEventHandler<HeadedEvent>
{
public void Handle(HeadedEvent e)
{
Console.WriteLine(e.Name+", Guo Ji Zhang is your last wife?");
}
}

看,我们可以任意增加关注事件的代码,不用修改原来的代码吧,说好的OCP没骗你吧? 那么问题来了,发出事件的人和接受事件的人怎么联系上的?在现实世界中,我们都是订阅报纸来看头条知道的,但是代码里我们就需要一个协调者了。如是我们就需要一个EventBus, 直接上代码吧

1
2
3
4
5
6
7
8
9
10
11
12
public void Head()
{
var NewsPaper = new NewsPaper("南都娱乐");
NewsPaper.WriteToHeader("汪峰");

RaiseEvent(new HeadedEvent {Name = "汪峰"});
}

private void RaiseEvent(HeadedEvent headedEvent)
{
EventBus.Publish<HeadedEvent>(new HeadedEvent { Name = "汪峰" });
}

EventBus找出所有Handle这个事件的实现类,调用对应的Handle方法,我们可以通过Castle或者任何注入框架轻易的实现

1
2
3
4
5
6
7
8
9
10
11
public class EventBus
{
public static void Publish<T>(T concreteEvent) where T: Event
{
var handlers = _container.ResolveAll<IEventHandler<T>>();
foreach (var handle in handlers)
{
handle.Handle(concreteEvent);
}
}
}

好了,哥只负责帮汪老师上头条,上完我发出了事件通知,谁关注谁自己处理去,我的代码也不用改。

我代码实现完了,如果各位还不知道如何实现一个同步的事件驱动架构,那拜托你们找个漂亮的妹子来问我。事件驱动架构我就只能帮你到这里了。

  
 DDD

领域驱动设计系列(三):事件驱动上

前言

今天讲一下事件驱动,这个不是领域驱动设计里的事件源(Event Source), 这个以后再讲,今天主要讲一下如何用事件来解耦,主要的原因是我们有个项目有个功能我觉得用事件的方式比较好,正好写篇博客,就不用专门给他们讲了。

解耦

说到解耦,我们很熟悉分层设计,比如上层依赖于抽象,不依赖于具体的实现。比如一个类使用另一个类,我们使用接口而不直接使用实现类。

1
2
3
4
5
public EquipmentService(IEmailService emailService, IEquipmentRepository equipmentRepository)
{
_emailService = emailService;
_equipmentRepository = equipmentRepository;
}

为何用事件?

SRP (单一职责)

比如我们一个会议室预定系统,我们的一个设备坏了。我们需要通知预定这个会议室的所有人。于是我们需要发邮件。

伪代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class EquipmentService
{
private readonly IEmailService _emailService;
private readonly IEquipmentRepository _equipmentRepository;

public EquipmentService(IEmailService emailService, IEquipmentRepository equipmentRepository)
{
_emailService = emailService;
_equipmentRepository = equipmentRepository;
}

public void SetEquipmentBroken(string Id)
{
var equipment = _equipmentRepository.GetById(Id);
equipment.DeActive();

_emailService.SendEmail();
}
}

但是,问题来了,如果后来我们要说,如果设备坏了,我们要更改可用库存的数量,这时候我们是不是要在这里修改代码而引入IInventoryService? 后来如果经理说设备坏了你们尽然不告诉我,你们要闹哪样?这个时候我们是不是要修改代码引入ISMSService.Info(Manager)? 即使我们不考虑OCP原则,不考虑单一职责,我们程序员也会哭,我就DeActive一个设备,你要我做这么多事,我哪里清楚所有的功能?我就骂过程序员,你做这个功能呢为什么没考虑全!!!漏掉了这么重要的功能。

而问题,程序员从来没考虑全过,因此我就想办法如何解决这个程序员不仔细的问题。

事件驱动

因为我熟悉iOS的开发,我就想到了iOS的Notification Center. 那我我DeActive一个设备,我就只DeActive这个设备,很SRP是不是? 但是别的地方如何拿到通知? 于是事件就自然的付出水面了。如果设备被DeActive了,程序就只需要喊一声,老子把设备DeActive了,你们要闹哪样你们自己看着办,代码如下。

1
2
3
4
5
6
7
8
public void SetEquipmentBroken(string Id)
{
var equipment = _equipmentRepository.GetById(Id);
equipment.DeActive();

EventBus.Publish(new EquipmentDeActivedEvent {Id = equipment.Id});

}

这样,通知会议室预定者的模块去通知,给老板发短信的模块就通知老板就OK了。

总结

这里我们先将事件驱动,下一篇展示如何实现同步的事件,以后转换为异步那也很容易,让多个接受者处理这个事件,接受者可以是动态的哦,以后老板娘也想知道的话,代码也不用改的亲,好,我先去写实现代码去!

  
 DDD